diff --git a/.gitignore b/.gitignore
index 07a8f2b..89d4419 100644
--- a/.gitignore
+++ b/.gitignore
@@ -185,6 +185,7 @@
 /ios/build/util/CANARY_VERSION
 /ios/third_party/fishhook/src
 /ios/third_party/gcdwebserver/src
+/ios/third_party/ochamcrest/src
 /llvm
 /media/cast/logging/cast_logging_proto_lib.xml
 /media/cdm/api
@@ -342,6 +343,7 @@
 /third_party/junit/src
 /third_party/kasko
 /third_party/khronos_glcts
+/third_party/leakcanary/src
 /third_party/leveldatabase/src
 /third_party/leveldb
 /third_party/libc++-static/libc++.a
diff --git a/BUILD.gn b/BUILD.gn
index c9d40e8..5956fa4c 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -12,7 +12,6 @@
 import("//build/config/sanitizers/sanitizers.gni")
 import("//build/config/ui.gni")
 import("//build_overrides/v8.gni")
-import("//build_overrides/webrtc.gni")
 import("//media/media_options.gni")
 import("//third_party/openh264/openh264_args.gni")
 
@@ -199,22 +198,19 @@
     ]
   } else {
     deps += [
+      #"//ios/chrome:ios_chrome_unittests", TODO(GYP)
+      #"//ios/chrome/app", TODO(GYP)
+      #"//ios/chrome/browser", TODO(GYP)
+      "//ios/chrome/common",
       "//ios/net:ios_net_unittests",
+      "//ios/public/provider/chrome/browser",
       "//ios/public/provider/web",
       "//ios/testing:ocmock_support_unittest",
+      "//ios/third_party/fishhook",
+      "//ios/third_party/ochamcrest",
       "//ios/web:ios_web_unittests",
       "//ios/web/shell:ios_web_shell",
     ]
-
-    if (ios_use_webrtc) {
-      deps += [
-        "//ios/chrome:ios_chrome_unittests",
-        "//ios/chrome/app",
-        "//ios/chrome/browser",
-        "//ios/chrome/common",
-        "//ios/public/provider/chrome/browser",
-      ]
-    }
   }
 
   deps += root_extra_deps
diff --git a/DEPS b/DEPS
index 33caf860..8e937bc 100644
--- a/DEPS
+++ b/DEPS
@@ -39,19 +39,19 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'd0c4e092d54d281991ecfdc2e4ddd5217e45b42a',
+  'skia_revision': '8e9f5e39d774198a5a5d9345bc9f863e855c593b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'd096cc28cb565f7738f450add68ff32443b68339',
+  'v8_revision': '14b19be8bacdae3184e30790e67da8993000e6db',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
-  'swarming_revision': '0b908f18767c8304dc089454bc1c91755d21f1f5',
+  'swarming_revision': '71c61c858bb2c2deda83781978fe65e94171f58f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '6253415f35e07536ceace10cc9258e516b06dc7e',
+  'angle_revision': '6151af8cb21bd1991eeb79792d1030fb7a305803',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -59,7 +59,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'e4ac3369dc7bb1d0ae913404f008aea1fcd92480',
+  'pdfium_revision': '28de044e5d6ab3cb0335ad4e5dd64fdf3376b2eb',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -87,7 +87,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': '5fd19bf665dfca8fde6496065d093f147d7793d9',
+  'nacl_revision': '6c6f5e2b5863b83e6ba079970fcd20d72957c0c6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling dEQP
   # and whatever else without interference from each other.
@@ -134,7 +134,7 @@
    Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'e466f6ac8f60bb9697af4a91c6911c6fc4aec95f',
 
   'src/third_party/libexif/sources':
-   Var('chromium_git') + '/chromium/deps/libexif/sources.git' + '@' + '045b7fb9aa6d9b7f1954db248caf5eefe917476d',
+   Var('chromium_git') + '/chromium/deps/libexif/sources.git' + '@' + '9d467f7d21e4749ee22ee7520e561ac7b38484b9',
 
   'src/third_party/hunspell_dictionaries':
    Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + 'c106afdcec5d3de2622e19f1b3294c47bbd8bd72',
@@ -188,7 +188,7 @@
    Var('chromium_git') + '/webm/libvpx.git' + '@' +  '89cc68252846478fa7f2d570d96ff93776cefac6',
 
   'src/third_party/ffmpeg':
-   Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'e6e47f514216bbcdbfe796eb1f398c9afece93c8',
+   Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'b828a1bc02572754455e97508e4b78fc06d5e6fa',
 
   'src/third_party/libjingle/source/talk':
     Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + '761433d1de0c48512861d6077f821fb328456cda', # commit position 11592
@@ -275,7 +275,7 @@
 
   'src/third_party/catapult':
     Var('chromium_git') + '/external/github.com/catapult-project/catapult.git' + '@' +
-    '93b42473c3ae3106080f07a1ff4e391e8b1d1791',
+    '89c5cbe52157736332fd2ae17dbeab372f09e818',
 
   'src/third_party/openh264/src':
     Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + 'b37cda248234162033e3e11b0335f3131cdfe488',
@@ -341,6 +341,9 @@
     'src/ios/third_party/gcdwebserver/src':
      Var('chromium_git') + '/external/github.com/swisspol/GCDWebServer.git' + '@' + '3d5fd0b8281a7224c057deb2d17709b5bea64836',
 
+    'src/ios/third_party/ochamcrest/src':
+     Var('chromium_git') + '/external/github.com/hamcrest/OCHamcrest.git' + '@' + '5b50930c66d1e537918a87eef0943d6750729dc5',
+
     'src/third_party/google_toolbox_for_mac/src':
       Var('chromium_git') + '/external/github.com/google/google-toolbox-for-mac.git' + '@' + Var('google_toolbox_for_mac_revision'),
 
@@ -498,6 +501,9 @@
     'src/third_party/ub-uiautomator/lib':
       Var('chromium_git') + '/chromium/third_party/ub-uiautomator.git' + '@' + '00270549ce3161ae72ceb24712618ea28b4f9434',
 
+    'src/third_party/leakcanary/src':
+      Var('chromium_git') + '/external/github.com/square/leakcanary.git' + '@' + '608ded739e036a3aa69db47ac43777dcee506f8e',
+
     'src/third_party/lss':
       Var('chromium_git') + '/external/linux-syscall-support/lss.git' + '@' + Var('lss_revision'),
 
diff --git a/OWNERS b/OWNERS
index 5c3e10b7..56659aa51 100644
--- a/OWNERS
+++ b/OWNERS
@@ -5,6 +5,8 @@
 jam@chromium.org
 
 per-file .gitignore=*
+per-file .git-blame-ignore-revs=mgiuca@chromium.org
+per-file .git-blame-ignore-revs=thakis@chromium.org
 per-file BUILD.gn=dpranke@chromium.org
 per-file DEPS=*
 per-file AUTHORS=*
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 81b3710..10f7ac06 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -171,6 +171,8 @@
         r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]"
             "customization_document_browsertest\.cc$",
         r"^components[\\\/]crash[\\\/]app[\\\/]breakpad_mac\.mm$",
+        r"^content[\\\/]shell[\\\/]browser[\\\/]layout_test[\\\/]" +
+            r"test_info_extractor\.cc$",
         r"^content[\\\/]shell[\\\/]browser[\\\/]shell_browser_main\.cc$",
         r"^content[\\\/]shell[\\\/]browser[\\\/]shell_message_filter\.cc$",
         r"^mojo[\\\/]edk[\\\/]embedder[\\\/]" +
@@ -1559,7 +1561,9 @@
   return [output_api.PresubmitError(
       "Found new compiled_resources.gyp files:\n%s\n\n"
       "compiled_resources.gyp files are deprecated,\n"
-      "please use compiled_resources2.gyp instead" %
+      "please use compiled_resources2.gyp instead:\n"
+      "https://chromium.googlesource.com/chromium/src/+/master/docs/closure_compilation.md"
+      %
       "\n".join(added_compiled_resources))]
 
 
diff --git a/WATCHLISTS b/WATCHLISTS
index e48ecbfb..2c59a76 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -376,9 +376,6 @@
                   'components/gcm_driver/|'\
                   'google_apis/gcm/',
     },
-    'gcm_crypto': {
-      'filepath': 'components/gcm_driver/crypto/',
-    },
     'geolocation': {
       'filepath': 'chrome/browser/geolocation/|'\
                   'content/browser/geolocation|'\
@@ -1363,8 +1360,8 @@
     'filebrowse': ['rginda+watch@chromium.org'],
     'filesapp': ['mtomasz+watch@chromium.org'],
     'ftp': ['phajdan.jr@chromium.org'],
-    'gcm': ['zea+watch@chromium.org'],
-    'gcm_crypto': ['peter@chromium.org'],
+    'gcm': ['zea+watch@chromium.org', 'peter@chromium.org',
+            'johnme+watch@chromium.org'],
     'geolocation': ['mvanouwerkerk@chromium.org',
                     'mlamouri+watch-geolocation@chromium.org'],
     'gfx_geometry': ['cc-bugs@chromium.org'],
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index aee8ff3..c9505c3 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -448,6 +448,10 @@
     "browser/net/android_stream_reader_url_request_job.h",
     "browser/net/aw_http_user_agent_settings.cc",
     "browser/net/aw_http_user_agent_settings.h",
+    "browser/net/aw_network_change_notifier.cc",
+    "browser/net/aw_network_change_notifier.h",
+    "browser/net/aw_network_change_notifier_factory.cc",
+    "browser/net/aw_network_change_notifier_factory.h",
     "browser/net/aw_network_delegate.cc",
     "browser/net/aw_network_delegate.h",
     "browser/net/aw_request_interceptor.cc",
diff --git a/android_webview/android_webview.gyp b/android_webview/android_webview.gyp
index 7b09e43..f9cd1830 100644
--- a/android_webview/android_webview.gyp
+++ b/android_webview/android_webview.gyp
@@ -352,6 +352,10 @@
         'browser/net/android_stream_reader_url_request_job.h',
         'browser/net/aw_http_user_agent_settings.h',
         'browser/net/aw_http_user_agent_settings.cc',
+        'browser/net/aw_network_change_notifier.cc',
+        'browser/net/aw_network_change_notifier.h',
+        'browser/net/aw_network_change_notifier_factory.cc',
+        'browser/net/aw_network_change_notifier_factory.h',
         'browser/net/aw_network_delegate.cc',
         'browser/net/aw_network_delegate.h',
         'browser/net/aw_request_interceptor.cc',
diff --git a/android_webview/browser/aw_browser_main_parts.cc b/android_webview/browser/aw_browser_main_parts.cc
index c598a16d..54a3a52 100644
--- a/android_webview/browser/aw_browser_main_parts.cc
+++ b/android_webview/browser/aw_browser_main_parts.cc
@@ -9,6 +9,7 @@
 #include "android_webview/browser/aw_media_client_android.h"
 #include "android_webview/browser/aw_result_codes.h"
 #include "android_webview/browser/deferred_gpu_command_service.h"
+#include "android_webview/browser/net/aw_network_change_notifier_factory.h"
 #include "android_webview/common/aw_resource.h"
 #include "android_webview/common/aw_switches.h"
 #include "base/android/apk_assets.h"
@@ -46,8 +47,7 @@
 }
 
 void AwBrowserMainParts::PreEarlyInitialization() {
-  net::NetworkChangeNotifier::SetFactory(
-      new net::NetworkChangeNotifierFactoryAndroid());
+  net::NetworkChangeNotifier::SetFactory(new AwNetworkChangeNotifierFactory());
 
   // Android WebView does not use default MessageLoop. It has its own
   // Android specific MessageLoop. Also see MainMessageLoopRun.
diff --git a/android_webview/browser/aw_metrics_service_client.cc b/android_webview/browser/aw_metrics_service_client.cc
index 26d465f..68a485e1 100644
--- a/android_webview/browser/aw_metrics_service_client.cc
+++ b/android_webview/browser/aw_metrics_service_client.cc
@@ -46,7 +46,7 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
 
   // Try to read an existing GUID.
-  if (base::ReadFileToString(guid_file_path, guid, GUID_SIZE)) {
+  if (base::ReadFileToStringWithMaxSize(guid_file_path, guid, GUID_SIZE)) {
     if (base::IsValidGUID(*guid))
       return;
     else
diff --git a/android_webview/browser/net/android_stream_reader_url_request_job.cc b/android_webview/browser/net/android_stream_reader_url_request_job.cc
index 7ad10928..091c237a7 100644
--- a/android_webview/browser/net/android_stream_reader_url_request_job.cc
+++ b/android_webview/browser/net/android_stream_reader_url_request_job.cc
@@ -23,7 +23,6 @@
 #include "content/public/browser/browser_thread.h"
 #include "net/base/io_buffer.h"
 #include "net/base/mime_util.h"
-#include "net/base/net_util.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_response_info.h"
 #include "net/http/http_util.h"
diff --git a/android_webview/browser/net/aw_network_change_notifier.cc b/android_webview/browser/net/aw_network_change_notifier.cc
new file mode 100644
index 0000000..f91aefc
--- /dev/null
+++ b/android_webview/browser/net/aw_network_change_notifier.cc
@@ -0,0 +1,82 @@
+// Copyright 2016 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 "android_webview/browser/net/aw_network_change_notifier.h"
+
+namespace android_webview {
+
+AwNetworkChangeNotifier::~AwNetworkChangeNotifier() {
+  delegate_->RemoveObserver(this);
+}
+
+net::NetworkChangeNotifier::ConnectionType
+AwNetworkChangeNotifier::GetCurrentConnectionType() const {
+  return delegate_->GetCurrentConnectionType();
+}
+
+void AwNetworkChangeNotifier::GetCurrentMaxBandwidthAndConnectionType(
+    double* max_bandwidth_mbps,
+    ConnectionType* connection_type) const {
+  delegate_->GetCurrentMaxBandwidthAndConnectionType(max_bandwidth_mbps,
+                                                     connection_type);
+}
+
+bool AwNetworkChangeNotifier::AreNetworkHandlesCurrentlySupported() const {
+  return false;
+}
+
+void AwNetworkChangeNotifier::GetCurrentConnectedNetworks(
+    NetworkChangeNotifier::NetworkList* networks) const {
+  delegate_->GetCurrentlyConnectedNetworks(networks);
+}
+
+net::NetworkChangeNotifier::ConnectionType
+AwNetworkChangeNotifier::GetCurrentNetworkConnectionType(
+    NetworkHandle network) const {
+  return delegate_->GetNetworkConnectionType(network);
+}
+
+net::NetworkChangeNotifier::NetworkHandle
+AwNetworkChangeNotifier::GetCurrentDefaultNetwork() const {
+  return delegate_->GetCurrentDefaultNetwork();
+}
+
+void AwNetworkChangeNotifier::OnConnectionTypeChanged() {}
+
+void AwNetworkChangeNotifier::OnMaxBandwidthChanged(
+    double max_bandwidth_mbps,
+    ConnectionType type) {
+  // Note that this callback is sufficient for Network Information API because
+  // it also occurs on type changes (see network_change_notifier.h).
+  NetworkChangeNotifier::NotifyObserversOfMaxBandwidthChange(max_bandwidth_mbps,
+                                                             type);
+}
+
+void AwNetworkChangeNotifier::OnNetworkConnected(NetworkHandle network) {}
+void AwNetworkChangeNotifier::OnNetworkSoonToDisconnect(
+    NetworkHandle network) {}
+void AwNetworkChangeNotifier::OnNetworkDisconnected(
+    NetworkHandle network) {}
+void AwNetworkChangeNotifier::OnNetworkMadeDefault(NetworkHandle network){}
+
+AwNetworkChangeNotifier::AwNetworkChangeNotifier(
+    net::NetworkChangeNotifierDelegateAndroid* delegate)
+    : net::NetworkChangeNotifier(DefaultNetworkChangeCalculatorParams()),
+      delegate_(delegate) {
+  delegate_->AddObserver(this);
+}
+
+// static
+net::NetworkChangeNotifier::NetworkChangeCalculatorParams
+AwNetworkChangeNotifier::DefaultNetworkChangeCalculatorParams() {
+  net::NetworkChangeNotifier::NetworkChangeCalculatorParams params;
+  // Use defaults as in network_change_notifier_android.cc
+  params.ip_address_offline_delay_ = base::TimeDelta::FromSeconds(1);
+  params.ip_address_online_delay_ = base::TimeDelta::FromSeconds(1);
+  params.connection_type_offline_delay_ = base::TimeDelta::FromSeconds(0);
+  params.connection_type_online_delay_ = base::TimeDelta::FromSeconds(0);
+  return params;
+}
+
+}  // namespace android_webview
diff --git a/android_webview/browser/net/aw_network_change_notifier.h b/android_webview/browser/net/aw_network_change_notifier.h
new file mode 100644
index 0000000..6fc25b0
--- /dev/null
+++ b/android_webview/browser/net/aw_network_change_notifier.h
@@ -0,0 +1,66 @@
+// Copyright 2016 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 ANDROID_WEBVIEW_BROWSER_NET_AW_NETWORK_CHANGE_NOTIFIER_H_
+#define ANDROID_WEBVIEW_BROWSER_NET_AW_NETWORK_CHANGE_NOTIFIER_H_
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "net/android/network_change_notifier_delegate_android.h"
+#include "net/base/network_change_notifier.h"
+
+namespace android_webview {
+
+// AwNetworkChangeNotifier is similar to NetworkChangeNotifierAndroid except
+// it only propagates max-bandwidth changes in order to make the Network
+// Information API work in blink.
+//
+// This somewhat reduced functionality is necessary because of the way
+// NetworkChangeNotifier is enabled in WebView. It is enabled only when there
+// are living WebView instances (instead of using ApplicationStatus) hence the
+// existing Chrome for Android implementation is not applicable as is
+// (see crbug.com/529434).
+class AwNetworkChangeNotifier
+    : public net::NetworkChangeNotifier,
+      public net::NetworkChangeNotifierDelegateAndroid::Observer {
+ public:
+  ~AwNetworkChangeNotifier() override;
+
+  // NetworkChangeNotifier:
+  ConnectionType GetCurrentConnectionType() const override;
+  // Requires ACCESS_WIFI_STATE permission in order to provide precise WiFi link
+  // speed.
+  void GetCurrentMaxBandwidthAndConnectionType(
+      double* max_bandwidth_mbps,
+      ConnectionType* connection_type) const override;
+  bool AreNetworkHandlesCurrentlySupported() const override;
+  void GetCurrentConnectedNetworks(NetworkList* network_list) const override;
+  ConnectionType GetCurrentNetworkConnectionType(
+      NetworkHandle network) const override;
+  NetworkHandle GetCurrentDefaultNetwork() const override;
+
+  // NetworkChangeNotifierDelegateAndroid::Observer:
+  void OnConnectionTypeChanged() override;
+  void OnMaxBandwidthChanged(double max_bandwidth_mbps,
+                             ConnectionType type) override;
+  void OnNetworkConnected(NetworkHandle network) override;
+  void OnNetworkSoonToDisconnect(NetworkHandle network) override;
+  void OnNetworkDisconnected(NetworkHandle network) override;
+  void OnNetworkMadeDefault(NetworkHandle network) override;
+
+ private:
+  friend class AwNetworkChangeNotifierFactory;
+
+  AwNetworkChangeNotifier(net::NetworkChangeNotifierDelegateAndroid* delegate);
+
+  static NetworkChangeCalculatorParams DefaultNetworkChangeCalculatorParams();
+
+  net::NetworkChangeNotifierDelegateAndroid* const delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(AwNetworkChangeNotifier);
+};
+
+}  // namespace android_webview
+
+#endif  // ANDROID_WEBVIEW_BROWSER_NET_AW_NETWORK_CHANGE_NOTIFIER_H_
diff --git a/android_webview/browser/net/aw_network_change_notifier_factory.cc b/android_webview/browser/net/aw_network_change_notifier_factory.cc
new file mode 100644
index 0000000..f05627f9
--- /dev/null
+++ b/android_webview/browser/net/aw_network_change_notifier_factory.cc
@@ -0,0 +1,19 @@
+// Copyright 2016 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 "android_webview/browser/net/aw_network_change_notifier_factory.h"
+
+#include "android_webview/browser/net/aw_network_change_notifier.h"
+
+namespace android_webview {
+
+AwNetworkChangeNotifierFactory::AwNetworkChangeNotifierFactory() {}
+
+AwNetworkChangeNotifierFactory::~AwNetworkChangeNotifierFactory() {}
+
+net::NetworkChangeNotifier* AwNetworkChangeNotifierFactory::CreateInstance() {
+  return new AwNetworkChangeNotifier(&delegate_);
+}
+
+}  // namespace android_webview
diff --git a/android_webview/browser/net/aw_network_change_notifier_factory.h b/android_webview/browser/net/aw_network_change_notifier_factory.h
new file mode 100644
index 0000000..6cfbd20
--- /dev/null
+++ b/android_webview/browser/net/aw_network_change_notifier_factory.h
@@ -0,0 +1,41 @@
+// Copyright 2016 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 ANDROID_WEBVIEW_NET_AW_NETWORK_CHANGE_NOTIFIER_FACTORY_H_
+#define ANDROID_WEBVIEW_NET_AW_NETWORK_CHANGE_NOTIFIER_FACTORY_H_
+
+#include "net/android/network_change_notifier_delegate_android.h"
+#include "net/base/network_change_notifier_factory.h"
+
+namespace net {
+class NetworkChangeNotifier;
+class NetworkChangeNotifierDelegateAndroid;
+}
+
+namespace android_webview {
+
+// AwNetworkChangeNotifierFactory creates WebView-specific specialization of
+// NetworkChangeNotifier. See aw_network_change_notifier.h for more details.
+class AwNetworkChangeNotifierFactory :
+    public net::NetworkChangeNotifierFactory {
+ public:
+  // Must be called on the JNI thread.
+  AwNetworkChangeNotifierFactory();
+
+  // Must be called on the JNI thread.
+  ~AwNetworkChangeNotifierFactory() override;
+
+  // NetworkChangeNotifierFactory:
+  net::NetworkChangeNotifier* CreateInstance() override;
+
+ private:
+  // Delegate passed to the instances created by this class.
+  net::NetworkChangeNotifierDelegateAndroid delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(AwNetworkChangeNotifierFactory);
+};
+
+}  // namespace android_webview
+
+#endif  // ANDROID_WEBVIEW_NET_AW_NETWORK_CHANGE_NOTIFIER_FACTORY_H_
diff --git a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc
index 93045f3..5588193 100644
--- a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc
+++ b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc
@@ -80,6 +80,8 @@
   int render_frame_id() const { return render_frame_id_; }
 
  private:
+  scoped_ptr<AwContentsIoThreadClient> GetIoThreadClient() const;
+
   int render_process_id_;
   int render_frame_id_;
   net::URLRequest* request_;
@@ -102,17 +104,23 @@
   return "IoThreadClientThrottle";
 }
 
+scoped_ptr<AwContentsIoThreadClient>
+IoThreadClientThrottle::GetIoThreadClient() const {
+  if (content::ResourceRequestInfo::OriginatedFromServiceWorker(request_))
+    return AwContentsIoThreadClient::GetServiceWorkerIoThreadClient();
+
+  return AwContentsIoThreadClient::FromID(render_process_id_, render_frame_id_);
+}
+
 void IoThreadClientThrottle::WillStartRequest(bool* defer) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  if (render_frame_id_ < 1)
-    return;
-  DCHECK(render_process_id_);
+  // valid render_frame_id_ implies nonzero render_processs_id_
+  DCHECK((render_frame_id_ < 1) || (render_process_id_ != 0));
   *defer = false;
 
   // Defer all requests of a pop up that is still not associated with Java
   // client so that the client will get a chance to override requests.
-  scoped_ptr<AwContentsIoThreadClient> io_client =
-      AwContentsIoThreadClient::FromID(render_process_id_, render_frame_id_);
+  scoped_ptr<AwContentsIoThreadClient> io_client = GetIoThreadClient();
   if (io_client && io_client->PendingAssociation()) {
     *defer = true;
     AwResourceDispatcherHostDelegate::AddPendingThrottle(
@@ -146,8 +154,7 @@
 }
 
 bool IoThreadClientThrottle::ShouldBlockRequest() {
-  scoped_ptr<AwContentsIoThreadClient> io_client =
-      AwContentsIoThreadClient::FromID(render_process_id_, render_frame_id_);
+  scoped_ptr<AwContentsIoThreadClient> io_client = GetIoThreadClient();
   if (!io_client)
     return false;
 
diff --git a/android_webview/glue/glue.gni b/android_webview/glue/glue.gni
index fc9c65ab..e49cd3d6 100644
--- a/android_webview/glue/glue.gni
+++ b/android_webview/glue/glue.gni
@@ -11,6 +11,7 @@
   "//content/public/android:content_java",
   "//content/public/android:content_java_resources",
   "//components/web_contents_delegate_android:web_contents_delegate_android_java_resources",
+  "//net/android:net_java",
   "//ui/android:ui_java",
   "//ui/android:ui_java_resources",
 ]
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
index 4eb0eb7..3b4d3a4 100644
--- a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
+++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
@@ -34,6 +34,7 @@
 import org.chromium.android_webview.AwCookieManager;
 import org.chromium.android_webview.AwDataReductionProxyManager;
 import org.chromium.android_webview.AwDevToolsServer;
+import org.chromium.android_webview.AwNetworkChangeNotifierRegistrationPolicy;
 import org.chromium.android_webview.AwQuotaManagerBridge;
 import org.chromium.android_webview.AwResource;
 import org.chromium.android_webview.AwSettings;
@@ -50,6 +51,7 @@
 import org.chromium.base.library_loader.LibraryProcessType;
 import org.chromium.base.library_loader.ProcessInitException;
 import org.chromium.content.browser.ContentViewStatics;
+import org.chromium.net.NetworkChangeNotifier;
 import org.chromium.ui.base.ResourceBundle;
 
 import java.io.File;
@@ -119,13 +121,6 @@
             CommandLine.init(null);
         }
 
-        CommandLine cl = CommandLine.getInstance();
-        // TODO: currently in a relase build the DCHECKs only log. We either need to insall
-        // a report handler with SetLogReportHandler to make them assert, or else compile
-        // them out of the build altogether (b/8284203). Either way, so long they're
-        // compiled in, we may as unconditionally enable them here.
-        cl.appendSwitch("enable-dcheck");
-
         ThreadUtils.setWillOverrideUiThread();
         // Load chromium library.
         AwBrowserProcess.loadLibrary(getWrappedCurrentApplicationContext());
@@ -248,6 +243,9 @@
         setUpResources(webViewPackageName, context);
         ResourceBundle.initializeLocalePaks(context, R.array.locale_paks);
         initPlatSupportLibrary();
+        NetworkChangeNotifier.init(context);
+        NetworkChangeNotifier.setAutoDetectConnectivityState(
+                new AwNetworkChangeNotifierRegistrationPolicy());
         final int extraBindFlags = 0;
         AwBrowserProcess.configureChildProcessLauncher(webViewPackageName, extraBindFlags);
         AwBrowserProcess.start(context);
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index a710d51..7ec965f 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -69,6 +69,7 @@
 import org.chromium.content_public.browser.navigation_controller.UserAgentOverrideOption;
 import org.chromium.content_public.common.Referrer;
 import org.chromium.net.NetError;
+import org.chromium.net.NetworkChangeNotifier;
 import org.chromium.ui.base.ActivityWindowAndroid;
 import org.chromium.ui.base.PageTransition;
 import org.chromium.ui.base.WindowAndroid;
@@ -2536,7 +2537,13 @@
 
     public void setNetworkAvailable(boolean networkUp) {
         if (TRACE) Log.d(TAG, "setNetworkAvailable=%s", networkUp);
-        if (!isDestroyed(WARN)) nativeSetJsOnlineProperty(mNativeAwContents, networkUp);
+        if (!isDestroyed(WARN)) {
+            // For backward compatibility when an app uses this API disable the
+            // Network Information API to prevent inconsistencies,
+            // see crbug.com/520088.
+            NetworkChangeNotifier.setAutoDetectConnectivityState(false);
+            nativeSetJsOnlineProperty(mNativeAwContents, networkUp);
+        }
     }
 
     /**
diff --git a/android_webview/java/src/org/chromium/android_webview/AwNetworkChangeNotifierRegistrationPolicy.java b/android_webview/java/src/org/chromium/android_webview/AwNetworkChangeNotifierRegistrationPolicy.java
new file mode 100644
index 0000000..798a9af
--- /dev/null
+++ b/android_webview/java/src/org/chromium/android_webview/AwNetworkChangeNotifierRegistrationPolicy.java
@@ -0,0 +1,37 @@
+// Copyright 2016 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.
+
+package org.chromium.android_webview;
+
+import org.chromium.net.NetworkChangeNotifierAutoDetect;
+
+/**
+ * Registration policy to make sure we only listen to network changes when
+ * there are live webview instances.
+ */
+public class AwNetworkChangeNotifierRegistrationPolicy
+        extends NetworkChangeNotifierAutoDetect.RegistrationPolicy
+        implements AwContentsLifecycleNotifier.Observer {
+
+    @Override
+    protected void init(NetworkChangeNotifierAutoDetect notifier) {
+        super.init(notifier);
+        AwContentsLifecycleNotifier.addObserver(this);
+    }
+
+    protected void destroy() {
+        AwContentsLifecycleNotifier.removeObserver(this);
+    }
+
+    // AwContentsLifecycleNotifier.Observer
+    @Override
+    public void onFirstWebViewCreated() {
+        register();
+    }
+
+    @Override
+    public void onLastWebViewDestroyed() {
+        unregister();
+    }
+}
diff --git a/android_webview/native/android_protocol_handler.cc b/android_webview/native/android_protocol_handler.cc
index 4ae10a4..a04e5d9 100644
--- a/android_webview/native/android_protocol_handler.cc
+++ b/android_webview/native/android_protocol_handler.cc
@@ -19,7 +19,6 @@
 #include "net/base/io_buffer.h"
 #include "net/base/mime_util.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/http/http_util.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_interceptor.h"
diff --git a/android_webview/tools/WebViewShell/res/menu/main_menu.xml b/android_webview/tools/WebViewShell/res/menu/main_menu.xml
index a22610d..f577c7c 100644
--- a/android_webview/tools/WebViewShell/res/menu/main_menu.xml
+++ b/android_webview/tools/WebViewShell/res/menu/main_menu.xml
@@ -6,6 +6,8 @@
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:id="@+id/menu_reset_webview"
           android:title="@string/menu_reset_webview"/>
+    <item android:id="@+id/menu_clear_cache"
+          android:title="@string/menu_clear_cache"/>
     <item android:id="@+id/menu_about"
           android:title="@string/menu_about"/>
 </menu>
diff --git a/android_webview/tools/WebViewShell/res/values/strings.xml b/android_webview/tools/WebViewShell/res/values/strings.xml
index 82ccaea0..3dfcc780 100644
--- a/android_webview/tools/WebViewShell/res/values/strings.xml
+++ b/android_webview/tools/WebViewShell/res/values/strings.xml
@@ -13,6 +13,7 @@
     <string name="title_activity_layout_test">WebView Layout Test</string>
     <string name="title_activity_page_cycler">WebView Page Cycler Test</string>
     <string name="menu_reset_webview">Destroy and create new WebView</string>
+    <string name="menu_clear_cache">Clear cache</string>
     <string name="menu_about">About WebView</string>
     <string name="load_url">Load URL</string>
 </resources>
diff --git a/android_webview/tools/WebViewShell/src/org/chromium/webview_shell/WebViewBrowserActivity.java b/android_webview/tools/WebViewShell/src/org/chromium/webview_shell/WebViewBrowserActivity.java
index 4c748fd..2aee9e37 100644
--- a/android_webview/tools/WebViewShell/src/org/chromium/webview_shell/WebViewBrowserActivity.java
+++ b/android_webview/tools/WebViewShell/src/org/chromium/webview_shell/WebViewBrowserActivity.java
@@ -360,6 +360,11 @@
                 }
                 createAndInitializeWebView();
                 return true;
+            case R.id.menu_clear_cache:
+                if (mWebView != null) {
+                    mWebView.clearCache(true);
+                }
+                return true;
             case R.id.menu_about:
                 about();
                 hideKeyboard(mUrlBar);
diff --git a/android_webview/tools/WebViewShell/test/webexposed/global-interface-listing-expected.txt b/android_webview/tools/WebViewShell/test/webexposed/global-interface-listing-expected.txt
index da2b84ac..620d2ec 100644
--- a/android_webview/tools/WebViewShell/test/webexposed/global-interface-listing-expected.txt
+++ b/android_webview/tools/WebViewShell/test/webexposed/global-interface-listing-expected.txt
@@ -3516,11 +3516,6 @@
     method constructor
 interface SVGElement : Element
     getter className
-    getter offsetHeight
-    getter offsetLeft
-    getter offsetParent
-    getter offsetTop
-    getter offsetWidth
     getter onabort
     getter onblur
     getter oncancel
diff --git a/apps/DEPS b/apps/DEPS
index e2f3d695..d1ec499 100644
--- a/apps/DEPS
+++ b/apps/DEPS
@@ -30,6 +30,7 @@
   # Pieces of the extensions system that need to move to src/extensions.
   # See http://crbug.com/162530 for details.
   "+chrome/browser/extensions/api/file_handlers/app_file_handler_util.h",
+  "+chrome/browser/extensions/api/file_handlers/directory_util.h",
   "+chrome/browser/extensions/api/file_handlers/mime_util.h",
   "+chrome/browser/extensions/api/file_system/file_system_api.h",
   "+chrome/browser/extensions/chrome_extension_web_contents_observer.h",
diff --git a/apps/launcher.cc b/apps/launcher.cc
index 9b01a4d0..2ae064873 100644
--- a/apps/launcher.cc
+++ b/apps/launcher.cc
@@ -12,9 +12,11 @@
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
+#include "chrome/browser/extensions/api/file_handlers/directory_util.h"
 #include "chrome/browser/extensions/api/file_handlers/mime_util.h"
 #include "chrome/browser/extensions/api/file_system/file_system_api.h"
 #include "chrome/browser/profiles/profile.h"
@@ -24,6 +26,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
 #include "extensions/browser/api/app_runtime/app_runtime_api.h"
+#include "extensions/browser/entry_info.h"
 #include "extensions/browser/event_router.h"
 #include "extensions/browser/extension_host.h"
 #include "extensions/browser/extension_prefs.h"
@@ -35,7 +38,6 @@
 #include "extensions/common/extension.h"
 #include "extensions/common/manifest_handlers/kiosk_mode_info.h"
 #include "net/base/filename_util.h"
-#include "net/base/net_util.h"
 #include "url/gurl.h"
 
 #if defined(OS_CHROMEOS)
@@ -47,9 +49,9 @@
 using content::BrowserThread;
 using extensions::AppRuntimeEventRouter;
 using extensions::app_file_handler_util::CreateFileEntry;
-using extensions::app_file_handler_util::FileHandlerCanHandleFile;
+using extensions::app_file_handler_util::FileHandlerCanHandleEntry;
 using extensions::app_file_handler_util::FileHandlerForId;
-using extensions::app_file_handler_util::FirstFileHandlerForFile;
+using extensions::app_file_handler_util::FirstFileHandlerForEntry;
 using extensions::app_file_handler_util::HasFileSystemWritePermission;
 using extensions::app_file_handler_util::PrepareFilesForWritableApp;
 using extensions::EventRouter;
@@ -94,18 +96,22 @@
  public:
   PlatformAppPathLauncher(Profile* profile,
                           const Extension* extension,
-                          const std::vector<base::FilePath>& file_paths)
+                          const std::vector<base::FilePath>& entry_paths)
       : profile_(profile),
         extension_id(extension->id()),
-        file_paths_(file_paths),
-        collector_(profile) {}
+        entry_paths_(entry_paths),
+        mime_type_collector_(profile),
+        is_directory_collector_(profile) {}
 
   PlatformAppPathLauncher(Profile* profile,
                           const Extension* extension,
                           const base::FilePath& file_path)
-      : profile_(profile), extension_id(extension->id()), collector_(profile) {
+      : profile_(profile),
+        extension_id(extension->id()),
+        mime_type_collector_(profile),
+        is_directory_collector_(profile) {
     if (!file_path.empty())
-      file_paths_.push_back(file_path);
+      entry_paths_.push_back(file_path);
   }
 
   void Launch() {
@@ -115,26 +121,19 @@
     if (!extension)
       return;
 
-    if (file_paths_.empty()) {
+    if (entry_paths_.empty()) {
       LaunchWithNoLaunchData();
       return;
     }
 
-    for (size_t i = 0; i < file_paths_.size(); ++i) {
-      DCHECK(file_paths_[i].IsAbsolute());
+    for (size_t i = 0; i < entry_paths_.size(); ++i) {
+      DCHECK(entry_paths_[i].IsAbsolute());
     }
 
-    if (HasFileSystemWritePermission(extension)) {
-      PrepareFilesForWritableApp(
-          file_paths_,
-          profile_,
-          false,
-          base::Bind(&PlatformAppPathLauncher::OnFilesValid, this),
-          base::Bind(&PlatformAppPathLauncher::OnFilesInvalid, this));
-      return;
-    }
-
-    OnFilesValid();
+    is_directory_collector_.CollectForEntriesPaths(
+        entry_paths_,
+        base::Bind(&PlatformAppPathLauncher::OnAreDirectoriesCollected, this,
+                   HasFileSystemWritePermission(extension)));
   }
 
   void LaunchWithHandler(const std::string& handler_id) {
@@ -159,9 +158,8 @@
   void MakePathAbsolute(const base::FilePath& current_directory) {
     DCHECK_CURRENTLY_ON(BrowserThread::FILE);
 
-    for (std::vector<base::FilePath>::iterator it = file_paths_.begin();
-         it != file_paths_.end();
-         ++it) {
+    for (std::vector<base::FilePath>::iterator it = entry_paths_.begin();
+         it != entry_paths_.end(); ++it) {
       if (!DoMakePathAbsolute(current_directory, &*it)) {
         LOG(WARNING) << "Cannot make absolute path from " << it->value();
         BrowserThread::PostTask(
@@ -177,10 +175,12 @@
                             base::Bind(&PlatformAppPathLauncher::Launch, this));
   }
 
-  void OnFilesValid() {
-    collector_.CollectForLocalPaths(
-        file_paths_,
-        base::Bind(&PlatformAppPathLauncher::OnMimeTypesCollected, this));
+  void OnFilesValid(scoped_ptr<std::set<base::FilePath>> directory_paths) {
+    mime_type_collector_.CollectForLocalPaths(
+        entry_paths_,
+        base::Bind(
+            &PlatformAppPathLauncher::OnAreDirectoriesAndMimeTypesCollected,
+            this, base::Passed(std::move(directory_paths))));
   }
 
   void OnFilesInvalid(const base::FilePath& /* error_path */) {
@@ -199,45 +199,60 @@
         profile_, extension, extensions::SOURCE_FILE_HANDLER);
   }
 
-  void OnMimeTypesCollected(scoped_ptr<std::vector<std::string> > mime_types) {
-    DCHECK(file_paths_.size() == mime_types->size());
+  void OnAreDirectoriesCollected(
+      bool has_file_system_write_permission,
+      scoped_ptr<std::set<base::FilePath>> directory_paths) {
+    if (has_file_system_write_permission) {
+      std::set<base::FilePath>* const directory_paths_ptr =
+          directory_paths.get();
+      PrepareFilesForWritableApp(
+          entry_paths_, profile_, *directory_paths_ptr,
+          base::Bind(&PlatformAppPathLauncher::OnFilesValid, this,
+                     base::Passed(std::move(directory_paths))),
+          base::Bind(&PlatformAppPathLauncher::OnFilesInvalid, this));
+      return;
+    }
+
+    OnFilesValid(std::move(directory_paths));
+  }
+
+  void OnAreDirectoriesAndMimeTypesCollected(
+      scoped_ptr<std::set<base::FilePath>> directory_paths,
+      scoped_ptr<std::vector<std::string>> mime_types) {
+    DCHECK(entry_paths_.size() == mime_types->size());
+    // If fetching a mime type failed, then use a fallback one.
+    for (size_t i = 0; i < entry_paths_.size(); ++i) {
+      const std::string mime_type =
+          !(*mime_types)[i].empty() ? (*mime_types)[i] : kFallbackMimeType;
+      bool is_directory =
+          directory_paths->find(entry_paths_[i]) != directory_paths->end();
+      entries_.push_back(
+          extensions::EntryInfo(entry_paths_[i], mime_type, is_directory));
+    }
 
     const Extension* extension = GetExtension();
     if (!extension)
       return;
 
-    // If fetching a mime type failed, then use a fallback one.
-    for (size_t i = 0; i < mime_types->size(); ++i) {
-      const std::string mime_type =
-          !(*mime_types)[i].empty() ? (*mime_types)[i] : kFallbackMimeType;
-      mime_types_.push_back(mime_type);
-    }
-
     // Find file handler from the platform app for the file being opened.
     const extensions::FileHandlerInfo* handler = NULL;
     if (!handler_id_.empty()) {
       handler = FileHandlerForId(*extension, handler_id_);
       if (handler) {
-        for (size_t i = 0; i < file_paths_.size(); ++i) {
-          if (!FileHandlerCanHandleFile(
-                  *handler, mime_types_[i], file_paths_[i])) {
+        for (size_t i = 0; i < entry_paths_.size(); ++i) {
+          if (!FileHandlerCanHandleEntry(*handler, entries_[i])) {
             LOG(WARNING)
                 << "Extension does not provide a valid file handler for "
-                << file_paths_[i].value();
+                << entry_paths_[i].value();
             handler = NULL;
             break;
           }
         }
       }
     } else {
-      std::set<std::pair<base::FilePath, std::string> > path_and_file_type_set;
-      for (size_t i = 0; i < file_paths_.size(); ++i) {
-        path_and_file_type_set.insert(
-            std::make_pair(file_paths_[i], mime_types_[i]));
-      }
       const std::vector<const extensions::FileHandlerInfo*>& handlers =
-          extensions::app_file_handler_util::FindFileHandlersForFiles(
-              *extension, path_and_file_type_set);
+          extensions::app_file_handler_util::FindFileHandlersForEntries(
+              *extension, entries_);
       if (!handlers.empty())
         handler = handlers[0];
     }
@@ -287,15 +302,15 @@
       return;
     }
 
-    std::vector<GrantedFileEntry> file_entries;
-    for (size_t i = 0; i < file_paths_.size(); ++i) {
-      file_entries.push_back(CreateFileEntry(
+    std::vector<GrantedFileEntry> granted_entries;
+    for (size_t i = 0; i < entry_paths_.size(); ++i) {
+      granted_entries.push_back(CreateFileEntry(
           profile_, extension, host->render_process_host()->GetID(),
-          file_paths_[i], false));
+          entries_[i].path, entries_[i].is_directory));
     }
 
     AppRuntimeEventRouter::DispatchOnLaunchedEventWithFileEntries(
-        profile_, extension, handler_id_, mime_types_, file_entries);
+        profile_, extension, handler_id_, entries_, granted_entries);
   }
 
   const Extension* GetExtension() const {
@@ -309,12 +324,16 @@
   // not kept as the extension may be unloaded and deleted during the course of
   // the launch.
   const std::string extension_id;
-  // The path to be passed through to the app.
-  std::vector<base::FilePath> file_paths_;
-  std::vector<std::string> mime_types_;
+  // A list of files and directories to be passed through to the app.
+  std::vector<base::FilePath> entry_paths_;
+  // A corresponding list with EntryInfo for every base::FilePath in
+  // entry_paths_.
+  std::vector<extensions::EntryInfo> entries_;
   // The ID of the file handler used to launch the app.
   std::string handler_id_;
-  extensions::app_file_handler_util::MimeTypeCollector collector_;
+  extensions::app_file_handler_util::MimeTypeCollector mime_type_collector_;
+  extensions::app_file_handler_util::IsDirectoryCollector
+      is_directory_collector_;
 
   DISALLOW_COPY_AND_ASSIGN(PlatformAppPathLauncher);
 };
@@ -389,9 +408,9 @@
     Profile* profile,
     const Extension* extension,
     const std::string& handler_id,
-    const std::vector<base::FilePath>& file_paths) {
+    const std::vector<base::FilePath>& entry_paths) {
   scoped_refptr<PlatformAppPathLauncher> launcher =
-      new PlatformAppPathLauncher(profile, extension, file_paths);
+      new PlatformAppPathLauncher(profile, extension, entry_paths);
   launcher->LaunchWithHandler(handler_id);
 }
 
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 88d917c..31aaeba8 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -5,6 +5,7 @@
 import("//build/config/features.gni")
 import("//build/config/ui.gni")
 import("//testing/test.gni")
+import("//ui/base/ui_features.gni")
 
 assert(use_aura)
 assert(enable_hidpi)
diff --git a/ash/ash.gyp b/ash/ash.gyp
index 30640e6..e39e0196 100644
--- a/ash/ash.gyp
+++ b/ash/ash.gyp
@@ -824,6 +824,8 @@
       'display/display_color_manager_chromeos_unittest.cc',
       'display/display_error_observer_chromeos_unittest.cc',
       'display/display_info_unittest.cc',
+      'display/display_layout_unittest.cc',
+      'display/display_layout_builder_unittest.cc',
       'display/display_manager_unittest.cc',
       'display/display_util_unittest.cc',
       'display/extended_mouse_warp_controller_unittest.cc',
diff --git a/ash/display/display_change_observer_chromeos.cc b/ash/display/display_change_observer_chromeos.cc
index 1f379e6..23f3665 100644
--- a/ash/display/display_change_observer_chromeos.cc
+++ b/ash/display/display_change_observer_chromeos.cc
@@ -154,10 +154,14 @@
 ui::MultipleDisplayState DisplayChangeObserver::GetStateForDisplayIds(
     const ui::DisplayConfigurator::DisplayStateList& display_states) const {
   UpdateInternalDisplayId(display_states);
-  if (display_states.size() != 2)
-    return ui::MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED;
-  DisplayIdList list = CreateDisplayIdList(display_states[0]->display_id(),
-                                           display_states[1]->display_id());
+  if (display_states.size() == 1)
+    return ui::MULTIPLE_DISPLAY_STATE_SINGLE;
+  DisplayIdList list =
+      GenerateDisplayIdList(display_states.begin(), display_states.end(),
+                            [](const ui::DisplaySnapshot* display_state) {
+                              return display_state->display_id();
+                            });
+
   const DisplayLayout& layout = Shell::GetInstance()
                                     ->display_manager()
                                     ->layout_store()
diff --git a/ash/display/display_info.cc b/ash/display/display_info.cc
index a85d175..7c6b39eb 100644
--- a/ash/display/display_info.cc
+++ b/ash/display/display_info.cc
@@ -264,6 +264,8 @@
       clear_overscan_insets_(false),
       color_profile_(ui::COLOR_PROFILE_STANDARD) {}
 
+DisplayInfo::DisplayInfo(const DisplayInfo& other) = default;
+
 DisplayInfo::~DisplayInfo() {
 }
 
diff --git a/ash/display/display_info.h b/ash/display/display_info.h
index 6cdf93d..5206b04 100644
--- a/ash/display/display_info.h
+++ b/ash/display/display_info.h
@@ -95,6 +95,7 @@
 
   DisplayInfo();
   DisplayInfo(int64_t id, const std::string& name, bool has_overscan);
+  DisplayInfo(const DisplayInfo& other);
   ~DisplayInfo();
 
   int64_t id() const { return id_; }
diff --git a/ash/display/display_layout.cc b/ash/display/display_layout.cc
index 6b5341373..f5aa8f406 100644
--- a/ash/display/display_layout.cc
+++ b/ash/display/display_layout.cc
@@ -4,7 +4,7 @@
 
 #include "ash/display/display_layout.h"
 
-#include <ostream>
+#include <sstream>
 
 #include "ash/ash_switches.h"
 #include "ash/display/display_pref_util.h"
@@ -25,15 +25,16 @@
 const int kMaxValidOffset = 10000;
 
 // Persistent key names
-const char kPositionKey[] = "position";
-const char kOffsetKey[] = "offset";
 const char kMirroredKey[] = "mirrored";
 const char kDefaultUnifiedKey[] = "default_unified";
 const char kPrimaryIdKey[] = "primary-id";
+const char kDisplayPlacementKey[] = "display_placement";
 
-// TODO(oshima): Support multiple placements.
-const char kPlacementDisplayIdKey[] = "placement.display_id";
-const char kPlacementParentDisplayIdKey[] = "placement.parent_display_id";
+// DisplayPlacement
+const char kPositionKey[] = "position";
+const char kOffsetKey[] = "offset";
+const char kDisplayPlacementDisplayIdKey[] = "display_id";
+const char kDisplayPlacementParentDisplayIdKey[] = "parent_display_id";
 
 using PositionToStringMap = std::map<DisplayPlacement::Position, std::string>;
 using DisplayPlacementMap = std::unordered_map<int64_t, DisplayPlacement>;
@@ -63,17 +64,30 @@
   return base::StringToInt64(position, field);
 }
 
-bool GetDisplayIdByKey(const base::DictionaryValue* dict_value,
-                       const char* key,
-                       int64_t* id_out) {
-  std::string out;
-  return dict_value->GetString(key, &out) && base::StringToInt64(out, id_out);
+bool IsIdInList(int64_t id, const DisplayIdList& list) {
+  const auto iter =
+      std::find_if(list.begin(), list.end(),
+                   [id](int64_t display_id) { return display_id == id; });
+  return iter != list.end();
 }
 
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
 // DisplayPlacement
+
+DisplayPlacement::DisplayPlacement()
+    : display_id(gfx::Display::kInvalidDisplayID),
+      parent_display_id(gfx::Display::kInvalidDisplayID),
+      position(DisplayPlacement::RIGHT),
+      offset(0) {}
+
+DisplayPlacement::DisplayPlacement(const DisplayPlacement& placement)
+    : display_id(placement.display_id),
+      parent_display_id(placement.parent_display_id),
+      position(placement.position),
+      offset(placement.offset) {}
+
 DisplayPlacement::DisplayPlacement(Position pos, int offset)
     : display_id(gfx::Display::kInvalidDisplayID),
       parent_display_id(gfx::Display::kInvalidDisplayID),
@@ -110,16 +124,35 @@
 }
 
 std::string DisplayPlacement::ToString() const {
-  return base::StringPrintf("%s, %d", ToPositionString(position).c_str(),
-                            offset);
+  std::stringstream s;
+  if (display_id != gfx::Display::kInvalidDisplayID)
+    s << "id=" << display_id << ", ";
+  if (parent_display_id != gfx::Display::kInvalidDisplayID)
+    s << "parent=" << parent_display_id << ", ";
+  s << ToPositionString(position) << ", ";
+  s << offset;
+  return s.str();
+}
+
+// static
+void DisplayPlacement::RegisterJSONConverter(
+    base::JSONValueConverter<DisplayPlacement>* converter) {
+  converter->RegisterIntField(kOffsetKey, &DisplayPlacement::offset);
+  converter->RegisterCustomField<DisplayPlacement::Position>(
+      kPositionKey, &DisplayPlacement::position, &GetPositionFromString);
+  converter->RegisterCustomField<int64_t>(kDisplayPlacementDisplayIdKey,
+                                          &DisplayPlacement::display_id,
+                                          &GetDisplayIdFromString);
+  converter->RegisterCustomField<int64_t>(kDisplayPlacementParentDisplayIdKey,
+                                          &DisplayPlacement::parent_display_id,
+                                          &GetDisplayIdFromString);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // DisplayLayout
 
 DisplayLayout::DisplayLayout()
-    : placement(DisplayPlacement::RIGHT, 0),
-      mirrored(false),
+    : mirrored(false),
       default_unified(true),
       primary_id(gfx::Display::kInvalidDisplayID) {}
 
@@ -128,22 +161,25 @@
 // static
 bool DisplayLayout::ConvertFromValue(const base::Value& value,
                                      DisplayLayout* layout) {
+  layout->placement_list.clear();
   base::JSONValueConverter<DisplayLayout> converter;
-  converter.Convert(value, layout);
-
+  if (!converter.Convert(value, layout))
+    return false;
+  if (layout->placement_list.size() != 0u)
+    return true;
+  // For compatibility with old format.
   const base::DictionaryValue* dict_value = nullptr;
   if (!value.GetAsDictionary(&dict_value) || dict_value == nullptr)
     return false;
-
-  dict_value->GetInteger(kOffsetKey, &layout->placement.offset);
-  std::string position;
-  if (dict_value->GetString(kPositionKey, &position))
-    GetPositionFromString(position, &layout->placement.position);
-
-  GetDisplayIdByKey(dict_value, kPlacementDisplayIdKey,
-                    &layout->placement.display_id);
-  GetDisplayIdByKey(dict_value, kPlacementParentDisplayIdKey,
-                    &layout->placement.parent_display_id);
+  int offset;
+  if (dict_value->GetInteger(kOffsetKey, &offset)) {
+    DisplayPlacement::Position position;
+    std::string position_str;
+    if (!dict_value->GetString(kPositionKey, &position_str))
+      return false;
+    GetPositionFromString(position_str, &position);
+    layout->placement_list.push_back(new DisplayPlacement(position, offset));
+  }
   return true;
 }
 
@@ -154,36 +190,28 @@
   if (!value->GetAsDictionary(&dict_value) || dict_value == nullptr)
     return false;
 
-  dict_value->SetString(kPositionKey,
-                        ToPositionString(layout.placement.position));
-  dict_value->SetInteger(kOffsetKey, layout.placement.offset);
   dict_value->SetBoolean(kMirroredKey, layout.mirrored);
   dict_value->SetBoolean(kDefaultUnifiedKey, layout.default_unified);
   dict_value->SetString(kPrimaryIdKey, base::Int64ToString(layout.primary_id));
 
-  dict_value->SetString(kPlacementDisplayIdKey,
-                        base::Int64ToString(layout.placement.display_id));
-  dict_value->SetString(
-      kPlacementParentDisplayIdKey,
-      base::Int64ToString(layout.placement.parent_display_id));
+  scoped_ptr<base::ListValue> placement_list(new base::ListValue);
+  for (const auto* placement : layout.placement_list) {
+    scoped_ptr<base::DictionaryValue> placement_value(
+        new base::DictionaryValue);
+    placement_value->SetString(kPositionKey,
+                               ToPositionString(placement->position));
+    placement_value->SetInteger(kOffsetKey, placement->offset);
+    placement_value->SetString(kDisplayPlacementDisplayIdKey,
+                               base::Int64ToString(placement->display_id));
+    placement_value->SetString(
+        kDisplayPlacementParentDisplayIdKey,
+        base::Int64ToString(placement->parent_display_id));
+    placement_list->Append(std::move(placement_value));
+  }
+  dict_value->Set(kDisplayPlacementKey, std::move(placement_list));
   return true;
 }
 
-std::string DisplayLayout::ToString() const {
-  return base::StringPrintf("%s%s%s", placement.ToString().c_str(),
-                            mirrored ? ", mirrored" : "",
-                            default_unified ? ", default_unified" : "");
-}
-
-scoped_ptr<DisplayLayout> DisplayLayout::Copy() const {
-  scoped_ptr<DisplayLayout> copy(new DisplayLayout);
-  copy->placement = placement;
-  copy->mirrored = mirrored;
-  copy->default_unified = default_unified;
-  copy->primary_id = primary_id;
-  return copy;
-}
-
 // static
 void DisplayLayout::RegisterJSONConverter(
     base::JSONValueConverter<DisplayLayout>* converter) {
@@ -192,6 +220,102 @@
                                &DisplayLayout::default_unified);
   converter->RegisterCustomField<int64_t>(
       kPrimaryIdKey, &DisplayLayout::primary_id, &GetDisplayIdFromString);
+  converter->RegisterRepeatedMessage<DisplayPlacement>(
+      kDisplayPlacementKey, &DisplayLayout::placement_list);
+}
+
+// static
+bool DisplayLayout::Validate(const DisplayIdList& list,
+                             const DisplayLayout& layout) {
+  // The primary display should be in the list.
+  DCHECK(IsIdInList(layout.primary_id, list));
+
+  // Unified mode, or mirror mode switched from unified mode,
+  // may not have the placement yet.
+  if (layout.placement_list.size() == 0u)
+    return true;
+
+  bool has_primary_as_parent = false;
+  int64_t id = 0;
+
+  for (const auto* placement : layout.placement_list) {
+    // Placements are sorted by display_id.
+    if (id >= placement->display_id) {
+      LOG(ERROR) << "PlacementList must be sorted by display_id";
+      return false;
+    }
+    if (placement->display_id == gfx::Display::kInvalidDisplayID) {
+      LOG(ERROR) << "display_id is not initialized";
+      return false;
+    }
+    if (placement->parent_display_id == gfx::Display::kInvalidDisplayID) {
+      LOG(ERROR) << "display_parent_id is not initialized";
+      return false;
+    }
+    if (placement->display_id == placement->parent_display_id) {
+      LOG(ERROR) << "display_id must not be same as parent_display_id";
+      return false;
+    }
+    if (!IsIdInList(placement->display_id, list)) {
+      LOG(ERROR) << "display_id is not in the id list:"
+                 << placement->ToString();
+      return false;
+    }
+
+    if (!IsIdInList(placement->parent_display_id, list)) {
+      LOG(ERROR) << "parent_display_id is not in the id list:"
+                 << placement->ToString();
+      return false;
+    }
+    has_primary_as_parent |= layout.primary_id == placement->parent_display_id;
+  }
+  if (!has_primary_as_parent)
+    LOG(ERROR) << "At least, one placement must have the primary as a parent.";
+  return has_primary_as_parent;
+}
+
+scoped_ptr<DisplayLayout> DisplayLayout::Copy() const {
+  scoped_ptr<DisplayLayout> copy(new DisplayLayout);
+  for (auto placement : placement_list)
+    copy->placement_list.push_back(new DisplayPlacement(*placement));
+  copy->mirrored = mirrored;
+  copy->default_unified = default_unified;
+  copy->primary_id = primary_id;
+  return copy;
+}
+
+bool DisplayLayout::HasSamePlacementList(const DisplayLayout& layout) const {
+  if (placement_list.size() != layout.placement_list.size())
+    return false;
+  for (size_t index = 0; index < placement_list.size(); index++) {
+    const DisplayPlacement& placement1 = *placement_list[index];
+    const DisplayPlacement& placement2 = *layout.placement_list[index];
+    if (placement1.position != placement2.position ||
+        placement1.offset != placement2.offset ||
+        placement1.display_id != placement2.display_id ||
+        placement1.parent_display_id != placement2.parent_display_id) {
+      return false;
+    }
+  }
+  return true;
+}
+
+std::string DisplayLayout::ToString() const {
+  std::stringstream s;
+  s << "primary=" << primary_id;
+  if (mirrored)
+    s << ", mirrored";
+  if (default_unified)
+    s << ", default_unified";
+  bool added = false;
+  for (const auto* placement : placement_list) {
+    s << (added ? "),(" : " [(");
+    s << placement->ToString();
+    added = true;
+  }
+  if (added)
+    s << ")]";
+  return s.str();
 }
 
 }  // namespace ash
diff --git a/ash/display/display_layout.h b/ash/display/display_layout.h
index 9b4b19b..3b7b4d0 100644
--- a/ash/display/display_layout.h
+++ b/ash/display/display_layout.h
@@ -13,6 +13,11 @@
 #include "ash/ash_export.h"
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+
+namespace gfx {
+class Display;
+}
 
 namespace base {
 class Value;
@@ -25,6 +30,8 @@
 // DisplayLayoutStore.
 using DisplayIdList = std::vector<int64_t>;
 
+using DisplayList = std::vector<gfx::Display>;
+
 // DisplayPlacement specifies where the display (D) is placed relative
 // to parent (P) display.  In the following example, the display (D)
 // given by |display_id| is placed at the left side of the parent
@@ -53,11 +60,18 @@
   // based on the top/left edge of the primary display.
   int offset;
 
+  explicit DisplayPlacement(const DisplayPlacement& placement);
   DisplayPlacement(Position position, int offset);
+  DisplayPlacement();
 
   DisplayPlacement& Swap();
 
   std::string ToString() const;
+
+  // Used by JSONValueConverter to generate DisplayPlacement from a
+  // JSON value.  See json_value_converter.h.
+  static void RegisterJSONConverter(
+      base::JSONValueConverter<DisplayPlacement>* converter);
 };
 
 class ASH_EXPORT DisplayLayout final {
@@ -69,10 +83,15 @@
   static bool ConvertFromValue(const base::Value& value, DisplayLayout* layout);
   static bool ConvertToValue(const DisplayLayout& layout, base::Value* value);
 
+  // Used by JSONValueConverter to generate DisplayLayout from a
+  // JSON value.  See json_value_converter.h.
   static void RegisterJSONConverter(
       base::JSONValueConverter<DisplayLayout>* converter);
 
-  DisplayPlacement placement;
+  // Validates the layout object.
+  static bool Validate(const DisplayIdList& list, const DisplayLayout& layout);
+
+  ScopedVector<DisplayPlacement> placement_list;
 
   // True if displays are mirrored.
   bool mirrored;
@@ -83,12 +102,15 @@
   // The id of the display used as a primary display.
   int64_t primary_id;
 
-  // Returns string representation of the layout for debugging/testing.
-  // This includes "unified" only if the unified desktop feature is enabled.
-  std::string ToString() const;
-
   scoped_ptr<DisplayLayout> Copy() const;
 
+  // Test if the |layout| has the same placement list. Other fields such
+  // as mirrored, primary_id are ignored.
+  bool HasSamePlacementList(const DisplayLayout& layout) const;
+
+  // Returns string representation of the layout for debugging/testing.
+  std::string ToString() const;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(DisplayLayout);
 };
diff --git a/ash/display/display_layout_builder.cc b/ash/display/display_layout_builder.cc
index 46cb979..9952f7089 100644
--- a/ash/display/display_layout_builder.cc
+++ b/ash/display/display_layout_builder.cc
@@ -27,18 +27,34 @@
   return *this;
 }
 
+DisplayLayoutBuilder& DisplayLayoutBuilder::AddDisplayPlacement(
+    int64_t display_id,
+    int64_t parent_display_id,
+    DisplayPlacement::Position position,
+    int offset) {
+  scoped_ptr<DisplayPlacement> placement(new DisplayPlacement);
+  placement->position = position;
+  placement->offset = offset;
+  placement->display_id = display_id;
+  placement->parent_display_id = parent_display_id;
+  layout_->placement_list.push_back(std::move(placement));
+  return *this;
+}
+
 DisplayLayoutBuilder& DisplayLayoutBuilder::SetSecondaryPlacement(
     int64_t secondary_id,
     DisplayPlacement::Position position,
     int offset) {
-  layout_->placement.position = position;
-  layout_->placement.offset = offset;
-  layout_->placement.display_id = secondary_id;
-  layout_->placement.parent_display_id = layout_->primary_id;
+  layout_->placement_list.clear();
+  AddDisplayPlacement(secondary_id, layout_->primary_id, position, offset);
   return *this;
 }
 
 scoped_ptr<DisplayLayout> DisplayLayoutBuilder::Build() {
+  std::sort(layout_->placement_list.begin(), layout_->placement_list.end(),
+            [](const DisplayPlacement* a, const DisplayPlacement* b) {
+              return a->display_id < b->display_id;
+            });
   return std::move(layout_);
 }
 
diff --git a/ash/display/display_layout_builder.h b/ash/display/display_layout_builder.h
index defef03..b71d12d 100644
--- a/ash/display/display_layout_builder.h
+++ b/ash/display/display_layout_builder.h
@@ -28,6 +28,12 @@
 
   DisplayLayoutBuilder& SetMirrored(bool mirrored);
 
+  // Adds a display placement.
+  DisplayLayoutBuilder& AddDisplayPlacement(int64_t display_id,
+                                            int64_t parent_id,
+                                            DisplayPlacement::Position position,
+                                            int offset);
+
   // Sets the display placement for the secondary display.
   DisplayLayoutBuilder& SetSecondaryPlacement(
       int64_t secondary_id,
diff --git a/ash/display/display_layout_builder_unittest.cc b/ash/display/display_layout_builder_unittest.cc
new file mode 100644
index 0000000..91232052
--- /dev/null
+++ b/ash/display/display_layout_builder_unittest.cc
@@ -0,0 +1,51 @@
+// Copyright 2016 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 "ash/display/display_layout_builder.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ash {
+
+typedef testing::Test DisplayLayoutBuilderTest;
+
+TEST_F(DisplayLayoutBuilderTest, SecondaryPlacement) {
+  DisplayLayoutBuilder builder(1);
+  builder.SetSecondaryPlacement(2, DisplayPlacement::LEFT, 30);
+  scoped_ptr<DisplayLayout> layout(builder.Build());
+  ASSERT_EQ(1u, layout->placement_list.size());
+
+  EXPECT_EQ(2, layout->placement_list[0]->display_id);
+  EXPECT_EQ(1, layout->placement_list[0]->parent_display_id);
+  EXPECT_EQ(30, layout->placement_list[0]->offset);
+  EXPECT_EQ(DisplayPlacement::LEFT, layout->placement_list[0]->position);
+}
+
+TEST_F(DisplayLayoutBuilderTest, MultiplePlacement) {
+  DisplayLayoutBuilder builder(1);
+  builder.AddDisplayPlacement(5, 1, DisplayPlacement::TOP, 30);
+  builder.AddDisplayPlacement(3, 5, DisplayPlacement::LEFT, 20);
+  builder.AddDisplayPlacement(4, 5, DisplayPlacement::RIGHT, 10);
+  scoped_ptr<DisplayLayout> layout(builder.Build());
+
+  ASSERT_EQ(3u, layout->placement_list.size());
+
+  // placmenets are sorted by display_id.
+  EXPECT_EQ(3, layout->placement_list[0]->display_id);
+  EXPECT_EQ(5, layout->placement_list[0]->parent_display_id);
+  EXPECT_EQ(20, layout->placement_list[0]->offset);
+  EXPECT_EQ(DisplayPlacement::LEFT, layout->placement_list[0]->position);
+
+  EXPECT_EQ(4, layout->placement_list[1]->display_id);
+  EXPECT_EQ(5, layout->placement_list[1]->parent_display_id);
+  EXPECT_EQ(10, layout->placement_list[1]->offset);
+  EXPECT_EQ(DisplayPlacement::RIGHT, layout->placement_list[1]->position);
+
+  EXPECT_EQ(5, layout->placement_list[2]->display_id);
+  EXPECT_EQ(1, layout->placement_list[2]->parent_display_id);
+  EXPECT_EQ(30, layout->placement_list[2]->offset);
+  EXPECT_EQ(DisplayPlacement::TOP, layout->placement_list[2]->position);
+}
+
+}  // namespace ash
diff --git a/ash/display/display_layout_store.cc b/ash/display/display_layout_store.cc
index 3a64bccf..b78bf98 100644
--- a/ash/display/display_layout_store.cc
+++ b/ash/display/display_layout_store.cc
@@ -16,7 +16,7 @@
 namespace ash {
 
 DisplayLayoutStore::DisplayLayoutStore()
-    : default_display_layout_(new DisplayLayout) {
+    : default_display_placement_(DisplayPlacement::RIGHT, 0) {
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   if (command_line->HasSwitch(switches::kAshSecondaryDisplayLayout)) {
     std::string value = command_line->GetSwitchValueASCII(
@@ -25,14 +25,14 @@
     int offset = 0;
     if (sscanf(value.c_str(), "%c,%d", &layout, &offset) == 2) {
       if (layout == 't')
-        default_display_layout_->placement.position = DisplayPlacement::TOP;
+        default_display_placement_.position = DisplayPlacement::TOP;
       else if (layout == 'b')
-        default_display_layout_->placement.position = DisplayPlacement::BOTTOM;
+        default_display_placement_.position = DisplayPlacement::BOTTOM;
       else if (layout == 'r')
-        default_display_layout_->placement.position = DisplayPlacement::RIGHT;
+        default_display_placement_.position = DisplayPlacement::RIGHT;
       else if (layout == 'l')
-        default_display_layout_->placement.position = DisplayPlacement::LEFT;
-      default_display_layout_->placement.offset = offset;
+        default_display_placement_.position = DisplayPlacement::LEFT;
+      default_display_placement_.offset = offset;
     }
   }
 }
@@ -40,17 +40,16 @@
 DisplayLayoutStore::~DisplayLayoutStore() {
 }
 
-void DisplayLayoutStore::SetDefaultDisplayLayout(
-    scoped_ptr<DisplayLayout> layout) {
+void DisplayLayoutStore::SetDefaultDisplayPlacement(
+    const DisplayPlacement& placement) {
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   if (!command_line->HasSwitch(switches::kAshSecondaryDisplayLayout))
-    default_display_layout_ = std::move(layout);
+    default_display_placement_ = placement;
 }
 
 void DisplayLayoutStore::RegisterLayoutForDisplayIdList(
     const DisplayIdList& list,
     scoped_ptr<DisplayLayout> layout) {
-  DCHECK_EQ(2u, list.size());
 
   // Do not overwrite the valid data with old invalid date.
   if (layouts_.count(list) && !CompareDisplayIds(list[0], list[1]))
@@ -58,15 +57,18 @@
 
   // Old data may not have the display_id/parent_display_id.
   // Guess these values based on the saved primary_id.
-  if (layout->placement.display_id == gfx::Display::kInvalidDisplayID) {
+  if (layout->placement_list.size() >= 1 &&
+      layout->placement_list[0]->display_id ==
+          gfx::Display::kInvalidDisplayID) {
     if (layout->primary_id == list[1]) {
-      layout->placement.display_id = list[0];
-      layout->placement.parent_display_id = list[1];
+      layout->placement_list[0]->display_id = list[0];
+      layout->placement_list[0]->parent_display_id = list[1];
     } else {
-      layout->placement.display_id = list[1];
-      layout->placement.parent_display_id = list[0];
+      layout->placement_list[0]->display_id = list[1];
+      layout->placement_list[0]->parent_display_id = list[0];
     }
   }
+  DCHECK(DisplayLayout::Validate(list, *layout.get())) << layout->ToString();
   layouts_[list] = std::move(layout);
 }
 
@@ -77,11 +79,7 @@
   const DisplayLayout* layout = iter != layouts_.end()
                                     ? iter->second.get()
                                     : CreateDefaultDisplayLayout(list);
-  DCHECK_EQ(layout->primary_id, layout->placement.parent_display_id);
-  DCHECK((layout->placement.display_id == list[0] &&
-          layout->placement.parent_display_id == list[1]) ||
-         (layout->placement.display_id == list[1] &&
-          layout->placement.parent_display_id == list[0]));
+  DCHECK(DisplayLayout::Validate(list, *layout)) << layout->ToString();
   DCHECK_NE(layout->primary_id, gfx::Display::kInvalidDisplayID);
   return *layout;
 }
@@ -99,10 +97,17 @@
 
 DisplayLayout* DisplayLayoutStore::CreateDefaultDisplayLayout(
     const DisplayIdList& list) {
-  scoped_ptr<DisplayLayout> layout(default_display_layout_->Copy());
+  scoped_ptr<DisplayLayout> layout(new DisplayLayout);
+  // The first display is the primary by default.
   layout->primary_id = list[0];
-  layout->placement.display_id = list[1];
-  layout->placement.parent_display_id = list[0];
+  layout->placement_list.clear();
+  for (size_t i = 0; i < list.size() - 1; i++) {
+    scoped_ptr<DisplayPlacement> placement(
+        new DisplayPlacement(default_display_placement_));
+    placement->display_id = list[i + 1];
+    placement->parent_display_id = list[i];
+    layout->placement_list.push_back(std::move(placement));
+  }
   layouts_[list] = std::move(layout);
   auto iter = layouts_.find(list);
   return iter->second.get();
diff --git a/ash/display/display_layout_store.h b/ash/display/display_layout_store.h
index 773c01a..6dd7b8a 100644
--- a/ash/display/display_layout_store.h
+++ b/ash/display/display_layout_store.h
@@ -21,7 +21,7 @@
   DisplayLayoutStore();
   ~DisplayLayoutStore();
 
-  void SetDefaultDisplayLayout(scoped_ptr<DisplayLayout> layout);
+  void SetDefaultDisplayPlacement(const DisplayPlacement& placement);
 
   // Registeres the display layout info for the specified display(s).
   void RegisterLayoutForDisplayIdList(const DisplayIdList& list,
@@ -42,8 +42,8 @@
   // Creates new layout for display list from |default_display_layout_|.
   DisplayLayout* CreateDefaultDisplayLayout(const DisplayIdList& display_list);
 
-  // The default display layout.
-  scoped_ptr<DisplayLayout> default_display_layout_;
+  // The default display placement.
+  DisplayPlacement default_display_placement_;
 
   // Display layout per list of devices.
   std::map<DisplayIdList, scoped_ptr<DisplayLayout>> layouts_;
diff --git a/ash/display/display_layout_unittest.cc b/ash/display/display_layout_unittest.cc
new file mode 100644
index 0000000..7a614df
--- /dev/null
+++ b/ash/display/display_layout_unittest.cc
@@ -0,0 +1,93 @@
+// Copyright 2016 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 "ash/display/display_layout.h"
+
+#include "base/json/json_reader.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ash {
+
+typedef testing::Test DisplayLayoutTest;
+
+TEST_F(DisplayLayoutTest, ConvertFromToValue) {
+  DisplayLayout layout;
+  layout.primary_id = 1;
+  layout.mirrored = true;
+  layout.default_unified = false;
+  layout.placement_list.push_back(new DisplayPlacement);
+  layout.placement_list.push_back(new DisplayPlacement);
+  layout.placement_list[0]->display_id = 2;
+  layout.placement_list[0]->parent_display_id = 1;
+  layout.placement_list[0]->position = DisplayPlacement::BOTTOM;
+
+  layout.placement_list[1]->display_id = 3;
+  layout.placement_list[1]->parent_display_id = 2;
+  layout.placement_list[1]->position = DisplayPlacement::LEFT;
+  layout.placement_list[1]->offset = 30;
+
+  base::DictionaryValue value;
+  DisplayLayout::ConvertToValue(layout, &value);
+
+  const char data[] =
+      "{\n"
+      "  \"primary-id\": \"1\",\n"
+      "  \"mirrored\": true,\n"
+      "  \"default_unified\": false,\n"
+      "  \"display_placement\": [{\n"
+      "    \"display_id\": \"2\",\n"
+      "    \"parent_display_id\": \"1\",\n"
+      "    \"position\": \"bottom\",\n"
+      "    \"offset\": 0\n"
+      "  },{\n"
+      "    \"display_id\": \"3\",\n"
+      "    \"parent_display_id\": \"2\",\n"
+      "    \"position\": \"left\",\n"
+      "    \"offset\": 30\n"
+      "  }]\n"
+      "}";
+  int error_code = 0, error_line, error_column;
+  std::string error_msg;
+  scoped_ptr<base::Value> read_value(base::JSONReader::ReadAndReturnError(
+      data, 0, &error_code, &error_msg, &error_line, &error_column));
+  ASSERT_EQ(0, error_code) << error_msg << " at " << error_line << ":"
+                           << error_column;
+  EXPECT_TRUE(value.Equals(read_value.get()));
+
+  DisplayLayout read_layout;
+  EXPECT_TRUE(DisplayLayout::ConvertFromValue(*read_value, &read_layout));
+  EXPECT_EQ(read_layout.mirrored, layout.mirrored);
+  EXPECT_EQ(read_layout.primary_id, layout.primary_id);
+  EXPECT_EQ(read_layout.default_unified, layout.default_unified);
+  EXPECT_TRUE(read_layout.HasSamePlacementList(layout));
+}
+
+TEST_F(DisplayLayoutTest, ConvertFromOldJSON) {
+  const char data[] =
+      "{\n"
+      "  \"primary-id\": \"1\",\n"
+      "  \"mirrored\": true,\n"
+      "  \"default_unified\": false,\n"
+      "  \"position\": \"bottom\",\n"
+      "  \"offset\": 20\n"
+      "}";
+  int error_code = 0, error_line, error_column;
+  std::string error_msg;
+  scoped_ptr<base::Value> read_value(base::JSONReader::ReadAndReturnError(
+      data, 0, &error_code, &error_msg, &error_line, &error_column));
+  ASSERT_EQ(0, error_code) << error_msg << " at " << error_line << ":"
+                           << error_column;
+
+  DisplayLayout read_layout;
+  EXPECT_TRUE(DisplayLayout::ConvertFromValue(*read_value, &read_layout));
+  EXPECT_EQ(true, read_layout.mirrored);
+  EXPECT_EQ(1, read_layout.primary_id);
+  EXPECT_EQ(false, read_layout.default_unified);
+  ASSERT_EQ(1u, read_layout.placement_list.size());
+  EXPECT_EQ(DisplayPlacement::BOTTOM, read_layout.placement_list[0]->position);
+  EXPECT_EQ(20, read_layout.placement_list[0]->offset);
+}
+
+}  // namespace ash
diff --git a/ash/display/display_manager.cc b/ash/display/display_manager.cc
index 4b21140..25dfc06 100644
--- a/ash/display/display_manager.cc
+++ b/ash/display/display_manager.cc
@@ -226,8 +226,7 @@
 
 DisplayIdList DisplayManager::GetCurrentDisplayIdList() const {
   if (IsInUnifiedMode()) {
-    return CreateDisplayIdList(software_mirroring_display_list_[0].id(),
-                               software_mirroring_display_list_[1].id());
+    return CreateDisplayIdList(software_mirroring_display_list_);
   } else if (IsInMirrorMode()) {
     if (software_mirroring_enabled()) {
       CHECK_EQ(2u, num_connected_displays());
@@ -235,54 +234,43 @@
       // between two checks.
       CHECK_EQ(1u, active_display_list_.size());
     }
-    return CreateDisplayIdList(active_display_list_[0].id(),
-                               mirroring_display_id_);
+    int64_t ids[] = {active_display_list_[0].id(), mirroring_display_id_};
+    return ash::GenerateDisplayIdList(std::begin(ids), std::end(ids));
   } else {
     CHECK_LE(2u, active_display_list_.size());
-    return CreateDisplayIdList(active_display_list_[0].id(),
-                               active_display_list_[1].id());
+    return CreateDisplayIdList(active_display_list_);
   }
 }
 
 void DisplayManager::SetLayoutForCurrentDisplays(
     scoped_ptr<DisplayLayout> layout) {
-  if (GetNumDisplays() != 2)
+  if (GetNumDisplays() == 1)
     return;
   const DisplayIdList list = GetCurrentDisplayIdList();
 
-  DCHECK_NE(gfx::Display::kInvalidDisplayID, layout->primary_id);
-
-  DCHECK_NE(layout->placement.display_id, gfx::Display::kInvalidDisplayID);
-
-  DCHECK((list[0] == layout->placement.display_id &&
-          list[1] == layout->placement.parent_display_id) ||
-         (list[1] == layout->placement.display_id &&
-          list[0] == layout->placement.parent_display_id));
+  DCHECK(DisplayLayout::Validate(list, *layout));
 
   const DisplayLayout& current_layout =
       layout_store_->GetRegisteredDisplayLayout(list);
 
-  if (layout->placement.position == current_layout.placement.position &&
-      layout->placement.offset == current_layout.placement.offset &&
-      layout->placement.display_id == current_layout.placement.display_id &&
-      layout->placement.parent_display_id ==
-          current_layout.placement.parent_display_id) {
+  if (layout->HasSamePlacementList(current_layout))
     return;
-  }
 
   layout_store_->RegisterLayoutForDisplayIdList(list, std::move(layout));
   if (delegate_)
     delegate_->PreDisplayConfigurationChange(false);
 
   // TODO(oshima): Call UpdateDisplays instead.
-  ApplyDisplayLayout(GetCurrentDisplayLayout(), &active_display_list_);
+  std::vector<int64_t> updated_ids;
+  ApplyDisplayLayout(GetCurrentDisplayLayout(), &active_display_list_,
+                     &updated_ids);
+  for (int64_t id : updated_ids) {
+    screen_->NotifyMetricsChanged(
+        GetDisplayForId(id),
+        gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
+            gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA);
+  }
 
-  // Primary's bounds stay the same. Just notify bounds change
-  // on the secondary.
-  screen_->NotifyMetricsChanged(
-      ScreenUtil::GetSecondaryDisplay(),
-      gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
-      gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA);
   if (delegate_)
     delegate_->PostDisplayConfigurationChange();
 }
@@ -626,8 +614,10 @@
 #if defined(OS_CHROMEOS)
   if (!base::SysInfo::IsRunningOnChromeOS() &&
       new_display_info_list.size() > 1) {
-    DisplayIdList list = CreateDisplayIdList(new_display_info_list[0].id(),
-                                             new_display_info_list[1].id());
+    DisplayIdList list = GenerateDisplayIdList(
+        new_display_info_list.begin(), new_display_info_list.end(),
+        [](const DisplayInfo& info) { return info.id(); });
+
     const DisplayLayout& layout =
         layout_store_->GetRegisteredDisplayLayout(list);
     // Mirror mode is set by DisplayConfigurator on the device.
@@ -664,8 +654,9 @@
             DisplayInfoSortFunctor());
 
   if (new_display_info_list.size() > 1) {
-    DisplayIdList list = CreateDisplayIdList(new_display_info_list[0].id(),
-                                             new_display_info_list[1].id());
+    DisplayIdList list = GenerateDisplayIdList(
+        new_display_info_list.begin(), new_display_info_list.end(),
+        [](const DisplayInfo& info) { return info.id(); });
     const DisplayLayout& layout =
         layout_store_->GetRegisteredDisplayLayout(list);
     current_default_multi_display_mode_ =
@@ -775,20 +766,16 @@
     delegate_->PreDisplayConfigurationChange(clear_focus);
 
   std::vector<size_t> updated_indices;
-  if (UpdateNonPrimaryDisplayBoundsForLayout(&new_displays, &updated_indices)) {
-    for (std::vector<size_t>::iterator it = updated_indices.begin();
-         it != updated_indices.end(); ++it) {
-      size_t updated_index = *it;
-      if (std::find(added_display_indices.begin(),
-                    added_display_indices.end(),
-                    updated_index) == added_display_indices.end()) {
-        uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
-                           gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
-        if (display_changes.find(updated_index) != display_changes.end())
-          metrics |= display_changes[updated_index];
+  UpdateNonPrimaryDisplayBoundsForLayout(&new_displays, &updated_indices);
+  for (size_t updated_index : updated_indices) {
+    if (std::find(added_display_indices.begin(), added_display_indices.end(),
+                  updated_index) == added_display_indices.end()) {
+      uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS |
+                         gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA;
+      if (display_changes.find(updated_index) != display_changes.end())
+        metrics |= display_changes[updated_index];
 
-        display_changes[updated_index] = metrics;
-      }
+      display_changes[updated_index] = metrics;
     }
   }
 
@@ -939,7 +926,8 @@
 }
 
 void DisplayManager::SetMirrorMode(bool mirror) {
-  if (num_connected_displays() <= 1)
+  // TODO(oshima): Enable mirror mode for 2> displays. crbug.com/589319.
+  if (num_connected_displays() != 2)
     return;
 
 #if defined(OS_CHROMEOS)
@@ -1293,54 +1281,31 @@
   return new_display;
 }
 
-bool DisplayManager::UpdateNonPrimaryDisplayBoundsForLayout(
+void DisplayManager::UpdateNonPrimaryDisplayBoundsForLayout(
     DisplayList* display_list,
     std::vector<size_t>* updated_indices) {
-  if (display_list->size() < 2U)
-    return false;
-
-  if (display_list->size() > 2U) {
-    // For more than 2 displays, always use horizontal layout.
-    int x_offset = display_list->at(0).bounds().width();
-    for (size_t i = 1; i < display_list->size(); ++i) {
-      gfx::Display& display = display_list->at(i);
-      const gfx::Rect& bounds = display.bounds();
-      gfx::Point origin = gfx::Point(x_offset, 0);
-      gfx::Insets insets = display.GetWorkAreaInsets();
-      display.set_bounds(gfx::Rect(origin, bounds.size()));
-      display.UpdateWorkAreaFromInsets(insets);
-      x_offset += bounds.width();
-      updated_indices->push_back(i);
-    }
-    return true;
-  }
+  if (display_list->size() == 1u)
+    return;
 
   const DisplayLayout& layout = layout_store_->GetRegisteredDisplayLayout(
-      CreateDisplayIdList(display_list->at(0).id(), display_list->at(1).id()));
+      CreateDisplayIdList(*display_list));
 
   // Ignore if a user has a old format (should be extremely rare)
   // and this will be replaced with DCHECK.
-  if (layout.primary_id != gfx::Display::kInvalidDisplayID) {
-    const int64_t display_id = layout.placement.display_id;
+  if (layout.primary_id == gfx::Display::kInvalidDisplayID)
+    return;
+
+  std::vector<int64_t> ids;
+  ApplyDisplayLayout(layout, display_list, &ids);
+  for (int64_t display_id : ids) {
     DCHECK_NE(gfx::Display::kInvalidDisplayID, display_id);
     const auto iter = std::find_if(display_list->begin(), display_list->end(),
                                    [display_id](const gfx::Display& display) {
                                      return display.id() == display_id;
                                    });
     DCHECK(display_list->end() != iter);
-    size_t display_index = iter - display_list->begin();
-
-    // This function may be called before the secondary display is
-    // registered. The bounds is empty in that case and will
-    // return true.
-    gfx::Rect bounds = GetDisplayForId(iter->id()).bounds();
-
-    ApplyDisplayLayout(layout, display_list);
-
-    updated_indices->push_back(display_index);
-    return bounds != iter->bounds();
+    updated_indices->push_back(iter - display_list->begin());
   }
-  return false;
 }
 
 void DisplayManager::CreateMirrorWindowIfAny() {
@@ -1353,11 +1318,25 @@
 }
 
 void DisplayManager::ApplyDisplayLayout(const DisplayLayout& layout,
-                                        DisplayList* display_list) {
-  ApplyDisplayPlacement(layout.placement, display_list);
+                                        DisplayList* display_list,
+                                        std::vector<int64_t>* updated_ids) {
+  // Layout from primary, then dependent displays.
+  std::set<int64_t> parents;
+  parents.insert(layout.primary_id);
+  while (parents.size()) {
+    int64_t parent_id = *parents.begin();
+    parents.erase(parent_id);
+    for (const DisplayPlacement* placement : layout.placement_list) {
+      if (placement->parent_display_id == parent_id) {
+        if (ApplyDisplayPlacement(*placement, display_list) && updated_ids)
+          updated_ids->push_back(placement->display_id);
+        parents.insert(placement->display_id);
+      }
+    }
+  }
 }
 
-void DisplayManager::ApplyDisplayPlacement(const DisplayPlacement& placement,
+bool DisplayManager::ApplyDisplayPlacement(const DisplayPlacement& placement,
                                            DisplayList* display_list) {
   const gfx::Display& parent_display =
       *FindDisplayById(display_list, placement.parent_display_id);
@@ -1401,10 +1380,20 @@
       new_target_origin.Offset(-target_bounds.width(), offset);
       break;
   }
+
+  // This function may be called before the secondary display is
+  // registered, in which case, the function should return true.
+  gfx::Display* old_display = FindDisplayForId(placement.display_id);
+  gfx::Rect old_bounds;
+  if (old_display)
+    old_bounds = old_display->bounds();
+
   gfx::Insets insets = target_display->GetWorkAreaInsets();
   target_display->set_bounds(
       gfx::Rect(new_target_origin, target_bounds.size()));
   target_display->UpdateWorkAreaFromInsets(insets);
+
+  return old_bounds != target_display->bounds();
 }
 
 void DisplayManager::RunPendingTasksForTest() {
diff --git a/ash/display/display_manager.h b/ash/display/display_manager.h
index 4a4f16df..6a437bc2 100644
--- a/ash/display/display_manager.h
+++ b/ash/display/display_manager.h
@@ -82,8 +82,6 @@
     virtual void PostDisplayConfigurationChange() = 0;
   };
 
-  typedef std::vector<gfx::Display> DisplayList;
-
   // How the second display will be used.
   // 1) EXTENDED mode extends the desktop to the second dislpay.
   // 2) MIRRORING mode copies the content of the primary display to
@@ -390,9 +388,7 @@
   // When the size of |display_list| equals 2, the bounds are updated using
   // the layout registered for the display pair. For more than 2 displays,
   // the bounds are updated using horizontal layout.
-  // Returns true if any of the non-primary display's bounds has been changed
-  // from current value, or false otherwise.
-  bool UpdateNonPrimaryDisplayBoundsForLayout(
+  void UpdateNonPrimaryDisplayBoundsForLayout(
       DisplayList* display_list,
       std::vector<size_t>* updated_indices);
 
@@ -400,10 +396,15 @@
 
   void RunPendingTasksForTest();
 
+  // Applies the |layout| and updates the bounds of displays in |display_list|.
+  // |updated_ids| contains the ids for displays whose bounds have changed.
   void ApplyDisplayLayout(const DisplayLayout& layout,
-                          DisplayList* display_list);
+                          DisplayList* display_list,
+                          std::vector<int64_t>* updated_ids);
 
-  void ApplyDisplayPlacement(const DisplayPlacement& placement,
+  // Apply the display placement to the display layout.
+  // Returns true if the display bounds has been updated.
+  bool ApplyDisplayPlacement(const DisplayPlacement& placement,
                              DisplayList* display_list);
 
   Delegate* delegate_;  // not owned.
diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc
index 64d081e4..3424058 100644
--- a/ash/display/display_manager_unittest.cc
+++ b/ash/display/display_manager_unittest.cc
@@ -270,18 +270,18 @@
   display_manager()->AddRemoveDisplay();
   EXPECT_EQ(2U, display_manager()->GetNumDisplays());
   EXPECT_EQ("0 1 0", GetCountSummary());
-  reset();
 }
 
 // Tests support for 3 displays.
-TEST_F(DisplayManagerTest, UpdateThreeDisplaysTest) {
+TEST_F(DisplayManagerTest, UpdateThreeDisplaysWithDefaultLayout) {
   if (!SupportsMultipleDisplays())
     return;
 
   EXPECT_EQ(1U, display_manager()->GetNumDisplays());
 
-  // Test with three displays.
-  UpdateDisplay("0+0-640x480,640+0-320x200,960+0-400x300");
+  // Test with three displays. Native origin will not affect ash
+  // display layout.
+  UpdateDisplay("0+0-640x480,1000+0-320x200,2000+0-400x300");
 
   EXPECT_EQ(3U, display_manager()->GetNumDisplays());
   EXPECT_EQ("0,0 640x480",
@@ -298,10 +298,10 @@
   EXPECT_EQ("0,0 640x480", changed()[0].bounds().ToString());
   // Secondary and terniary displays are on right.
   EXPECT_EQ("640,0 320x200", added()[0].bounds().ToString());
-  EXPECT_EQ("640,0 320x200",
+  EXPECT_EQ("1000,0 320x200",
             GetDisplayInfo(added()[0]).bounds_in_native().ToString());
   EXPECT_EQ("960,0 400x300", added()[1].bounds().ToString());
-  EXPECT_EQ("960,0 400x300",
+  EXPECT_EQ("2000,0 400x300",
             GetDisplayInfo(added()[1]).bounds_in_native().ToString());
 
   // Verify calling ReconfigureDisplays doesn't change anything.
@@ -314,7 +314,140 @@
   EXPECT_EQ("960,0 400x300",
             display_manager()->GetDisplayAt(2).bounds().ToString());
 
-  reset();
+  DisplayPlacement default_placement(DisplayPlacement::BOTTOM, 10);
+  display_manager()->layout_store()->SetDefaultDisplayPlacement(
+      default_placement);
+
+  // Test with new displays.
+  UpdateDisplay("640x480");
+  UpdateDisplay("640x480,320x200,400x300");
+
+  EXPECT_EQ("0,0 640x480",
+            display_manager()->GetDisplayAt(0).bounds().ToString());
+  EXPECT_EQ("10,480 320x200",
+            display_manager()->GetDisplayAt(1).bounds().ToString());
+  EXPECT_EQ("20,680 400x300",
+            display_manager()->GetDisplayAt(2).bounds().ToString());
+}
+
+TEST_F(DisplayManagerTest, LayoutMorethanThreeDisplaysTest) {
+  if (!SupportsMultipleDisplays())
+    return;
+
+  int64_t primary_id = gfx::Screen::GetScreen()->GetPrimaryDisplay().id();
+  DisplayIdList list = ash::test::CreateDisplayIdListN(
+      3, primary_id, primary_id + 1, primary_id + 2);
+  {
+    // Layout: [2]
+    //         [1][P]
+    DisplayLayoutBuilder builder(primary_id);
+    builder.AddDisplayPlacement(list[1], primary_id, DisplayPlacement::LEFT,
+                                10);
+    builder.AddDisplayPlacement(list[2], list[1], DisplayPlacement::TOP, 10);
+    display_manager()->layout_store()->RegisterLayoutForDisplayIdList(
+        list, builder.Build());
+
+    UpdateDisplay("640x480,320x200,400x300");
+
+    EXPECT_EQ(3U, display_manager()->GetNumDisplays());
+
+    EXPECT_EQ("0,0 640x480",
+              display_manager()->GetDisplayAt(0).bounds().ToString());
+    EXPECT_EQ("-320,10 320x200",
+              display_manager()->GetDisplayAt(1).bounds().ToString());
+    EXPECT_EQ("-310,-290 400x300",
+              display_manager()->GetDisplayAt(2).bounds().ToString());
+  }
+  {
+    // Layout: [1]
+    //         [P][2]
+    DisplayLayoutBuilder builder(primary_id);
+    builder.AddDisplayPlacement(list[1], primary_id, DisplayPlacement::TOP, 10);
+    builder.AddDisplayPlacement(list[2], primary_id, DisplayPlacement::RIGHT,
+                                10);
+    display_manager()->layout_store()->RegisterLayoutForDisplayIdList(
+        list, builder.Build());
+
+    UpdateDisplay("640x480,320x200,400x300");
+
+    EXPECT_EQ(3U, display_manager()->GetNumDisplays());
+
+    EXPECT_EQ("0,0 640x480",
+              display_manager()->GetDisplayAt(0).bounds().ToString());
+    EXPECT_EQ("10,-200 320x200",
+              display_manager()->GetDisplayAt(1).bounds().ToString());
+    EXPECT_EQ("640,10 400x300",
+              display_manager()->GetDisplayAt(2).bounds().ToString());
+  }
+  {
+    // Layout: [P]
+    //         [2]
+    //         [1]
+    DisplayLayoutBuilder builder(primary_id);
+    builder.AddDisplayPlacement(list[1], list[2], DisplayPlacement::BOTTOM, 10);
+    builder.AddDisplayPlacement(list[2], primary_id, DisplayPlacement::BOTTOM,
+                                10);
+    display_manager()->layout_store()->RegisterLayoutForDisplayIdList(
+        list, builder.Build());
+
+    UpdateDisplay("640x480,320x200,400x300");
+
+    EXPECT_EQ(3U, display_manager()->GetNumDisplays());
+
+    EXPECT_EQ("0,0 640x480",
+              display_manager()->GetDisplayAt(0).bounds().ToString());
+    EXPECT_EQ("20,780 320x200",
+              display_manager()->GetDisplayAt(1).bounds().ToString());
+    EXPECT_EQ("10,480 400x300",
+              display_manager()->GetDisplayAt(2).bounds().ToString());
+  }
+
+  {
+    list = ash::test::CreateDisplayIdListN(5, primary_id, primary_id + 1,
+                                           primary_id + 2, primary_id + 3,
+                                           primary_id + 4);
+    // Layout: [P][2]
+    //      [3][4]
+    //      [1]
+    DisplayLayoutBuilder builder(primary_id);
+    builder.AddDisplayPlacement(list[2], primary_id, DisplayPlacement::RIGHT,
+                                10);
+    builder.AddDisplayPlacement(list[1], list[3], DisplayPlacement::BOTTOM, 10);
+    builder.AddDisplayPlacement(list[3], list[4], DisplayPlacement::LEFT, 10);
+    builder.AddDisplayPlacement(list[4], primary_id, DisplayPlacement::BOTTOM,
+                                10);
+    display_manager()->layout_store()->RegisterLayoutForDisplayIdList(
+        list, builder.Build());
+
+    UpdateDisplay("640x480,320x200,400x300,300x200,200x100");
+
+    EXPECT_EQ(5U, display_manager()->GetNumDisplays());
+
+    EXPECT_EQ("0,0 640x480",
+              display_manager()->GetDisplayAt(0).bounds().ToString());
+    // 2nd is right of the primary.
+    EXPECT_EQ("640,10 400x300",
+              display_manager()->GetDisplayAt(2).bounds().ToString());
+    // 4th is bottom of the primary.
+    EXPECT_EQ("10,480 200x100",
+              display_manager()->GetDisplayAt(4).bounds().ToString());
+    // 3rd is the left of 4th.
+    EXPECT_EQ("-290,480 300x200",
+              display_manager()->GetDisplayAt(3).bounds().ToString());
+    // 1st is the bottom of 3rd.
+    EXPECT_EQ("-280,680 320x200",
+              display_manager()->GetDisplayAt(1).bounds().ToString());
+  }
+}
+
+TEST_F(DisplayManagerTest, NoMirrorInThreeDisplays) {
+  if (!SupportsMultipleDisplays())
+    return;
+
+  UpdateDisplay("640x480,320x200,400x300");
+  display_manager()->SetMirrorMode(true);
+  EXPECT_FALSE(display_manager()->IsInMirrorMode());
+  EXPECT_EQ(3u, display_manager()->GetNumDisplays());
 }
 
 TEST_F(DisplayManagerTest, OverscanInsetsTest) {
@@ -1625,7 +1758,7 @@
   // if the displays are configured to use mirroring when running on desktop.
   // This is a workdaround to force the display manager to forget
   // the mirroing layout.
-  DisplayIdList list = CreateDisplayIdList(1, 2);
+  DisplayIdList list = test::CreateDisplayIdList2(1, 2);
   DisplayLayoutBuilder builder(
       display_manager()->layout_store()->GetRegisteredDisplayLayout(list));
   builder.SetMirrored(false);
@@ -2050,7 +2183,7 @@
   good_builder.SetSecondaryPlacement(id2, DisplayPlacement::LEFT, 0);
   scoped_ptr<DisplayLayout> good(good_builder.Build());
 
-  DisplayIdList good_list = CreateDisplayIdList(id1, id2);
+  DisplayIdList good_list = test::CreateDisplayIdList2(id1, id2);
   layout_store->RegisterLayoutForDisplayIdList(good_list, good->Copy());
 
   DisplayLayoutBuilder bad(id1);
@@ -2070,16 +2203,17 @@
   int64_t id2 = 10002;
 
   scoped_ptr<DisplayLayout> old_layout(new DisplayLayout);
-  old_layout->placement = DisplayPlacement(DisplayPlacement::BOTTOM, 0);
+  old_layout->placement_list.push_back(
+      new DisplayPlacement(DisplayPlacement::BOTTOM, 0));
   old_layout->primary_id = id1;
 
   DisplayLayoutStore* layout_store = display_manager()->layout_store();
-  DisplayIdList list = CreateDisplayIdList(id1, id2);
+  DisplayIdList list = test::CreateDisplayIdList2(id1, id2);
   layout_store->RegisterLayoutForDisplayIdList(list, std::move(old_layout));
   const DisplayLayout& stored = layout_store->GetRegisteredDisplayLayout(list);
 
-  EXPECT_EQ(id1, stored.placement.parent_display_id);
-  EXPECT_EQ(id2, stored.placement.display_id);
+  EXPECT_EQ(id1, stored.placement_list[0]->parent_display_id);
+  EXPECT_EQ(id2, stored.placement_list[0]->display_id);
 }
 
 #endif  // OS_CHROMEOS
diff --git a/ash/display/display_util.cc b/ash/display/display_util.cc
index 865d733..7c1b7c9 100644
--- a/ash/display/display_util.cc
+++ b/ash/display/display_util.cc
@@ -222,41 +222,63 @@
   return std::find_if(modes.begin(), modes.end(), comparator) != modes.end();
 }
 
-void ComputeBoundary(const gfx::Display& primary_display,
-                     const gfx::Display& secondary_display,
-                     DisplayPlacement::Position position,
-                     gfx::Rect* primary_edge_in_screen,
-                     gfx::Rect* secondary_edge_in_screen) {
-  const gfx::Rect& primary = primary_display.bounds();
-  const gfx::Rect& secondary = secondary_display.bounds();
+void ComputeBoundary(const gfx::Display& a_display,
+                     const gfx::Display& b_display,
+                     gfx::Rect* a_edge_in_screen,
+                     gfx::Rect* b_edge_in_screen) {
+  const gfx::Rect& a_bounds = a_display.bounds();
+  const gfx::Rect& b_bounds = b_display.bounds();
+
+  // Find touching side.
+  int rx = std::max(a_bounds.x(), b_bounds.x());
+  int ry = std::max(a_bounds.y(), b_bounds.y());
+  int rr = std::min(a_bounds.right(), b_bounds.right());
+  int rb = std::min(a_bounds.bottom(), b_bounds.bottom());
+
+  DisplayPlacement::Position position;
+  if ((rb - ry) == 0) {
+    // top bottom
+    if (a_bounds.bottom() == b_bounds.y()) {
+      position = DisplayPlacement::BOTTOM;
+    } else {
+      DCHECK_EQ(a_bounds.y(), b_bounds.bottom());
+      position = DisplayPlacement::TOP;
+    }
+  } else {
+    DCHECK((rr - rx) == 0);
+    // left right
+    if (a_bounds.right() == b_bounds.x()) {
+      position = DisplayPlacement::RIGHT;
+    } else {
+      DCHECK_EQ(a_bounds.x(), b_bounds.right());
+      position = DisplayPlacement::LEFT;
+    }
+  }
+
   switch (position) {
     case DisplayPlacement::TOP:
     case DisplayPlacement::BOTTOM: {
-      int left = std::max(primary.x(), secondary.x());
-      int right = std::min(primary.right(), secondary.right());
+      int left = std::max(a_bounds.x(), b_bounds.x());
+      int right = std::min(a_bounds.right(), b_bounds.right());
       if (position == DisplayPlacement::TOP) {
-        primary_edge_in_screen->SetRect(left, primary.y(), right - left, 1);
-        secondary_edge_in_screen->SetRect(left, secondary.bottom() - 1,
-                                          right - left, 1);
+        a_edge_in_screen->SetRect(left, a_bounds.y(), right - left, 1);
+        b_edge_in_screen->SetRect(left, b_bounds.bottom() - 1, right - left, 1);
       } else {
-        primary_edge_in_screen->SetRect(left, primary.bottom() - 1,
-                                        right - left, 1);
-        secondary_edge_in_screen->SetRect(left, secondary.y(), right - left, 1);
+        a_edge_in_screen->SetRect(left, a_bounds.bottom() - 1, right - left, 1);
+        b_edge_in_screen->SetRect(left, b_bounds.y(), right - left, 1);
       }
       break;
     }
     case DisplayPlacement::LEFT:
     case DisplayPlacement::RIGHT: {
-      int top = std::max(primary.y(), secondary.y());
-      int bottom = std::min(primary.bottom(), secondary.bottom());
+      int top = std::max(a_bounds.y(), b_bounds.y());
+      int bottom = std::min(a_bounds.bottom(), b_bounds.bottom());
       if (position == DisplayPlacement::LEFT) {
-        primary_edge_in_screen->SetRect(primary.x(), top, 1, bottom - top);
-        secondary_edge_in_screen->SetRect(secondary.right() - 1, top, 1,
-                                          bottom - top);
+        a_edge_in_screen->SetRect(a_bounds.x(), top, 1, bottom - top);
+        b_edge_in_screen->SetRect(b_bounds.right() - 1, top, 1, bottom - top);
       } else {
-        primary_edge_in_screen->SetRect(primary.right() - 1, top, 1,
-                                        bottom - top);
-        secondary_edge_in_screen->SetRect(secondary.y(), top, 1, bottom - top);
+        a_edge_in_screen->SetRect(a_bounds.right() - 1, top, 1, bottom - top);
+        b_edge_in_screen->SetRect(b_bounds.y(), top, 1, bottom - top);
       }
       break;
     }
@@ -349,14 +371,15 @@
   return iter == displays.end() ? -1 : (iter - displays.begin());
 }
 
-DisplayIdList CreateDisplayIdList(int64_t id1, int64_t id2) {
-  std::vector<int64_t> ids;
+DisplayIdList CreateDisplayIdList(const DisplayList& list) {
+  return GenerateDisplayIdList(
+      list.begin(), list.end(),
+      [](const gfx::Display& display) { return display.id(); });
+}
 
-  ids.push_back(id1);
-  ids.push_back(id2);
-  std::sort(ids.begin(), ids.end(),
+void SortDisplayIdList(DisplayIdList* ids) {
+  std::sort(ids->begin(), ids->end(),
             [](int64_t a, int64_t b) { return CompareDisplayIds(a, b); });
-  return ids;
 }
 
 std::string DisplayIdListToString(const ash::DisplayIdList& list) {
diff --git a/ash/display/display_util.h b/ash/display/display_util.h
index b15372e..f48ad34 100644
--- a/ash/display/display_util.h
+++ b/ash/display/display_util.h
@@ -62,11 +62,9 @@
 // Tests if the |info| has display mode that matches |ui_scale|.
 bool HasDisplayModeForUIScale(const DisplayInfo& info, float ui_scale);
 
-// Computes the bounds that defines the bounds between two displays
-// based on the layout |position|.
+// Computes the bounds that defines the bounds between two displays.
 void ComputeBoundary(const gfx::Display& primary_display,
                      const gfx::Display& secondary_display,
-                     DisplayPlacement::Position position,
                      gfx::Rect* primary_edge_in_screen,
                      gfx::Rect* secondary_edge_in_screen);
 
@@ -89,9 +87,31 @@
     const std::vector<gfx::Display>& displays,
     const gfx::Point& point_in_screen);
 
-// Creates the DisplayIdList where ids are sorted using |CompareDisplayIds|
-// below.
-ASH_EXPORT DisplayIdList CreateDisplayIdList(int64_t id1, int64_t id2);
+// Sorts id list using |CompareDisplayIds| below.
+ASH_EXPORT void SortDisplayIdList(DisplayIdList* list);
+
+// Default id generator.
+class DefaultDisplayIdGenerator {
+ public:
+  int64_t operator()(int64_t id) { return id; }
+};
+
+// Generate sorted DisplayIdList from iterators.
+template <class ForwardIterator, class Generator = DefaultDisplayIdGenerator>
+DisplayIdList GenerateDisplayIdList(ForwardIterator first,
+                                    ForwardIterator last,
+                                    Generator generator = Generator()) {
+  DisplayIdList list;
+  while (first != last) {
+    list.push_back(generator(*first));
+    ++first;
+  }
+  SortDisplayIdList(&list);
+  return list;
+}
+
+// Creates sorted DisplayIdList.
+ASH_EXPORT DisplayIdList CreateDisplayIdList(const DisplayList& list);
 
 ASH_EXPORT std::string DisplayIdListToString(const DisplayIdList& list);
 
diff --git a/ash/display/display_util_unittest.cc b/ash/display/display_util_unittest.cc
index dabb91e..14e3b03a 100644
--- a/ash/display/display_util_unittest.cc
+++ b/ash/display/display_util_unittest.cc
@@ -91,31 +91,41 @@
   }
 }
 
-TEST_F(DisplayUtilTest, CreateDisplayIdPair) {
-  DisplayIdList list = CreateDisplayIdList(10, 1);
-  EXPECT_EQ(1, list[0]);
-  EXPECT_EQ(10, list[1]);
-  list = CreateDisplayIdList(10, 100);
-  EXPECT_EQ(10, list[0]);
-  EXPECT_EQ(100, list[1]);
+TEST_F(DisplayUtilTest, GenerateDisplayIdList) {
+  DisplayIdList list;
+  {
+    int64_t ids[] = {10, 1};
+    list = GenerateDisplayIdList(std::begin(ids), std::end(ids));
+    EXPECT_EQ(1, list[0]);
+    EXPECT_EQ(10, list[1]);
+  }
+  {
+    int64_t ids[] = {10, 100};
+    list = GenerateDisplayIdList(std::begin(ids), std::end(ids));
+    EXPECT_EQ(10, list[0]);
+    EXPECT_EQ(100, list[1]);
+  }
   {
     test::ScopedSetInternalDisplayId set_internal(100);
-    list = CreateDisplayIdList(10, 100);
+    int64_t ids[] = {10, 100};
+    list = GenerateDisplayIdList(std::begin(ids), std::end(ids));
     EXPECT_EQ(100, list[0]);
     EXPECT_EQ(10, list[1]);
 
-    list = CreateDisplayIdList(100, 10);
+    std::swap(ids[0], ids[1]);
+    list = GenerateDisplayIdList(std::begin(ids), std::end(ids));
     EXPECT_EQ(100, list[0]);
     EXPECT_EQ(10, list[1]);
   }
-
   {
     test::ScopedSetInternalDisplayId set_internal(10);
-    list = CreateDisplayIdList(10, 100);
+    int64_t ids[] = {10, 100};
+    list = GenerateDisplayIdList(std::begin(ids), std::end(ids));
     EXPECT_EQ(10, list[0]);
     EXPECT_EQ(100, list[1]);
 
-    list = CreateDisplayIdList(100, 10);
+    std::swap(ids[0], ids[1]);
+    list = GenerateDisplayIdList(std::begin(ids), std::end(ids));
     EXPECT_EQ(10, list[0]);
     EXPECT_EQ(100, list[1]);
   }
diff --git a/ash/display/extended_mouse_warp_controller.cc b/ash/display/extended_mouse_warp_controller.cc
index 39d9077..9fe1254 100644
--- a/ash/display/extended_mouse_warp_controller.cc
+++ b/ash/display/extended_mouse_warp_controller.cc
@@ -79,26 +79,15 @@
   ash::DisplayManager* display_manager =
       Shell::GetInstance()->display_manager();
 
-  // For the time being, 3 or more displays are always always laid out
-  // horizontally, with each display being RIGHT of the previous one.
-  if (display_manager->GetNumDisplays() > 2) {
-    for (size_t i = 1; i < display_manager->GetNumDisplays(); ++i) {
-      const gfx::Display& left = display_manager->GetDisplayAt(i - 1);
-      const gfx::Display& right = display_manager->GetDisplayAt(i);
+  // TODO(oshima): Use ComputeBondary instead and try all combinations.
+  for (const auto* placement :
+       display_manager->GetCurrentDisplayLayout().placement_list) {
+    DisplayPlacement::Position position = placement->position;
+    const gfx::Display& a =
+        display_manager->GetDisplayForId(placement->parent_display_id);
+    const gfx::Display& b =
+        display_manager->GetDisplayForId(placement->display_id);
 
-      AddWarpRegion(
-          CreateVerticalEdgeBounds(left, right, DisplayPlacement::RIGHT),
-          drag_source != nullptr);
-    }
-  } else {
-    // Make sure to set |a| as the primary display, and |b| as the secondary
-    // display. DisplayPlacement::Position is defined in terms of primary.
-    DisplayPlacement::Position position =
-        display_manager->GetCurrentDisplayLayout().placement.position;
-    const gfx::Display& a = gfx::Screen::GetScreen()->GetPrimaryDisplay();
-    const gfx::Display& b = ScreenUtil::GetSecondaryDisplay();
-
-    // TODO(oshima): Use ComputeBondary instead.
     if (position == DisplayPlacement::TOP ||
         position == DisplayPlacement::BOTTOM) {
       AddWarpRegion(CreateHorizontalEdgeBounds(a, b, position),
diff --git a/ash/display/extended_mouse_warp_controller_unittest.cc b/ash/display/extended_mouse_warp_controller_unittest.cc
index 004645e2..8709620 100644
--- a/ash/display/extended_mouse_warp_controller_unittest.cc
+++ b/ash/display/extended_mouse_warp_controller_unittest.cc
@@ -61,7 +61,7 @@
             mouse_warp_controller()->warp_regions_[0]->b_indicator_bounds());
 
   // Move 2nd display downwards a bit.
-  layout->placement.offset = 5;
+  layout->placement_list[0]->offset = 5;
   display_manager->SetLayoutForCurrentDisplays(layout->Copy());
   event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
   // This is same as before because the 2nd display's y is above
@@ -79,7 +79,7 @@
 
   // Move it down further so that the shared edge is shorter than
   // minimum hole size (160).
-  layout->placement.offset = 200;
+  layout->placement_list[0]->offset = 200;
   display_manager->SetLayoutForCurrentDisplays(layout->Copy());
   event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
   ASSERT_EQ(1U, mouse_warp_controller()->warp_regions_.size());
@@ -95,7 +95,7 @@
             mouse_warp_controller()->warp_regions_[0]->b_indicator_bounds());
 
   // Now move 2nd display upwards
-  layout->placement.offset = -5;
+  layout->placement_list[0]->offset = -5;
   display_manager->SetLayoutForCurrentDisplays(layout->Copy());
   event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
   ASSERT_EQ(1U, mouse_warp_controller()->warp_regions_.size());
@@ -139,7 +139,7 @@
   EXPECT_EQ(gfx::Rect(0, 0, 1, 360),
             mouse_warp_controller()->warp_regions_[0]->b_indicator_bounds());
 
-  layout->placement.offset = 250;
+  layout->placement_list[0]->offset = 250;
   display_manager->SetLayoutForCurrentDisplays(layout->Copy());
   event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
   ASSERT_EQ(1U, mouse_warp_controller()->warp_regions_.size());
@@ -180,7 +180,7 @@
   EXPECT_EQ(gfx::Rect(0, 0, 360, 1),
             mouse_warp_controller()->warp_regions_[0]->b_indicator_bounds());
 
-  layout->placement.offset = 250;
+  layout->placement_list[0]->offset = 250;
   display_manager->SetLayoutForCurrentDisplays(layout->Copy());
   event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
   ASSERT_EQ(1U, mouse_warp_controller()->warp_regions_.size());
@@ -195,8 +195,8 @@
   EXPECT_EQ(gfx::Rect(250, 0, 110, 1),
             mouse_warp_controller()->warp_regions_[0]->b_indicator_bounds());
 
-  layout->placement.position = DisplayPlacement::BOTTOM;
-  layout->placement.offset = 0;
+  layout->placement_list[0]->position = DisplayPlacement::BOTTOM;
+  layout->placement_list[0]->offset = 0;
   display_manager->SetLayoutForCurrentDisplays(layout->Copy());
   event_filter()->ShowSharedEdgeIndicator(root_windows[0] /* primary */);
   ASSERT_EQ(1U, mouse_warp_controller()->warp_regions_.size());
@@ -264,9 +264,7 @@
   UpdateDisplay("360x360,700x700,1000x1000");
   run_test();
 
-  UpdateDisplay("360x360,700x700,1000x1000");
-  test::SwapPrimaryDisplay();
-  run_test();
+  // TODO(oshima): Add test cases with layouts, primary swap.
 }
 
 }  // namespace ash
diff --git a/ash/display/mirror_window_controller.cc b/ash/display/mirror_window_controller.cc
index 929b8d7..7633e13 100644
--- a/ash/display/mirror_window_controller.cc
+++ b/ash/display/mirror_window_controller.cc
@@ -332,10 +332,9 @@
     if (pair.second->ash_host->AsWindowTreeHost()->window() == root) {
       // Sanity check to catch an error early.
       int64_t id = pair.first;
-      const DisplayManager::DisplayList& list =
-          Shell::GetInstance()
-              ->display_manager()
-              ->software_mirroring_display_list();
+      const DisplayList& list = Shell::GetInstance()
+                                    ->display_manager()
+                                    ->software_mirroring_display_list();
       auto iter = std::find_if(
           list.begin(), list.end(),
           [id](const gfx::Display& display) { return display.id() == id; });
diff --git a/ash/display/mouse_cursor_event_filter_unittest.cc b/ash/display/mouse_cursor_event_filter_unittest.cc
index e00c87d..fb0e586a 100644
--- a/ash/display/mouse_cursor_event_filter_unittest.cc
+++ b/ash/display/mouse_cursor_event_filter_unittest.cc
@@ -45,7 +45,8 @@
   ASSERT_EQ(DisplayPlacement::RIGHT, Shell::GetInstance()
                                          ->display_manager()
                                          ->GetCurrentDisplayLayout()
-                                         .placement.position);
+                                         .placement_list[0]
+                                         ->position);
 
   EXPECT_FALSE(TestIfMouseWarpsAt(gfx::Point(11, 11)));
 
@@ -84,7 +85,8 @@
   ASSERT_EQ(DisplayPlacement::RIGHT, Shell::GetInstance()
                                          ->display_manager()
                                          ->GetCurrentDisplayLayout()
-                                         .placement.position);
+                                         .placement_list[0]
+                                         ->position);
 
   // Touch the left edge of the secondary root window. Pointer should NOT warp
   // because 1px left of (0, 500) is outside the primary root window.
@@ -111,7 +113,8 @@
   ASSERT_EQ(DisplayPlacement::RIGHT, Shell::GetInstance()
                                          ->display_manager()
                                          ->GetCurrentDisplayLayout()
-                                         .placement.position);
+                                         .placement_list[0]
+                                         ->position);
 
   aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(900, 123));
 
diff --git a/ash/display/screen_position_controller_unittest.cc b/ash/display/screen_position_controller_unittest.cc
index 3a550e8..20120b53 100644
--- a/ash/display/screen_position_controller_unittest.cc
+++ b/ash/display/screen_position_controller_unittest.cc
@@ -46,7 +46,7 @@
                                        ->display_manager()
                                        ->GetCurrentDisplayLayout()
                                        .Copy());
-  layout->placement.position = position;
+  layout->placement_list[0]->position = position;
   Shell::GetInstance()->display_manager()->SetLayoutForCurrentDisplays(
       std::move(layout));
 }
diff --git a/ash/display/unified_mouse_warp_controller.cc b/ash/display/unified_mouse_warp_controller.cc
index a3348bb..267f2f53 100644
--- a/ash/display/unified_mouse_warp_controller.cc
+++ b/ash/display/unified_mouse_warp_controller.cc
@@ -37,10 +37,9 @@
 // the |point_in_screen|. Returns nullptr if such WTH does not exist.
 aura::WindowTreeHost* FindMirroringWindowTreeHostFromScreenPoint(
     const gfx::Point& point_in_screen) {
-  DisplayManager::DisplayList mirroring_display_list =
-      Shell::GetInstance()
-          ->display_manager()
-          ->software_mirroring_display_list();
+  DisplayList mirroring_display_list = Shell::GetInstance()
+                                           ->display_manager()
+                                           ->software_mirroring_display_list();
   int index =
       FindDisplayIndexContainingPoint(mirroring_display_list, point_in_screen);
   if (index < 0)
@@ -76,7 +75,7 @@
     aura::client::CursorClient* cursor_client =
         aura::client::GetCursorClient(target->GetRootWindow());
     if (cursor_client) {
-      DisplayManager::DisplayList mirroring_display_list =
+      DisplayList mirroring_display_list =
           Shell::GetInstance()
               ->display_manager()
               ->software_mirroring_display_list();
@@ -120,10 +119,9 @@
 }
 
 void UnifiedMouseWarpController::ComputeBounds() {
-  DisplayManager::DisplayList display_list =
-      Shell::GetInstance()
-          ->display_manager()
-          ->software_mirroring_display_list();
+  DisplayList display_list = Shell::GetInstance()
+                                 ->display_manager()
+                                 ->software_mirroring_display_list();
 
   if (display_list.size() < 2) {
     LOG(ERROR) << "Mirroring Display lost during re-configuration";
@@ -133,8 +131,7 @@
 
   const gfx::Display& first = display_list[0];
   const gfx::Display& second = display_list[1];
-  ComputeBoundary(first, second, DisplayPlacement::RIGHT,
-                  &first_edge_bounds_in_native_,
+  ComputeBoundary(first, second, &first_edge_bounds_in_native_,
                   &second_edge_bounds_in_native_);
 
   first_edge_bounds_in_native_ =
@@ -154,10 +151,9 @@
   bool in_second_edge = second_edge_bounds_in_native_.Contains(point_in_native);
   if (!in_first_edge && !in_second_edge)
     return false;
-  DisplayManager::DisplayList display_list =
-      Shell::GetInstance()
-          ->display_manager()
-          ->software_mirroring_display_list();
+  DisplayList display_list = Shell::GetInstance()
+                                 ->display_manager()
+                                 ->software_mirroring_display_list();
   // Wait updating the cursor until the cursor moves to the new display
   // to avoid showing the wrong sized cursor at the source display.
   current_cursor_display_id_ =
diff --git a/ash/display/window_tree_host_manager.cc b/ash/display/window_tree_host_manager.cc
index eb109b81..4b59621 100644
--- a/ash/display/window_tree_host_manager.cc
+++ b/ash/display/window_tree_host_manager.cc
@@ -398,6 +398,9 @@
       window_tree_hosts_.size() < 2) {
     return;
   }
+  // TODO(oshima): Implement swapping primary for 2> displays.
+  if (GetDisplayManager()->GetNumDisplays() > 2)
+    return;
 
   const gfx::Display& new_primary_display =
       GetDisplayManager()->GetDisplayForId(id);
@@ -442,7 +445,7 @@
   // Only update the layout if it is requested to swap primary display.
   if (layout.primary_id != new_primary_display.id()) {
     scoped_ptr<DisplayLayout> swapped_layout(layout.Copy());
-    swapped_layout->placement.Swap();
+    swapped_layout->placement_list[0]->Swap();
     swapped_layout->primary_id = new_primary_display.id();
     DisplayIdList list = display_manager->GetCurrentDisplayIdList();
     GetDisplayManager()->layout_store()->RegisterLayoutForDisplayIdList(
diff --git a/ash/display/window_tree_host_manager_unittest.cc b/ash/display/window_tree_host_manager_unittest.cc
index 69110bc..eb01743 100644
--- a/ash/display/window_tree_host_manager_unittest.cc
+++ b/ash/display/window_tree_host_manager_unittest.cc
@@ -196,13 +196,12 @@
 }
 
 void SetDefaultDisplayLayout(DisplayPlacement::Position position) {
-  scoped_ptr<DisplayLayout> default_layout(new DisplayLayout);
-  default_layout->placement = DisplayPlacement(position, 0);
+  DisplayPlacement default_placement(position, 0);
 
   Shell::GetInstance()
       ->display_manager()
       ->layout_store()
-      ->SetDefaultDisplayLayout(std::move(default_layout));
+      ->SetDefaultDisplayPlacement(default_placement);
 }
 
 class WindowTreeHostManagerShutdownTest : public test::AshTestBase {
@@ -708,99 +707,6 @@
   EXPECT_EQ(0, observer.GetActivationChangedCountAndReset());
 }
 
-TEST_F(WindowTreeHostManagerTest, SwapPrimary) {
-  if (!SupportsMultipleDisplays())
-    return;
-
-  WindowTreeHostManager* window_tree_host_manager =
-      Shell::GetInstance()->window_tree_host_manager();
-  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
-
-  UpdateDisplay("200x200,300x300");
-  gfx::Display primary_display = gfx::Screen::GetScreen()->GetPrimaryDisplay();
-  gfx::Display secondary_display = ScreenUtil::GetSecondaryDisplay();
-
-  display_manager->SetLayoutForCurrentDisplays(
-      test::CreateDisplayLayout(DisplayPlacement::RIGHT, 50));
-
-  EXPECT_NE(primary_display.id(), secondary_display.id());
-  aura::Window* primary_root =
-      window_tree_host_manager->GetRootWindowForDisplayId(primary_display.id());
-  aura::Window* secondary_root =
-      window_tree_host_manager->GetRootWindowForDisplayId(
-          secondary_display.id());
-  EXPECT_NE(primary_root, secondary_root);
-  aura::Window* shelf_window =
-      Shelf::ForPrimaryDisplay()->shelf_widget()->GetNativeView();
-  EXPECT_TRUE(primary_root->Contains(shelf_window));
-  EXPECT_FALSE(secondary_root->Contains(shelf_window));
-  EXPECT_EQ(primary_display.id(),
-            gfx::Screen::GetScreen()
-                ->GetDisplayNearestPoint(gfx::Point(-100, -100))
-                .id());
-  EXPECT_EQ(primary_display.id(),
-            gfx::Screen::GetScreen()->GetDisplayNearestWindow(nullptr).id());
-
-  EXPECT_EQ("0,0 200x200", primary_display.bounds().ToString());
-  EXPECT_EQ("0,0 200x153", primary_display.work_area().ToString());
-  EXPECT_EQ("200,0 300x300", secondary_display.bounds().ToString());
-  EXPECT_EQ("200,0 300x253", secondary_display.work_area().ToString());
-  EXPECT_EQ("right, 50, default_unified",
-            display_manager->GetCurrentDisplayLayout().ToString());
-
-  // Switch primary and secondary
-  window_tree_host_manager->SetPrimaryDisplayId(secondary_display.id());
-  const DisplayLayout& inverted_layout =
-      display_manager->GetCurrentDisplayLayout();
-  EXPECT_EQ("left, -50, default_unified", inverted_layout.ToString());
-
-  EXPECT_EQ(secondary_display.id(),
-            gfx::Screen::GetScreen()->GetPrimaryDisplay().id());
-  EXPECT_EQ(primary_display.id(), ScreenUtil::GetSecondaryDisplay().id());
-  EXPECT_EQ(primary_display.id(),
-            gfx::Screen::GetScreen()
-                ->GetDisplayNearestPoint(gfx::Point(-100, -100))
-                .id());
-  EXPECT_EQ(secondary_display.id(),
-            gfx::Screen::GetScreen()->GetDisplayNearestWindow(nullptr).id());
-
-  EXPECT_EQ(primary_root, window_tree_host_manager->GetRootWindowForDisplayId(
-                              secondary_display.id()));
-  EXPECT_EQ(secondary_root, window_tree_host_manager->GetRootWindowForDisplayId(
-                                primary_display.id()));
-  EXPECT_TRUE(primary_root->Contains(shelf_window));
-  EXPECT_FALSE(secondary_root->Contains(shelf_window));
-
-  // Test if the bounds are correctly swapped.
-  gfx::Display swapped_primary = gfx::Screen::GetScreen()->GetPrimaryDisplay();
-  gfx::Display swapped_secondary = ScreenUtil::GetSecondaryDisplay();
-  EXPECT_EQ("0,0 300x300", swapped_primary.bounds().ToString());
-  EXPECT_EQ("0,0 300x253", swapped_primary.work_area().ToString());
-  EXPECT_EQ("-200,-50 200x200", swapped_secondary.bounds().ToString());
-
-  EXPECT_EQ("-200,-50 200x153", swapped_secondary.work_area().ToString());
-
-  aura::WindowTracker tracker;
-  tracker.Add(primary_root);
-  tracker.Add(secondary_root);
-
-  // Deleting 2nd display should move the primary to original primary display.
-  UpdateDisplay("200x200");
-  RunAllPendingInMessageLoop();  // RootWindow is deleted in a posted task.
-  EXPECT_EQ(1, gfx::Screen::GetScreen()->GetNumDisplays());
-  EXPECT_EQ(primary_display.id(),
-            gfx::Screen::GetScreen()->GetPrimaryDisplay().id());
-  EXPECT_EQ(primary_display.id(),
-            gfx::Screen::GetScreen()
-                ->GetDisplayNearestPoint(gfx::Point(-100, -100))
-                .id());
-  EXPECT_EQ(primary_display.id(),
-            gfx::Screen::GetScreen()->GetDisplayNearestWindow(nullptr).id());
-  EXPECT_TRUE(tracker.Contains(primary_root));
-  EXPECT_FALSE(tracker.Contains(secondary_root));
-  EXPECT_TRUE(primary_root->Contains(shelf_window));
-}
-
 TEST_F(WindowTreeHostManagerTest, FindNearestDisplay) {
   if (!SupportsMultipleDisplays())
     return;
@@ -895,6 +801,14 @@
   EXPECT_EQ(primary_display.id(),
             gfx::Screen::GetScreen()->GetDisplayNearestWindow(nullptr).id());
 
+  EXPECT_EQ("0,0 200x200", primary_display.bounds().ToString());
+  EXPECT_EQ("0,0 200x153", primary_display.work_area().ToString());
+  EXPECT_EQ("200,0 300x300", secondary_display.bounds().ToString());
+  EXPECT_EQ("200,0 300x253", secondary_display.work_area().ToString());
+  EXPECT_EQ(
+      "id=2200000001, parent=2200000000, right, 50",
+      display_manager->GetCurrentDisplayLayout().placement_list[0]->ToString());
+
   // Switch primary and secondary by display ID.
   TestObserver observer;
   window_tree_host_manager->SetPrimaryDisplayId(secondary_display.id());
@@ -913,14 +827,20 @@
   const DisplayLayout& inverted_layout =
       display_manager->GetCurrentDisplayLayout();
 
-  EXPECT_EQ("left, -50, default_unified", inverted_layout.ToString());
+  EXPECT_EQ("id=2200000000, parent=2200000001, left, -50",
+            inverted_layout.placement_list[0]->ToString());
+  // Test if the bounds are correctly swapped.
+  gfx::Display swapped_primary = gfx::Screen::GetScreen()->GetPrimaryDisplay();
+  gfx::Display swapped_secondary = ScreenUtil::GetSecondaryDisplay();
+  EXPECT_EQ("0,0 300x300", swapped_primary.bounds().ToString());
+  EXPECT_EQ("0,0 300x253", swapped_primary.work_area().ToString());
+  EXPECT_EQ("-200,-50 200x200", swapped_secondary.bounds().ToString());
+  EXPECT_EQ("-200,-50 200x153", swapped_secondary.work_area().ToString());
 
   // Calling the same ID don't do anything.
   window_tree_host_manager->SetPrimaryDisplayId(secondary_display.id());
   EXPECT_EQ(0, observer.CountAndReset());
 
-  LOG(ERROR) << "A";
-
   aura::WindowTracker tracker;
   tracker.Add(primary_root);
   tracker.Add(secondary_root);
@@ -941,8 +861,6 @@
   EXPECT_FALSE(tracker.Contains(secondary_root));
   EXPECT_TRUE(primary_root->Contains(shelf_window));
 
-  LOG(ERROR) << "B:" << primary_display.ToString();
-
   // Adding 2nd display with the same ID.  The 2nd display should become primary
   // since secondary id is still stored as desirable_primary_id.
   std::vector<DisplayInfo> display_info_list;
@@ -953,8 +871,6 @@
 
   display_manager->OnNativeDisplaysChanged(display_info_list);
 
-  LOG(ERROR) << "C 0";
-
   EXPECT_EQ(2, gfx::Screen::GetScreen()->GetNumDisplays());
   EXPECT_EQ(secondary_display.id(),
             gfx::Screen::GetScreen()->GetPrimaryDisplay().id());
@@ -965,8 +881,6 @@
                               primary_display.id()));
   EXPECT_TRUE(primary_root->Contains(shelf_window));
 
-  LOG(ERROR) << "C";
-
   // Deleting 2nd display and adding 2nd display with a different ID.  The 2nd
   // display shouldn't become primary.
   UpdateDisplay("200x200");
@@ -975,8 +889,6 @@
   third_display_info.SetBounds(secondary_display.bounds());
   ASSERT_NE(primary_display.id(), third_display_info.id());
 
-  LOG(ERROR) << "D";
-
   const DisplayInfo& primary_display_info =
       display_manager->GetDisplayInfo(primary_display.id());
   std::vector<DisplayInfo> display_info_list2;
@@ -994,6 +906,17 @@
   EXPECT_TRUE(primary_root->Contains(shelf_window));
 }
 
+TEST_F(WindowTreeHostManagerTest, NoSwapPrimaryWithThreeDisplays) {
+  if (!SupportsMultipleDisplays())
+    return;
+  int64_t primary = gfx::Screen::GetScreen()->GetPrimaryDisplay().id();
+  UpdateDisplay("500x400,400x300,300x200");
+  EXPECT_EQ(primary, gfx::Screen::GetScreen()->GetPrimaryDisplay().id());
+  Shell::GetInstance()->window_tree_host_manager()->SetPrimaryDisplayId(
+      ScreenUtil::GetSecondaryDisplay().id());
+  EXPECT_EQ(primary, gfx::Screen::GetScreen()->GetPrimaryDisplay().id());
+}
+
 TEST_F(WindowTreeHostManagerTest, OverscanInsets) {
   if (!SupportsMultipleDisplays())
     return;
@@ -1441,9 +1364,8 @@
   // Set the 2nd display on the left.
   DisplayLayoutStore* layout_store =
       Shell::GetInstance()->display_manager()->layout_store();
-  scoped_ptr<DisplayLayout> layout(new DisplayLayout);
-  layout->placement.position = DisplayPlacement::LEFT;
-  layout_store->SetDefaultDisplayLayout(std::move(layout));
+  DisplayPlacement new_default(DisplayPlacement::LEFT, 0);
+  layout_store->SetDefaultDisplayPlacement(new_default);
 
   UpdateDisplay("200x200,300x300");
   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
diff --git a/ash/extended_desktop_unittest.cc b/ash/extended_desktop_unittest.cc
index 3e82e88..d4fc79b 100644
--- a/ash/extended_desktop_unittest.cc
+++ b/ash/extended_desktop_unittest.cc
@@ -36,7 +36,7 @@
 void SetSecondaryDisplayLayout(DisplayPlacement::Position position) {
   scoped_ptr<DisplayLayout> layout =
       Shell::GetInstance()->display_manager()->GetCurrentDisplayLayout().Copy();
-  layout->placement.position = position;
+  layout->placement_list[0]->position = position;
   Shell::GetInstance()->display_manager()->SetLayoutForCurrentDisplays(
       std::move(layout));
 }
diff --git a/ash/mus/sysui_application.cc b/ash/mus/sysui_application.cc
index d5e008c..739242d 100644
--- a/ash/mus/sysui_application.cc
+++ b/ash/mus/sysui_application.cc
@@ -256,7 +256,8 @@
 
 void SysUIApplication::Initialize(mojo::Shell* shell,
                                   const std::string& url,
-                                  uint32_t id) {
+                                  uint32_t id,
+                                  uint32_t user_id) {
   ash_init_.reset(new AshInit());
   ash_init_->Initialize(shell);
 }
diff --git a/ash/mus/sysui_application.h b/ash/mus/sysui_application.h
index d7bebe5..c09804e8 100644
--- a/ash/mus/sysui_application.h
+++ b/ash/mus/sysui_application.h
@@ -24,7 +24,8 @@
   // mojo::ShellClient:
   void Initialize(mojo::Shell* shell,
                   const std::string& url,
-                  uint32_t id) override;
+                  uint32_t id,
+                  uint32_t user_id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
   mojo::TracingImpl tracing_;
diff --git a/ash/resources/BUILD.gn b/ash/resources/BUILD.gn
index bbb66bd..399ad6f2 100644
--- a/ash/resources/BUILD.gn
+++ b/ash/resources/BUILD.gn
@@ -4,6 +4,7 @@
 
 import("//tools/grit/grit_rule.gni")
 import("//tools/grit/repack.gni")
+import("//ui/base/ui_features.gni")
 
 assert(enable_hidpi)
 
diff --git a/ash/system/chromeos/session/logout_confirmation_controller.cc b/ash/system/chromeos/session/logout_confirmation_controller.cc
index 970903d..7c724b0 100644
--- a/ash/system/chromeos/session/logout_confirmation_controller.cc
+++ b/ash/system/chromeos/session/logout_confirmation_controller.cc
@@ -30,7 +30,7 @@
   if (Shell::HasInstance())
     Shell::GetInstance()->RemoveShellObserver(this);
   if (dialog_)
-    dialog_->GetWidget()->Close();
+    dialog_->ControllerGone();
 }
 
 void LogoutConfirmationController::ConfirmLogout(
diff --git a/ash/system/chromeos/session/logout_confirmation_dialog.cc b/ash/system/chromeos/session/logout_confirmation_dialog.cc
index 80a71e84..b43e5e6 100644
--- a/ash/system/chromeos/session/logout_confirmation_dialog.cc
+++ b/ash/system/chromeos/session/logout_confirmation_dialog.cc
@@ -62,6 +62,11 @@
   UpdateLabel();
 }
 
+void LogoutConfirmationDialog::ControllerGone() {
+  controller_ = nullptr;
+  GetWidget()->Close();
+}
+
 bool LogoutConfirmationDialog::Accept() {
   logout_time_ = controller_->clock()->NowTicks();
   UpdateLabel();
@@ -84,13 +89,10 @@
   return views::DialogDelegateView::GetDialogButtonLabel(button);
 }
 
-void LogoutConfirmationDialog::OnClosed() {
+void LogoutConfirmationDialog::WindowClosing() {
   update_timer_.Stop();
-  controller_->OnDialogClosed();
-}
-
-void LogoutConfirmationDialog::DeleteDelegate() {
-  delete this;
+  if (controller_)
+    controller_->OnDialogClosed();
 }
 
 void LogoutConfirmationDialog::UpdateLabel() {
diff --git a/ash/system/chromeos/session/logout_confirmation_dialog.h b/ash/system/chromeos/session/logout_confirmation_dialog.h
index 61407b10..d9d2c3d 100644
--- a/ash/system/chromeos/session/logout_confirmation_dialog.h
+++ b/ash/system/chromeos/session/logout_confirmation_dialog.h
@@ -30,13 +30,15 @@
 
   void Update(base::TimeTicks logout_time);
 
+  // Called when |controller_| is no longer valid.
+  void ControllerGone();
+
   // views::DialogDelegateView:
   bool Accept() override;
   ui::ModalType GetModalType() const override;
   base::string16 GetWindowTitle() const override;
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
-  void OnClosed() override;
-  void DeleteDelegate() override;
+  void WindowClosing() override;
 
  private:
   void UpdateLabel();
diff --git a/ash/test/display_manager_test_api.cc b/ash/test/display_manager_test_api.cc
index 5ab7633..0e49e6d0 100644
--- a/ash/test/display_manager_test_api.cc
+++ b/ash/test/display_manager_test_api.cc
@@ -4,6 +4,7 @@
 
 #include "ash/test/display_manager_test_api.h"
 
+#include <cstdarg>
 #include <vector>
 
 #include "ash/ash_switches.h"
@@ -40,10 +41,9 @@
       specs, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
   size_t index = 0;
 
-  DisplayManager::DisplayList list =
-      display_manager->IsInUnifiedMode()
-          ? display_manager->software_mirroring_display_list()
-          : display_manager->active_display_list();
+  DisplayList list = display_manager->IsInUnifiedMode()
+                         ? display_manager->software_mirroring_display_list()
+                         : display_manager->active_display_list();
 
   for (std::vector<std::string>::const_iterator iter = parts.begin();
        iter != parts.end(); ++iter, ++index) {
@@ -187,5 +187,25 @@
   return builder.Build();
 }
 
+DisplayIdList CreateDisplayIdList2(int64_t id1, int64_t id2) {
+  DisplayIdList list;
+  list.push_back(id1);
+  list.push_back(id2);
+  SortDisplayIdList(&list);
+  return list;
+}
+
+DisplayIdList CreateDisplayIdListN(size_t count, ...) {
+  DisplayIdList list;
+  va_list args;
+  va_start(args, count);
+  for (size_t i = 0; i < count; i++) {
+    int64_t id = va_arg(args, int64_t);
+    list.push_back(id);
+  }
+  SortDisplayIdList(&list);
+  return list;
+}
+
 }  // namespace test
 }  // namespace ash
diff --git a/ash/test/display_manager_test_api.h b/ash/test/display_manager_test_api.h
index 0bd66ad..573f212 100644
--- a/ash/test/display_manager_test_api.h
+++ b/ash/test/display_manager_test_api.h
@@ -102,6 +102,10 @@
     DisplayPlacement::Position position,
     int offset);
 
+// Creates the DisplayIdList from ints.
+DisplayIdList CreateDisplayIdList2(int64_t id1, int64_t id2);
+DisplayIdList CreateDisplayIdListN(size_t count, ...);
+
 }  // namespace test
 }  // namespace ash
 
diff --git a/ash/test/test_session_state_animator.cc b/ash/test/test_session_state_animator.cc
index f16a1c5..d144b63c 100644
--- a/ash/test/test_session_state_animator.cc
+++ b/ash/test/test_session_state_animator.cc
@@ -97,6 +97,9 @@
       failed_callback(failed_callback) {
 }
 
+TestSessionStateAnimator::ActiveAnimation::ActiveAnimation(
+    const ActiveAnimation& other) = default;
+
 TestSessionStateAnimator::ActiveAnimation::~ActiveAnimation() {
 }
 
diff --git a/ash/test/test_session_state_animator.h b/ash/test/test_session_state_animator.h
index 1668dfd..83ce101 100644
--- a/ash/test/test_session_state_animator.h
+++ b/ash/test/test_session_state_animator.h
@@ -93,6 +93,7 @@
         AnimationSpeed speed,
         base::Closure success_callback,
         base::Closure failed_callback);
+    ActiveAnimation(const ActiveAnimation& other);
     virtual ~ActiveAnimation();
 
     // The time epoch that this animation was scheduled.
diff --git a/ash/wm/workspace/multi_window_resize_controller.cc b/ash/wm/workspace/multi_window_resize_controller.cc
index 64da854..95afc20 100644
--- a/ash/wm/workspace/multi_window_resize_controller.cc
+++ b/ash/wm/workspace/multi_window_resize_controller.cc
@@ -148,6 +148,9 @@
       direction(TOP_BOTTOM){
 }
 
+MultiWindowResizeController::ResizeWindows::ResizeWindows(
+    const ResizeWindows& other) = default;
+
 MultiWindowResizeController::ResizeWindows::~ResizeWindows() {
 }
 
diff --git a/ash/wm/workspace/multi_window_resize_controller.h b/ash/wm/workspace/multi_window_resize_controller.h
index 73cb0b8..a40197b 100644
--- a/ash/wm/workspace/multi_window_resize_controller.h
+++ b/ash/wm/workspace/multi_window_resize_controller.h
@@ -61,6 +61,7 @@
   // Used to track the two resizable windows and direction.
   struct ResizeWindows {
     ResizeWindows();
+    ResizeWindows(const ResizeWindows& other);
     ~ResizeWindows();
 
     // Returns true if |other| equals this ResizeWindows. This does *not*
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 2014163..9d1c838 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1853,7 +1853,10 @@
 
   if (is_linux) {
     sources -= [ "file_version_info_unittest.cc" ]
-    sources += [ "nix/xdg_util_unittest.cc" ]
+
+    if (is_desktop_linux) {
+      sources += [ "nix/xdg_util_unittest.cc" ]
+    }
 
     deps += [ "//base/test:malloc_wrapper" ]
 
@@ -1867,7 +1870,7 @@
     }
   }
 
-  if (!is_linux || use_ozone) {
+  if (!use_glib) {
     sources -= [ "message_loop/message_pump_glib_unittest.cc" ]
   }
 
diff --git a/base/allocator/tcmalloc_unittest.cc b/base/allocator/tcmalloc_unittest.cc
index eb1b0f0ca8..37c0ef6 100644
--- a/base/allocator/tcmalloc_unittest.cc
+++ b/base/allocator/tcmalloc_unittest.cc
@@ -189,7 +189,8 @@
   TCMallocDoFreeForTest(p);
 }
 
-TEST(TCMallocFreeTest, BadPageAlignedPointerInsideLargeObject) {
+// TODO(ssid): Fix flakiness and enable the test, crbug.com/571549.
+TEST(TCMallocFreeTest, DISABLED_BadPageAlignedPointerInsideLargeObject) {
   const size_t kPageSize = base::GetPageSize();
   const size_t kMaxSize = 10 * kPageSize;
   char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(kMaxSize + 1));
diff --git a/base/android/java/src/org/chromium/base/PathUtils.java b/base/android/java/src/org/chromium/base/PathUtils.java
index 09c3b08..9d53a96 100644
--- a/base/android/java/src/org/chromium/base/PathUtils.java
+++ b/base/android/java/src/org/chromium/base/PathUtils.java
@@ -30,49 +30,116 @@
     private static final int DATABASE_DIRECTORY = 1;
     private static final int CACHE_DIRECTORY = 2;
     private static final int NUM_DIRECTORIES = 3;
-    private static AsyncTask<String, Void, String[]> sDirPathFetchTask;
+    private static AsyncTask<Void, Void, String[]> sDirPathFetchTask;
 
     private static File sThumbnailDirectory;
 
+    // In setPrivateDataDirectorySuffix(), we store the app's context. If the AsyncTask started in
+    // setPrivateDataDirectorySuffix() fails to complete by the time we need the values, we will
+    // need the context so that we can restart the task synchronously on the UI thread.
+    private static Context sDataDirectoryAppContext;
+
+    // We also store the directory path suffix from setPrivateDataDirectorySuffix() for the same
+    // reason as above.
+    private static String sDataDirectorySuffix;
+
     // Prevent instantiation.
     private PathUtils() {}
 
     /**
+     * Initialization-on-demand holder. This exists for thread-safe lazy initialization. It will
+     * cause getOrComputeDirectoryPaths() to be called (safely) the first time DIRECTORY_PATHS is
+     * accessed.
+     *
+     * <p>See https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom.
+     */
+    private static class Holder {
+        private static final String[] DIRECTORY_PATHS = getOrComputeDirectoryPaths();
+    }
+
+    /**
+     * Get the directory paths from sDirPathFetchTask if available, or compute it synchronously
+     * on the UI thread otherwise. This should only be called as part of Holder's initialization
+     * above to guarantee thread-safety as part of the initialization-on-demand holder idiom.
+     */
+    private static String[] getOrComputeDirectoryPaths() {
+        try {
+            // We need to call sDirPathFetchTask.cancel() here to prevent races. If it returns
+            // true, that means that the task got canceled successfully (and thus, it did not
+            // finish running its task). Otherwise, it failed to cancel, meaning that it was
+            // already finished.
+            if (sDirPathFetchTask.cancel(false)) {
+                // Allow disk access here because we have no other choice.
+                StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+                StrictMode.allowThreadDiskWrites();
+                try {
+                    // sDirPathFetchTask did not complete. We have to run the code it was supposed
+                    // to be responsible for synchronously on the UI thread.
+                    return PathUtils.setPrivateDataDirectorySuffixInternal();
+                } finally {
+                    StrictMode.setThreadPolicy(oldPolicy);
+                }
+            } else {
+                // sDirPathFetchTask succeeded, and the values we need should be ready to access
+                // synchronously in its internal future.
+                return sDirPathFetchTask.get();
+            }
+        } catch (InterruptedException e) {
+        } catch (ExecutionException e) {
+        }
+
+        return null;
+    }
+
+    /**
+     * Fetch the path of the directory where private data is to be stored by the application. This
+     * is meant to be called in an AsyncTask in setPrivateDataDirectorySuffix(), but if we need the
+     * result before the AsyncTask has had a chance to finish, then it's best to cancel the task
+     * and run it on the UI thread instead, inside getOrComputeDirectoryPaths().
+     *
+     * @see Context#getDir(String, int)
+     */
+    private static String[] setPrivateDataDirectorySuffixInternal() {
+        String[] paths = new String[NUM_DIRECTORIES];
+        paths[DATA_DIRECTORY] = sDataDirectoryAppContext.getDir(sDataDirectorySuffix,
+                Context.MODE_PRIVATE).getPath();
+        paths[DATABASE_DIRECTORY] = sDataDirectoryAppContext.getDatabasePath("foo").getParent();
+        // TODO(wnwen): Find a way to avoid calling this function in renderer process.
+        if (sDataDirectoryAppContext.getCacheDir() != null) {
+            paths[CACHE_DIRECTORY] = sDataDirectoryAppContext.getCacheDir().getPath();
+        }
+        return paths;
+    }
+
+    /**
      * Starts an asynchronous task to fetch the path of the directory where private data is to be
      * stored by the application.
      *
+     * <p>This task can run long (or more likely be delayed in a large task queue), in which case we
+     * want to cancel it and run on the UI thread instead. Unfortunately, this means keeping a bit
+     * of extra static state - we need to store the suffix and the application context in case we
+     * need to try to re-execute later.
+     *
      * @param suffix The private data directory suffix.
      * @see Context#getDir(String, int)
      */
     public static void setPrivateDataDirectorySuffix(String suffix, Context context) {
-        final Context appContext = context.getApplicationContext();
-        sDirPathFetchTask = new AsyncTask<String, Void, String[]>() {
+        sDataDirectorySuffix = suffix;
+        sDataDirectoryAppContext = context.getApplicationContext();
+        sDirPathFetchTask = new AsyncTask<Void, Void, String[]>() {
             @Override
-            protected String[] doInBackground(String... dataDirectorySuffix) {
-                String[] paths = new String[NUM_DIRECTORIES];
-                paths[DATA_DIRECTORY] =
-                        appContext.getDir(dataDirectorySuffix[0], Context.MODE_PRIVATE).getPath();
-                paths[DATABASE_DIRECTORY] = appContext.getDatabasePath("foo").getParent();
-                // TODO(wnwen): Find a way to avoid calling this function in renderer process.
-                if (appContext.getCacheDir() != null) {
-                    paths[CACHE_DIRECTORY] = appContext.getCacheDir().getPath();
-                }
-                return paths;
+            protected String[] doInBackground(Void... unused) {
+                return PathUtils.setPrivateDataDirectorySuffixInternal();
             }
-        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, suffix);
+        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     }
 
     /**
      * @param index The index of the cached directory path.
-     * @return The directory path requested, or null if not available.
+     * @return The directory path requested.
      */
     private static String getDirectoryPath(int index) {
-        try {
-            return sDirPathFetchTask.get()[index];
-        } catch (InterruptedException e) {
-        } catch (ExecutionException e) {
-        }
-        return null;
+        return Holder.DIRECTORY_PATHS[index];
     }
 
     /**
diff --git a/base/debug/asan_invalid_access.cc b/base/debug/asan_invalid_access.cc
index 0abde8c..ba0a10b 100644
--- a/base/debug/asan_invalid_access.cc
+++ b/base/debug/asan_invalid_access.cc
@@ -60,36 +60,33 @@
 static const size_t kArraySize = 5;
 
 void AsanHeapOverflow() {
-  scoped_ptr<int[]> array(new int[kArraySize]);
-  // Declares the dummy value as volatile to make sure it doesn't get optimized
-  // away.
-  int volatile dummy = 0;
-  dummy = array[kArraySize];
-  base::debug::Alias(const_cast<int*>(&dummy));
+  // Declares the array as volatile to make sure it doesn't get optimized away.
+  scoped_ptr<volatile int[]> array(
+      const_cast<volatile int*>(new int[kArraySize]));
+  int dummy = array[kArraySize];
+  base::debug::Alias(&dummy);
 }
 
 void AsanHeapUnderflow() {
-  scoped_ptr<int[]> array(new int[kArraySize]);
-  // Declares the dummy value as volatile to make sure it doesn't get optimized
-  // away.
-  int volatile dummy = 0;
+  // Declares the array as volatile to make sure it doesn't get optimized away.
+  scoped_ptr<volatile int[]> array(
+      const_cast<volatile int*>(new int[kArraySize]));
   // We need to store the underflow address in a temporary variable as trying to
   // access array[-1] will trigger a warning C4245: "conversion from 'int' to
   // 'size_t', signed/unsigned mismatch".
-  int* underflow_address = &array[0] - 1;
-  dummy = *underflow_address;
-  base::debug::Alias(const_cast<int*>(&dummy));
+  volatile int* underflow_address = &array[0] - 1;
+  int dummy = *underflow_address;
+  base::debug::Alias(&dummy);
 }
 
 void AsanHeapUseAfterFree() {
-  scoped_ptr<int[]> array(new int[kArraySize]);
-  // Declares the dummy value as volatile to make sure it doesn't get optimized
-  // away.
-  int volatile dummy = 0;
-  int* dangling = array.get();
+  // Declares the array as volatile to make sure it doesn't get optimized away.
+  scoped_ptr<volatile int[]> array(
+      const_cast<volatile int*>(new int[kArraySize]));
+  volatile int* dangling = array.get();
   array.reset();
-  dummy = dangling[kArraySize / 2];
-  base::debug::Alias(const_cast<int*>(&dummy));
+  int dummy = dangling[kArraySize / 2];
+  base::debug::Alias(&dummy);
 }
 
 #endif  // ADDRESS_SANITIZER || SYZYASAN
diff --git a/base/files/file_util.cc b/base/files/file_util.cc
index 9e35b67..3169370 100644
--- a/base/files/file_util.cc
+++ b/base/files/file_util.cc
@@ -124,9 +124,9 @@
 }
 #endif  // !defined(OS_NACL_NONSFI)
 
-bool ReadFileToString(const FilePath& path,
-                      std::string* contents,
-                      size_t max_size) {
+bool ReadFileToStringWithMaxSize(const FilePath& path,
+                                 std::string* contents,
+                                 size_t max_size) {
   if (contents)
     contents->clear();
   if (path.ReferencesParent())
@@ -162,7 +162,8 @@
 }
 
 bool ReadFileToString(const FilePath& path, std::string* contents) {
-  return ReadFileToString(path, contents, std::numeric_limits<size_t>::max());
+  return ReadFileToStringWithMaxSize(path, contents,
+                                     std::numeric_limits<size_t>::max());
 }
 
 #if !defined(OS_NACL_NONSFI)
diff --git a/base/files/file_util.h b/base/files/file_util.h
index dfc10a3..05b3cbf 100644
--- a/base/files/file_util.h
+++ b/base/files/file_util.h
@@ -154,9 +154,9 @@
 // |max_size|.
 // |contents| may be NULL, in which case this function is useful for its side
 // effect of priming the disk cache (could be used for unit tests).
-BASE_EXPORT bool ReadFileToString(const FilePath& path,
-                                  std::string* contents,
-                                  size_t max_size);
+BASE_EXPORT bool ReadFileToStringWithMaxSize(const FilePath& path,
+                                             std::string* contents,
+                                             size_t max_size);
 
 #if defined(OS_POSIX)
 
diff --git a/base/files/file_util_unittest.cc b/base/files/file_util_unittest.cc
index 61ccba4..a0d0a289 100644
--- a/base/files/file_util_unittest.cc
+++ b/base/files/file_util_unittest.cc
@@ -2066,26 +2066,26 @@
   EXPECT_EQ(kTestData, data);
 
   data = "temp";
-  EXPECT_FALSE(ReadFileToString(file_path, &data, 0));
+  EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &data, 0));
   EXPECT_EQ(0u, data.length());
 
   data = "temp";
-  EXPECT_FALSE(ReadFileToString(file_path, &data, 2));
+  EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &data, 2));
   EXPECT_EQ("01", data);
 
   data.clear();
-  EXPECT_FALSE(ReadFileToString(file_path, &data, 3));
+  EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &data, 3));
   EXPECT_EQ("012", data);
 
   data.clear();
-  EXPECT_TRUE(ReadFileToString(file_path, &data, 4));
+  EXPECT_TRUE(ReadFileToStringWithMaxSize(file_path, &data, 4));
   EXPECT_EQ("0123", data);
 
   data.clear();
-  EXPECT_TRUE(ReadFileToString(file_path, &data, 6));
+  EXPECT_TRUE(ReadFileToStringWithMaxSize(file_path, &data, 6));
   EXPECT_EQ("0123", data);
 
-  EXPECT_TRUE(ReadFileToString(file_path, NULL, 6));
+  EXPECT_TRUE(ReadFileToStringWithMaxSize(file_path, NULL, 6));
 
   EXPECT_TRUE(ReadFileToString(file_path, NULL));
 
@@ -2101,7 +2101,7 @@
   EXPECT_EQ(0u, data.length());
 
   data = "temp";
-  EXPECT_FALSE(ReadFileToString(file_path, &data, 6));
+  EXPECT_FALSE(ReadFileToStringWithMaxSize(file_path, &data, 6));
   EXPECT_EQ(0u, data.length());
 }
 
diff --git a/base/memory/discardable_shared_memory.cc b/base/memory/discardable_shared_memory.cc
index 860fed6..7449f462 100644
--- a/base/memory/discardable_shared_memory.cc
+++ b/base/memory/discardable_shared_memory.cc
@@ -206,7 +206,7 @@
 
   size_t start = offset / base::GetPageSize();
   size_t end = start + length / base::GetPageSize();
-  DCHECK_LT(start, end);
+  DCHECK_LE(start, end);
   DCHECK_LE(end, AlignToPageSize(mapped_size_) / base::GetPageSize());
 
   // Add pages to |locked_page_count_|.
@@ -281,7 +281,7 @@
 
   size_t start = offset / base::GetPageSize();
   size_t end = start + length / base::GetPageSize();
-  DCHECK_LT(start, end);
+  DCHECK_LE(start, end);
   DCHECK_LE(end, AlignToPageSize(mapped_size_) / base::GetPageSize());
 
   // Remove pages from |locked_page_count_|.
diff --git a/base/memory/discardable_shared_memory_unittest.cc b/base/memory/discardable_shared_memory_unittest.cc
index 3348ed1..f55479b 100644
--- a/base/memory/discardable_shared_memory_unittest.cc
+++ b/base/memory/discardable_shared_memory_unittest.cc
@@ -68,7 +68,7 @@
   EXPECT_FALSE(memory1.IsMemoryLocked());
 
   // Lock and unlock memory.
-  auto lock_rv = memory1.Lock(0, 0);
+  DiscardableSharedMemory::LockResult lock_rv = memory1.Lock(0, 0);
   EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv);
   memory1.SetNow(Time::FromDoubleT(2));
   memory1.Unlock(0, 0);
@@ -145,7 +145,7 @@
   EXPECT_TRUE(rv);
 
   // Lock should fail as memory has been purged.
-  auto lock_rv = memory2.Lock(0, 0);
+  DiscardableSharedMemory::LockResult lock_rv = memory2.Lock(0, 0);
   EXPECT_EQ(DiscardableSharedMemory::FAILED, lock_rv);
 
   ASSERT_FALSE(memory2.IsMemoryResident());
@@ -172,7 +172,7 @@
 
   EXPECT_EQ(memory2.last_known_usage(), Time::FromDoubleT(1));
 
-  auto lock_rv = memory2.Lock(0, 0);
+  DiscardableSharedMemory::LockResult lock_rv = memory2.Lock(0, 0);
   EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv);
 
   // This should fail as memory is locked.
@@ -242,7 +242,7 @@
   EXPECT_TRUE(rv);
 
   // Lock should fail as memory has been purged.
-  auto lock_rv = memory2.Lock(0, 0);
+  DiscardableSharedMemory::LockResult lock_rv = memory2.Lock(0, 0);
   EXPECT_EQ(DiscardableSharedMemory::FAILED, lock_rv);
 }
 
@@ -273,7 +273,8 @@
 
   // Lock first page again.
   memory2.SetNow(Time::FromDoubleT(3));
-  auto lock_rv = memory2.Lock(0, base::GetPageSize());
+  DiscardableSharedMemory::LockResult lock_rv =
+      memory2.Lock(0, base::GetPageSize());
   EXPECT_NE(DiscardableSharedMemory::FAILED, lock_rv);
 
   // Unlock first page.
@@ -338,7 +339,25 @@
   memory.Unlock(0, 0);
 
   // Lock and unlock memory.
-  auto lock_rv = memory.Lock(0, 0);
+  DiscardableSharedMemory::LockResult lock_rv = memory.Lock(0, 0);
+  EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv);
+  memory.SetNow(Time::FromDoubleT(2));
+  memory.Unlock(0, 0);
+}
+
+TEST(DiscardableSharedMemoryTest, ZeroSize) {
+  TestDiscardableSharedMemory memory;
+  bool rv = memory.CreateAndMap(0);
+  ASSERT_TRUE(rv);
+
+  EXPECT_LE(0u, memory.mapped_size());
+
+  // Memory is initially locked. Unlock it.
+  memory.SetNow(Time::FromDoubleT(1));
+  memory.Unlock(0, 0);
+
+  // Lock and unlock memory.
+  DiscardableSharedMemory::LockResult lock_rv = memory.Lock(0, 0);
   EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv);
   memory.SetNow(Time::FromDoubleT(2));
   memory.Unlock(0, 0);
diff --git a/base/memory/ref_counted.h b/base/memory/ref_counted.h
index a1c1269..e7395148 100644
--- a/base/memory/ref_counted.h
+++ b/base/memory/ref_counted.h
@@ -360,15 +360,25 @@
  private:
   template <typename U> friend class scoped_refptr;
 
-  // Allow scoped_refptr<T> to be used in boolean expressions, but not
-  // implicitly convertible to a real bool (which is dangerous).
+  // Implement "Safe Bool Idiom"
+  // https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool
   //
-  // Note that this trick is only safe when the == and != operators
-  // are declared explicitly, as otherwise "refptr1 == refptr2"
-  // will compile but do the wrong thing (i.e., convert to Testable
-  // and then do the comparison).
+  // Allow scoped_refptr<T> to be used in boolean expressions such as
+  //   if (ref_ptr_instance)
+  // But do not become convertible to a real bool (which is dangerous).
+  //   Implementation requires:
+  //     typedef Testable
+  //     operator Testable() const
+  //     operator==
+  //     operator!=
+  //
+  // == and != operators must be declared explicitly or dissallowed, as
+  // otherwise "ptr1 == ptr2" will compile but do the wrong thing (i.e., convert
+  // to Testable and then do the comparison).
+  //
+  // C++11 provides for "explicit operator bool()", however it is currently
+  // banned due to MSVS2013. https://chromium-cpp.appspot.com/#core-blacklist
   typedef T* scoped_refptr::*Testable;
-
  public:
   operator Testable() const { return ptr_ ? &scoped_refptr::ptr_ : nullptr; }
 
@@ -416,8 +426,6 @@
   return scoped_refptr<T>(t);
 }
 
-// Temporary operator overloads to facilitate the transition. See
-// https://crbug.com/110610.
 template <typename T, typename U>
 bool operator==(const scoped_refptr<T>& lhs, const U* rhs) {
   return lhs.get() == rhs;
diff --git a/base/memory/ref_counted_unittest.cc b/base/memory/ref_counted_unittest.cc
index dbc6f33..3f56b4a 100644
--- a/base/memory/ref_counted_unittest.cc
+++ b/base/memory/ref_counted_unittest.cc
@@ -150,10 +150,31 @@
 }
 
 TEST(RefCountedUnitTest, BooleanTesting) {
-  scoped_refptr<SelfAssign> p;
-  EXPECT_FALSE(p);
-  p = new SelfAssign;
-  EXPECT_TRUE(p);
+  scoped_refptr<SelfAssign> ptr_to_an_instance = new SelfAssign;
+  EXPECT_TRUE(ptr_to_an_instance);
+  EXPECT_FALSE(!ptr_to_an_instance);
+
+  if (ptr_to_an_instance) {
+  } else {
+    ADD_FAILURE() << "Pointer to an instance should result in true.";
+  }
+
+  if (!ptr_to_an_instance) {  // check for operator!().
+    ADD_FAILURE() << "Pointer to an instance should result in !x being false.";
+  }
+
+  scoped_refptr<SelfAssign> null_ptr;
+  EXPECT_FALSE(null_ptr);
+  EXPECT_TRUE(!null_ptr);
+
+  if (null_ptr) {
+    ADD_FAILURE() << "Null pointer should result in false.";
+  }
+
+  if (!null_ptr) {  // check for operator!().
+  } else {
+    ADD_FAILURE() << "Null pointer should result in !x being true.";
+  }
 }
 
 TEST(RefCountedUnitTest, Equality) {
diff --git a/base/memory/scoped_ptr.h b/base/memory/scoped_ptr.h
index 282a01486..896674123 100644
--- a/base/memory/scoped_ptr.h
+++ b/base/memory/scoped_ptr.h
@@ -33,6 +33,15 @@
 //     foo[10].Method();     // Foo::Method on the 10th element.
 //   }
 //
+// Scopers are testable as booleans:
+//   {
+//     scoped_ptr<Foo> foo;
+//     if (!foo)
+//       foo.reset(new Foo());
+//     if (foo)
+//       LOG(INFO) << "This code is reached."
+//   }
+//
 // These scopers also implement part of the functionality of C++11 unique_ptr
 // in that they are "movable but not copyable."  You can use the scopers in
 // the parameter and return types of functions to signify ownership transfer
@@ -365,17 +374,27 @@
   deleter_type& get_deleter() { return impl_.get_deleter(); }
   const deleter_type& get_deleter() const { return impl_.get_deleter(); }
 
-  // Allow scoped_ptr<element_type> to be used in boolean expressions, but not
-  // implicitly convertible to a real bool (which is dangerous).
+  // Implement "Safe Bool Idiom"
+  // https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool
   //
-  // Note that this trick is only safe when the == and != operators
-  // are declared explicitly, as otherwise "scoped_ptr1 ==
-  // scoped_ptr2" will compile but do the wrong thing (i.e., convert
+  // Allow scoped_ptr<element_type> to be used in boolean expressions such as
+  //   if (scoped_ptr_instance)
+  // But do not become convertible to a real bool (which is dangerous).
+  //   Implementation requires:
+  //     typedef Testable
+  //     operator Testable() const
+  //     operator==
+  //     operator!=
+  //
+  // == and != operators must be declared explicitly or dissallowed, as
+  // otherwise "ptr1 == ptr2" will compile but do the wrong thing (i.e., convert
   // to Testable and then do the comparison).
+  //
+  // C++11 provides for "explicit operator bool()", however it is currently
+  // banned due to MSVS2013. https://chromium-cpp.appspot.com/#core-blacklist
  private:
   typedef base::internal::scoped_ptr_impl<element_type, deleter_type>
       scoped_ptr::*Testable;
-
  public:
   operator Testable() const {
     return impl_.get() ? &scoped_ptr::impl_ : nullptr;
diff --git a/base/memory/scoped_ptr_unittest.cc b/base/memory/scoped_ptr_unittest.cc
index 8bea43b..f48657d 100644
--- a/base/memory/scoped_ptr_unittest.cc
+++ b/base/memory/scoped_ptr_unittest.cc
@@ -840,3 +840,32 @@
   EXPECT_TRUE(pnull <= nullptr);
   EXPECT_TRUE(nullptr <= pnull);
 }
+
+// Boolean tests can be performed.
+TEST(ScopedPtrTest, BooleanTesting) {
+  scoped_ptr<int> ptr_to_an_instance(new int);
+  EXPECT_TRUE(ptr_to_an_instance);
+  EXPECT_FALSE(!ptr_to_an_instance);
+
+  if (ptr_to_an_instance) {
+  } else {
+    ADD_FAILURE() << "Pointer to an instance should result in true.";
+  }
+
+  if (!ptr_to_an_instance) {  // check for operator!().
+    ADD_FAILURE() << "Pointer to an instance should result in !x being false.";
+  }
+
+  scoped_ptr<int> null_ptr;
+  EXPECT_FALSE(null_ptr);
+  EXPECT_TRUE(!null_ptr);
+
+  if (null_ptr) {
+    ADD_FAILURE() << "Null pointer should result in false.";
+  }
+
+  if (!null_ptr) {  // check for operator!().
+  } else {
+    ADD_FAILURE() << "Null pointer should result in !x being true.";
+  }
+}
diff --git a/base/memory/weak_ptr.h b/base/memory/weak_ptr.h
index ffe6f97..4e50c27 100644
--- a/base/memory/weak_ptr.h
+++ b/base/memory/weak_ptr.h
@@ -219,27 +219,38 @@
     return get();
   }
 
-  // Allow WeakPtr<element_type> to be used in boolean expressions, but not
-  // implicitly convertible to a real bool (which is dangerous).
+  void reset() {
+    ref_ = internal::WeakReference();
+    ptr_ = NULL;
+  }
+
+  // Implement "Safe Bool Idiom"
+  // https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool
   //
-  // Note that this trick is only safe when the == and != operators
-  // are declared explicitly, as otherwise "weak_ptr1 == weak_ptr2"
-  // will compile but do the wrong thing (i.e., convert to Testable
-  // and then do the comparison).
+  // Allow WeakPtr<element_type> to be used in boolean expressions such as
+  //   if (weak_ptr_instance)
+  // But do not become convertible to a real bool (which is dangerous).
+  //   Implementation requires:
+  //     typedef Testable
+  //     operator Testable() const
+  //     operator==
+  //     operator!=
+  //
+  // == and != operators must be declared explicitly or dissallowed, as
+  // otherwise "ptr1 == ptr2" will compile but do the wrong thing (i.e., convert
+  // to Testable and then do the comparison).
+  //
+  // C++11 provides for "explicit operator bool()", however it is currently
+  // banned due to MSVS2013. https://chromium-cpp.appspot.com/#core-blacklist
  private:
   typedef T* WeakPtr::*Testable;
 
  public:
   operator Testable() const { return get() ? &WeakPtr::ptr_ : NULL; }
 
-  void reset() {
-    ref_ = internal::WeakReference();
-    ptr_ = NULL;
-  }
-
  private:
-  // Explicitly declare comparison operators as required by the bool
-  // trick, but keep them private.
+  // Explicitly declare comparison operators as required by the "Safe Bool
+  // Idiom", but keep them private.
   template <class U> bool operator==(WeakPtr<U> const&) const;
   template <class U> bool operator!=(WeakPtr<U> const&) const;
 
diff --git a/base/memory/weak_ptr_unittest.cc b/base/memory/weak_ptr_unittest.cc
index 20e5c7b..5f9b6b6 100644
--- a/base/memory/weak_ptr_unittest.cc
+++ b/base/memory/weak_ptr_unittest.cc
@@ -261,6 +261,37 @@
   EXPECT_EQ(&target, ptr.get());
 }
 
+TEST(WeakPtrFactoryTest, BooleanTesting) {
+  int data;
+  WeakPtrFactory<int> factory(&data);
+
+  WeakPtr<int> ptr_to_an_instance = factory.GetWeakPtr();
+  EXPECT_TRUE(ptr_to_an_instance);
+  EXPECT_FALSE(!ptr_to_an_instance);
+
+  if (ptr_to_an_instance) {
+  } else {
+    ADD_FAILURE() << "Pointer to an instance should result in true.";
+  }
+
+  if (!ptr_to_an_instance) {  // check for operator!().
+    ADD_FAILURE() << "Pointer to an instance should result in !x being false.";
+  }
+
+  WeakPtr<int> null_ptr;
+  EXPECT_FALSE(null_ptr);
+  EXPECT_TRUE(!null_ptr);
+
+  if (null_ptr) {
+    ADD_FAILURE() << "Null pointer should result in false.";
+  }
+
+  if (!null_ptr) {  // check for operator!().
+  } else {
+    ADD_FAILURE() << "Null pointer should result in !x being true.";
+  }
+}
+
 TEST(WeakPtrTest, InvalidateWeakPtrs) {
   int data;
   WeakPtrFactory<int> factory(&data);
diff --git a/base/metrics/histogram_persistence.cc b/base/metrics/histogram_persistence.cc
index bd250ec8..f18d175 100644
--- a/base/metrics/histogram_persistence.cc
+++ b/base/metrics/histogram_persistence.cc
@@ -62,18 +62,19 @@
 // so that, if the structure of that object changes, stored older versions
 // will be safely ignored.
 enum : uint32_t {
-  kTypeIdHistogram   = 0xF1645910 + 1,  // SHA1(Histogram) v1
+  kTypeIdHistogram   = 0xF1645910 + 2,  // SHA1(Histogram) v2
   kTypeIdRangesArray = 0xBCEA225A + 1,  // SHA1(RangesArray) v1
   kTypeIdCountsArray = 0x53215530 + 1,  // SHA1(CountsArray) v1
 };
 
 // This data must be held in persistent memory in order for processes to
-// locate and use histograms created elsewhere.
+// locate and use histograms created elsewhere. All elements must be of a
+// fixed width to ensure 32/64-bit interoperability.
 struct PersistentHistogramData {
-  int histogram_type;
-  int flags;
-  int minimum;
-  int maximum;
+  int32_t histogram_type;
+  int32_t flags;
+  int32_t minimum;
+  int32_t maximum;
   uint32_t bucket_count;
   PersistentMemoryAllocator::Reference ranges_ref;
   uint32_t ranges_checksum;
diff --git a/base/metrics/histogram_samples.h b/base/metrics/histogram_samples.h
index 3da3e2d8..29fbe17 100644
--- a/base/metrics/histogram_samples.h
+++ b/base/metrics/histogram_samples.h
@@ -19,7 +19,10 @@
 class PickleIterator;
 class SampleCountIterator;
 
-// HistogramSamples is a container storing all samples of a histogram.
+// HistogramSamples is a container storing all samples of a histogram. All
+// elements must be of a fixed width to ensure 32/64-bit interoperability.
+// If this structure changes, bump the version number for kTypeIdHistogram
+// in histogram_persistence.cc.
 class BASE_EXPORT HistogramSamples {
  public:
   struct Metadata {
diff --git a/base/test/gtest_util.cc b/base/test/gtest_util.cc
index b9ab4a3a..8ad54364 100644
--- a/base/test/gtest_util.cc
+++ b/base/test/gtest_util.cc
@@ -16,6 +16,8 @@
 TestIdentifier::TestIdentifier() {
 }
 
+TestIdentifier::TestIdentifier(const TestIdentifier& other) = default;
+
 std::string FormatFullTestName(const std::string& test_case_name,
                                const std::string& test_name) {
   return test_case_name + "." + test_name;
diff --git a/base/test/gtest_util.h b/base/test/gtest_util.h
index c0e088f4..f353d83 100644
--- a/base/test/gtest_util.h
+++ b/base/test/gtest_util.h
@@ -17,6 +17,7 @@
 
 struct TestIdentifier {
   TestIdentifier();
+  TestIdentifier(const TestIdentifier& other);
 
   std::string test_case_name;
   std::string test_name;
diff --git a/base/test/launcher/test_results_tracker.cc b/base/test/launcher/test_results_tracker.cc
index b6516ec..813e8e4 100644
--- a/base/test/launcher/test_results_tracker.cc
+++ b/base/test/launcher/test_results_tracker.cc
@@ -358,12 +358,18 @@
 TestResultsTracker::AggregateTestResult::AggregateTestResult() {
 }
 
+TestResultsTracker::AggregateTestResult::AggregateTestResult(
+    const AggregateTestResult& other) = default;
+
 TestResultsTracker::AggregateTestResult::~AggregateTestResult() {
 }
 
 TestResultsTracker::PerIterationData::PerIterationData() {
 }
 
+TestResultsTracker::PerIterationData::PerIterationData(
+    const PerIterationData& other) = default;
+
 TestResultsTracker::PerIterationData::~PerIterationData() {
 }
 
diff --git a/base/test/launcher/test_results_tracker.h b/base/test/launcher/test_results_tracker.h
index 163d75e..8910f73 100644
--- a/base/test/launcher/test_results_tracker.h
+++ b/base/test/launcher/test_results_tracker.h
@@ -85,6 +85,7 @@
 
   struct AggregateTestResult {
     AggregateTestResult();
+    AggregateTestResult(const AggregateTestResult& other);
     ~AggregateTestResult();
 
     std::vector<TestResult> test_results;
@@ -92,6 +93,7 @@
 
   struct PerIterationData {
     PerIterationData();
+    PerIterationData(const PerIterationData& other);
     ~PerIterationData();
 
     // Aggregate test results grouped by full test name.
diff --git a/base/test/test_pending_task.cc b/base/test/test_pending_task.cc
index 3f2c79df..7347e45 100644
--- a/base/test/test_pending_task.cc
+++ b/base/test/test_pending_task.cc
@@ -22,6 +22,8 @@
       delay(delay),
       nestability(nestability) {}
 
+TestPendingTask::TestPendingTask(const TestPendingTask& other) = default;
+
 TimeTicks TestPendingTask::GetTimeToRun() const {
   return post_time + delay;
 }
diff --git a/base/test/test_pending_task.h b/base/test/test_pending_task.h
index 829baa6..df5eadec 100644
--- a/base/test/test_pending_task.h
+++ b/base/test/test_pending_task.h
@@ -21,6 +21,7 @@
   enum TestNestability { NESTABLE, NON_NESTABLE };
 
   TestPendingTask();
+  TestPendingTask(const TestPendingTask& other);
   TestPendingTask(const tracked_objects::Location& location,
                   const Closure& task,
                   TimeTicks post_time,
diff --git a/base/test/trace_event_analyzer.cc b/base/test/trace_event_analyzer.cc
index 2046355..fc775f2 100644
--- a/base/test/trace_event_analyzer.cc
+++ b/base/test/trace_event_analyzer.cc
@@ -26,6 +26,8 @@
       other_event(NULL) {
 }
 
+TraceEvent::TraceEvent(const TraceEvent& other) = default;
+
 TraceEvent::~TraceEvent() {
 }
 
diff --git a/base/test/trace_event_analyzer.h b/base/test/trace_event_analyzer.h
index f67445ace..253dbb4 100644
--- a/base/test/trace_event_analyzer.h
+++ b/base/test/trace_event_analyzer.h
@@ -111,6 +111,7 @@
   };
 
   TraceEvent();
+  TraceEvent(const TraceEvent& other);
   ~TraceEvent();
 
   bool SetFromJSON(const base::Value* event_value) WARN_UNUSED_RESULT;
diff --git a/base/threading/platform_thread_android.cc b/base/threading/platform_thread_android.cc
index 1e4ae93..802ab994 100644
--- a/base/threading/platform_thread_android.cc
+++ b/base/threading/platform_thread_android.cc
@@ -28,13 +28,12 @@
 // above an Android system threshold that enables heavy throttling starting at
 // 10; we want to be lower-priority than Chrome's other threads without
 // incurring this behavior.
-// - DISPLAY is -6 due to being midway between Android's DISPLAY (-4) and
-// URGENT_DISPLAY (-8).
+// - DISPLAY corresponds to Android's PRIORITY_DISPLAY = -4 value.
 // - REALTIME_AUDIO corresponds to Android's THREAD_PRIORITY_AUDIO = -16 value.
 const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4] = {
     {ThreadPriority::BACKGROUND, 9},
     {ThreadPriority::NORMAL, 0},
-    {ThreadPriority::DISPLAY, -6},
+    {ThreadPriority::DISPLAY, -4},
     {ThreadPriority::REALTIME_AUDIO, -16},
 };
 
diff --git a/base/threading/thread.cc b/base/threading/thread.cc
index c5a71bb6..1d2ae64 100644
--- a/base/threading/thread.cc
+++ b/base/threading/thread.cc
@@ -52,6 +52,8 @@
       priority(ThreadPriority::NORMAL) {
 }
 
+Thread::Options::Options(const Options& other) = default;
+
 Thread::Options::~Options() {
 }
 
diff --git a/base/threading/thread.h b/base/threading/thread.h
index da985da..ec19722 100644
--- a/base/threading/thread.h
+++ b/base/threading/thread.h
@@ -45,6 +45,7 @@
 
     Options();
     Options(MessageLoop::Type type, size_t size);
+    Options(const Options& other);
     ~Options();
 
     // Specifies the type of message loop that will be allocated on the thread.
diff --git a/base/tracked_objects.cc b/base/tracked_objects.cc
index 543e436b..d24cedf 100644
--- a/base/tracked_objects.cc
+++ b/base/tracked_objects.cc
@@ -968,6 +968,9 @@
 #endif
 }
 
+ProcessDataSnapshot::ProcessDataSnapshot(const ProcessDataSnapshot& other) =
+    default;
+
 ProcessDataSnapshot::~ProcessDataSnapshot() {
 }
 
diff --git a/base/tracked_objects.h b/base/tracked_objects.h
index 4553c0a..168b17db 100644
--- a/base/tracked_objects.h
+++ b/base/tracked_objects.h
@@ -808,6 +808,7 @@
 struct BASE_EXPORT ProcessDataSnapshot {
  public:
   ProcessDataSnapshot();
+  ProcessDataSnapshot(const ProcessDataSnapshot& other);
   ~ProcessDataSnapshot();
 
   PhasedProcessDataSnapshotMap phased_snapshots;
diff --git a/base/values.cc b/base/values.cc
index ab3c38a..5a789e9 100644
--- a/base/values.cc
+++ b/base/values.cc
@@ -837,6 +837,8 @@
     : target_(target),
       it_(target.dictionary_.begin()) {}
 
+DictionaryValue::Iterator::Iterator(const Iterator& other) = default;
+
 DictionaryValue::Iterator::~Iterator() {}
 
 DictionaryValue* DictionaryValue::DeepCopy() const {
diff --git a/base/values.h b/base/values.h
index 07e5b6c..141ea93 100644
--- a/base/values.h
+++ b/base/values.h
@@ -360,6 +360,7 @@
   class BASE_EXPORT Iterator {
    public:
     explicit Iterator(const DictionaryValue& target);
+    Iterator(const Iterator& other);
     ~Iterator();
 
     bool IsAtEnd() const { return it_ == target_.dictionary_.end(); }
diff --git a/base/version.cc b/base/version.cc
index 19b9922..02213fbf 100644
--- a/base/version.cc
+++ b/base/version.cc
@@ -80,6 +80,8 @@
 Version::Version() {
 }
 
+Version::Version(const Version& other) = default;
+
 Version::~Version() {
 }
 
diff --git a/base/version.h b/base/version.h
index 30cb735..25b570a 100644
--- a/base/version.h
+++ b/base/version.h
@@ -23,6 +23,8 @@
   // Version object is assign to it.
   Version();
 
+  Version(const Version& other);
+
   ~Version();
 
   // Initializes from a decimal dotted version number, like "0.1.1".
diff --git a/blimp/client/BUILD.gn b/blimp/client/BUILD.gn
index 6029cd0..d2ddc2b 100644
--- a/blimp/client/BUILD.gn
+++ b/blimp/client/BUILD.gn
@@ -309,6 +309,7 @@
       "app/android/java/src/org/chromium/blimp/BlimpLibraryLoader.java",
       "app/android/java/src/org/chromium/blimp/BlimpRendererActivity.java",
       "app/android/java/src/org/chromium/blimp/BlimpView.java",
+      "app/android/java/src/org/chromium/blimp/input/TextInputFeature.java",
       "app/android/java/src/org/chromium/blimp/session/BlimpClientSession.java",
       "app/android/java/src/org/chromium/blimp/session/TabControlFeature.java",
       "app/android/java/src/org/chromium/blimp/toolbar/Toolbar.java",
diff --git a/blimp/client/app/android/AndroidManifest.xml.jinja2 b/blimp/client/app/android/AndroidManifest.xml.jinja2
index 3256dca..adb5b2f7 100644
--- a/blimp/client/app/android/AndroidManifest.xml.jinja2
+++ b/blimp/client/app/android/AndroidManifest.xml.jinja2
@@ -19,6 +19,7 @@
                   android:launchMode="singleTask"
                   android:theme="@android:style/Theme.Holo.Light.NoActionBar"
                   android:configChanges="orientation|keyboardHidden|keyboard|screenSize"
+                  android:windowSoftInputMode="adjustResize"
                   android:hardwareAccelerated="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
diff --git a/blimp/client/app/android/java/res/drawable-hdpi/web_input_background.9.png b/blimp/client/app/android/java/res/drawable-hdpi/web_input_background.9.png
new file mode 100644
index 0000000..21ceba93
--- /dev/null
+++ b/blimp/client/app/android/java/res/drawable-hdpi/web_input_background.9.png
Binary files differ
diff --git a/blimp/client/app/android/java/res/drawable-mdpi/web_input_background.9.png b/blimp/client/app/android/java/res/drawable-mdpi/web_input_background.9.png
new file mode 100644
index 0000000..a08335dc
--- /dev/null
+++ b/blimp/client/app/android/java/res/drawable-mdpi/web_input_background.9.png
Binary files differ
diff --git a/blimp/client/app/android/java/res/drawable-xhdpi/web_input_background.9.png b/blimp/client/app/android/java/res/drawable-xhdpi/web_input_background.9.png
new file mode 100644
index 0000000..58c92c5c
--- /dev/null
+++ b/blimp/client/app/android/java/res/drawable-xhdpi/web_input_background.9.png
Binary files differ
diff --git a/blimp/client/app/android/java/res/drawable-xxhdpi/web_input_background.9.png b/blimp/client/app/android/java/res/drawable-xxhdpi/web_input_background.9.png
new file mode 100644
index 0000000..df41f87
--- /dev/null
+++ b/blimp/client/app/android/java/res/drawable-xxhdpi/web_input_background.9.png
Binary files differ
diff --git a/blimp/client/app/android/java/res/drawable-xxxhdpi/web_input_background.9.png b/blimp/client/app/android/java/res/drawable-xxxhdpi/web_input_background.9.png
new file mode 100644
index 0000000..92b702f3
--- /dev/null
+++ b/blimp/client/app/android/java/res/drawable-xxxhdpi/web_input_background.9.png
Binary files differ
diff --git a/blimp/client/app/android/java/res/layout/blimp_main.xml b/blimp/client/app/android/java/res/layout/blimp_main.xml
index a019db2..f814674 100644
--- a/blimp/client/app/android/java/res/layout/blimp_main.xml
+++ b/blimp/client/app/android/java/res/layout/blimp_main.xml
@@ -4,7 +4,7 @@
      found in the LICENSE file. -->
 
 <merge xmlns:android="http://schemas.android.com/apk/res/android">
-    <LinearLayout
+    <RelativeLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:orientation="vertical">
@@ -13,6 +13,7 @@
             android:id="@+id/toolbar"
             android:layout_width="match_parent"
             android:layout_height="56dp"
+            android:layout_alignParentTop="true"
             android:paddingStart="5dp"
             android:orientation="horizontal"
             android:gravity="center"
@@ -41,6 +42,19 @@
         <org.chromium.blimp.BlimpView
             android:id="@+id/renderer"
             android:layout_width="match_parent"
-            android:layout_height="match_parent" />
-    </LinearLayout>
+            android:layout_height="match_parent"
+            android:layout_below="@+id/toolbar"/>
+        <org.chromium.blimp.input.TextInputFeature
+                android:id="@+id/editText"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:background="@drawable/web_input_background"
+                android:layout_alignParentBottom="true"
+                android:layout_marginTop="45dp"
+                android:padding="10dp"
+                android:paddingTop="16dp"
+                android:inputType="text|textWebEditText"
+                android:visibility="gone"/>
+
+    </RelativeLayout>
 </merge>
\ No newline at end of file
diff --git a/blimp/client/app/android/java/src/org/chromium/blimp/BlimpRendererActivity.java b/blimp/client/app/android/java/src/org/chromium/blimp/BlimpRendererActivity.java
index 35f8e19..90b5512 100644
--- a/blimp/client/app/android/java/src/org/chromium/blimp/BlimpRendererActivity.java
+++ b/blimp/client/app/android/java/src/org/chromium/blimp/BlimpRendererActivity.java
@@ -13,6 +13,7 @@
 import org.chromium.blimp.auth.RetryingTokenSource;
 import org.chromium.blimp.auth.TokenSource;
 import org.chromium.blimp.auth.TokenSourceImpl;
+import org.chromium.blimp.input.TextInputFeature;
 import org.chromium.blimp.session.BlimpClientSession;
 import org.chromium.blimp.session.TabControlFeature;
 import org.chromium.blimp.toolbar.Toolbar;
@@ -25,7 +26,7 @@
 public class BlimpRendererActivity extends Activity
         implements BlimpLibraryLoader.Callback, TokenSource.Callback, BlimpClientSession.Callback {
     private static final int ACCOUNT_CHOOSER_INTENT_REQUEST_CODE = 100;
-    private static final String TAG = "Blimp";
+    private static final String TAG = "BlimpRendererActivity";
 
     /** Provides user authentication tokens that can be used to query for engine assignments.  This
      *  can potentially query GoogleAuthUtil for an OAuth2 authentication token with userinfo.email
@@ -36,6 +37,7 @@
     private Toolbar mToolbar;
     private BlimpClientSession mBlimpClientSession;
     private TabControlFeature mTabControlFeature;
+    private TextInputFeature mTextInputFeature;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -135,6 +137,8 @@
 
         mTabControlFeature = new TabControlFeature(mBlimpClientSession, mBlimpView);
         mToolbar.loadUrl("http://www.google.com/");
+
+        mTextInputFeature = (TextInputFeature) findViewById(R.id.editText);
     }
 
     // TokenSource.Callback implementation.
diff --git a/blimp/client/app/android/java/src/org/chromium/blimp/input/TextInputFeature.java b/blimp/client/app/android/java/src/org/chromium/blimp/input/TextInputFeature.java
new file mode 100644
index 0000000..1d44f95
--- /dev/null
+++ b/blimp/client/app/android/java/src/org/chromium/blimp/input/TextInputFeature.java
@@ -0,0 +1,70 @@
+// Copyright 2016 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.
+
+package org.chromium.blimp.input;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import org.chromium.base.Log;
+import org.chromium.ui.UiUtils;
+
+/**
+ * A {@link View} that allows users to enter text into a web page.
+ * This is a floating text box which closes when the user hits enter or presses back button.
+ */
+public class TextInputFeature extends EditText {
+    private static final String TAG = "TextInputFeature";
+
+    public TextInputFeature(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setOnEditorActionListener(new TextView.OnEditorActionListener() {
+            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+                if (actionId == EditorInfo.IME_ACTION_NEXT
+                        || actionId == EditorInfo.IME_ACTION_DONE) {
+                    sendTextToBrowser(v.getText().toString());
+                    hideIme();
+                    return true;
+                }
+                return false;
+            }
+        });
+    }
+
+    @Override
+    public boolean dispatchKeyEventPreIme(KeyEvent event) {
+        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+            setVisibility(View.GONE);
+        }
+        return super.dispatchKeyEventPreIme(event);
+    }
+
+    /**
+     *  Brings up the IME along with the edit text above it.
+     */
+    public void showIme() {
+        setVisibility(View.VISIBLE);
+        requestFocus();
+        UiUtils.showKeyboard(this);
+    }
+
+    /**
+     * Hides the edit text along with the IME.
+     */
+    private void hideIme() {
+        setText("");
+        setVisibility(View.GONE);
+        UiUtils.hideKeyboard(this);
+    }
+
+    private void sendTextToBrowser(String text) {
+        Log.d(TAG, "Send to browser : " + text);
+        // TODO(shaktisahu): Send data to server.
+    }
+}
diff --git a/blimp/docs/build.md b/blimp/docs/build.md
index 13aad6b6..425ad370 100644
--- a/blimp/docs/build.md
+++ b/blimp/docs/build.md
@@ -42,7 +42,7 @@
 ## Engine inside a Docker container
 
 Create another out-directory and set the GN args. Note, when building to run
-inside a Docker container you'll need to set the target_os to "chromeos":
+inside a [Docker container](container.md) you'll need to set the target_os to "chromeos":
 
 ```bash
 mkdir -p out-chromeos/Debug
diff --git a/blimp/docs/running.md b/blimp/docs/running.md
index f4a1d96..a32b436 100644
--- a/blimp/docs/running.md
+++ b/blimp/docs/running.md
@@ -18,23 +18,45 @@
 Set up any command line flags with:
 
 ```bash
-./build/android/adb_blimp_command_line --enable-webgl
+./build/android/adb_blimp_command_line --your-flag-here
 ```
 
 To have the client connect to a custom engine use the `--blimplet-endpoint`
 flag.  This takes values in the form of scheme:ip:port.  The possible valid
 schemes are 'tcp', 'quic', and 'ssl'.  An example valid endpoint would be
-`--blimplet-endpoint=tcp:127.0.0.1:500`.
+`--blimplet-endpoint=tcp:127.0.0.1:25467`.
+
+To see your current command line, run `adb_blimp_command_line` without any
+arguments.
 
 Run the Blimp APK with:
 
 ```bash
-adb_run_blimp_client
+./build/android/adb_run_blimp_client
 ```
 
 ### Linux Client
 
-TBD
+The blimp client is built as part of the `blimp` target. To run it with local
+logging enabled, execute:
+
+```bash
+./out-linux/Debug/blimp_shell \
+  --user-data-dir=/tmp/blimpclient \
+  --enable-logging=stderr \
+  --vmodule="*=1"
+```
+
+### Instructing client to connect to specific host
+If you run the engine on your local host and you want the client to connect to
+it instead of using the assigner, you need to instruct the client to use the
+correct host and port to connect to by giving it the correct command line flag.
+
+Typically this flag would be:
+
+```bash
+--blimplet-endpoint=tcp:127.0.0.1:25467
+```
 
 ## Running the engine
 
@@ -42,13 +64,59 @@
 For running the engine in a container, see [container](container.md).
 
 ### On a workstation
+To run the engine on a workstation and make your Android client connect to it,
+you need to forward a port from the Android device to the host, and also
+instruct the client to connect using that port on its localhost address.
+
+#### Port forwarding
 If you are running the engine on your workstation and are connected to the
 client device via USB, you'll need remote port forwarding to allow the Blimp
-client to talk to your computer. Follow the instructions
-[here](https://developer.chrome.com/devtools/docs/remote-debugging) to get
-started. You'll probably want to remap 25467 to "localhost:25467".
+client to talk to your computer.
 
-### Required flags
-*   `--blimp-client-token-path=$PATH`: Path to a file containing a nonempty
-token string. If this is not present, the engine will fail to boot.
+##### Option A
+Follow the
+[remote debugging instructions](https://developer.chrome.com/devtools/docs/remote-debugging)
+to get started. You'll probably want to remap 25467 to "localhost:25467".
+*Note* This requires the separate `Chrome` application to be running on the
+device. Otherwise you will not see the green light for the port forwarding.
 
+##### Option B
+If you are having issues with using the built-in Chrome port forwarding, you can
+also start a new shell and keep the following command running:
+
+```bash
+./build/android/adb_reverse_forwarder.py --debug -v 25467 25467
+```
+
+### Required engine binary flags
+* `--blimp-client-token-path=$PATH`: Path to a file containing a nonempty
+  token string. If this is not present, the engine will fail to boot.
+* `--use-remote-compositing`: Ensures that the renderer uses the remote
+  compositor.
+* `--disable-cached-picture-raster`: Ensures that rasterized content is not
+  destroyed before serialization.
+
+#### Typical invocation
+When the client connects to a manually specified engine instead of using the
+assigner, it will use a dummy token. The engine needs to know what this token
+is, so it must be provided using the `--blimp-client-token-path` flag. The token
+is available in the constant `kDummyClientToken` in
+`blimp/client/session/assignment_source.h`. You can easily store that to a file
+by running the following command once:
+
+```bash
+awk '{if ( match($0, /^\s*const char kDummyClientToken.*/) ) { print substr($5, 2, length($5)-3);} }' \
+  ./blimp/client/session/assignment_source.h > /tmp/blimpengine-token
+```
+
+Then start the engine using these flags:
+
+```bash
+out-linux/Debug/blimp_engine_app \
+  --use-remote-compositing \
+  --disable-cached-picture-raster \
+  --blimp-client-token-path=/tmp/blimpengine-token \
+  --user-data-dir=/tmp/blimpengine \
+  --enable-logging=stderr \
+  --vmodule="blimp*=1"
+```
diff --git a/blimp/engine/BUILD.gn b/blimp/engine/BUILD.gn
index b228cf0..b91730fe 100644
--- a/blimp/engine/BUILD.gn
+++ b/blimp/engine/BUILD.gn
@@ -88,34 +88,24 @@
     "app/ui/blimp_layout_manager.h",
     "app/ui/blimp_screen.cc",
     "app/ui/blimp_screen.h",
+    "app/ui/blimp_ui_context_factory.cc",
+    "app/ui/blimp_ui_context_factory.h",
+    "app/ui/blimp_window_tree_host.cc",
+    "app/ui/blimp_window_tree_host.h",
   ]
 
-  if (!use_x11) {
-    sources += [
-      "app/ui/blimp_ui_context_factory.cc",
-      "app/ui/blimp_ui_context_factory.h",
-      "app/ui/blimp_window_tree_host.cc",
-      "app/ui/blimp_window_tree_host.h",
-    ]
-  }
-
   deps = [
+    "//blimp/common:blimp_common",
+    "//cc",
+    "//cc/surfaces",
     "//ui/aura",
+    "//ui/compositor",
+    "//ui/events",
     "//ui/gfx",
     "//ui/platform_window",
+    "//ui/platform_window",
+    "//ui/platform_window/stub/",
   ]
-
-  if (!use_x11) {
-    deps += [
-      "//blimp/common:blimp_common",
-      "//cc",
-      "//cc/surfaces",
-      "//ui/compositor",
-      "//ui/events",
-      "//ui/platform_window",
-      "//ui/platform_window/stub/",
-    ]
-  }
 }
 
 source_set("common") {
@@ -172,6 +162,7 @@
 
   sources = [
     "app/blimp_engine_config_unittest.cc",
+    "app/ui/blimp_screen_unittest.cc",
   ]
 
   deps = [
@@ -181,6 +172,7 @@
     "//base/test:test_support",
     "//testing/gmock",
     "//testing/gtest",
+    "//ui/gfx:test_support",
   ]
 }
 
diff --git a/blimp/engine/app/blimp_browser_main_parts.cc b/blimp/engine/app/blimp_browser_main_parts.cc
index 3a7edd6..66ce080 100644
--- a/blimp/engine/app/blimp_browser_main_parts.cc
+++ b/blimp/engine/app/blimp_browser_main_parts.cc
@@ -16,10 +16,6 @@
 #include "net/base/net_module.h"
 #include "net/log/net_log.h"
 
-#if defined(USE_X11)
-#include "ui/base/ime/input_method_initializer.h"
-#endif
-
 namespace blimp {
 namespace engine {
 
@@ -29,10 +25,6 @@
 BlimpBrowserMainParts::~BlimpBrowserMainParts() {}
 
 void BlimpBrowserMainParts::PreEarlyInitialization() {
-#if defined(USE_X11)
-  // TODO(haibinlu): Rename the method below. crbug/548330.
-  ui::InitializeInputMethodForTesting();
-#endif
   // Fetch the engine config from the command line, and crash if invalid. Allow
   // IO operations even though this is not in the FILE thread as this is
   // necessary for Blimp startup and occurs before any user interaction.
diff --git a/blimp/engine/app/ui/BUILD.gn b/blimp/engine/app/ui/BUILD.gn
index b0aaf0c..c1501334 100644
--- a/blimp/engine/app/ui/BUILD.gn
+++ b/blimp/engine/app/ui/BUILD.gn
@@ -10,32 +10,22 @@
     "blimp_layout_manager.h",
     "blimp_screen.cc",
     "blimp_screen.h",
+    "blimp_ui_context_factory.cc",
+    "blimp_ui_context_factory.h",
+    "blimp_window_tree_host.cc",
+    "blimp_window_tree_host.h",
   ]
 
-  if (!use_x11) {
-    sources += [
-      "blimp_ui_context_factory.cc",
-      "blimp_ui_context_factory.h",
-      "blimp_window_tree_host.cc",
-      "blimp_window_tree_host.h",
-    ]
-  }
-
   deps = [
+    "//blimp/common:blimp_common",
+    "//cc",
+    "//cc/surfaces",
     "//ui/aura",
+    "//ui/compositor",
+    "//ui/events",
     "//ui/gfx",
     "//ui/platform_window",
+    "//ui/platform_window",
+    "//ui/platform_window/stub/",
   ]
-
-  if (!use_x11) {
-    deps += [
-      "//blimp/common:blimp_common",
-      "//cc",
-      "//cc/surfaces",
-      "//ui/compositor",
-      "//ui/events",
-      "//ui/platform_window",
-      "//ui/platform_window/stub/",
-    ]
-  }
 }
diff --git a/blimp/engine/app/ui/blimp_screen.cc b/blimp/engine/app/ui/blimp_screen.cc
index 720d19e..9338193 100644
--- a/blimp/engine/app/ui/blimp_screen.cc
+++ b/blimp/engine/app/ui/blimp_screen.cc
@@ -4,6 +4,11 @@
 
 #include "blimp/engine/app/ui/blimp_screen.h"
 
+#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/gfx/display_observer.h"
+#include "ui/gfx/geometry/size.h"
+
 namespace blimp {
 namespace engine {
 
@@ -20,7 +25,22 @@
 
 void BlimpScreen::UpdateDisplayScaleAndSize(float scale,
                                             const gfx::Size& size) {
+  if (scale == display_.device_scale_factor() &&
+      size == display_.GetSizeInPixel()) {
+    return;
+  }
+
+  uint32_t metrics = gfx::DisplayObserver::DISPLAY_METRIC_NONE;
+  if (scale != display_.device_scale_factor())
+    metrics |= gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
+
+  if (size != display_.GetSizeInPixel())
+    metrics |= gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS;
+
   display_.SetScaleAndBounds(scale, gfx::Rect(size));
+
+  FOR_EACH_OBSERVER(gfx::DisplayObserver, observers_,
+                    OnDisplayMetricsChanged(display_, metrics));
 }
 
 gfx::Point BlimpScreen::GetCursorScreenPoint() {
@@ -33,8 +53,9 @@
 }
 
 gfx::NativeWindow BlimpScreen::GetWindowAtScreenPoint(const gfx::Point& point) {
-  NOTIMPLEMENTED();
-  return gfx::NativeWindow(nullptr);
+  return window_tree_host_
+             ? window_tree_host_->window()->GetTopWindowContainingPoint(point)
+             : gfx::NativeWindow(nullptr);
 }
 
 int BlimpScreen::GetNumDisplays() const {
@@ -64,9 +85,13 @@
   return display_;
 }
 
-void BlimpScreen::AddObserver(gfx::DisplayObserver* observer) {}
+void BlimpScreen::AddObserver(gfx::DisplayObserver* observer) {
+  observers_.AddObserver(observer);
+}
 
-void BlimpScreen::RemoveObserver(gfx::DisplayObserver* observer) {}
+void BlimpScreen::RemoveObserver(gfx::DisplayObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
 
 }  // namespace engine
 }  // namespace blimp
diff --git a/blimp/engine/app/ui/blimp_screen.h b/blimp/engine/app/ui/blimp_screen.h
index 305e062e..991a028 100644
--- a/blimp/engine/app/ui/blimp_screen.h
+++ b/blimp/engine/app/ui/blimp_screen.h
@@ -8,9 +8,14 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/observer_list.h"
 #include "ui/gfx/display.h"
 #include "ui/gfx/screen.h"
 
+namespace aura {
+class WindowTreeHost;
+}
+
 namespace blimp {
 namespace engine {
 
@@ -20,6 +25,10 @@
   BlimpScreen();
   ~BlimpScreen() override;
 
+  void set_window_tree_host(aura::WindowTreeHost* window_tree_host) {
+    window_tree_host_ = window_tree_host;
+  }
+
   // Updates the size reported by the primary display.
   void UpdateDisplayScaleAndSize(float scale, const gfx::Size& size);
 
@@ -37,8 +46,9 @@
   void RemoveObserver(gfx::DisplayObserver* observer) override;
 
  private:
+  aura::WindowTreeHost* window_tree_host_;
   gfx::Display display_;
-
+  base::ObserverList<gfx::DisplayObserver> observers_;
   DISALLOW_COPY_AND_ASSIGN(BlimpScreen);
 };
 
diff --git a/blimp/engine/app/ui/blimp_screen_unittest.cc b/blimp/engine/app/ui/blimp_screen_unittest.cc
new file mode 100644
index 0000000..e865517
--- /dev/null
+++ b/blimp/engine/app/ui/blimp_screen_unittest.cc
@@ -0,0 +1,113 @@
+// Copyright 2016 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 "blimp/engine/app/ui/blimp_screen.h"
+
+#include <string>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/stringprintf.h"
+#include "blimp/engine/app/switches.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/display.h"
+#include "ui/gfx/display_observer.h"
+#include "ui/gfx/screen.h"
+
+using testing::InSequence;
+
+namespace blimp {
+namespace engine {
+namespace {
+
+// Checks if two gfx::Displays have the ID.
+MATCHER_P(EqualsDisplay, display, "") {
+  return display.id() == arg.id();
+}
+
+class MockDisplayObserver : public gfx::DisplayObserver {
+ public:
+  MockDisplayObserver() {}
+  ~MockDisplayObserver() override {}
+
+  MOCK_METHOD1(OnDisplayAdded, void(const gfx::Display&));
+  MOCK_METHOD1(OnDisplayRemoved, void(const gfx::Display&));
+  MOCK_METHOD2(OnDisplayMetricsChanged,
+               void(const gfx::Display& display, uint32_t changed_metrics));
+};
+
+class BlimpScreenTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    screen_ = make_scoped_ptr(new BlimpScreen);
+    screen_->AddObserver(&observer1_);
+    screen_->AddObserver(&observer2_);
+  }
+
+  scoped_ptr<BlimpScreen> screen_;
+  testing::StrictMock<MockDisplayObserver> observer1_;
+  testing::StrictMock<MockDisplayObserver> observer2_;
+};
+
+TEST_F(BlimpScreenTest, ObserversAreInfomed) {
+  auto display = screen_->GetPrimaryDisplay();
+  uint32_t changed_metrics =
+      gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR |
+      gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS;
+
+  InSequence s;
+  EXPECT_CALL(observer1_,
+              OnDisplayMetricsChanged(EqualsDisplay(display), changed_metrics));
+  EXPECT_CALL(observer2_,
+              OnDisplayMetricsChanged(EqualsDisplay(display), changed_metrics));
+
+  changed_metrics = gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS;
+  EXPECT_CALL(observer1_,
+              OnDisplayMetricsChanged(EqualsDisplay(display), changed_metrics));
+  EXPECT_CALL(observer2_,
+              OnDisplayMetricsChanged(EqualsDisplay(display), changed_metrics));
+
+  changed_metrics = gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR;
+  EXPECT_CALL(observer1_,
+              OnDisplayMetricsChanged(EqualsDisplay(display), changed_metrics));
+  EXPECT_CALL(observer2_,
+              OnDisplayMetricsChanged(EqualsDisplay(display), changed_metrics));
+
+  gfx::Size size1(100, 200);
+  screen_->UpdateDisplayScaleAndSize(2.0f, size1);
+  EXPECT_EQ(size1, screen_->GetPrimaryDisplay().GetSizeInPixel());
+  EXPECT_EQ(2.0f, screen_->GetPrimaryDisplay().device_scale_factor());
+
+  screen_->UpdateDisplayScaleAndSize(2.0f, size1);
+
+  gfx::Size size2(200, 100);
+  screen_->UpdateDisplayScaleAndSize(2.0f, size2);
+  EXPECT_EQ(size2, screen_->GetPrimaryDisplay().GetSizeInPixel());
+  EXPECT_EQ(2.0f, screen_->GetPrimaryDisplay().device_scale_factor());
+
+  screen_->UpdateDisplayScaleAndSize(3.0f, size2);
+  EXPECT_EQ(3.0f, screen_->GetPrimaryDisplay().device_scale_factor());
+}
+
+TEST_F(BlimpScreenTest, RemoveObserver) {
+  screen_->RemoveObserver(&observer2_);
+  auto display = screen_->GetPrimaryDisplay();
+  uint32_t changed_metrics =
+      gfx::DisplayObserver::DISPLAY_METRIC_DEVICE_SCALE_FACTOR |
+      gfx::DisplayObserver::DISPLAY_METRIC_BOUNDS;
+  EXPECT_CALL(observer1_,
+              OnDisplayMetricsChanged(EqualsDisplay(display), changed_metrics));
+
+  gfx::Size size1(100, 100);
+  screen_->UpdateDisplayScaleAndSize(2.0f, size1);
+  EXPECT_EQ(size1, screen_->GetPrimaryDisplay().GetSizeInPixel());
+}
+
+}  // namespace
+}  // namespace engine
+}  // namespace blimp
diff --git a/blimp/engine/engine-manifest.txt b/blimp/engine/engine-manifest.txt
index 9b78601..d84b8f9 100644
--- a/blimp/engine/engine-manifest.txt
+++ b/blimp/engine/engine-manifest.txt
@@ -1,11 +1,12 @@
 # Runtime dependencies for the Blimp Engine
 #
 # This file was generated by running:
-# generate-engine-manifest.py --build-dir out-linux/Debug --target //blimp/engine:blimp_engine --output blimp/engine/engine-manifest.txt
+# generate-engine-manifest.py --build-dir out/Linux --target //blimp/engine:blimp_engine --output blimp/engine/engine-manifest.txt
 #
-# Note: After generating, you should remove any unnecessary dependencies.
+# Note: Any unnecessary dependencies should be added to
+#       manifest-blacklist.txt and this file should be regenerated.
 ./blimp_engine_app
 icudtl.dat
 natives_blob.bin
 blimp_engine.pak
-./chrome_sandbox
+./chrome_sandbox
\ No newline at end of file
diff --git a/blimp/engine/session/blimp_engine_session.cc b/blimp/engine/session/blimp_engine_session.cc
index 386902ff..d84afcf 100644
--- a/blimp/engine/session/blimp_engine_session.cc
+++ b/blimp/engine/session/blimp_engine_session.cc
@@ -4,6 +4,8 @@
 
 #include "blimp/engine/session/blimp_engine_session.h"
 
+#include <string>
+
 #include "base/strings/utf_string_conversions.h"
 #include "blimp/common/create_blimp_message.h"
 #include "blimp/common/proto/tab_control.pb.h"
@@ -11,6 +13,7 @@
 #include "blimp/engine/app/ui/blimp_layout_manager.h"
 #include "blimp/engine/app/ui/blimp_screen.h"
 #include "blimp/engine/app/ui/blimp_ui_context_factory.h"
+#include "blimp/engine/app/ui/blimp_window_tree_host.h"
 #include "blimp/engine/common/blimp_browser_context.h"
 #include "blimp/net/blimp_connection.h"
 #include "blimp/net/blimp_message_multiplexer.h"
@@ -38,9 +41,6 @@
 #include "ui/wm/core/default_activation_client.h"
 #include "ui/wm/core/focus_controller.h"
 
-#if !defined(USE_X11)
-#include "blimp/engine/app/ui/blimp_window_tree_host.h"
-#endif
 
 namespace blimp {
 namespace engine {
@@ -190,15 +190,11 @@
   DCHECK(!gfx::Screen::GetScreen());
   gfx::Screen::SetScreenInstance(screen_.get());
 
-#if defined(USE_X11)
-  window_tree_host_.reset(aura::WindowTreeHost::Create(
-      gfx::Rect(screen_->GetPrimaryDisplay().size())));
-#else
   context_factory_.reset(new BlimpUiContextFactory());
   aura::Env::GetInstance()->set_context_factory(context_factory_.get());
   window_tree_host_.reset(new BlimpWindowTreeHost());
-#endif
 
+  screen_->set_window_tree_host(window_tree_host_.get());
   window_tree_host_->InitHost();
   window_tree_host_->window()->SetLayoutManager(
       new BlimpLayoutManager(window_tree_host_->window()));
@@ -210,10 +206,6 @@
   capture_client_.reset(
       new aura::client::DefaultCaptureClient(window_tree_host_->window()));
 
-#if defined(USE_X11)
-  window_tree_host_->Show();
-#endif
-
   window_tree_host_->SetBounds(gfx::Rect(screen_->GetPrimaryDisplay().size()));
 
   // Register features' message senders and receivers.
@@ -295,6 +287,12 @@
                                       const gfx::Size& size) {
   DVLOG(1) << "Resize to " << size.ToString() << ", " << device_pixel_ratio;
   screen_->UpdateDisplayScaleAndSize(device_pixel_ratio, size);
+  window_tree_host_->SetBounds(gfx::Rect(size));
+  if (web_contents_) {
+    const gfx::Size size_in_dips = screen_->GetPrimaryDisplay().bounds().size();
+    web_contents_->GetNativeView()->SetBounds(gfx::Rect(size_in_dips));
+  }
+
   if (web_contents_ && web_contents_->GetRenderViewHost() &&
       web_contents_->GetRenderViewHost()->GetWidget()) {
     web_contents_->GetRenderViewHost()->GetWidget()->WasResized();
diff --git a/blimp/engine/session/blimp_engine_session.h b/blimp/engine/session/blimp_engine_session.h
index 058932e..ebab04d1 100644
--- a/blimp/engine/session/blimp_engine_session.h
+++ b/blimp/engine/session/blimp_engine_session.h
@@ -162,7 +162,7 @@
 
   // Represents the (currently single) browser window into which tab(s) will
   // be rendered.
-  scoped_ptr<aura::WindowTreeHost> window_tree_host_;
+  scoped_ptr<BlimpWindowTreeHost> window_tree_host_;
 
   // Used to apply standard focus conventions to the windows in the
   // WindowTreeHost hierarchy.
diff --git a/blimp/tools/bundle-engine.py b/blimp/tools/bundle-engine.py
index 4c3aa04e..e94cf22b 100755
--- a/blimp/tools/bundle-engine.py
+++ b/blimp/tools/bundle-engine.py
@@ -66,6 +66,10 @@
     subprocess.check_output(
         ["tar",
          "-zcf", args.output,
+         # Ensure tarball content group permissions are appropriately set for
+         # use as part of a "docker build". That is group readable with
+         # executable files also being group executable.
+         "--mode=g+rX",
          "-C", dockerfile_dirname, dockerfile_basename,
          "-C", startup_script_dirname, startup_script_basename,
          "-C", args.build_dir] + deps,
diff --git a/blimp/tools/generate-engine-manifest.py b/blimp/tools/generate-engine-manifest.py
index 0c5c90c0..f8e70bb 100755
--- a/blimp/tools/generate-engine-manifest.py
+++ b/blimp/tools/generate-engine-manifest.py
@@ -9,11 +9,17 @@
 
 import argparse
 import errno
+import fnmatch
 import os
 import subprocess
 import sys
 import tarfile
 
+# Returns True if |entry| matches any of the patterns in |blacklist|.
+def IsBlacklisted(entry, blacklist):
+  return any([next_pat for next_pat in blacklist
+              if fnmatch.fnmatch(entry, next_pat)])
+
 def main():
   parser = argparse.ArgumentParser(description=__doc__)
   parser.add_argument('--build-dir',
@@ -31,7 +37,7 @@
 
   try:
     deps = subprocess.check_output(['gn', 'desc', args.build_dir, args.target,
-                                    'runtime_deps'])
+                                    'runtime_deps']).split()
   except subprocess.CalledProcessError as e:
     print "Error: " + ' '.join(e.cmd)
     print e.output
@@ -44,12 +50,22 @@
     '# This file was generated by running:',
     '# ' + command_line + '',
     '#',
-    '# Note: After generating, you should remove any unnecessary dependencies.',
+    '# Note: Any unnecessary dependencies should be added to',
+    '#       manifest-blacklist.txt and this file should be regenerated.',
     '',
   ]
+
+  blacklist_patterns = []
+  with open(os.path.join(os.sys.path[0], 'manifest-blacklist.txt'), 'r') \
+      as blacklist_file:
+    blacklist_patterns = \
+        [entry.partition('#')[0].strip() for entry \
+         in blacklist_file.readlines()]
+
   with open(args.output, 'w') as manifest:
     manifest.write('\n'.join(header))
-    manifest.write(deps)
+    manifest.write('\n'.join([dep for dep in deps
+                              if not IsBlacklisted(dep, blacklist_patterns)]))
 
   print 'Created ' + args.output
 
diff --git a/blimp/tools/manifest-blacklist.txt b/blimp/tools/manifest-blacklist.txt
new file mode 100644
index 0000000..ce4c1c9b
--- /dev/null
+++ b/blimp/tools/manifest-blacklist.txt
@@ -0,0 +1,14 @@
+# Listing of filename patterns to be excluded from the Blimp Docker manifest.
+# Wildcards (* or ?) are allowed.
+
+*.mojo
+./libfont_service_library.so
+./libtracing_library.so
+./libmus_library.so
+./libosmesa.so
+./libresource_provider_library.so
+./mojo_runner
+gen/*
+mus/mus.mojo
+snapshot_blob.bin
+
diff --git a/build/all.gyp b/build/all.gyp
index a487355..881ab59e 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -186,6 +186,13 @@
             '../third_party/crashpad/crashpad/crashpad.gyp:*',
             '../third_party/ocmock/ocmock.gyp:*',
           ],
+          'conditions': [
+            ['enable_ipc_fuzzer==1', {
+              'dependencies': [
+                '../tools/ipc_fuzzer/ipc_fuzzer.gyp:*',
+              ],
+            }],
+          ],
         }],
         ['OS=="linux"', {
           'dependencies': [
@@ -725,7 +732,7 @@
               ],
             }],
             ['enable_ipc_fuzzer==1 and component!="shared_library" and '
-                 '(OS=="linux" or OS=="win")', {
+                 '(OS=="linux" or OS=="win" or OS=="mac")', {
               'dependencies': [
                 '../tools/ipc_fuzzer/ipc_fuzzer.gyp:*',
               ],
@@ -1411,6 +1418,13 @@
             '../chrome/test/media_router/e2e_tests.gyp:media_router_e2e_tests_run',
           ],
         }, # target_name: media_router_swarming_tests
+        {
+          'target_name': 'media_router_swarming_perf_tests',
+          'type': 'none',
+          'dependencies': [
+            '../chrome/test/media_router/e2e_tests.gyp:media_router_perf_tests_run',
+          ],
+        }, # target_name: media_router_swarming_perf_tests
       ]
     }],
     ['OS=="mac" and toolkit_views==1', {
diff --git a/build/android/gyp/javac.py b/build/android/gyp/javac.py
index a818ff85..1f6d1ba 100755
--- a/build/android/gyp/javac.py
+++ b/build/android/gyp/javac.py
@@ -228,6 +228,12 @@
         classpath_idx = javac_cmd.index('-classpath')
         javac_cmd[classpath_idx + 1] += ':' + classes_dir
 
+      # Can happen when a target goes from having no sources, to having sources.
+      # It's created by the call to build_utils.Touch() below.
+      if options.incremental:
+        if os.path.exists(pdb_path) and not os.path.getsize(pdb_path):
+          os.unlink(pdb_path)
+
       # Don't include the output directory in the initial set of args since it
       # being in a temp dir makes it unstable (breaks md5 stamping).
       cmd = javac_cmd + ['-d', classes_dir] + java_files
@@ -253,6 +259,9 @@
                '(http://crbug.com/551449).')
         os.unlink(pdb_path)
         attempt_build()
+    elif options.incremental:
+      # Make sure output exists.
+      build_utils.Touch(pdb_path)
 
     if options.main_class or options.manifest_entry:
       entries = []
diff --git a/build/android/incremental_install/java/org/chromium/incrementalinstall/ClassLoaderPatcher.java b/build/android/incremental_install/java/org/chromium/incrementalinstall/ClassLoaderPatcher.java
index c382799..8bf3779 100644
--- a/build/android/incremental_install/java/org/chromium/incrementalinstall/ClassLoaderPatcher.java
+++ b/build/android/incremental_install/java/org/chromium/incrementalinstall/ClassLoaderPatcher.java
@@ -94,8 +94,8 @@
         Object dexPathList = Reflect.getField(mClassLoader, "pathList");
         Object[] dexElements = (Object[]) Reflect.getField(dexPathList, "dexElements");
         Object[] additionalElements = makeDexElements(dexFilesArr, optimizedDir);
-        Reflect.setField(
-                dexPathList, "dexElements", Reflect.concatArrays(dexElements, additionalElements));
+        Reflect.setField(dexPathList, "dexElements",
+                Reflect.concatArrays(dexElements, dexElements, additionalElements));
     }
 
     /**
@@ -150,11 +150,11 @@
         // Switched from an array to an ArrayList in Lollipop.
         if (currentDirs instanceof List) {
             List<File> dirsAsList = (List<File>) currentDirs;
-            dirsAsList.add(nativeLibDir);
+            dirsAsList.add(0, nativeLibDir);
         } else {
             File[] dirsAsArray = (File[]) currentDirs;
             Reflect.setField(dexPathList, "nativeLibraryDirectories",
-                    Reflect.concatArrays(dirsAsArray, newDirs));
+                    Reflect.concatArrays(newDirs, newDirs, dirsAsArray));
         }
 
         Object[] nativeLibraryPathElements;
@@ -166,9 +166,9 @@
             return;
         }
         Object[] additionalElements = makeNativePathElements(newDirs);
-        Reflect.setField(
-                dexPathList, "nativeLibraryPathElements",
-                Reflect.concatArrays(nativeLibraryPathElements, additionalElements));
+        Reflect.setField(dexPathList, "nativeLibraryPathElements",
+                Reflect.concatArrays(nativeLibraryPathElements, additionalElements,
+                        nativeLibraryPathElements));
     }
 
     private static void copyChangedFiles(File srcDir, File dstDir) throws IOException {
diff --git a/build/android/incremental_install/java/org/chromium/incrementalinstall/Reflect.java b/build/android/incremental_install/java/org/chromium/incrementalinstall/Reflect.java
index 7790690..c64dc1e8 100644
--- a/build/android/incremental_install/java/org/chromium/incrementalinstall/Reflect.java
+++ b/build/android/incremental_install/java/org/chromium/incrementalinstall/Reflect.java
@@ -46,9 +46,9 @@
      * Concatenates two arrays into a new array. The arrays must be of the same
      * type.
      */
-    static Object[] concatArrays(Object[] left, Object[] right) {
+    static Object[] concatArrays(Object[] arrType, Object[] left, Object[] right) {
         Object[] result = (Object[]) Array.newInstance(
-                left.getClass().getComponentType(), left.length + right.length);
+                arrType.getClass().getComponentType(), left.length + right.length);
         System.arraycopy(left, 0, result, 0, left.length);
         System.arraycopy(right, 0, result, left.length, right.length);
         return result;
diff --git a/build/common.gypi b/build/common.gypi
index 8afb0653..7f976adf 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -2743,9 +2743,6 @@
       ['use_clipboard_aurax11==1', {
         'defines': ['USE_CLIPBOARD_AURAX11=1'],
       }],
-      ['enable_one_click_signin==1', {
-        'defines': ['ENABLE_ONE_CLICK_SIGNIN'],
-      }],
       ['image_loader_extension==1', {
         'defines': ['IMAGE_LOADER_EXTENSION=1'],
       }],
@@ -2773,9 +2770,6 @@
       ['notifications==1', {
         'defines': ['ENABLE_NOTIFICATIONS'],
       }],
-      ['enable_hidpi==1', {
-        'defines': ['ENABLE_HIDPI=1'],
-      }],
       ['enable_topchrome_md==1', {
         'defines': ['ENABLE_TOPCHROME_MD=1'],
       }],
@@ -3944,13 +3938,6 @@
                       '-Wno-abi',
                     ],
                   }],
-                  ['clang==1', {
-                    'cflags': [
-                      # Disable an incorrect loop optimization.
-                      # See http://llvm.org/bugs/show_bug.cgi?id=26600.
-                      '-mllvm -enable-interleaved-mem-accesses=0',
-                    ],
-                  }],
                   ['clang==1 and arm_arch!="" and OS!="android"', {
                     'cflags': [
                       '-target arm-linux-gnueabihf',
diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn
index 32ec333..faa00e4 100644
--- a/build/config/BUILD.gn
+++ b/build/config/BUILD.gn
@@ -228,12 +228,6 @@
   if (enable_image_loader_extension) {
     defines += [ "IMAGE_LOADER_EXTENSION=1" ]
   }
-  if (enable_one_click_signin) {
-    defines += [ "ENABLE_ONE_CLICK_SIGNIN" ]
-  }
-  if (enable_hidpi) {
-    defines += [ "ENABLE_HIDPI=1" ]
-  }
   if (enable_topchrome_md) {
     defines += [ "ENABLE_TOPCHROME_MD=1" ]
   }
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 3f23e8e..accbed0 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -6,7 +6,7 @@
 import("//build/config/chrome_build.gni")
 import("//build/config/compiler/compiler.gni")
 import("//build/config/nacl/config.gni")
-import("//build/toolchain/ccache.gni")
+import("//build/toolchain/cc_wrapper.gni")
 
 if (current_cpu == "arm") {
   import("//build/config/arm.gni")
@@ -88,7 +88,7 @@
 
 if (use_debug_fission == "default") {
   use_debug_fission = is_debug && !is_win && use_gold &&
-                      linux_use_bundled_binutils && !use_ccache
+                      linux_use_bundled_binutils && cc_wrapper == ""
 }
 
 # default_include_dirs ---------------------------------------------------------
@@ -593,14 +593,7 @@
         ]
       }
     } else if (current_cpu == "arm") {
-      if (is_clang) {
-        # Disable an incorrect loop optimization.
-        # See http://llvm.org/bugs/show_bug.cgi?id=26600.
-        cflags += [
-          "-mllvm",
-          "-enable-interleaved-mem-accesses=0",
-        ]
-      } else {
+      if (!is_clang) {
         # Clang doesn't support these flags.
         cflags += [
           # The tree-sra optimization (scalar replacement for
diff --git a/build/config/features.gni b/build/config/features.gni
index df6192a..64ae56b9 100644
--- a/build/config/features.gni
+++ b/build/config/features.gni
@@ -41,7 +41,6 @@
   debug_devtools = false
 
   # Enables WebRTC.
-  # TODO(GYP) make mac work.
   enable_webrtc = !is_ios
 
   # Enables the Media Router.
@@ -72,8 +71,6 @@
 
   enable_autofill_dialog = !is_ios
 
-  enable_one_click_signin = is_win || is_mac || (is_linux && !is_chromeos)
-
   enable_remoting = !is_ios && !is_chromecast && !is_headless
 
   # Enable hole punching for the protected video.
diff --git a/build/config/ui.gni b/build/config/ui.gni
index a1025633..926dabc 100644
--- a/build/config/ui.gni
+++ b/build/config/ui.gni
@@ -85,5 +85,3 @@
 use_atk = is_desktop_linux && use_x11
 
 use_clipboard_aurax11 = is_linux && use_aura && use_x11
-
-enable_hidpi = is_mac || is_win || is_linux
diff --git a/build/install-build-deps.sh b/build/install-build-deps.sh
index c0d8d99..04f6e59 100755
--- a/build/install-build-deps.sh
+++ b/build/install-build-deps.sh
@@ -182,7 +182,7 @@
 # be more than one with the same name in the case of multiarch). Expand into an
 # array.
 mesa_packages=($(dpkg-query -Wf'${package} ${status}\n' \
-                            libgl1-mesa-glx-lts-\* | \
+                            libgl1-mesa-glx-lts-\* 2>/dev/null | \
                  grep " ok installed" | cut -d " " -f 1 | sort -u))
 if [ "${#mesa_packages[@]}" -eq 0 ]; then
   mesa_variant=""
diff --git a/build/toolchain/cc_wrapper.gni b/build/toolchain/cc_wrapper.gni
new file mode 100644
index 0000000..1fa1850
--- /dev/null
+++ b/build/toolchain/cc_wrapper.gni
@@ -0,0 +1,35 @@
+# Copyright (c) 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.
+
+# Defines the configuration of cc wrapper
+# ccache: a c/c++ compiler cache which can greatly reduce recompilation times.
+# icecc, distcc: it takes compile jobs from a build and distributes them among
+#                remote machines allowing a parallel build.
+#
+# TIPS
+#
+# 1) ccache
+# Set clang_use_chrome_plugins=false if using ccache 3.1.9 or earlier, since
+# these versions don't support -Xclang.  (3.1.10 and later will silently
+# ignore -Xclang, so it doesn't matter if you disable clang_use_chrome_plugins
+# or not).
+#
+# Use ccache 3.2 or later to avoid clang unused argument warnings:
+# https://bugzilla.samba.org/show_bug.cgi?id=8118
+#
+# To avoid -Wparentheses-equality clang warnings, at some cost in terms of
+# speed, you can do:
+# export CCACHE_CPP2=yes
+#
+# 2) icecc
+# Set clang_use_chrome_plugins=false because icecc cannot distribute custom
+# clang libraries.
+#
+# To use icecc and ccache together, set cc_wrapper = "ccache" with
+# export CCACHE_PREFIX=icecc
+
+declare_args() {
+  # Set to "ccache", "icecc" or "distcc".  Probably doesn't work on windows.
+  cc_wrapper = ""
+}
diff --git a/build/toolchain/ccache.gni b/build/toolchain/ccache.gni
deleted file mode 100644
index 806e079a..0000000
--- a/build/toolchain/ccache.gni
+++ /dev/null
@@ -1,25 +0,0 @@
-# Copyright (c) 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.
-
-# Defines the configuration of ccache - a c/c++ compiler cache which can
-# greatly reduce recompilation times.
-#
-# TIPS:
-#
-# Set clang_use_chrome_plugins=false if using ccache 3.1.9 or earlier, since
-# these versions don't support -Xclang.  (3.1.10 and later will silently
-# ignore -Xclang, so it doesn't matter if you disable clang_use_chrome_plugins
-# or not).
-#
-# Use ccache 3.2 or later to avoid clang unused argument warnings:
-# https://bugzilla.samba.org/show_bug.cgi?id=8118
-#
-# To avoid -Wparentheses-equality clang warnings, at some cost in terms of
-# speed, you can do:
-# export CCACHE_CPP2=yes
-
-declare_args() {
-  # Set to true to enable ccache.  Probably doesn't work on windows.
-  use_ccache = false
-}
diff --git a/build/toolchain/cros/BUILD.gn b/build/toolchain/cros/BUILD.gn
index dec710e..f313b424 100644
--- a/build/toolchain/cros/BUILD.gn
+++ b/build/toolchain/cros/BUILD.gn
@@ -67,5 +67,5 @@
   toolchain_cpu = target_cpu
   toolchain_os = "linux"
   is_clang = is_clang
-  use_ccache = false
+  cc_wrapper = ""
 }
diff --git a/build/toolchain/gcc_toolchain.gni b/build/toolchain/gcc_toolchain.gni
index a4578f5..0c314bb 100644
--- a/build/toolchain/gcc_toolchain.gni
+++ b/build/toolchain/gcc_toolchain.gni
@@ -4,7 +4,7 @@
 
 import("//build/config/nacl/config.gni")
 import("//build/config/sanitizers/sanitizers.gni")
-import("//build/toolchain/ccache.gni")
+import("//build/toolchain/cc_wrapper.gni")
 import("//build/toolchain/goma.gni")
 import("//build/toolchain/toolchain.gni")
 
@@ -80,9 +80,10 @@
 #      default setting.
 #  - is_nacl_glibc
 #      Whether NaCl code is built using Glibc instead of Newlib.
-#  - use_ccache
-#      Override the global use_ccache setting, useful to opt-out of ccache in
-#      a particular toolchain by setting use_ccache = false in it.
+#  - cc_wrapper
+#      Override the global cc_wrapper setting. e.g. "ccache" or "icecc".
+#      useful to opt-out of cc_wrapper in a particular toolchain by setting
+#      cc_wrapper = "" in it.
 #  - use_goma
 #      Override the global use_goma setting, useful to opt-out of goma in a
 #      particular toolchain by setting use_gome = false in it.
@@ -100,17 +101,17 @@
     assert(defined(invoker.toolchain_os),
            "gcc_toolchain() must specify a \"toolchain_os\"")
 
-    if (defined(invoker.use_ccache)) {
-      use_ccache = invoker.use_ccache
+    if (defined(invoker.cc_wrapper)) {
+      cc_wrapper = invoker.cc_wrapper
     }
     if (defined(invoker.use_goma)) {
       use_goma = invoker.use_goma
     }
     if (use_goma) {
-      assert(!use_ccache, "Goma and ccache can't be used together.")
+      assert(cc_wrapper == "", "Goma and cc_wrapper can't be used together.")
       compiler_prefix = "$goma_dir/gomacc "
-    } else if (use_ccache) {
-      compiler_prefix = "ccache "
+    } else if (cc_wrapper != "") {
+      compiler_prefix = cc_wrapper + " "
     } else {
       compiler_prefix = ""
     }
@@ -425,10 +426,6 @@
   }
 }
 
-declare_args() {
-  clang_dir = "//third_party/llvm-build/Release+Asserts"
-}
-
 # This is a shorthand for gcc_toolchain instances based on the
 # Chromium-built version of Clang.  Only the toolchain_cpu and
 # toolchain_os variables need to be specified by the invoker, and
@@ -448,7 +445,8 @@
   }
 
   gcc_toolchain(target_name) {
-    prefix = rebase_path(clang_dir + "/bin", root_build_dir)
+    prefix = rebase_path("//third_party/llvm-build/Release+Asserts/bin",
+                         root_build_dir)
     cc = "$prefix/clang"
     cxx = "$prefix/clang++"
     ld = cxx
diff --git a/build/toolchain/linux/BUILD.gn b/build/toolchain/linux/BUILD.gn
index c26452f..1ae2108d 100644
--- a/build/toolchain/linux/BUILD.gn
+++ b/build/toolchain/linux/BUILD.gn
@@ -81,6 +81,6 @@
   toolchain_cpu = "mipsel"
   toolchain_os = "linux"
   is_clang = false
-  use_ccache = false
+  cc_wrapper = ""
   use_goma = false
 }
diff --git a/build/toolchain/nacl/BUILD.gn b/build/toolchain/nacl/BUILD.gn
index b69e638..085f8a6 100644
--- a/build/toolchain/nacl/BUILD.gn
+++ b/build/toolchain/nacl/BUILD.gn
@@ -54,7 +54,7 @@
   # When the compilers are run via goma or ccache rather than directly by
   # GN/Ninja, the goma/ccache wrapper handles .bat files but gets confused
   # by being given the scriptprefix.
-  if (host_os == "win" && !use_goma && !use_ccache) {
+  if (host_os == "win" && !use_goma && cc_wrapper == "") {
     compiler_scriptprefix = scriptprefix
   } else {
     compiler_scriptprefix = ""
diff --git a/build_overrides/webrtc.gni b/build_overrides/webrtc.gni
index 9b6b160..c521db7 100644
--- a/build_overrides/webrtc.gni
+++ b/build_overrides/webrtc.gni
@@ -10,11 +10,3 @@
 
 # Exclude internal ADM since Chromium uses its own IO handling.
 rtc_include_internal_audio_device = false
-
-declare_args() {
-  # TODO(dpranke): This is a hack needed to get iOS to build w/ a
-  # patched version of WebRTC so that we can access the xmllite
-  # library. Remove this once we've figured out how to get WebRTC building
-  # properly.
-  ios_use_webrtc = false
-}
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index d922e79..5d0bd0d 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -34,12 +34,6 @@
     "animation/layer_animation_value_provider.h",
     "animation/scroll_offset_animation_curve.cc",
     "animation/scroll_offset_animation_curve.h",
-    "animation/scrollbar_animation_controller.cc",
-    "animation/scrollbar_animation_controller.h",
-    "animation/scrollbar_animation_controller_linear_fade.cc",
-    "animation/scrollbar_animation_controller_linear_fade.h",
-    "animation/scrollbar_animation_controller_thinning.cc",
-    "animation/scrollbar_animation_controller_thinning.h",
     "animation/timing_function.cc",
     "animation/timing_function.h",
     "animation/transform_operation.cc",
@@ -106,6 +100,12 @@
     "input/scroll_state.h",
     "input/scroll_state_data.cc",
     "input/scroll_state_data.h",
+    "input/scrollbar_animation_controller.cc",
+    "input/scrollbar_animation_controller.h",
+    "input/scrollbar_animation_controller_linear_fade.cc",
+    "input/scrollbar_animation_controller_linear_fade.h",
+    "input/scrollbar_animation_controller_thinning.cc",
+    "input/scrollbar_animation_controller_thinning.h",
     "input/selection.h",
     "input/selection_bound_type.h",
     "input/top_controls_manager.cc",
@@ -755,8 +755,6 @@
     "animation/keyframed_animation_curve_unittest.cc",
     "animation/layer_animation_controller_unittest.cc",
     "animation/scroll_offset_animation_curve_unittest.cc",
-    "animation/scrollbar_animation_controller_linear_fade_unittest.cc",
-    "animation/scrollbar_animation_controller_thinning_unittest.cc",
     "animation/transform_operations_unittest.cc",
     "base/contiguous_container_unittest.cc",
     "base/delayed_unique_notifier_unittest.cc",
@@ -777,6 +775,8 @@
     "debug/rendering_stats_unittest.cc",
     "input/layer_selection_bound_unittest.cc",
     "input/scroll_state_unittest.cc",
+    "input/scrollbar_animation_controller_linear_fade_unittest.cc",
+    "input/scrollbar_animation_controller_thinning_unittest.cc",
     "input/top_controls_manager_unittest.cc",
     "layers/heads_up_display_layer_impl_unittest.cc",
     "layers/heads_up_display_unittest.cc",
diff --git a/cc/animation/animation_events.cc b/cc/animation/animation_events.cc
index bb4cbb2..bdf6592 100644
--- a/cc/animation/animation_events.cc
+++ b/cc/animation/animation_events.cc
@@ -20,6 +20,8 @@
       opacity(0.f) {
 }
 
+AnimationEvent::AnimationEvent(const AnimationEvent& other) = default;
+
 AnimationEvents::AnimationEvents() {}
 
 AnimationEvents::~AnimationEvents() {}
diff --git a/cc/animation/animation_events.h b/cc/animation/animation_events.h
index 63645ec..b65a678b 100644
--- a/cc/animation/animation_events.h
+++ b/cc/animation/animation_events.h
@@ -22,6 +22,7 @@
                  int group_id,
                  Animation::TargetProperty target_property,
                  base::TimeTicks monotonic_time);
+  AnimationEvent(const AnimationEvent& other);
 
   Type type;
   int layer_id;
diff --git a/cc/blink/web_layer_impl.cc b/cc/blink/web_layer_impl.cc
index e497d33..eed02ff4 100644
--- a/cc/blink/web_layer_impl.cc
+++ b/cc/blink/web_layer_impl.cc
@@ -320,8 +320,14 @@
   layer_->AddMainThreadScrollingReasons(main_thread_scrolling_reasons);
 }
 
-void WebLayerImpl::clearMainThreadScrollingReasons() {
-  layer_->ClearMainThreadScrollingReasons();
+void WebLayerImpl::clearMainThreadScrollingReasons(
+    uint32_t main_thread_scrolling_reasons_to_clear) {
+  layer_->ClearMainThreadScrollingReasons(
+      main_thread_scrolling_reasons_to_clear);
+}
+
+uint32_t WebLayerImpl::mainThreadScrollingReasons() {
+  return layer_->main_thread_scrolling_reasons();
 }
 
 bool WebLayerImpl::shouldScrollOnMainThread() const {
diff --git a/cc/blink/web_layer_impl.h b/cc/blink/web_layer_impl.h
index e67137ad..28da932 100644
--- a/cc/blink/web_layer_impl.h
+++ b/cc/blink/web_layer_impl.h
@@ -124,7 +124,9 @@
   bool userScrollableVertical() const override;
   void addMainThreadScrollingReasons(
       uint32_t main_thread_scrolling_reasons) override;
-  void clearMainThreadScrollingReasons() override;
+  void clearMainThreadScrollingReasons(
+      uint32_t main_thread_scrolling_reasons_to_clear) override;
+  uint32_t mainThreadScrollingReasons() override;
   bool shouldScrollOnMainThread() const override;
   void setNonFastScrollableRegion(
       const blink::WebVector<blink::WebRect>& region) override;
diff --git a/cc/cc.gyp b/cc/cc.gyp
index 8eba025..22c01e23 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -63,12 +63,6 @@
         'animation/layer_animation_value_provider.h',
         'animation/scroll_offset_animation_curve.cc',
         'animation/scroll_offset_animation_curve.h',
-        'animation/scrollbar_animation_controller.cc',
-        'animation/scrollbar_animation_controller.h',
-        'animation/scrollbar_animation_controller_linear_fade.cc',
-        'animation/scrollbar_animation_controller_linear_fade.h',
-        'animation/scrollbar_animation_controller_thinning.cc',
-        'animation/scrollbar_animation_controller_thinning.h',
         'animation/timing_function.cc',
         'animation/timing_function.h',
         'animation/transform_operation.cc',
@@ -168,8 +162,14 @@
         'input/scroll_state.h',
         'input/scroll_state_data.cc',
         'input/scroll_state_data.h',
-        'input/selection_bound_type.h',
+        'input/scrollbar_animation_controller.cc',
+        'input/scrollbar_animation_controller.h',
+        'input/scrollbar_animation_controller_linear_fade.cc',
+        'input/scrollbar_animation_controller_linear_fade.h',
+        'input/scrollbar_animation_controller_thinning.cc',
+        'input/scrollbar_animation_controller_thinning.h',
         'input/selection.h',
+        'input/selection_bound_type.h',
         'input/top_controls_manager.cc',
         'input/top_controls_manager.h',
         'input/top_controls_manager_client.h',
@@ -426,7 +426,6 @@
         'raster/one_copy_tile_task_worker_pool.h',
         'raster/raster_buffer.cc',
         'raster/raster_buffer.h',
-        'raster/task_category.h',
         'raster/scoped_gpu_raster.cc',
         'raster/scoped_gpu_raster.h',
         'raster/single_thread_task_graph_runner.cc',
@@ -570,10 +569,10 @@
         'trees/proxy_impl.h',
         'trees/proxy_main.cc',
         'trees/proxy_main.h',
-	'trees/remote_channel_impl.cc',
-	'trees/remote_channel_impl.h',
-	'trees/remote_channel_main.cc',
-	'trees/remote_channel_main.h',
+        'trees/remote_channel_impl.cc',
+        'trees/remote_channel_impl.h',
+        'trees/remote_channel_main.cc',
+        'trees/remote_channel_main.h',
         'trees/remote_proto_channel.h',
         'trees/scoped_abort_remaining_swap_promises.h',
         'trees/single_thread_proxy.cc',
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index b8f5b1c..91933d6 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -14,8 +14,6 @@
       'animation/keyframed_animation_curve_unittest.cc',
       'animation/layer_animation_controller_unittest.cc',
       'animation/scroll_offset_animation_curve_unittest.cc',
-      'animation/scrollbar_animation_controller_linear_fade_unittest.cc',
-      'animation/scrollbar_animation_controller_thinning_unittest.cc',
       'animation/transform_operations_unittest.cc',
       'base/contiguous_container_unittest.cc',
       'base/delayed_unique_notifier_unittest.cc',
@@ -36,6 +34,8 @@
       'debug/rendering_stats_unittest.cc',
       'input/layer_selection_bound_unittest.cc',
       'input/scroll_state_unittest.cc',
+      'input/scrollbar_animation_controller_linear_fade_unittest.cc',
+      'input/scrollbar_animation_controller_thinning_unittest.cc',
       'input/top_controls_manager_unittest.cc',
       'layers/heads_up_display_layer_impl_unittest.cc',
       'layers/heads_up_display_unittest.cc',
@@ -157,8 +157,8 @@
       'trees/tree_synchronizer_unittest.cc',
     ],
     'cc_surfaces_unit_tests_source_files': [
-      'surfaces/display_unittest.cc',
       'surfaces/display_scheduler_unittest.cc',
+      'surfaces/display_unittest.cc',
       'surfaces/surface_aggregator_unittest.cc',
       'surfaces/surface_display_output_surface_unittest.cc',
       'surfaces/surface_factory_unittest.cc',
diff --git a/cc/debug/layer_tree_debug_state.cc b/cc/debug/layer_tree_debug_state.cc
index a7ea1d63..3779dcc 100644
--- a/cc/debug/layer_tree_debug_state.cc
+++ b/cc/debug/layer_tree_debug_state.cc
@@ -28,6 +28,9 @@
       show_picture_borders(false),
       record_rendering_stats_(false) {}
 
+LayerTreeDebugState::LayerTreeDebugState(const LayerTreeDebugState& other) =
+    default;
+
 LayerTreeDebugState::~LayerTreeDebugState() {}
 
 void LayerTreeDebugState::SetRecordRenderingStats(bool enabled) {
diff --git a/cc/debug/layer_tree_debug_state.h b/cc/debug/layer_tree_debug_state.h
index 3b5ba3af..0e40d13c 100644
--- a/cc/debug/layer_tree_debug_state.h
+++ b/cc/debug/layer_tree_debug_state.h
@@ -16,6 +16,7 @@
 class CC_EXPORT LayerTreeDebugState {
  public:
   LayerTreeDebugState();
+  LayerTreeDebugState(const LayerTreeDebugState& other);
   ~LayerTreeDebugState();
 
   bool show_fps_counter;
diff --git a/cc/debug/rendering_stats.cc b/cc/debug/rendering_stats.cc
index a3d7a43b..b78b4f9 100644
--- a/cc/debug/rendering_stats.cc
+++ b/cc/debug/rendering_stats.cc
@@ -9,6 +9,9 @@
 RenderingStats::TimeDeltaList::TimeDeltaList() {
 }
 
+RenderingStats::TimeDeltaList::TimeDeltaList(const TimeDeltaList& other) =
+    default;
+
 RenderingStats::TimeDeltaList::~TimeDeltaList() {
 }
 
@@ -42,6 +45,8 @@
       checkerboarded_no_recording_content_area(0),
       checkerboarded_needs_raster_content_area(0) {}
 
+RenderingStats::RenderingStats(const RenderingStats& other) = default;
+
 RenderingStats::~RenderingStats() {
 }
 
diff --git a/cc/debug/rendering_stats.h b/cc/debug/rendering_stats.h
index f296447..d6d4478 100644
--- a/cc/debug/rendering_stats.h
+++ b/cc/debug/rendering_stats.h
@@ -22,6 +22,7 @@
   class CC_EXPORT TimeDeltaList {
    public:
     TimeDeltaList();
+    TimeDeltaList(const TimeDeltaList& other);
     ~TimeDeltaList();
 
     void Append(base::TimeDelta value);
@@ -37,6 +38,7 @@
   };
 
   RenderingStats();
+  RenderingStats(const RenderingStats& other);
   ~RenderingStats();
 
   // Note: when adding new members, please remember to update Add in
diff --git a/cc/input/main_thread_scrolling_reason.h b/cc/input/main_thread_scrolling_reason.h
index 7e921fc0..1f384eb 100644
--- a/cc/input/main_thread_scrolling_reason.h
+++ b/cc/input/main_thread_scrolling_reason.h
@@ -18,6 +18,7 @@
   enum : uint32_t { kThreadedScrollingDisabled = 1 << 2 };
   enum : uint32_t { kScrollbarScrolling = 1 << 3 };
   enum : uint32_t { kPageOverlay = 1 << 4 };
+  enum : uint32_t { kAnimatingScrollOnMainThread = 1 << 13 };
 
   // Transient scrolling reasons. These are computed for each scroll begin.
   enum : uint32_t { kNonFastScrollableRegion = 1 << 5 };
@@ -30,7 +31,7 @@
   enum : uint32_t { kPageBasedScrolling = 1 << 12 };
 
   // The number of flags in this struct (excluding itself).
-  enum : uint32_t { kMainThreadScrollingReasonCount = 14 };
+  enum : uint32_t { kMainThreadScrollingReasonCount = 15 };
 
   // Returns true if the given MainThreadScrollingReason can be set by the main
   // thread.
@@ -38,7 +39,7 @@
     uint32_t reasons_set_by_main_thread =
         kNotScrollingOnMain | kHasBackgroundAttachmentFixedObjects |
         kHasNonLayerViewportConstrainedObjects | kThreadedScrollingDisabled |
-        kScrollbarScrolling | kPageOverlay;
+        kScrollbarScrolling | kPageOverlay | kAnimatingScrollOnMainThread;
     return (reasons & reasons_set_by_main_thread) == reasons;
   }
 
diff --git a/cc/input/scroll_state.cc b/cc/input/scroll_state.cc
index 6c67025..aa0baf16 100644
--- a/cc/input/scroll_state.cc
+++ b/cc/input/scroll_state.cc
@@ -12,6 +12,8 @@
 
 ScrollState::ScrollState(ScrollStateData data) : data_(data) {}
 
+ScrollState::ScrollState(const ScrollState& other) = default;
+
 ScrollState::~ScrollState() {}
 
 void ScrollState::ConsumeDelta(double x, double y) {
diff --git a/cc/input/scroll_state.h b/cc/input/scroll_state.h
index 7a8761f..35a4f97 100644
--- a/cc/input/scroll_state.h
+++ b/cc/input/scroll_state.h
@@ -22,6 +22,7 @@
 class CC_EXPORT ScrollState {
  public:
   explicit ScrollState(ScrollStateData data);
+  ScrollState(const ScrollState& other);
   ~ScrollState();
 
   // Reduce deltas by x, y.
diff --git a/cc/input/scroll_state_data.cc b/cc/input/scroll_state_data.cc
index 47f2f653c..50e1269 100644
--- a/cc/input/scroll_state_data.cc
+++ b/cc/input/scroll_state_data.cc
@@ -26,6 +26,8 @@
       current_native_scrolling_node_(nullptr),
       current_native_scrolling_element_(0) {}
 
+ScrollStateData::ScrollStateData(const ScrollStateData& other) = default;
+
 ScrollNode* ScrollStateData::current_native_scrolling_node() const {
   return current_native_scrolling_node_;
 }
diff --git a/cc/input/scroll_state_data.h b/cc/input/scroll_state_data.h
index 27fb7878..63fbe43 100644
--- a/cc/input/scroll_state_data.h
+++ b/cc/input/scroll_state_data.h
@@ -17,6 +17,7 @@
 class CC_EXPORT ScrollStateData {
  public:
   ScrollStateData();
+  ScrollStateData(const ScrollStateData& other);
 
   // Scroll delta in viewport coordinates (DIP).
   double delta_x;
diff --git a/cc/animation/scrollbar_animation_controller.cc b/cc/input/scrollbar_animation_controller.cc
similarity index 97%
rename from cc/animation/scrollbar_animation_controller.cc
rename to cc/input/scrollbar_animation_controller.cc
index 56ed559a..45feb3a 100644
--- a/cc/animation/scrollbar_animation_controller.cc
+++ b/cc/input/scrollbar_animation_controller.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "cc/animation/scrollbar_animation_controller.h"
+#include "cc/input/scrollbar_animation_controller.h"
 
 #include <algorithm>
 
diff --git a/cc/animation/scrollbar_animation_controller.h b/cc/input/scrollbar_animation_controller.h
similarity index 93%
rename from cc/animation/scrollbar_animation_controller.h
rename to cc/input/scrollbar_animation_controller.h
index bfc246b..92656ff1 100644
--- a/cc/animation/scrollbar_animation_controller.h
+++ b/cc/input/scrollbar_animation_controller.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CC_ANIMATION_SCROLLBAR_ANIMATION_CONTROLLER_H_
-#define CC_ANIMATION_SCROLLBAR_ANIMATION_CONTROLLER_H_
+#ifndef CC_INPUT_SCROLLBAR_ANIMATION_CONTROLLER_H_
+#define CC_INPUT_SCROLLBAR_ANIMATION_CONTROLLER_H_
 
 #include "base/cancelable_callback.h"
 #include "base/memory/weak_ptr.h"
@@ -83,4 +83,4 @@
 
 }  // namespace cc
 
-#endif  // CC_ANIMATION_SCROLLBAR_ANIMATION_CONTROLLER_H_
+#endif  // CC_INPUT_SCROLLBAR_ANIMATION_CONTROLLER_H_
diff --git a/cc/animation/scrollbar_animation_controller_linear_fade.cc b/cc/input/scrollbar_animation_controller_linear_fade.cc
similarity index 94%
rename from cc/animation/scrollbar_animation_controller_linear_fade.cc
rename to cc/input/scrollbar_animation_controller_linear_fade.cc
index 13b9754..079ac83 100644
--- a/cc/animation/scrollbar_animation_controller_linear_fade.cc
+++ b/cc/input/scrollbar_animation_controller_linear_fade.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "cc/animation/scrollbar_animation_controller_linear_fade.h"
+#include "cc/input/scrollbar_animation_controller_linear_fade.h"
 
 #include "base/time/time.h"
 #include "cc/layers/layer_impl.h"
@@ -35,8 +35,7 @@
                                    duration) {}
 
 ScrollbarAnimationControllerLinearFade::
-    ~ScrollbarAnimationControllerLinearFade() {
-}
+    ~ScrollbarAnimationControllerLinearFade() {}
 
 void ScrollbarAnimationControllerLinearFade::RunAnimationFrame(float progress) {
   ApplyOpacityToScrollbars(1.f - progress);
diff --git a/cc/animation/scrollbar_animation_controller_linear_fade.h b/cc/input/scrollbar_animation_controller_linear_fade.h
similarity index 82%
rename from cc/animation/scrollbar_animation_controller_linear_fade.h
rename to cc/input/scrollbar_animation_controller_linear_fade.h
index 8fce904..356c2cd 100644
--- a/cc/animation/scrollbar_animation_controller_linear_fade.h
+++ b/cc/input/scrollbar_animation_controller_linear_fade.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CC_ANIMATION_SCROLLBAR_ANIMATION_CONTROLLER_LINEAR_FADE_H_
-#define CC_ANIMATION_SCROLLBAR_ANIMATION_CONTROLLER_LINEAR_FADE_H_
+#ifndef CC_INPUT_SCROLLBAR_ANIMATION_CONTROLLER_LINEAR_FADE_H_
+#define CC_INPUT_SCROLLBAR_ANIMATION_CONTROLLER_LINEAR_FADE_H_
 
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
-#include "cc/animation/scrollbar_animation_controller.h"
 #include "cc/base/cc_export.h"
+#include "cc/input/scrollbar_animation_controller.h"
 
 namespace cc {
 class LayerImpl;
@@ -46,4 +46,4 @@
 
 }  // namespace cc
 
-#endif  // CC_ANIMATION_SCROLLBAR_ANIMATION_CONTROLLER_LINEAR_FADE_H_
+#endif  // CC_INPUT_SCROLLBAR_ANIMATION_CONTROLLER_LINEAR_FADE_H_
diff --git a/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc b/cc/input/scrollbar_animation_controller_linear_fade_unittest.cc
similarity index 96%
rename from cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc
rename to cc/input/scrollbar_animation_controller_linear_fade_unittest.cc
index 8231c9dd..35eacb51 100644
--- a/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc
+++ b/cc/input/scrollbar_animation_controller_linear_fade_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "cc/animation/scrollbar_animation_controller_linear_fade.h"
+#include "cc/input/scrollbar_animation_controller_linear_fade.h"
 
 #include "cc/layers/solid_color_scrollbar_layer_impl.h"
 #include "cc/test/fake_impl_task_runner_provider.h"
@@ -51,14 +51,9 @@
 
     scoped_ptr<LayerImpl> scroll_layer =
         LayerImpl::Create(host_impl_.active_tree(), 1);
-    scrollbar_layer_ =
-        SolidColorScrollbarLayerImpl::Create(host_impl_.active_tree(),
-                                             2,
-                                             orientation(),
-                                             kThumbThickness,
-                                             kTrackStart,
-                                             kIsLeftSideVerticalScrollbar,
-                                             kIsOverlayScrollbar);
+    scrollbar_layer_ = SolidColorScrollbarLayerImpl::Create(
+        host_impl_.active_tree(), 2, orientation(), kThumbThickness,
+        kTrackStart, kIsLeftSideVerticalScrollbar, kIsOverlayScrollbar);
     clip_layer_ = LayerImpl::Create(host_impl_.active_tree(), 3);
     scroll_layer->SetScrollClipLayer(clip_layer_->id());
     LayerImpl* scroll_layer_ptr = scroll_layer.get();
diff --git a/cc/animation/scrollbar_animation_controller_thinning.cc b/cc/input/scrollbar_animation_controller_thinning.cc
similarity index 98%
rename from cc/animation/scrollbar_animation_controller_thinning.cc
rename to cc/input/scrollbar_animation_controller_thinning.cc
index d8a2d6d..8b801ab9 100644
--- a/cc/animation/scrollbar_animation_controller_thinning.cc
+++ b/cc/input/scrollbar_animation_controller_thinning.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "cc/animation/scrollbar_animation_controller_thinning.h"
+#include "cc/input/scrollbar_animation_controller_thinning.h"
 
 #include "base/time/time.h"
 #include "cc/layers/layer_impl.h"
@@ -49,8 +49,7 @@
   ApplyOpacityAndThumbThicknessScale(kIdleOpacity, kIdleThicknessScale);
 }
 
-ScrollbarAnimationControllerThinning::~ScrollbarAnimationControllerThinning() {
-}
+ScrollbarAnimationControllerThinning::~ScrollbarAnimationControllerThinning() {}
 
 void ScrollbarAnimationControllerThinning::RunAnimationFrame(float progress) {
   float opacity = OpacityAtAnimationProgress(progress);
diff --git a/cc/animation/scrollbar_animation_controller_thinning.h b/cc/input/scrollbar_animation_controller_thinning.h
similarity index 88%
rename from cc/animation/scrollbar_animation_controller_thinning.h
rename to cc/input/scrollbar_animation_controller_thinning.h
index b700db83..0519d39 100644
--- a/cc/animation/scrollbar_animation_controller_thinning.h
+++ b/cc/input/scrollbar_animation_controller_thinning.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CC_ANIMATION_SCROLLBAR_ANIMATION_CONTROLLER_THINNING_H_
-#define CC_ANIMATION_SCROLLBAR_ANIMATION_CONTROLLER_THINNING_H_
+#ifndef CC_INPUT_SCROLLBAR_ANIMATION_CONTROLLER_THINNING_H_
+#define CC_INPUT_SCROLLBAR_ANIMATION_CONTROLLER_THINNING_H_
 
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
-#include "cc/animation/scrollbar_animation_controller.h"
 #include "cc/base/cc_export.h"
+#include "cc/input/scrollbar_animation_controller.h"
 
 namespace cc {
 class LayerImpl;
@@ -50,11 +50,7 @@
  private:
   // Describes whether the current animation should INCREASE (darken / thicken)
   // a bar or DECREASE it (lighten / thin).
-  enum AnimationChange {
-    NONE,
-    INCREASE,
-    DECREASE
-  };
+  enum AnimationChange { NONE, INCREASE, DECREASE };
   float OpacityAtAnimationProgress(float progress);
   float ThumbThicknessScaleAtAnimationProgress(float progress);
   float AdjustScale(float new_value,
@@ -77,4 +73,4 @@
 
 }  // namespace cc
 
-#endif  // CC_ANIMATION_SCROLLBAR_ANIMATION_CONTROLLER_THINNING_H_
+#endif  // CC_INPUT_SCROLLBAR_ANIMATION_CONTROLLER_THINNING_H_
diff --git a/cc/animation/scrollbar_animation_controller_thinning_unittest.cc b/cc/input/scrollbar_animation_controller_thinning_unittest.cc
similarity index 96%
rename from cc/animation/scrollbar_animation_controller_thinning_unittest.cc
rename to cc/input/scrollbar_animation_controller_thinning_unittest.cc
index 475b368..da5d625 100644
--- a/cc/animation/scrollbar_animation_controller_thinning_unittest.cc
+++ b/cc/input/scrollbar_animation_controller_thinning_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "cc/animation/scrollbar_animation_controller_thinning.h"
+#include "cc/input/scrollbar_animation_controller_thinning.h"
 
 #include "cc/layers/solid_color_scrollbar_layer_impl.h"
 #include "cc/test/fake_impl_task_runner_provider.h"
@@ -54,14 +54,9 @@
     const int kTrackStart = 0;
     const bool kIsLeftSideVerticalScrollbar = false;
     const bool kIsOverlayScrollbar = true;
-    scrollbar_layer_ =
-        SolidColorScrollbarLayerImpl::Create(host_impl_.active_tree(),
-                                             kId,
-                                             HORIZONTAL,
-                                             kThumbThickness,
-                                             kTrackStart,
-                                             kIsLeftSideVerticalScrollbar,
-                                             kIsOverlayScrollbar);
+    scrollbar_layer_ = SolidColorScrollbarLayerImpl::Create(
+        host_impl_.active_tree(), kId, HORIZONTAL, kThumbThickness, kTrackStart,
+        kIsLeftSideVerticalScrollbar, kIsOverlayScrollbar);
 
     scrollbar_layer_->SetScrollLayerId(scroll_layer_ptr->id());
     clip_layer_->SetBounds(gfx::Size(100, 100));
diff --git a/cc/layers/heads_up_display_layer_impl.cc b/cc/layers/heads_up_display_layer_impl.cc
index 55e13e7..6606c0fb 100644
--- a/cc/layers/heads_up_display_layer_impl.cc
+++ b/cc/layers/heads_up_display_layer_impl.cc
@@ -207,6 +207,7 @@
   resource_provider->CopyToResource(resources_.back()->id(),
                                     static_cast<const uint8_t*>(pixels),
                                     internal_content_bounds_);
+  resource_provider->GenerateSyncTokenForResource(resources_.back()->id());
 }
 
 void HeadsUpDisplayLayerImpl::ReleaseResources() {
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index 8d58b31a0..e7053a8 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -52,7 +52,6 @@
 Layer::Layer(const LayerSettings& settings)
     : needs_push_properties_(false),
       num_dependents_need_push_properties_(0),
-      stacking_order_changed_(false),
       // Layer IDs start from 1.
       layer_id_(g_next_layer_id.GetNext() + 1),
       ignore_set_needs_commit_(false),
@@ -291,7 +290,7 @@
   AddDrawableDescendants(child->NumDescendantsThatDrawContent() +
                          (child->DrawsContent() ? 1 : 0));
   child->SetParent(this);
-  child->stacking_order_changed_ = true;
+  child->SetSubtreePropertyChanged();
 
   index = std::min(index, children_.size());
   children_.insert(children_.begin() + index, child);
@@ -684,6 +683,7 @@
   if (transform_ == transform)
     return;
 
+  SetSubtreePropertyChanged();
   if (layer_tree_host_) {
     if (TransformNode* transform_node =
             layer_tree_host_->property_trees()->transform_tree.Node(
@@ -697,6 +697,7 @@
             Are2dAxisAligned(transform_, transform, &invertible);
         transform_node->data.local = transform;
         transform_node->data.needs_local_transform_update = true;
+        transform_node->data.transform_changed = true;
         layer_tree_host_->property_trees()->transform_tree.set_needs_update(
             true);
         if (preserves_2d_axis_alignment)
@@ -965,18 +966,23 @@
     uint32_t main_thread_scrolling_reasons) {
   DCHECK(IsPropertyChangeAllowed());
   DCHECK(main_thread_scrolling_reasons);
-  if (main_thread_scrolling_reasons_ == main_thread_scrolling_reasons)
+  uint32_t new_reasons =
+      main_thread_scrolling_reasons_ | main_thread_scrolling_reasons;
+  if (main_thread_scrolling_reasons_ == new_reasons)
     return;
-  main_thread_scrolling_reasons_ |= main_thread_scrolling_reasons;
+  main_thread_scrolling_reasons_ = new_reasons;
   SetNeedsCommit();
 }
 
-void Layer::ClearMainThreadScrollingReasons() {
+void Layer::ClearMainThreadScrollingReasons(
+    uint32_t main_thread_scrolling_reasons_to_clear) {
   DCHECK(IsPropertyChangeAllowed());
-  if (!main_thread_scrolling_reasons_)
+  DCHECK(main_thread_scrolling_reasons_to_clear);
+  uint32_t new_reasons =
+      ~main_thread_scrolling_reasons_to_clear & main_thread_scrolling_reasons_;
+  if (new_reasons == main_thread_scrolling_reasons_)
     return;
-  main_thread_scrolling_reasons_ =
-      MainThreadScrollingReason::kNotScrollingOnMain;
+  main_thread_scrolling_reasons_ = new_reasons;
   SetNeedsCommit();
 }
 
@@ -1363,8 +1369,6 @@
   update_rect_.Union(layer->update_rect());
   layer->SetUpdateRect(update_rect_);
 
-  layer->SetStackingOrderChanged(stacking_order_changed_);
-
   if (layer->layer_animation_controller() && layer_animation_controller_)
     layer_animation_controller_->PushAnimationUpdatesTo(
         layer->layer_animation_controller());
@@ -1375,7 +1379,6 @@
   }
 
   // Reset any state that should be cleared for the next update.
-  stacking_order_changed_ = false;
   subtree_property_changed_ = false;
   update_rect_ = gfx::Rect();
 
@@ -1590,14 +1593,12 @@
   // See crbug.com/570374.
 
   RectToProto(update_rect_, base->mutable_update_rect());
-  base->set_stacking_order_changed(stacking_order_changed_);
 
   // TODO(nyquist): Figure out what to do with LayerAnimationController.
   // See crbug.com/570376.
   // TODO(nyquist): Figure out what to do with FrameTimingRequests. See
   // crbug.com/570377.
 
-  stacking_order_changed_ = false;
   update_rect_ = gfx::Rect();
 }
 
@@ -1693,7 +1694,6 @@
       ProtoToVector2dF(base.scroll_compensation_adjustment());
 
   update_rect_.Union(ProtoToRect(base.update_rect()));
-  stacking_order_changed_ = base.stacking_order_changed();
 }
 
 scoped_ptr<LayerImpl> Layer::CreateLayerImpl(LayerTreeImpl* tree_impl) {
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index 547b422..cdc0feee 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -280,7 +280,8 @@
   bool user_scrollable_vertical() const { return user_scrollable_vertical_; }
 
   void AddMainThreadScrollingReasons(uint32_t main_thread_scrolling_reasons);
-  void ClearMainThreadScrollingReasons();
+  void ClearMainThreadScrollingReasons(
+      uint32_t main_thread_scrolling_reasons_to_clear);
   uint32_t main_thread_scrolling_reasons() const {
     return main_thread_scrolling_reasons_;
   }
@@ -650,10 +651,6 @@
   // side.
   int num_dependents_need_push_properties_;
 
-  // Tracks whether this layer may have changed stacking order with its
-  // siblings.
-  bool stacking_order_changed_;
-
   // The update rect is the region of the compositor resource that was
   // actually updated by the compositor. For layers that may do updating
   // outside the compositor's control (i.e. plugin layers), this information
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 6b8e58ab..b0515b0d 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -62,7 +62,6 @@
           MainThreadScrollingReason::kNotScrollingOnMain),
       user_scrollable_horizontal_(true),
       user_scrollable_vertical_(true),
-      stacking_order_changed_(false),
       double_sided_(true),
       should_flatten_transform_(true),
       should_flatten_transform_from_property_tree_(false),
@@ -610,7 +609,6 @@
   update_rect_.Union(layer->update_rect());
   layer->SetUpdateRect(update_rect_);
 
-  layer->SetStackingOrderChanged(stacking_order_changed_);
   layer->SetDebugInfo(debug_info_);
 
   if (frame_timing_requests_dirty_) {
@@ -619,7 +617,6 @@
   }
 
   // Reset any state that should be cleared for the next update.
-  stacking_order_changed_ = false;
   layer_property_changed_ = false;
   update_rect_ = gfx::Rect();
   needs_push_properties_ = false;
@@ -686,13 +683,6 @@
   return result;
 }
 
-void LayerImpl::SetStackingOrderChanged(bool stacking_order_changed) {
-  if (stacking_order_changed) {
-    stacking_order_changed_ = true;
-    NoteLayerPropertyChangedForSubtree();
-  }
-}
-
 bool LayerImpl::LayerPropertyChanged() const {
   if (layer_property_changed_)
     return true;
@@ -1269,7 +1259,6 @@
   }
   transform_ = transform;
   transform_is_invertible_ = transform_is_invertible;
-  NoteLayerPropertyChangedForSubtree();
 }
 
 bool LayerImpl::TransformIsAnimating() const {
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index 0c91ea34..d4bf384 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -508,11 +508,9 @@
       uint32_t main_thread_scrolling_reasons) {
     main_thread_scrolling_reasons_ = main_thread_scrolling_reasons;
   }
-
   uint32_t main_thread_scrolling_reasons() const {
     return main_thread_scrolling_reasons_;
   }
-
   bool should_scroll_on_main_thread() const {
     return !!main_thread_scrolling_reasons_;
   }
@@ -571,8 +569,6 @@
 
   virtual base::DictionaryValue* LayerTreeAsJson() const;
 
-  void SetStackingOrderChanged(bool stacking_order_changed);
-
   bool LayerPropertyChanged() const;
 
   void ResetAllChangeTrackingForSubtree();
@@ -764,7 +760,6 @@
 
   bool user_scrollable_horizontal_ : 1;
   bool user_scrollable_vertical_ : 1;
-  bool stacking_order_changed_ : 1;
   // Whether the "back" of this layer should draw.
   bool double_sided_ : 1;
   bool should_flatten_transform_ : 1;
diff --git a/cc/layers/layer_proto_converter_unittest.cc b/cc/layers/layer_proto_converter_unittest.cc
index e72ab58..af1e902 100644
--- a/cc/layers/layer_proto_converter_unittest.cc
+++ b/cc/layers/layer_proto_converter_unittest.cc
@@ -189,12 +189,46 @@
   layer_src_b->SetMaskLayer(layer_src_b_mask.get());
   layer_src_b->SetReplicaLayer(layer_src_b_replica.get());
 
+  proto::LayerUpdate layer_update;
+  LayerProtoConverter::SerializeLayerProperties(layer_src_root.get(),
+                                                &layer_update);
+
+  // All flags for pushing properties should have been cleared.
+  EXPECT_FALSE(layer_src_root->needs_push_properties());
+  EXPECT_FALSE(layer_src_root->descendant_needs_push_properties());
+  EXPECT_FALSE(layer_src_a->needs_push_properties());
+  EXPECT_FALSE(layer_src_a->descendant_needs_push_properties());
+  EXPECT_FALSE(layer_src_b->needs_push_properties());
+  EXPECT_FALSE(layer_src_b->descendant_needs_push_properties());
+  EXPECT_FALSE(layer_src_b_mask->needs_push_properties());
+  EXPECT_FALSE(layer_src_b_mask->descendant_needs_push_properties());
+  EXPECT_FALSE(layer_src_b_replica->needs_push_properties());
+  EXPECT_FALSE(layer_src_b_replica->descendant_needs_push_properties());
+  EXPECT_FALSE(layer_src_c->needs_push_properties());
+  EXPECT_FALSE(layer_src_c->descendant_needs_push_properties());
+  EXPECT_FALSE(layer_src_d->needs_push_properties());
+  EXPECT_FALSE(layer_src_d->descendant_needs_push_properties());
+
+  // AddChild changes the stacking order of child and it needs to push
+  // properties.
+  ASSERT_EQ(5, layer_update.layers_size());
+  EXPECT_EQ(layer_src_root->id(), layer_update.layers(0).id());
+  proto::LayerProperties dest_root = layer_update.layers(0);
+  EXPECT_EQ(layer_src_a->id(), layer_update.layers(1).id());
+  proto::LayerProperties dest_a = layer_update.layers(1);
+  EXPECT_EQ(layer_src_c->id(), layer_update.layers(2).id());
+  proto::LayerProperties dest_c = layer_update.layers(2);
+  EXPECT_EQ(layer_src_b->id(), layer_update.layers(3).id());
+  proto::LayerProperties dest_b = layer_update.layers(3);
+  EXPECT_EQ(layer_src_d->id(), layer_update.layers(4).id());
+  proto::LayerProperties dest_d = layer_update.layers(4);
+  layer_update.Clear();
+
   layer_src_a->SetNeedsPushProperties();
   layer_src_b->SetNeedsPushProperties();
   layer_src_b_mask->SetNeedsPushProperties();
   layer_src_d->SetNeedsPushProperties();
 
-  proto::LayerUpdate layer_update;
   LayerProtoConverter::SerializeLayerProperties(layer_src_root.get(),
                                                 &layer_update);
 
@@ -217,13 +251,13 @@
   // Only 5 of the layers should have been serialized.
   ASSERT_EQ(5, layer_update.layers_size());
   EXPECT_EQ(layer_src_root->id(), layer_update.layers(0).id());
-  proto::LayerProperties dest_root = layer_update.layers(0);
+  dest_root = layer_update.layers(0);
   EXPECT_EQ(layer_src_a->id(), layer_update.layers(1).id());
-  proto::LayerProperties dest_a = layer_update.layers(1);
+  dest_a = layer_update.layers(1);
   EXPECT_EQ(layer_src_b->id(), layer_update.layers(2).id());
-  proto::LayerProperties dest_b = layer_update.layers(2);
+  dest_b = layer_update.layers(2);
   EXPECT_EQ(layer_src_d->id(), layer_update.layers(3).id());
-  proto::LayerProperties dest_d = layer_update.layers(3);
+  dest_d = layer_update.layers(3);
   EXPECT_EQ(layer_src_b_mask->id(), layer_update.layers(4).id());
   proto::LayerProperties dest_b_mask = layer_update.layers(4);
 
@@ -268,10 +302,17 @@
   layer_src_b->AddChild(layer_src_c);
   layer_src_b->SetMaskLayer(layer_src_b_mask.get());
 
+  proto::LayerUpdate layer_update;
+  LayerProtoConverter::SerializeLayerProperties(layer_src_root.get(),
+                                                &layer_update);
+  // AddChild changes stacking order of child and we need to push proeprties of
+  // child.
+  ASSERT_EQ(3, layer_update.layers_size());
+  layer_update.Clear();
+
   layer_src_b->SetNeedsPushProperties();
   layer_src_b_mask->SetNeedsPushProperties();
 
-  proto::LayerUpdate layer_update;
   LayerProtoConverter::SerializeLayerProperties(layer_src_root.get(),
                                                 &layer_update);
 
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc
index ce71b08..1b10a914 100644
--- a/cc/layers/layer_unittest.cc
+++ b/cc/layers/layer_unittest.cc
@@ -102,9 +102,8 @@
     src->SetNeedsPushProperties();
     src->SetLayerTreeHost(layer_tree_host_.get());
 
-    // The following two members are reset during serialization, so
-    // store the original values.
-    bool stacking_order_changed = src->stacking_order_changed_;
+    // The following member is reset during serialization, so store the original
+    // values.
     gfx::Rect update_rect = src->update_rect_;
 
     // Serialize |src| to protobuf and read the first entry in the
@@ -185,7 +184,6 @@
     EXPECT_EQ(src->scroll_compensation_adjustment_,
               dest->scroll_compensation_adjustment_);
     EXPECT_EQ(update_rect, dest->update_rect_);
-    EXPECT_EQ(stacking_order_changed, dest->stacking_order_changed_);
 
     if (src->scroll_parent_) {
       ASSERT_TRUE(dest->scroll_parent_);
@@ -213,8 +211,7 @@
       EXPECT_FALSE(dest->clip_children_);
     }
 
-    // The following two members should have been reset during serialization.
-    EXPECT_FALSE(src->stacking_order_changed_);
+    // The following member should have been reset during serialization.
     EXPECT_EQ(gfx::Rect(), src->update_rect_);
 
     // Before deleting |dest|, the LayerTreeHost must be unset.
@@ -293,7 +290,6 @@
     layer->scroll_offset_ = gfx::ScrollOffset(3, 14);
     layer->scroll_compensation_adjustment_ = gfx::Vector2dF(6.28f, 3.14f);
     layer->update_rect_ = gfx::Rect(14, 15);
-    layer->stacking_order_changed_ = true;
 
     VerifyBaseLayerPropertiesSerializationAndDeserialization(layer.get());
   }
@@ -344,7 +340,6 @@
     layer->scroll_offset_ = gfx::ScrollOffset(3, 14);
     layer->scroll_compensation_adjustment_ = gfx::Vector2dF(6.28f, 3.14f);
     layer->update_rect_ = gfx::Rect(14, 15);
-    layer->stacking_order_changed_ = !layer->stacking_order_changed_;
 
     VerifyBaseLayerPropertiesSerializationAndDeserialization(layer.get());
   }
@@ -1109,6 +1104,20 @@
   node = layer_tree_host_->property_trees()->transform_tree.Node(
       root->transform_tree_index());
   EXPECT_TRUE(node->data.transform_changed);
+  EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET(
+      root->PushPropertiesTo(root_impl.get());
+      child->PushPropertiesTo(child_impl.get());
+      child2->PushPropertiesTo(child2_impl.get());
+      grand_child->PushPropertiesTo(grand_child_impl.get());
+      layer_tree_host_->property_trees()->transform_tree.ResetChangeTracking());
+
+  gfx::Transform arbitrary_transform;
+  arbitrary_transform.Scale3d(0.1f, 0.2f, 0.3f);
+  EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1);
+  root->SetTransform(arbitrary_transform);
+  node = layer_tree_host_->property_trees()->transform_tree.Node(
+      root->transform_tree_index());
+  EXPECT_TRUE(node->data.transform_changed);
 }
 
 TEST_F(LayerTest, AddAndRemoveChild) {
@@ -1538,6 +1547,57 @@
   EXPECT_TRUE(test_layer->NeedsDisplayForTesting());
 }
 
+TEST_F(LayerTest, TestSettingMainThreadScrollingReason) {
+  scoped_refptr<Layer> test_layer = Layer::Create(layer_settings_);
+  EXPECT_SET_NEEDS_FULL_TREE_SYNC(1,
+                                  layer_tree_host_->SetRootLayer(test_layer));
+  EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetIsDrawable(true));
+
+  // sanity check of initial test condition
+  EXPECT_FALSE(test_layer->NeedsDisplayForTesting());
+
+  uint32_t reasons = 0, reasons_to_clear = 0, reasons_after_clearing = 0;
+  reasons |= MainThreadScrollingReason::kEventHandlers;
+  reasons |= MainThreadScrollingReason::kContinuingMainThreadScroll;
+  reasons |= MainThreadScrollingReason::kScrollbarScrolling;
+
+  reasons_to_clear |= MainThreadScrollingReason::kContinuingMainThreadScroll;
+  reasons_to_clear |= MainThreadScrollingReason::kThreadedScrollingDisabled;
+
+  reasons_after_clearing |= MainThreadScrollingReason::kEventHandlers;
+  reasons_after_clearing |= MainThreadScrollingReason::kScrollbarScrolling;
+
+  // Check that the reasons are added correctly.
+  EXPECT_SET_NEEDS_COMMIT(1, test_layer->AddMainThreadScrollingReasons(
+                                 MainThreadScrollingReason::kEventHandlers));
+  EXPECT_SET_NEEDS_COMMIT(
+      1, test_layer->AddMainThreadScrollingReasons(
+             MainThreadScrollingReason::kContinuingMainThreadScroll));
+  EXPECT_SET_NEEDS_COMMIT(1,
+                          test_layer->AddMainThreadScrollingReasons(
+                              MainThreadScrollingReason::kScrollbarScrolling));
+  EXPECT_EQ(reasons, test_layer->main_thread_scrolling_reasons());
+
+  // Check that the reasons can be selectively cleared.
+  EXPECT_SET_NEEDS_COMMIT(
+      1, test_layer->ClearMainThreadScrollingReasons(reasons_to_clear));
+  EXPECT_EQ(reasons_after_clearing,
+            test_layer->main_thread_scrolling_reasons());
+
+  // Check that clearing non-set reasons doesn't set needs commit.
+  reasons_to_clear = 0;
+  reasons_to_clear |= MainThreadScrollingReason::kThreadedScrollingDisabled;
+  reasons_to_clear |= MainThreadScrollingReason::kNoScrollingLayer;
+  EXPECT_SET_NEEDS_COMMIT(
+      0, test_layer->ClearMainThreadScrollingReasons(reasons_to_clear));
+  EXPECT_EQ(reasons_after_clearing,
+            test_layer->main_thread_scrolling_reasons());
+
+  // Check that adding an existing condition doesn't set needs commit.
+  EXPECT_SET_NEEDS_COMMIT(0, test_layer->AddMainThreadScrollingReasons(
+                                 MainThreadScrollingReason::kEventHandlers));
+}
+
 TEST_F(LayerTest, CheckPropertyChangeCausesCorrectBehavior) {
   scoped_refptr<Layer> test_layer = Layer::Create(layer_settings_);
   EXPECT_SET_NEEDS_FULL_TREE_SYNC(
@@ -1661,58 +1721,6 @@
 }
 
 TEST_F(LayerTest,
-       PushPropsDoesntCauseLayerPropertyChangedDuringImplOnlyTransformAnim) {
-  scoped_refptr<Layer> test_layer = Layer::Create(layer_settings_);
-  scoped_ptr<LayerImpl> impl_layer =
-      LayerImpl::Create(host_impl_.active_tree(), 1);
-
-  EXPECT_SET_NEEDS_FULL_TREE_SYNC(1,
-                                  layer_tree_host_->SetRootLayer(test_layer));
-
-  scoped_ptr<AnimationRegistrar> registrar;
-  if (settings().use_compositor_animation_timelines) {
-    AddAnimatedTransformToLayerWithPlayer(impl_layer->id(), timeline_impl(),
-                                          1.0, 0, 100);
-  } else {
-    registrar = AnimationRegistrar::Create();
-    impl_layer->layer_animation_controller()->SetAnimationRegistrar(
-        registrar.get());
-
-    AddAnimatedTransformToController(impl_layer->layer_animation_controller(),
-                                     1.0, 0, 100);
-  }
-
-  gfx::Transform transform;
-  transform.Rotate(45.0);
-  EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetTransform(transform));
-
-  EXPECT_FALSE(impl_layer->LayerPropertyChanged());
-  test_layer->PushPropertiesTo(impl_layer.get());
-  EXPECT_TRUE(impl_layer->LayerPropertyChanged());
-
-  impl_layer->ResetAllChangeTrackingForSubtree();
-  if (settings().use_compositor_animation_timelines) {
-    int animation_id = AddAnimatedTransformToLayerWithPlayer(
-        impl_layer->id(), timeline_impl(), 1.0, 0, 100);
-    GetAnimationFromLayerWithExistingPlayer(impl_layer->id(), timeline_impl(),
-                                            animation_id)
-        ->set_is_impl_only(true);
-  } else {
-    AddAnimatedTransformToController(impl_layer->layer_animation_controller(),
-                                     1.0, 0, 100);
-    impl_layer->layer_animation_controller()
-        ->GetAnimation(Animation::TRANSFORM)
-        ->set_is_impl_only(true);
-  }
-  transform.Rotate(45.0);
-  EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetTransform(transform));
-
-  EXPECT_FALSE(impl_layer->LayerPropertyChanged());
-  test_layer->PushPropertiesTo(impl_layer.get());
-  EXPECT_FALSE(impl_layer->LayerPropertyChanged());
-}
-
-TEST_F(LayerTest,
        PushPropsDoesntCauseLayerPropertyChangedDuringImplOnlyOpacityAnim) {
   scoped_refptr<Layer> test_layer = Layer::Create(layer_settings_);
   scoped_ptr<LayerImpl> impl_layer =
@@ -2612,6 +2620,25 @@
   layer_src_b->SetMaskLayer(layer_src_b_mask.get());
   layer_src_b->SetReplicaLayer(layer_src_b_replica.get());
 
+  proto::LayerUpdate layer_update_root;
+  // Only layers with descendants that require pushing properties will
+  // return true from ToLayerPropertiesProto and AddChild will change the
+  // stacking order of child which will make it push properties.
+  EXPECT_TRUE(layer_src_root->ToLayerPropertiesProto(&layer_update_root));
+  proto::LayerUpdate layer_update_a;
+  EXPECT_TRUE(layer_src_a->ToLayerPropertiesProto(&layer_update_a));
+  proto::LayerUpdate layer_update_b;
+  EXPECT_TRUE(layer_src_b->ToLayerPropertiesProto(&layer_update_b));
+  proto::LayerUpdate layer_update_c;
+  EXPECT_FALSE(layer_src_c->ToLayerPropertiesProto(&layer_update_c));
+  proto::LayerUpdate layer_update_d;
+  EXPECT_FALSE(layer_src_d->ToLayerPropertiesProto(&layer_update_d));
+  layer_update_root.Clear();
+  layer_update_a.Clear();
+  layer_update_b.Clear();
+  layer_update_c.Clear();
+  layer_update_d.Clear();
+
   layer_src_a->SetNeedsPushProperties();
   layer_src_b->SetNeedsPushProperties();
   layer_src_b_mask->SetNeedsPushProperties();
@@ -2619,20 +2646,15 @@
 
   // Only layers with descendants that require pushing properties will
   // return true from ToLayerPropertiesProto.
-  proto::LayerUpdate layer_update_root;
   EXPECT_TRUE(layer_src_root->ToLayerPropertiesProto(&layer_update_root));
-  proto::LayerUpdate layer_update_a;
   EXPECT_FALSE(layer_src_a->ToLayerPropertiesProto(&layer_update_a));
-  proto::LayerUpdate layer_update_b;
   EXPECT_TRUE(layer_src_b->ToLayerPropertiesProto(&layer_update_b));
   proto::LayerUpdate layer_update_b_mask;
   EXPECT_FALSE(layer_src_b_mask->ToLayerPropertiesProto(&layer_update_b_mask));
   proto::LayerUpdate layer_update_b_replica;
   EXPECT_FALSE(
       layer_src_b_replica->ToLayerPropertiesProto(&layer_update_b_replica));
-  proto::LayerUpdate layer_update_c;
   EXPECT_FALSE(layer_src_c->ToLayerPropertiesProto(&layer_update_c));
-  proto::LayerUpdate layer_update_d;
   EXPECT_FALSE(layer_src_d->ToLayerPropertiesProto(&layer_update_d));
 
   // All flags for pushing properties should have been cleared.
diff --git a/cc/layers/painted_scrollbar_layer_impl.cc b/cc/layers/painted_scrollbar_layer_impl.cc
index 229e7f29..eb44f0df 100644
--- a/cc/layers/painted_scrollbar_layer_impl.cc
+++ b/cc/layers/painted_scrollbar_layer_impl.cc
@@ -6,7 +6,7 @@
 
 #include <algorithm>
 
-#include "cc/animation/scrollbar_animation_controller.h"
+#include "cc/input/scrollbar_animation_controller.h"
 #include "cc/layers/layer.h"
 #include "cc/quads/solid_color_draw_quad.h"
 #include "cc/quads/texture_draw_quad.h"
diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc
index 01da2d9..d7beffb1 100644
--- a/cc/layers/scrollbar_layer_unittest.cc
+++ b/cc/layers/scrollbar_layer_unittest.cc
@@ -7,7 +7,7 @@
 #include <unordered_map>
 
 #include "base/thread_task_runner_handle.h"
-#include "cc/animation/scrollbar_animation_controller.h"
+#include "cc/input/scrollbar_animation_controller.h"
 #include "cc/layers/append_quads_data.h"
 #include "cc/layers/painted_scrollbar_layer.h"
 #include "cc/layers/painted_scrollbar_layer_impl.h"
diff --git a/cc/layers/texture_layer_impl.cc b/cc/layers/texture_layer_impl.cc
index 0d2f4e7..8b1a8cb 100644
--- a/cc/layers/texture_layer_impl.cc
+++ b/cc/layers/texture_layer_impl.cc
@@ -131,6 +131,7 @@
 
       resource_provider->CopyToResource(texture_copy_->id(), pixels,
                                         texture_mailbox_.size_in_pixels());
+      resource_provider->GenerateSyncTokenForResource(texture_copy_->id());
 
       valid_texture_copy_ = true;
     }
diff --git a/cc/output/ca_layer_overlay.cc b/cc/output/ca_layer_overlay.cc
index 2a0d84c..2dd2353 100644
--- a/cc/output/ca_layer_overlay.cc
+++ b/cc/output/ca_layer_overlay.cc
@@ -193,6 +193,8 @@
 
 CALayerOverlay::CALayerOverlay() {}
 
+CALayerOverlay::CALayerOverlay(const CALayerOverlay& other) = default;
+
 CALayerOverlay::~CALayerOverlay() {}
 
 bool ProcessForCALayerOverlays(ResourceProvider* resource_provider,
diff --git a/cc/output/ca_layer_overlay.h b/cc/output/ca_layer_overlay.h
index f0b7c2234..00a4039f 100644
--- a/cc/output/ca_layer_overlay.h
+++ b/cc/output/ca_layer_overlay.h
@@ -18,6 +18,7 @@
 class CC_EXPORT CALayerOverlay {
  public:
   CALayerOverlay();
+  CALayerOverlay(const CALayerOverlay& other);
   ~CALayerOverlay();
 
   // If |is_clipped| is true, then clip to |clip_rect| in the target space.
diff --git a/cc/output/compositor_frame_metadata.cc b/cc/output/compositor_frame_metadata.cc
index b3a9b2d..d77cca00 100644
--- a/cc/output/compositor_frame_metadata.cc
+++ b/cc/output/compositor_frame_metadata.cc
@@ -15,6 +15,9 @@
       root_overflow_y_hidden(false),
       root_background_color(SK_ColorWHITE) {}
 
+CompositorFrameMetadata::CompositorFrameMetadata(
+    const CompositorFrameMetadata& other) = default;
+
 CompositorFrameMetadata::~CompositorFrameMetadata() {
 }
 
diff --git a/cc/output/compositor_frame_metadata.h b/cc/output/compositor_frame_metadata.h
index ad3cdd8..54b2047 100644
--- a/cc/output/compositor_frame_metadata.h
+++ b/cc/output/compositor_frame_metadata.h
@@ -22,6 +22,7 @@
 class CC_EXPORT CompositorFrameMetadata {
  public:
   CompositorFrameMetadata();
+  CompositorFrameMetadata(const CompositorFrameMetadata& other);
   ~CompositorFrameMetadata();
 
   // The device scale factor used to generate this compositor frame.
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index 2b20d25..57e3f330 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -2192,14 +2192,23 @@
   SetUseProgram(program->program());
 
   ToGLMatrix(&gl_matrix[0], quad->matrix);
-  gl_->UniformMatrix4fv(program->vertex_shader().tex_matrix_location(), 1,
-                        false, gl_matrix);
 
   ResourceProvider::ScopedReadLockGL lock(resource_provider_,
                                           quad->resource_id());
+
   DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_));
   gl_->BindTexture(GL_TEXTURE_EXTERNAL_OES, lock.texture_id());
 
+  // TODO(liberato): stream_texture_android should stop sending |gl_matrix| to
+  // the video frame provider with this change (and to us), but it should
+  // start reporting the current matrix via
+  // GLStreamTextureImage::GetTextureMatrix.  Until then, though, this will use
+  // the matrix that we provide to it, unless the GLStreamTextureImage
+  // overrides it.  This lets it also work with AVDACodecImage, which provides
+  // the correct custom matrix and supplies a default one to us.
+  gl_->UniformMatrix4fvStreamTextureMatrixCHROMIUM(
+      program->vertex_shader().tex_matrix_location(), false, gl_matrix);
+
   gl_->Uniform1i(program->fragment_shader().sampler_location(), 0);
 
   SetShaderOpacity(quad->shared_quad_state->opacity,
diff --git a/cc/output/overlay_candidate.cc b/cc/output/overlay_candidate.cc
index 367f316..1a734ce 100644
--- a/cc/output/overlay_candidate.cc
+++ b/cc/output/overlay_candidate.cc
@@ -178,6 +178,8 @@
       is_unoccluded(false),
       overlay_handled(false) {}
 
+OverlayCandidate::OverlayCandidate(const OverlayCandidate& other) = default;
+
 OverlayCandidate::~OverlayCandidate() {}
 
 // static
diff --git a/cc/output/overlay_candidate.h b/cc/output/overlay_candidate.h
index 1a735618..adf837e 100644
--- a/cc/output/overlay_candidate.h
+++ b/cc/output/overlay_candidate.h
@@ -46,6 +46,7 @@
                          QuadList::ConstIterator quad_list_end);
 
   OverlayCandidate();
+  OverlayCandidate(const OverlayCandidate& other);
   ~OverlayCandidate();
 
   // Transformation to apply to layer during composition.
diff --git a/cc/output/renderer_settings.cc b/cc/output/renderer_settings.cc
index c0927cc..b5d8e76 100644
--- a/cc/output/renderer_settings.cc
+++ b/cc/output/renderer_settings.cc
@@ -27,6 +27,8 @@
       use_gpu_memory_buffer_resources(false),
       preferred_tile_format(PlatformColor::BestTextureFormat()) {}
 
+RendererSettings::RendererSettings(const RendererSettings& other) = default;
+
 RendererSettings::~RendererSettings() {
 }
 
diff --git a/cc/output/renderer_settings.h b/cc/output/renderer_settings.h
index 5aeaee63..e8cbd77 100644
--- a/cc/output/renderer_settings.h
+++ b/cc/output/renderer_settings.h
@@ -19,6 +19,7 @@
 class CC_EXPORT RendererSettings {
  public:
   RendererSettings();
+  RendererSettings(const RendererSettings& other);
   ~RendererSettings();
 
   bool allow_antialiasing;
diff --git a/cc/playback/display_list_raster_source.cc b/cc/playback/display_list_raster_source.cc
index f20252d6..ea4c337 100644
--- a/cc/playback/display_list_raster_source.cc
+++ b/cc/playback/display_list_raster_source.cc
@@ -7,6 +7,9 @@
 #include <stddef.h>
 
 #include "base/containers/adapters.h"
+#include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/trace_event.h"
 #include "cc/base/region.h"
 #include "cc/debug/debug_colors.h"
@@ -209,7 +212,16 @@
       slow_down_raster_scale_factor_for_debug_(
           other->slow_down_raster_scale_factor_for_debug_),
       should_attempt_to_use_distance_field_text_(false),
-      image_decode_controller_(nullptr) {}
+      image_decode_controller_(nullptr) {
+  // In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview).
+  // Don't register a dump provider in these cases.
+  // TODO(ericrk): Get this working in Android Webview. crbug.com/517156
+  if (base::ThreadTaskRunnerHandle::IsSet()) {
+    base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+        this, "cc::DisplayListRasterSource",
+        base::ThreadTaskRunnerHandle::Get());
+  }
+}
 
 DisplayListRasterSource::DisplayListRasterSource(
     const DisplayListRasterSource* other,
@@ -228,9 +240,23 @@
           other->slow_down_raster_scale_factor_for_debug_),
       should_attempt_to_use_distance_field_text_(
           other->should_attempt_to_use_distance_field_text_),
-      image_decode_controller_(other->image_decode_controller_) {}
+      image_decode_controller_(other->image_decode_controller_) {
+  // In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview).
+  // Don't register a dump provider in these cases.
+  // TODO(ericrk): Get this working in Android Webview. crbug.com/517156
+  if (base::ThreadTaskRunnerHandle::IsSet()) {
+    base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+        this, "cc::DisplayListRasterSource",
+        base::ThreadTaskRunnerHandle::Get());
+  }
+}
 
 DisplayListRasterSource::~DisplayListRasterSource() {
+  // For MemoryDumpProvider deregistration to work correctly, this must happen
+  // on the same thread that the DisplayListRasterSource was created on.
+  DCHECK(memory_dump_thread_checker_.CalledOnValidThread());
+  base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
+      this);
 }
 
 void DisplayListRasterSource::PlaybackToSharedCanvas(
@@ -507,4 +533,22 @@
   image_decode_controller_ = image_decode_controller;
 }
 
+bool DisplayListRasterSource::OnMemoryDump(
+    const base::trace_event::MemoryDumpArgs& args,
+    base::trace_event::ProcessMemoryDump* pmd) {
+  DCHECK(memory_dump_thread_checker_.CalledOnValidThread());
+
+  uint64_t memory_usage = GetPictureMemoryUsage();
+  if (memory_usage > 0) {
+    std::string dump_name = base::StringPrintf(
+        "cc/display_lists/display_list_raster_source_%p", this);
+    base::trace_event::MemoryAllocatorDump* dump =
+        pmd->CreateAllocatorDump(dump_name);
+    dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
+                    base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+                    memory_usage);
+  }
+  return true;
+}
+
 }  // namespace cc
diff --git a/cc/playback/display_list_raster_source.h b/cc/playback/display_list_raster_source.h
index 9ebfd4fb..9b25b3a3 100644
--- a/cc/playback/display_list_raster_source.h
+++ b/cc/playback/display_list_raster_source.h
@@ -11,6 +11,9 @@
 
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "base/trace_event/memory_allocator_dump.h"
+#include "base/trace_event/memory_dump_provider.h"
 #include "cc/base/cc_export.h"
 #include "cc/debug/rendering_stats_instrumentation.h"
 #include "cc/playback/display_list_recording_source.h"
@@ -24,7 +27,8 @@
 class ImageDecodeController;
 
 class CC_EXPORT DisplayListRasterSource
-    : public base::RefCountedThreadSafe<DisplayListRasterSource> {
+    : public base::trace_event::MemoryDumpProvider,
+      public base::RefCountedThreadSafe<DisplayListRasterSource> {
  public:
   static scoped_refptr<DisplayListRasterSource>
   CreateFromDisplayListRecordingSource(const DisplayListRecordingSource* other,
@@ -111,6 +115,10 @@
   // of the raster source, since the raster source will access it during raster.
   void SetImageDecodeController(ImageDecodeController* image_decode_controller);
 
+  // base::trace_event::MemoryDumpProvider implementation
+  bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
+                    base::trace_event::ProcessMemoryDump* pmd) override;
+
  protected:
   friend class base::RefCountedThreadSafe<DisplayListRasterSource>;
 
@@ -118,7 +126,7 @@
                           bool can_use_lcd_text);
   DisplayListRasterSource(const DisplayListRasterSource* other,
                           bool can_use_lcd_text);
-  virtual ~DisplayListRasterSource();
+  ~DisplayListRasterSource() override;
 
   // These members are const as this raster source may be in use on another
   // thread and so should not be touched after construction.
@@ -159,6 +167,9 @@
                                   const gfx::Rect& canvas_playback_rect,
                                   float contents_scale) const;
 
+  // Used to ensure that memory dump logic always happens on the same thread.
+  base::ThreadChecker memory_dump_thread_checker_;
+
   DISALLOW_COPY_AND_ASSIGN(DisplayListRasterSource);
 };
 
diff --git a/cc/proto/layer.proto b/cc/proto/layer.proto
index e644e55b..7708e461e 100644
--- a/cc/proto/layer.proto
+++ b/cc/proto/layer.proto
@@ -69,7 +69,7 @@
   optional PictureLayerProperties picture = 6;
 }
 
-// NEXT ID: 54
+// NEXT ID: 53
 message BaseLayerProperties {
   optional Point3F transform_origin = 1;
   optional uint32 background_color = 2;
@@ -83,7 +83,7 @@
   optional bool draws_content = 9;
   optional bool hide_layer_and_subtree = 10;
   optional bool has_render_surface = 11;
-  optional bool subtree_property_changed = 53;
+  optional bool subtree_property_changed = 47;
   // TODO(nyquist): Add support for FilterOperation. See crbug.com/541321.
   // repeated FilterOperation filters = 12;
   // repeated FilterOperation background_filters = 13;
@@ -125,7 +125,6 @@
   optional Vector2dF scroll_compensation_adjustment = 45;
 
   optional Rect update_rect = 46;
-  optional bool stacking_order_changed = 47;
 
   // TODO(nyquist): Figure out what to do with LayerAnimationController.
   // optional LayerAnimationController layer_animation_controller = 48;
diff --git a/cc/quads/draw_quad.cc b/cc/quads/draw_quad.cc
index 9bf17f23..e5d0e14 100644
--- a/cc/quads/draw_quad.cc
+++ b/cc/quads/draw_quad.cc
@@ -29,6 +29,8 @@
     : material(INVALID), needs_blending(false), shared_quad_state(0) {
 }
 
+DrawQuad::DrawQuad(const DrawQuad& other) = default;
+
 void DrawQuad::SetAll(const SharedQuadState* shared_quad_state,
                       Material material,
                       const gfx::Rect& rect,
diff --git a/cc/quads/draw_quad.h b/cc/quads/draw_quad.h
index bf824c15..4b6ae59b 100644
--- a/cc/quads/draw_quad.h
+++ b/cc/quads/draw_quad.h
@@ -50,6 +50,7 @@
     MATERIAL_LAST = YUV_VIDEO_CONTENT
   };
 
+  DrawQuad(const DrawQuad& other);
   virtual ~DrawQuad();
 
   Material material;
@@ -124,6 +125,12 @@
       return ids + count;
     }
 
+    const ResourceId* const_begin() const { return ids; }
+    const ResourceId* const_end() const {
+      DCHECK_LE(count, kMaxResourceIdCount);
+      return ids + count;
+    }
+
     uint32_t count;
     ResourceId ids[kMaxResourceIdCount];
   };
diff --git a/cc/quads/picture_draw_quad.cc b/cc/quads/picture_draw_quad.cc
index a1cf96a..bc528d0 100644
--- a/cc/quads/picture_draw_quad.cc
+++ b/cc/quads/picture_draw_quad.cc
@@ -14,6 +14,8 @@
 PictureDrawQuad::PictureDrawQuad() {
 }
 
+PictureDrawQuad::PictureDrawQuad(const PictureDrawQuad& other) = default;
+
 PictureDrawQuad::~PictureDrawQuad() {
 }
 
diff --git a/cc/quads/picture_draw_quad.h b/cc/quads/picture_draw_quad.h
index 93140eb..66ee776 100644
--- a/cc/quads/picture_draw_quad.h
+++ b/cc/quads/picture_draw_quad.h
@@ -21,6 +21,7 @@
 class CC_EXPORT PictureDrawQuad : public ContentDrawQuadBase {
  public:
   PictureDrawQuad();
+  PictureDrawQuad(const PictureDrawQuad& other);
   ~PictureDrawQuad() override;
 
   void SetNew(const SharedQuadState* shared_quad_state,
diff --git a/cc/quads/render_pass_draw_quad.cc b/cc/quads/render_pass_draw_quad.cc
index a346691..3832a02 100644
--- a/cc/quads/render_pass_draw_quad.cc
+++ b/cc/quads/render_pass_draw_quad.cc
@@ -15,6 +15,9 @@
 RenderPassDrawQuad::RenderPassDrawQuad() {
 }
 
+RenderPassDrawQuad::RenderPassDrawQuad(const RenderPassDrawQuad& other) =
+    default;
+
 RenderPassDrawQuad::~RenderPassDrawQuad() {
 }
 
diff --git a/cc/quads/render_pass_draw_quad.h b/cc/quads/render_pass_draw_quad.h
index 08e0cc0..2591ac8 100644
--- a/cc/quads/render_pass_draw_quad.h
+++ b/cc/quads/render_pass_draw_quad.h
@@ -19,6 +19,7 @@
 class CC_EXPORT RenderPassDrawQuad : public DrawQuad {
  public:
   RenderPassDrawQuad();
+  RenderPassDrawQuad(const RenderPassDrawQuad& other);
   ~RenderPassDrawQuad() override;
 
   void SetNew(const SharedQuadState* shared_quad_state,
diff --git a/cc/quads/texture_draw_quad.cc b/cc/quads/texture_draw_quad.cc
index 46f6be43..6d4c64e9 100644
--- a/cc/quads/texture_draw_quad.cc
+++ b/cc/quads/texture_draw_quad.cc
@@ -25,6 +25,8 @@
   this->vertex_opacity[3] = 0.f;
 }
 
+TextureDrawQuad::TextureDrawQuad(const TextureDrawQuad& other) = default;
+
 void TextureDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
                              const gfx::Rect& rect,
                              const gfx::Rect& opaque_rect,
diff --git a/cc/quads/texture_draw_quad.h b/cc/quads/texture_draw_quad.h
index 2ba5b9d..5ec060e 100644
--- a/cc/quads/texture_draw_quad.h
+++ b/cc/quads/texture_draw_quad.h
@@ -17,6 +17,7 @@
 class CC_EXPORT TextureDrawQuad : public DrawQuad {
  public:
   TextureDrawQuad();
+  TextureDrawQuad(const TextureDrawQuad& other);
 
   void SetNew(const SharedQuadState* shared_quad_state,
               const gfx::Rect& rect,
diff --git a/cc/quads/yuv_video_draw_quad.cc b/cc/quads/yuv_video_draw_quad.cc
index 93a0c91..b502971 100644
--- a/cc/quads/yuv_video_draw_quad.cc
+++ b/cc/quads/yuv_video_draw_quad.cc
@@ -13,6 +13,9 @@
 
 YUVVideoDrawQuad::YUVVideoDrawQuad() {
 }
+
+YUVVideoDrawQuad::YUVVideoDrawQuad(const YUVVideoDrawQuad& other) = default;
+
 YUVVideoDrawQuad::~YUVVideoDrawQuad() {}
 
 void YUVVideoDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
diff --git a/cc/quads/yuv_video_draw_quad.h b/cc/quads/yuv_video_draw_quad.h
index 015d5b7..7193377a 100644
--- a/cc/quads/yuv_video_draw_quad.h
+++ b/cc/quads/yuv_video_draw_quad.h
@@ -27,6 +27,7 @@
   ~YUVVideoDrawQuad() override;
 
   YUVVideoDrawQuad();
+  YUVVideoDrawQuad(const YUVVideoDrawQuad& other);
 
   void SetNew(const SharedQuadState* shared_quad_state,
               const gfx::Rect& rect,
diff --git a/cc/raster/task_graph_runner.cc b/cc/raster/task_graph_runner.cc
index ad5aaff..4f1af43 100644
--- a/cc/raster/task_graph_runner.cc
+++ b/cc/raster/task_graph_runner.cc
@@ -37,6 +37,8 @@
 
 TaskGraph::TaskGraph() {}
 
+TaskGraph::TaskGraph(const TaskGraph& other) = default;
+
 TaskGraph::~TaskGraph() {}
 
 void TaskGraph::Swap(TaskGraph* other) {
diff --git a/cc/raster/task_graph_runner.h b/cc/raster/task_graph_runner.h
index 4b3c664..23094ef 100644
--- a/cc/raster/task_graph_runner.h
+++ b/cc/raster/task_graph_runner.h
@@ -85,6 +85,7 @@
   };
 
   TaskGraph();
+  TaskGraph(const TaskGraph& other);
   ~TaskGraph();
 
   void Swap(TaskGraph* other);
diff --git a/cc/raster/task_graph_work_queue.cc b/cc/raster/task_graph_work_queue.cc
index 29474023..98413ee 100644
--- a/cc/raster/task_graph_work_queue.cc
+++ b/cc/raster/task_graph_work_queue.cc
@@ -47,6 +47,9 @@
 
 TaskGraphWorkQueue::TaskNamespace::TaskNamespace() {}
 
+TaskGraphWorkQueue::TaskNamespace::TaskNamespace(const TaskNamespace& other) =
+    default;
+
 TaskGraphWorkQueue::TaskNamespace::~TaskNamespace() {}
 
 TaskGraphWorkQueue::TaskGraphWorkQueue() : next_namespace_id_(1) {}
@@ -97,9 +100,11 @@
       continue;
 
     // Skip if already running.
-    if (std::find(task_namespace.running_tasks.begin(),
-                  task_namespace.running_tasks.end(),
-                  node.task) != task_namespace.running_tasks.end())
+    if (std::any_of(task_namespace.running_tasks.begin(),
+                    task_namespace.running_tasks.end(),
+                    [&node](const CategorizedTask& task) {
+                      return task.second == node.task;
+                    }))
       continue;
 
     task_namespace.ready_to_run_tasks[node.category].push_back(PrioritizedTask(
@@ -127,9 +132,11 @@
       continue;
 
     // Skip if already running.
-    if (std::find(task_namespace.running_tasks.begin(),
-                  task_namespace.running_tasks.end(),
-                  node.task) != task_namespace.running_tasks.end())
+    if (std::any_of(task_namespace.running_tasks.begin(),
+                    task_namespace.running_tasks.end(),
+                    [&node](const CategorizedTask& task) {
+                      return task.second == node.task;
+                    }))
       continue;
 
     DCHECK(std::find(task_namespace.completed_tasks.begin(),
@@ -195,7 +202,8 @@
   }
 
   // Add task to |running_tasks|.
-  task_namespace->running_tasks.push_back(task.task);
+  task_namespace->running_tasks.push_back(
+      std::make_pair(task.category, task.task));
 
   return task;
 }
@@ -205,8 +213,11 @@
   scoped_refptr<Task> task(completed_task.task);
 
   // Remove task from |running_tasks|.
-  auto it = std::find(task_namespace->running_tasks.begin(),
-                      task_namespace->running_tasks.end(), task);
+  auto it = std::find_if(task_namespace->running_tasks.begin(),
+                         task_namespace->running_tasks.end(),
+                         [&completed_task](const CategorizedTask& task) {
+                           return task.second == completed_task.task;
+                         });
   DCHECK(it != task_namespace->running_tasks.end());
   std::swap(*it, task_namespace->running_tasks.back());
   task_namespace->running_tasks.pop_back();
diff --git a/cc/raster/task_graph_work_queue.h b/cc/raster/task_graph_work_queue.h
index 95d3c772c..0c82f67 100644
--- a/cc/raster/task_graph_work_queue.h
+++ b/cc/raster/task_graph_work_queue.h
@@ -46,11 +46,14 @@
     uint16_t priority;
   };
 
+  using CategorizedTask = std::pair<uint16_t, scoped_refptr<Task>>;
+
   // Helper classes and static methods used by dependent classes.
   struct TaskNamespace {
     typedef std::vector<TaskNamespace*> Vector;
 
     TaskNamespace();
+    TaskNamespace(const TaskNamespace& other);
     ~TaskNamespace();
 
     // Current task graph.
@@ -64,7 +67,7 @@
     Task::Vector completed_tasks;
 
     // This set contains all currently running tasks.
-    Task::Vector running_tasks;
+    std::vector<CategorizedTask> running_tasks;
   };
 
   TaskGraphWorkQueue();
@@ -145,6 +148,19 @@
     return ready_to_run_namespaces_;
   }
 
+  size_t NumRunningTasksForCategory(uint16_t category) const {
+    size_t count = 0;
+    for (const auto& task_namespace_entry : namespaces_) {
+      for (const auto& categorized_task :
+           task_namespace_entry.second.running_tasks) {
+        if (categorized_task.first == category) {
+          ++count;
+        }
+      }
+    }
+    return count;
+  }
+
   // Helper function which ensures that graph dependencies were correctly
   // configured.
   static bool DependencyMismatch(const TaskGraph* graph);
diff --git a/cc/raster/tile_task_worker_pool.cc b/cc/raster/tile_task_worker_pool.cc
index b746d22..09051cf 100644
--- a/cc/raster/tile_task_worker_pool.cc
+++ b/cc/raster/tile_task_worker_pool.cc
@@ -129,60 +129,60 @@
     stride = info.minRowBytes();
   DCHECK_GT(stride, 0u);
 
-  {
-    TRACE_EVENT0("cc", "TileTaskWorkerPool::PlaybackToMemory::ConvertPixels");
-
-    switch (format) {
-      case RGBA_8888:
-      case BGRA_8888: {
-        skia::RefPtr<SkSurface> surface = skia::AdoptRef(
-            SkSurface::NewRasterDirect(info, memory, stride, &surface_props));
-        AutoSkipImageCanvas canvas(surface->getCanvas(), include_images);
-        raster_source->PlaybackToCanvas(canvas, canvas_bitmap_rect,
-                                        canvas_playback_rect, scale);
-        return;
-      }
-      case RGBA_4444:
-      case ETC1: {
-        skia::RefPtr<SkSurface> surface =
-            skia::AdoptRef(SkSurface::NewRaster(info, &surface_props));
-        AutoSkipImageCanvas canvas(surface->getCanvas(), include_images);
-        // TODO(reveman): Improve partial raster support by reducing the size of
-        // playback rect passed to PlaybackToCanvas. crbug.com/519070
-        raster_source->PlaybackToCanvas(canvas, canvas_bitmap_rect,
-                                        canvas_bitmap_rect, scale);
-
-        if (format == ETC1) {
-          DCHECK_EQ(size.width() % 4, 0);
-          DCHECK_EQ(size.height() % 4, 0);
-          scoped_ptr<TextureCompressor> texture_compressor =
-              TextureCompressor::Create(TextureCompressor::kFormatETC1);
-          texture_compressor->Compress(
-              reinterpret_cast<const uint8_t*>(
-                  surface->peekPixels(nullptr, nullptr)),
-              reinterpret_cast<uint8_t*>(memory), size.width(), size.height(),
-              TextureCompressor::kQualityHigh);
-        } else {
-          SkImageInfo dst_info = SkImageInfo::Make(
-              info.width(), info.height(), ResourceFormatToSkColorType(format),
-              info.alphaType(), info.profileType());
-          bool rv =
-              surface->getCanvas()->readPixels(dst_info, memory, stride, 0, 0);
-          DCHECK(rv);
-        }
-        return;
-      }
-      case ALPHA_8:
-      case LUMINANCE_8:
-      case RGB_565:
-      case RED_8:
-      case LUMINANCE_F16:
-        NOTREACHED();
-        return;
+  switch (format) {
+    case RGBA_8888:
+    case BGRA_8888: {
+      skia::RefPtr<SkSurface> surface = skia::AdoptRef(
+          SkSurface::NewRasterDirect(info, memory, stride, &surface_props));
+      AutoSkipImageCanvas canvas(surface->getCanvas(), include_images);
+      raster_source->PlaybackToCanvas(canvas, canvas_bitmap_rect,
+                                      canvas_playback_rect, scale);
+      return;
     }
+    case RGBA_4444:
+    case ETC1: {
+      skia::RefPtr<SkSurface> surface =
+          skia::AdoptRef(SkSurface::NewRaster(info, &surface_props));
+      AutoSkipImageCanvas canvas(surface->getCanvas(), include_images);
+      // TODO(reveman): Improve partial raster support by reducing the size of
+      // playback rect passed to PlaybackToCanvas. crbug.com/519070
+      raster_source->PlaybackToCanvas(canvas, canvas_bitmap_rect,
+                                      canvas_bitmap_rect, scale);
 
-    NOTREACHED();
+      if (format == ETC1) {
+        TRACE_EVENT0("cc",
+                     "TileTaskWorkerPool::PlaybackToMemory::CompressETC1");
+        DCHECK_EQ(size.width() % 4, 0);
+        DCHECK_EQ(size.height() % 4, 0);
+        scoped_ptr<TextureCompressor> texture_compressor =
+            TextureCompressor::Create(TextureCompressor::kFormatETC1);
+        texture_compressor->Compress(reinterpret_cast<const uint8_t*>(
+                                         surface->peekPixels(nullptr, nullptr)),
+                                     reinterpret_cast<uint8_t*>(memory),
+                                     size.width(), size.height(),
+                                     TextureCompressor::kQualityHigh);
+      } else {
+        TRACE_EVENT0("cc",
+                     "TileTaskWorkerPool::PlaybackToMemory::ConvertRGBA4444");
+        SkImageInfo dst_info = SkImageInfo::Make(
+            info.width(), info.height(), ResourceFormatToSkColorType(format),
+            info.alphaType(), info.profileType());
+        bool rv =
+            surface->getCanvas()->readPixels(dst_info, memory, stride, 0, 0);
+        DCHECK(rv);
+      }
+      return;
+    }
+    case ALPHA_8:
+    case LUMINANCE_8:
+    case RGB_565:
+    case RED_8:
+    case LUMINANCE_F16:
+      NOTREACHED();
+      return;
   }
+
+  NOTREACHED();
 }
 
 }  // namespace cc
diff --git a/cc/resources/resource_format.cc b/cc/resources/resource_format.cc
index ec553d8..befa0896f 100644
--- a/cc/resources/resource_format.cc
+++ b/cc/resources/resource_format.cc
@@ -88,7 +88,7 @@
 }
 
 GLenum GLInternalFormat(ResourceFormat format) {
-  return GLDataFormat(format);
+  return (format == RED_8) ? GL_R8_EXT : GLDataFormat(format);
 }
 
 gfx::BufferFormat BufferFormat(ResourceFormat format) {
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index 8913b0c5..d7fcee7 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -321,6 +321,8 @@
       shared_bitmap(NULL),
       gpu_memory_buffer(NULL) {}
 
+ResourceProvider::Resource::Resource(const Resource& other) = default;
+
 void ResourceProvider::Resource::set_mailbox(const TextureMailbox& mailbox) {
   mailbox_ = mailbox;
   if (IsGpuResourceType(type)) {
@@ -375,6 +377,8 @@
 ResourceProvider::Child::Child()
     : marked_for_deletion(false), needs_sync_tokens(true) {}
 
+ResourceProvider::Child::Child(const Child& other) = default;
+
 ResourceProvider::Child::~Child() {}
 
 scoped_ptr<ResourceProvider> ResourceProvider::Create(
@@ -1575,12 +1579,12 @@
     return;
 
   ReturnedResourceArray to_return;
+  to_return.reserve(unused.size());
+  std::vector<GLbyte*> unverified_sync_tokens;
 
-  GLES2Interface* gl = ContextGL();
   bool need_sync_token = false;
-  for (size_t i = 0; i < unused.size(); ++i) {
-    ResourceId local_id = unused[i];
-
+  GLES2Interface* gl = ContextGL();
+  for (ResourceId local_id : unused) {
     ResourceMap::iterator it = resources_.find(local_id);
     CHECK(it != resources_.end());
     Resource& resource = it->second;
@@ -1627,11 +1631,11 @@
 
     ReturnedResource returned;
     returned.id = child_id;
-    returned.sync_token = resource.mailbox().sync_token();
+    if (resource.needs_sync_token())
+      need_sync_token = true;
+    else
+      returned.sync_token = resource.mailbox().sync_token();
 
-    need_sync_token |=
-        (Resource::LOCALLY_USED == resource.synchronization_state() &&
-         IsGpuResourceType(resource.type));
     returned.count = resource.imported_count;
     returned.lost = is_lost;
     to_return.push_back(returned);
@@ -1640,17 +1644,35 @@
     child_info->child_to_parent_map.erase(child_id);
     resource.imported_count = 0;
     DeleteResourceInternal(it, style);
+
+    // Before returning any sync tokens, they must be verified. Note that we
+    // need to verify the sync token inside of the "to_return" array.
+    if (to_return.back().sync_token.HasData() &&
+        !to_return.back().sync_token.verified_flush()) {
+      unverified_sync_tokens.push_back(to_return.back().sync_token.GetData());
+    }
   }
+
+  gpu::SyncToken new_sync_token;
   if (need_sync_token && child_info->needs_sync_tokens) {
     DCHECK(gl);
-    const GLuint64 fence_sync = gl->InsertFenceSyncCHROMIUM();
-    gl->ShallowFlushCHROMIUM();
+    const uint64_t fence_sync = gl->InsertFenceSyncCHROMIUM();
+    gl->OrderingBarrierCHROMIUM();
+    gl->GenUnverifiedSyncTokenCHROMIUM(fence_sync, new_sync_token.GetData());
+    unverified_sync_tokens.push_back(new_sync_token.GetData());
+  }
 
-    gpu::SyncToken sync_token;
-    gl->GenSyncTokenCHROMIUM(fence_sync, sync_token.GetData());
-    for (size_t i = 0; i < to_return.size(); ++i) {
-      if (!to_return[i].sync_token.HasData())
-        to_return[i].sync_token = sync_token;
+  if (!unverified_sync_tokens.empty()) {
+    DCHECK(gl);
+    gl->VerifySyncTokensCHROMIUM(unverified_sync_tokens.data(),
+                                 unverified_sync_tokens.size());
+  }
+
+  if (new_sync_token.HasData()) {
+    DCHECK(need_sync_token && child_info->needs_sync_tokens);
+    for (ReturnedResource& returned_resource : to_return) {
+      if (!returned_resource.sync_token.HasData())
+        returned_resource.sync_token = new_sync_token;
     }
   }
 
diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h
index a033967..0b0caf0 100644
--- a/cc/resources/resource_provider.h
+++ b/cc/resources/resource_provider.h
@@ -518,6 +518,7 @@
              const gfx::Size& size,
              Origin origin,
              GLenum filter);
+    Resource(const Resource& other);
 
     bool needs_sync_token() const { return needs_sync_token_; }
 
@@ -580,6 +581,7 @@
 
   struct Child {
     Child();
+    Child(const Child& other);
     ~Child();
 
     ResourceIdMap child_to_parent_map;
diff --git a/cc/resources/transferable_resource.cc b/cc/resources/transferable_resource.cc
index af65ff6..cf463bf 100644
--- a/cc/resources/transferable_resource.cc
+++ b/cc/resources/transferable_resource.cc
@@ -15,6 +15,9 @@
       is_software(false),
       is_overlay_candidate(false) {}
 
+TransferableResource::TransferableResource(const TransferableResource& other) =
+    default;
+
 TransferableResource::~TransferableResource() {
 }
 
diff --git a/cc/resources/transferable_resource.h b/cc/resources/transferable_resource.h
index 55d2216a..ea63441 100644
--- a/cc/resources/transferable_resource.h
+++ b/cc/resources/transferable_resource.h
@@ -24,6 +24,7 @@
 
 struct CC_EXPORT TransferableResource {
   TransferableResource();
+  TransferableResource(const TransferableResource& other);
   ~TransferableResource();
 
   ReturnedResource ToReturnedResource() const;
diff --git a/cc/resources/ui_resource_bitmap.cc b/cc/resources/ui_resource_bitmap.cc
index b8fbf31a..3acc6dc4 100644
--- a/cc/resources/ui_resource_bitmap.cc
+++ b/cc/resources/ui_resource_bitmap.cc
@@ -77,6 +77,8 @@
   Create(pixel_ref, size, UIResourceBitmap::ETC1);
 }
 
+UIResourceBitmap::UIResourceBitmap(const UIResourceBitmap& other) = default;
+
 UIResourceBitmap::~UIResourceBitmap() {}
 
 AutoLockUIResourceBitmap::AutoLockUIResourceBitmap(
diff --git a/cc/resources/ui_resource_bitmap.h b/cc/resources/ui_resource_bitmap.h
index 34e73ee6..a90159f 100644
--- a/cc/resources/ui_resource_bitmap.h
+++ b/cc/resources/ui_resource_bitmap.h
@@ -43,6 +43,7 @@
   UIResourceBitmap(const gfx::Size& size, bool is_opaque);
   UIResourceBitmap(const skia::RefPtr<SkPixelRef>& pixel_ref,
                    const gfx::Size& size);
+  UIResourceBitmap(const UIResourceBitmap& other);
   ~UIResourceBitmap();
 
  private:
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc
index e6827ee3..46dbbc9 100644
--- a/cc/resources/video_resource_updater.cc
+++ b/cc/resources/video_resource_updater.cc
@@ -128,6 +128,9 @@
       plane_index(0u) {
 }
 
+VideoResourceUpdater::PlaneResource::PlaneResource(const PlaneResource& other) =
+    default;
+
 bool VideoResourceUpdater::PlaneResourceMatchesUniqueID(
     const PlaneResource& plane_resource,
     const media::VideoFrame* video_frame,
@@ -152,6 +155,9 @@
       offset(0.0f),
       multiplier(1.0f) {}
 
+VideoFrameExternalResources::VideoFrameExternalResources(
+    const VideoFrameExternalResources& other) = default;
+
 VideoFrameExternalResources::~VideoFrameExternalResources() {}
 
 VideoResourceUpdater::VideoResourceUpdater(ContextProvider* context_provider,
diff --git a/cc/resources/video_resource_updater.h b/cc/resources/video_resource_updater.h
index 4e11110..1307be9e 100644
--- a/cc/resources/video_resource_updater.h
+++ b/cc/resources/video_resource_updater.h
@@ -69,6 +69,7 @@
   float multiplier;
 
   VideoFrameExternalResources();
+  VideoFrameExternalResources(const VideoFrameExternalResources& other);
   ~VideoFrameExternalResources();
 };
 
@@ -105,6 +106,7 @@
                   const gfx::Size& resource_size,
                   ResourceFormat resource_format,
                   gpu::Mailbox mailbox);
+    PlaneResource(const PlaneResource& other);
   };
 
   static bool PlaneResourceMatchesUniqueID(const PlaneResource& plane_resource,
diff --git a/cc/test/fake_content_layer_client.cc b/cc/test/fake_content_layer_client.cc
index 7876d29..88c4f80 100644
--- a/cc/test/fake_content_layer_client.cc
+++ b/cc/test/fake_content_layer_client.cc
@@ -27,6 +27,8 @@
                                              const SkPaint& paint)
     : image(skia::SharePtr(img)), transform(transform), paint(paint) {}
 
+FakeContentLayerClient::ImageData::ImageData(const ImageData& other) = default;
+
 FakeContentLayerClient::ImageData::~ImageData() {}
 
 FakeContentLayerClient::FakeContentLayerClient()
diff --git a/cc/test/fake_content_layer_client.h b/cc/test/fake_content_layer_client.h
index 53548338c..198c414 100644
--- a/cc/test/fake_content_layer_client.h
+++ b/cc/test/fake_content_layer_client.h
@@ -30,6 +30,7 @@
     ImageData(const SkImage* image,
               const gfx::Transform& transform,
               const SkPaint& paint);
+    ImageData(const ImageData& other);
     ~ImageData();
     skia::RefPtr<const SkImage> image;
     gfx::Point point;
diff --git a/cc/trees/damage_tracker_unittest.cc b/cc/trees/damage_tracker_unittest.cc
index d62b6cc..0be6a68 100644
--- a/cc/trees/damage_tracker_unittest.cc
+++ b/cc/trees/damage_tracker_unittest.cc
@@ -1196,7 +1196,7 @@
 
   // Then test the property change.
   ClearDamageForAllSurfaces(root.get());
-  mask_layer->SetStackingOrderChanged(true);
+  mask_layer->NoteLayerPropertyChanged();
 
   EmulateDrawingOneFrame(root.get());
   child_damage_rect =
@@ -1270,7 +1270,7 @@
   // CASE 1: a property change on the mask should damage only the reflected
   //         region on the target surface.
   ClearDamageForAllSurfaces(root.get());
-  replica_mask_layer->SetStackingOrderChanged(true);
+  replica_mask_layer->NoteLayerPropertyChanged();
   EmulateDrawingOneFrame(root.get());
 
   gfx::Rect grand_child_damage_rect =
@@ -1348,7 +1348,7 @@
   // A property change on the replica_mask should damage the reflected region on
   // the target surface.
   ClearDamageForAllSurfaces(root.get());
-  replica_mask_layer->SetStackingOrderChanged(true);
+  replica_mask_layer->NoteLayerPropertyChanged();
 
   EmulateDrawingOneFrame(root.get());
 
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index d6e0402..0ffe578 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -26,7 +26,6 @@
 #include "cc/animation/animation_host.h"
 #include "cc/animation/animation_id_provider.h"
 #include "cc/animation/scroll_offset_animation_curve.h"
-#include "cc/animation/scrollbar_animation_controller.h"
 #include "cc/animation/timing_function.h"
 #include "cc/base/histograms.h"
 #include "cc/base/math_util.h"
@@ -41,6 +40,7 @@
 #include "cc/input/page_scale_animation.h"
 #include "cc/input/scroll_elasticity_helper.h"
 #include "cc/input/scroll_state.h"
+#include "cc/input/scrollbar_animation_controller.h"
 #include "cc/input/top_controls_manager.h"
 #include "cc/layers/append_quads_data.h"
 #include "cc/layers/heads_up_display_layer_impl.h"
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 041b903..cb7b9cfe 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -16,12 +16,12 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/time/time.h"
 #include "cc/animation/animation_registrar.h"
-#include "cc/animation/scrollbar_animation_controller.h"
 #include "cc/base/cc_export.h"
 #include "cc/base/synced_property.h"
 #include "cc/debug/frame_timing_tracker.h"
 #include "cc/debug/micro_benchmark_controller_impl.h"
 #include "cc/input/input_handler.h"
+#include "cc/input/scrollbar_animation_controller.h"
 #include "cc/input/top_controls_manager_client.h"
 #include "cc/layers/layer_lists.h"
 #include "cc/layers/render_pass_sink.h"
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 8cae5804..d7fc121 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -17,11 +17,11 @@
 #include "cc/animation/animation_events.h"
 #include "cc/animation/animation_host.h"
 #include "cc/animation/animation_id_provider.h"
-#include "cc/animation/scrollbar_animation_controller_thinning.h"
 #include "cc/animation/transform_operations.h"
 #include "cc/base/math_util.h"
 #include "cc/input/main_thread_scrolling_reason.h"
 #include "cc/input/page_scale_animation.h"
+#include "cc/input/scrollbar_animation_controller_thinning.h"
 #include "cc/input/top_controls_manager.h"
 #include "cc/layers/append_quads_data.h"
 #include "cc/layers/heads_up_display_layer_impl.h"
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 753a5c2..09840ce6 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -3278,20 +3278,9 @@
     int last_source_frame_number = layer_tree_host()->source_frame_number() - 1;
     switch (last_source_frame_number) {
       case 0:
+        // All layers except root will need push properties as they are added
+        // as a child to some other layer which changes their stacking order.
         EXPECT_FALSE(root_->needs_push_properties());
-        EXPECT_FALSE(root_->descendant_needs_push_properties());
-        EXPECT_FALSE(child_->needs_push_properties());
-        EXPECT_FALSE(child_->descendant_needs_push_properties());
-        EXPECT_FALSE(grandchild1_->needs_push_properties());
-        EXPECT_FALSE(grandchild1_->descendant_needs_push_properties());
-        EXPECT_FALSE(grandchild2_->needs_push_properties());
-        EXPECT_FALSE(grandchild2_->descendant_needs_push_properties());
-        EXPECT_FALSE(grandchild3_->needs_push_properties());
-        EXPECT_FALSE(grandchild3_->descendant_needs_push_properties());
-
-        layer_tree_host()->SetRootLayer(root_);
-
-        EXPECT_TRUE(root_->needs_push_properties());
         EXPECT_TRUE(root_->descendant_needs_push_properties());
         EXPECT_TRUE(child_->needs_push_properties());
         EXPECT_TRUE(child_->descendant_needs_push_properties());
@@ -3301,6 +3290,12 @@
         EXPECT_FALSE(grandchild2_->descendant_needs_push_properties());
         EXPECT_TRUE(grandchild3_->needs_push_properties());
         EXPECT_FALSE(grandchild3_->descendant_needs_push_properties());
+
+        layer_tree_host()->SetRootLayer(root_);
+
+        // Now, even the root will need to push properties.
+        EXPECT_TRUE(root_->needs_push_properties());
+        EXPECT_TRUE(root_->descendant_needs_push_properties());
         break;
       case 1:
         EndTest();
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index f34e448..268d01b 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -18,15 +18,15 @@
 #include "cc/animation/animation_host.h"
 #include "cc/animation/keyframed_animation_curve.h"
 #include "cc/animation/mutable_properties.h"
-#include "cc/animation/scrollbar_animation_controller.h"
-#include "cc/animation/scrollbar_animation_controller_linear_fade.h"
-#include "cc/animation/scrollbar_animation_controller_thinning.h"
 #include "cc/base/histograms.h"
 #include "cc/base/math_util.h"
 #include "cc/base/synced_property.h"
 #include "cc/debug/devtools_instrumentation.h"
 #include "cc/debug/traced_value.h"
 #include "cc/input/page_scale_animation.h"
+#include "cc/input/scrollbar_animation_controller.h"
+#include "cc/input/scrollbar_animation_controller_linear_fade.h"
+#include "cc/input/scrollbar_animation_controller_thinning.h"
 #include "cc/layers/heads_up_display_layer_impl.h"
 #include "cc/layers/layer.h"
 #include "cc/layers/layer_iterator.h"
diff --git a/cc/trees/layer_tree_settings.cc b/cc/trees/layer_tree_settings.cc
index 73a9eb3b..40606ed 100644
--- a/cc/trees/layer_tree_settings.cc
+++ b/cc/trees/layer_tree_settings.cc
@@ -107,6 +107,8 @@
                      gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING,
                      ManagedMemoryPolicy::kDefaultNumResourcesLimit) {}
 
+LayerTreeSettings::LayerTreeSettings(const LayerTreeSettings& other) = default;
+
 LayerTreeSettings::~LayerTreeSettings() {}
 
 bool LayerTreeSettings::operator==(const LayerTreeSettings& other) const {
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index dfad4a50..ed7615c 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -26,6 +26,7 @@
 class CC_EXPORT LayerTreeSettings {
  public:
   LayerTreeSettings();
+  LayerTreeSettings(const LayerTreeSettings& other);
   virtual ~LayerTreeSettings();
 
   bool operator==(const LayerTreeSettings& other) const;
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc
index a3c7e5b..31ebad1 100644
--- a/cc/trees/property_tree.cc
+++ b/cc/trees/property_tree.cc
@@ -65,6 +65,8 @@
       device_scale_factor_(1.f),
       device_transform_scale_factor_(1.f) {}
 
+TransformTree::TransformTree(const TransformTree& other) = default;
+
 TransformTree::~TransformTree() {
 }
 
@@ -152,6 +154,8 @@
       combined_maximum_animation_target_scale(0.f),
       combined_starting_animation_scale(0.f) {}
 
+TransformNodeData::TransformNodeData(const TransformNodeData& other) = default;
+
 TransformNodeData::~TransformNodeData() {
 }
 
@@ -364,6 +368,8 @@
       layers_are_clipped_when_surfaces_disabled(false),
       resets_clip(false) {}
 
+ClipNodeData::ClipNodeData(const ClipNodeData& other) = default;
+
 bool ClipNodeData::operator==(const ClipNodeData& other) const {
   return clip == other.clip &&
          combined_clip_in_target_space == other.combined_clip_in_target_space &&
@@ -433,6 +439,8 @@
       transform_id(0),
       clip_id(0) {}
 
+EffectNodeData::EffectNodeData(const EffectNodeData& other) = default;
+
 bool EffectNodeData::operator==(const EffectNodeData& other) const {
   return opacity == other.opacity &&
          screen_space_opacity == other.screen_space_opacity &&
@@ -490,6 +498,8 @@
       element_id(0),
       transform_id(0) {}
 
+ScrollNodeData::ScrollNodeData(const ScrollNodeData& other) = default;
+
 bool ScrollNodeData::operator==(const ScrollNodeData& other) const {
   return scrollable == other.scrollable &&
          main_thread_scrolling_reasons == other.main_thread_scrolling_reasons &&
diff --git a/cc/trees/property_tree.h b/cc/trees/property_tree.h
index 4961fd7..9be6e0c 100644
--- a/cc/trees/property_tree.h
+++ b/cc/trees/property_tree.h
@@ -50,6 +50,7 @@
 
 struct CC_EXPORT TransformNodeData {
   TransformNodeData();
+  TransformNodeData(const TransformNodeData& other);
   ~TransformNodeData();
 
   // The local transform information is combined to form to_parent (ignoring
@@ -193,6 +194,7 @@
 
 struct CC_EXPORT ClipNodeData {
   ClipNodeData();
+  ClipNodeData(const ClipNodeData& other);
 
   // The clip rect that this node contributes, expressed in the space of its
   // transform node.
@@ -246,6 +248,7 @@
 
 struct CC_EXPORT EffectNodeData {
   EffectNodeData();
+  EffectNodeData(const EffectNodeData& other);
 
   float opacity;
   float screen_space_opacity;
@@ -269,6 +272,7 @@
 
 struct CC_EXPORT ScrollNodeData {
   ScrollNodeData();
+  ScrollNodeData(const ScrollNodeData& other);
 
   bool scrollable;
   uint32_t main_thread_scrolling_reasons;
@@ -354,6 +358,7 @@
 class CC_EXPORT TransformTree final : public PropertyTree<TransformNode> {
  public:
   TransformTree();
+  TransformTree(const TransformTree& other);
   ~TransformTree() override;
 
   bool operator==(const TransformTree& other) const;
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index 4f9c6e8..3618201 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/buildflag_header.gni")
 import("//build/config/chrome_build.gni")
 import("//build/config/compiler/compiler.gni")
 import("//build/config/features.gni")
@@ -11,7 +12,9 @@
 import("//build/config/win/console_app.gni")
 import("//build/config/win/manifest.gni")
 import("//chrome/chrome_repack_locales.gni")
+import("//chrome/common/features.gni")
 import("//chrome/version.gni")
+import("//ui/base/ui_features.gni")
 
 declare_args() {
   # Specify the current PGO phase, only used for the Windows MSVS build. Here's
@@ -187,6 +190,7 @@
 
       public_deps = [
         ":xdg_mime",  # Needs to be public for installer to consume files.
+        "//chrome/common:features",
       ]
 
       # GYP has this in a 'profiling==0 and linux_disable_pie==0' condition.
@@ -204,6 +208,10 @@
           "//build/config/linux:xext",
         ]
       }
+
+      if (enable_package_mash_services) {
+        deps += [ "//chrome/app/mash" ]
+      }
     }
 
     if (is_mac) {
@@ -293,6 +301,7 @@
     deps = [
       ":browser_dependencies",
       "//build/config/sanitizers:deps",
+      "//chrome/common:features",
     ]
     if (is_win) {
       output_name = "chrome"
@@ -369,6 +378,10 @@
     if (enable_plugins && enable_pdf && !is_multi_dll_chrome) {
       deps += [ "//pdf" ]
     }
+
+    if (enable_package_mash_services) {
+      deps += [ "//chrome/app/mash" ]
+    }
   }
 
   if (is_multi_dll_chrome) {
@@ -395,6 +408,7 @@
         ":chrome_child_manifest",
         ":chrome_dll_version",
         "//build/config/sanitizers:deps",
+        "//chrome/common:features",
         "//components/browser_watcher:browser_watcher_client",
         "//components/crash/content/app",
         "//content/public/app:child",
diff --git a/chrome/VERSION b/chrome/VERSION
index 64e7872..3d797d6 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=50
 MINOR=0
-BUILD=2658
+BUILD=2659
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 5ca28a7..adac1c2 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -14,23 +14,13 @@
 import("channel.gni")
 
 manifest_package = "org.chromium.chrome"
-if (enable_configuration_policy) {
-  configuration_policy = 1
-} else {
-  configuration_policy = 0
-}
 
-chrome_public_jinja_variables = [
-  "channel=$android_channel",
-  "manifest_package=$manifest_package",
-  "configuration_policy=$configuration_policy",
-]
+chrome_public_jinja_variables = default_chrome_public_jinja_variables +
+                                [ "manifest_package=$manifest_package" ]
 
-chrome_sync_shell_jinja_variables = [
-  "channel=$android_channel",
-  "manifest_package=org.chromium.chrome.sync_shell",
-  "configuration_policy=$configuration_policy",
-]
+chrome_sync_shell_jinja_variables =
+    default_chrome_public_jinja_variables +
+    [ "manifest_package=org.chromium.chrome.sync_shell" ]
 
 chrome_apk_gypi = exec_script("//build/gypi_to_gn.py",
                               [ rebase_path("chrome_apk.gyp") ],
@@ -156,6 +146,7 @@
     "//third_party/cacheinvalidation:cacheinvalidation_proto_java",
     "//third_party/gif_player:gif_player_java",
     "//third_party/jsr-305:jsr_305_javalib",
+    "//third_party/leakcanary:leakcanary_java",
     "//ui/android:ui_java",
     "//ui/android:ui_java_resources",
     google_play_services_library,
@@ -303,6 +294,7 @@
     "//third_party/android_tools:android_support_v7_mediarouter_java",
     "//third_party/cacheinvalidation:cacheinvalidation_javalib",
     "//third_party/junit:hamcrest",
+    "//ui/android:ui_java",
     google_play_services_library,
   ]
 }
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index 5e6a718..04ddc8c0 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -4,6 +4,9 @@
 
 import("//base/android/linker/config.gni")
 import("//build/config/android/rules.gni")
+import("//chrome/common/features.gni")
+import("//third_party/leakcanary/config.gni")
+import("channel.gni")
 
 declare_args() {
   # Whether chrome_public_apk should use the crazy linker.
@@ -23,6 +26,16 @@
       (target_cpu == "arm64" || target_cpu == "x64")
 }
 
+default_chrome_public_jinja_variables = [
+  "channel=$android_channel",
+  "enable_leakcanary=$enable_leakcanary",
+]
+if (enable_configuration_policy) {
+  default_chrome_public_jinja_variables += [ "configuration_policy=1" ]
+} else {
+  default_chrome_public_jinja_variables += [ "configuration_policy=0" ]
+}
+
 # GYP: //chrome/android/chrome_apk.gypi
 template("chrome_public_apk_tmpl") {
   android_apk(target_name) {
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index 2cce2a7..0ca1758 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -207,7 +207,7 @@
             android:taskAffinity=""
             android:persistableMode="persistAcrossReboots"
             android:autoRemoveFromRecents="false"
-            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc"
+            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
             android:hardwareAccelerated="false">
         </activity>
         <activity-alias android:name="com.google.android.apps.chrome.document.DocumentActivity"
@@ -221,7 +221,7 @@
             android:taskAffinity=""
             android:persistableMode="persistNever"
             android:autoRemoveFromRecents="false"
-            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc"
+            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
             android:hardwareAccelerated="false">
         </activity>
         <activity-alias android:name="com.google.android.apps.chrome.document.IncognitoDocumentActivity"
@@ -240,7 +240,7 @@
              android:windowBackground="@drawable/window_background"
              android:windowSoftInputMode="adjustResize"
              android:launchMode="singleTask"
-             android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc"
+             android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
              android:hardwareAccelerated="false">
         </activity>
         <activity android:name="org.chromium.chrome.browser.multiwindow.MultiInstanceChromeTabbedActivity"
@@ -715,6 +715,39 @@
         <meta-data android:name="org.chromium.components.service_tab_launcher.SERVICE_TAB_LAUNCHER"
                    android:value="org.chromium.chrome.browser.ChromeServiceTabLauncher" />
 
+        {% set enable_leakcanary = enable_leakcanary|default(0) %}
+        {% if enable_leakcanary == "true" %}
+        {# Entries for LeakCanary copied from (and then tweaked):
+               //third_party/leakcanary/src/leakcanary-android/src/main/AndroidManifest.xml #}
+          <service
+              android:name="com.squareup.leakcanary.internal.HeapAnalyzerService"
+              android:process=":leakcanary"
+              android:enabled="false" />
+          <activity
+              android:theme="@style/leak_canary_LeakCanary.Base"
+              android:name="com.squareup.leakcanary.internal.DisplayLeakActivity"
+              android:process=":leakcanary2"  {# Added to avoid StrictMode violations crashing the activity #}
+              android:label="@string/app_name"  {# Changed from "string/leak_canary_display_activity_label" to help distinguaish when multiple apps include leakcanary. #}
+              android:icon="@drawable/leak_canary_icon"
+              android:taskAffinity=".com.squareup.leakcanary">  {# Added leading "." for multi-app case. #}
+            <intent-filter>
+              <action android:name="android.intent.action.MAIN" />
+              <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+          </activity>
+          <service
+              android:name="com.squareup.leakcanary.DisplayLeakService"
+              android:process=":leakcanary2"  {# Added to minimize interaction with browser process. #}
+              android:enabled="false" />
+          <activity  {# This is just a toast-like overlay, so leaving in browser process #}
+              android:theme="@style/leak_canary_Theme.Transparent"
+              android:name="com.squareup.leakcanary.internal.RequestStoragePermissionActivity"
+              android:taskAffinity="com.squareup.leakcanary"
+              android:enabled="false"
+              android:icon="@drawable/leak_canary_icon"
+              android:label="@string/leak_canary_storage_permission_activity_label" />
+        {% endif %}
+
         {% block extra_application_definitions %}
 
         <!-- Media route controllers to use for remote playback (cast).
diff --git a/chrome/android/java/res/layout/bookmark_row_content.xml b/chrome/android/java/res/layout/bookmark_row_content.xml
index 3cce2531..b51ec193 100644
--- a/chrome/android/java/res/layout/bookmark_row_content.xml
+++ b/chrome/android/java/res/layout/bookmark_row_content.xml
@@ -24,8 +24,9 @@
 
         <LinearLayout
             android:layout_width="0dp"
-            android:layout_height="48dp"
+            android:layout_height="wrap_content"
             android:layout_weight="1"
+            android:minHeight="48dp"
             android:gravity="center_vertical"
             android:orientation="vertical" >
 
diff --git a/chrome/android/java/res/values/ids.xml b/chrome/android/java/res/values/ids.xml
index 3df89941..8f21491d 100644
--- a/chrome/android/java/res/values/ids.xml
+++ b/chrome/android/java/res/values/ids.xml
@@ -29,9 +29,9 @@
     <item type="id" name="translate_infobar_target_spinner" />
 
     <!-- Menu items IDs in Settings -->
-    <item type="id" name="menu_id_help_general" />
-    <item type="id" name="menu_id_translate_help" />
-    <item type="id" name="menu_id_help_privacy" />
+    <item type="id" name="menu_id_general_help" />
+    <item type="id" name="menu_id_targeted_help" />
+    <item type="id" name="menu_id_reset" />
 
     <!-- Menu item IDs for FullscreenActivities -->
     <item type="id" name="menu_id_open_in_chrome" />
diff --git a/chrome/android/java/res/xml/privacy_preferences.xml b/chrome/android/java/res/xml/privacy_preferences.xml
index db7d35d..bf347e5 100644
--- a/chrome/android/java/res/xml/privacy_preferences.xml
+++ b/chrome/android/java/res/xml/privacy_preferences.xml
@@ -70,5 +70,6 @@
     <Preference
         android:key="clear_browsing_data"
         android:title="@string/clear_browsing_data_title"
+        android:summary="@string/clear_browsing_data_summary"
         android:fragment="org.chromium.chrome.browser.preferences.privacy.ClearBrowsingDataPreferences" />
 </PreferenceScreen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index ed00ff5..7fe5a78e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -89,6 +89,7 @@
 import org.chromium.chrome.browser.metrics.UmaSessionStats;
 import org.chromium.chrome.browser.nfc.BeamController;
 import org.chromium.chrome.browser.nfc.BeamProvider;
+import org.chromium.chrome.browser.ntp.snippets.SnippetsController;
 import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
 import org.chromium.chrome.browser.omaha.UpdateMenuItemHelper;
 import org.chromium.chrome.browser.pageinfo.WebsiteSettingsPopup;
@@ -693,6 +694,12 @@
             mToolbarManager.onDeferredStartup(getOnCreateTimestampMs(), simpleName);
         }
         recordKeyboardLocaleUma();
+
+        // TODO(treib): Remove this when we have the proper morning reads fetching logic in place
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_SNIPPETS)) {
+            // Initialize snippets
+            SnippetsController.get(this).fetchSnippets(false);
+        }
     }
 
     @Override
@@ -1046,19 +1053,6 @@
     }
 
     /**
-     * Saves an offline copy for the specified tab that is bookmarked.
-     * @param tab The tab that needs to save an offline copy.
-     */
-    public void saveBookmarkOffline(Tab tab) {
-        if (tab == null || tab.isFrozen()) {
-            return;
-        }
-
-        BookmarkUtils.saveBookmarkOffline(tab.getUserBookmarkId(),
-                new BookmarkModel(), tab, getSnackbarManager(), ChromeActivity.this);
-    }
-
-    /**
      * {@link TabModelSelector} no longer implements TabModel.  Use getTabModelSelector() or
      * getCurrentTabModel() depending on your needs.
      * @return The {@link TabModelSelector}, possibly null.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
index 739bf2c..b06f9e97 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
@@ -65,7 +65,6 @@
 import org.chromium.chrome.browser.physicalweb.PhysicalWebBleClient;
 import org.chromium.chrome.browser.policy.PolicyAuditor;
 import org.chromium.chrome.browser.preferences.AccessibilityPreferences;
-import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
 import org.chromium.chrome.browser.preferences.LocationSettings;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.browser.preferences.Preferences;
@@ -104,7 +103,6 @@
 import org.chromium.ui.UiUtils;
 import org.chromium.ui.base.ActivityWindowAndroid;
 import org.chromium.ui.base.ResourceBundle;
-import org.chromium.ui.widget.Toast;
 
 import java.lang.ref.WeakReference;
 import java.util.Locale;
@@ -866,13 +864,7 @@
      */
     private void cacheNativeFlags() {
         if (sIsFinishedCachingNativeFlags) return;
-
-        boolean isToastNeeded = ChromePreferenceManager.cacheHerbFlavor();
-        if (isToastNeeded) {
-            Toast.makeText(this,
-                    R.string.cache_native_flags_requires_restart, Toast.LENGTH_SHORT).show();
-        }
-
+        FeatureUtilities.cacheHerbFlavor();
         sIsFinishedCachingNativeFlags = true;
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
index b3498e2..0980e29e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -29,5 +29,7 @@
         return nativeIsEnabled(featureName);
     }
 
+    public static final String NTP_SNIPPETS = "NTPSnippets";
+
     private static native boolean nativeIsEnabled(String featureName);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java
index de38c30..61162427 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java
@@ -89,11 +89,6 @@
     public static final String DISABLE_LOFI_SNACKBAR = "disable-lo-fi-snackbar";
 
     /**
-     * Enable content snippets on the NTP
-     */
-    public static final String ENABLE_NTP_SNIPPETS = "enable-ntp-snippets";
-
-    /**
      * Enable interests on the NTP
      */
     public static final String ENABLE_INTERESTS = "enable-interests";
@@ -232,11 +227,20 @@
      * Determines which of the Herb prototypes is being tested.
      * See about:flags for descriptions.
      */
-    public static final String HERB_FLAVOR = "tab-management-experiment-type";
-    public static final String HERB_FLAVOR_ANISE = "anise";
-    public static final String HERB_FLAVOR_BASIL = "basil";
-    public static final String HERB_FLAVOR_CHIVE = "chive";
-    public static final String HERB_FLAVOR_DILL = "dill";
+    public static final String HERB_FLAVOR_DISABLED_SWITCH =
+            "tab-management-experiment-type-disabled";
+    public static final String HERB_FLAVOR_ANISE_SWITCH = "tab-management-experiment-type-anise";
+    public static final String HERB_FLAVOR_BASIL_SWITCH = "tab-management-experiment-type-basil";
+    public static final String HERB_FLAVOR_CHIVE_SWITCH = "tab-management-experiment-type-chive";
+    public static final String HERB_FLAVOR_DILL_SWITCH = "tab-management-experiment-type-dill";
+
+    public static final String HERB_FLAVOR_DEFAULT = "Default";
+    public static final String HERB_FLAVOR_CONTROL = "Control";
+    public static final String HERB_FLAVOR_DISABLED = "Disabled";
+    public static final String HERB_FLAVOR_ANISE = "Anise";
+    public static final String HERB_FLAVOR_BASIL = "Basil";
+    public static final String HERB_FLAVOR_CHIVE = "Chive";
+    public static final String HERB_FLAVOR_DILL = "Dill";
 
     /**
      * Enable tab switcher in document mode (merged tabs and apps option).
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index f92ddbe..174fe57 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -765,7 +765,7 @@
             boolean isAllowedToReturnToExternalApp = IntentUtils.safeGetBooleanExtra(intent,
                     ChromeLauncherActivity.EXTRA_IS_ALLOWED_TO_RETURN_TO_PARENT, true);
 
-            String herbFlavor = ChromePreferenceManager.getHerbFlavor();
+            String herbFlavor = FeatureUtilities.getHerbFlavor();
             if (isAllowedToReturnToExternalApp
                     && ChromeLauncherActivity.canBeHijackedByHerb(intent)
                     && TextUtils.equals(ChromeSwitches.HERB_FLAVOR_DILL, herbFlavor)) {
@@ -1110,7 +1110,7 @@
         if (alwaysAllowTabClosure) {
             isAllowedToCloseTab = true;
         } else {
-            String herbFlavor = ChromePreferenceManager.getHerbFlavor();
+            String herbFlavor = FeatureUtilities.getHerbFlavor();
             if (TextUtils.equals(ChromeSwitches.HERB_FLAVOR_BASIL, herbFlavor)
                     || TextUtils.equals(ChromeSwitches.HERB_FLAVOR_CHIVE, herbFlavor)) {
                 isAllowedToCloseTab = !currentTab.isAllowedToReturnToExternalApp();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/RepostFormWarningDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/RepostFormWarningDialog.java
index 0af541e..669a56fa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/RepostFormWarningDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/RepostFormWarningDialog.java
@@ -10,7 +10,11 @@
 import android.os.Bundle;
 import android.support.v7.app.AlertDialog;
 
+import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.tab.EmptyTabObserver;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tab.TabObserver;
 
 /**
  * Form resubmission warning dialog. Presents the cancel/continue choice and fires one of two
@@ -20,18 +24,28 @@
     // Warning dialog currently being shown, stored for testing.
     private static Dialog sCurrentDialog;
 
-    private final Runnable mCancelCallback;
-    private final Runnable mContinueCallback;
+    private final Tab mTab;
+    private final TabObserver mTabObserver;
 
     /** Empty constructor required for DialogFragments. */
     public RepostFormWarningDialog() {
-        mCancelCallback = null;
-        mContinueCallback = null;
+        mTab = null;
+        mTabObserver = null;
     }
 
-    public RepostFormWarningDialog(Runnable cancelCallback, Runnable continueCallback) {
-        mCancelCallback = cancelCallback;
-        mContinueCallback = continueCallback;
+    /**
+     * Handles the repost form warning for the given Tab.
+     * @param tab The tab waiting for confirmation on a repost form warning.
+     */
+    public RepostFormWarningDialog(Tab tab) {
+        mTab = tab;
+        mTabObserver = new EmptyTabObserver() {
+            @Override
+            public void onDestroyed(Tab tab) {
+                dismiss();
+            }
+        };
+        mTab.addObserver(mTabObserver);
     }
 
     @Override
@@ -52,27 +66,27 @@
                 .setMessage(R.string.http_post_warning);
 
         if (savedInstanceState == null) {
-            assert mCancelCallback != null;
-            assert mContinueCallback != null;
+            assert mTab != null;
             builder.setNegativeButton(R.string.cancel,
                     new DialogInterface.OnClickListener() {
                         @Override
                         public void onClick(DialogInterface dialog, int id) {
-                            mCancelCallback.run();
+                            if (!mTab.isInitialized()) return;
+                            mTab.getWebContents().getNavigationController().cancelPendingReload();
                         }
                     });
             builder.setPositiveButton(R.string.http_post_warning_resend,
                     new DialogInterface.OnClickListener() {
                         @Override
                         public void onClick(DialogInterface dialog, int id) {
-                            mContinueCallback.run();
+                            if (!mTab.isInitialized()) return;
+                            mTab.getWebContents().getNavigationController().continuePendingReload();
                         }
                     });
         }
 
-        assert getCurrentDialog() == null;
         Dialog dialog = builder.create();
-        setCurrentDialog(dialog);
+        setCurrentDialogForTesting(dialog);
 
         return dialog;
     }
@@ -80,21 +94,26 @@
     @Override
     public void onDismiss(DialogInterface dialog) {
         super.onDismiss(dialog);
-        setCurrentDialog(null);
+        setCurrentDialogForTesting(null);
+
+        if (mTab != null && mTabObserver != null) {
+            mTab.removeObserver(mTabObserver);
+        }
     }
 
     /**
      * Sets the currently displayed dialog in sCurrentDialog. This is required by findbugs, which
      * allows static fields only to be set from static methods.
      */
-    private static void setCurrentDialog(Dialog dialog) {
+    private static void setCurrentDialogForTesting(Dialog dialog) {
         sCurrentDialog = dialog;
     }
 
     /**
      * @return dialog currently being displayed.
      */
-    public static Dialog getCurrentDialog() {
+    @VisibleForTesting
+    public static Dialog getCurrentDialogForTesting() {
         return sCurrentDialog;
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java
index 1c3cc6b..a9d02069 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java
@@ -17,7 +17,6 @@
 import org.chromium.chrome.browser.omaha.UpdateMenuItemHelper;
 import org.chromium.chrome.browser.preferences.ManagedPreferencesUtils;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
-import org.chromium.chrome.browser.provider.ChromeBrowserProviderClient;
 import org.chromium.chrome.browser.share.ShareHelper;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.util.FeatureUtilities;
@@ -249,7 +248,7 @@
      */
     protected void updateBookmarkMenuItem(MenuItem bookmarkMenuItem, Tab currentTab) {
         bookmarkMenuItem.setEnabled(mBookmarkBridge.isEditBookmarksEnabled());
-        if (currentTab.getBookmarkId() != ChromeBrowserProviderClient.INVALID_BOOKMARK_ID) {
+        if (currentTab.getBookmarkId() != Tab.INVALID_BOOKMARK_ID) {
             bookmarkMenuItem.setIcon(R.drawable.btn_star_filled);
             bookmarkMenuItem.setChecked(true);
             bookmarkMenuItem.setTitleCondensed(mActivity.getString(R.string.edit_bookmark));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkModel.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkModel.java
index 637f091e6..4bfab9c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkModel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkModel.java
@@ -12,7 +12,6 @@
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge.SavePageCallback;
 import org.chromium.chrome.browser.offlinepages.OfflinePageItem;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.provider.ChromeBrowserProviderClient;
 import org.chromium.components.bookmarks.BookmarkId;
 import org.chromium.components.bookmarks.BookmarkType;
 import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils;
@@ -231,7 +230,6 @@
     */
     public void saveOfflinePage(final BookmarkId bookmarkId, WebContents webContents,
             final AddBookmarkCallback callback) {
-        assert bookmarkId.getId() != ChromeBrowserProviderClient.INVALID_BOOKMARK_ID;
         if (mOfflinePageBridge != null) {
             RecordHistogram.recordBooleanHistogram("OfflinePages.IncognitoSave",
                     webContents.isIncognito());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUtils.java
index 45d9f9d..faee49c0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUtils.java
@@ -30,7 +30,6 @@
 import org.chromium.chrome.browser.offlinepages.OfflinePageOpenStorageSettingsDialog;
 import org.chromium.chrome.browser.offlinepages.OfflinePageStorageSpacePolicy;
 import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
-import org.chromium.chrome.browser.provider.ChromeBrowserProviderClient;
 import org.chromium.chrome.browser.snackbar.Snackbar;
 import org.chromium.chrome.browser.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarController;
@@ -63,7 +62,7 @@
         WebContents webContentsToSave = null;
         if (!shouldSkipSavingTabOffline(tab)) webContentsToSave = tab.getWebContents();
 
-        if (idToAdd != ChromeBrowserProviderClient.INVALID_BOOKMARK_ID) {
+        if (idToAdd != Tab.INVALID_BOOKMARK_ID) {
             startEditActivity(activity, new BookmarkId(idToAdd, BookmarkType.NORMAL),
                     webContentsToSave);
             return;
@@ -108,7 +107,7 @@
      */
     public static void saveBookmarkOffline(long id, BookmarkModel bookmarkModel,
             Tab tab, final SnackbarManager snackbarManager, Activity activity) {
-        assert id != ChromeBrowserProviderClient.INVALID_BOOKMARK_ID;
+        assert id != Tab.INVALID_BOOKMARK_ID;
         BookmarkId bookmarkId = new BookmarkId(id, BookmarkType.NORMAL);
 
         // Bail out if the ID no longer points to a valid bookmark, which might happen if the user
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
index 7f881eb..ef57345 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
@@ -113,7 +113,6 @@
     private View mView;
 
     private TabObserver mTabObserver;
-    private boolean mIsTablet;
     private boolean mEnableCompositorTabStrip;
 
     // Cache objects that should not be created frequently.
@@ -205,7 +204,6 @@
         };
 
         mEnableCompositorTabStrip = DeviceFormFactor.isTablet(getContext());
-        mIsTablet = DeviceFormFactor.isTablet(getContext());
 
         addOnLayoutChangeListener(new OnLayoutChangeListener() {
             @Override
@@ -501,7 +499,7 @@
         if (mLayoutManager != null) {
             mLayoutManager.onUpdate();
 
-            if (!mIsTablet && mControlContainer != null) {
+            if (!DeviceFormFactor.isTablet(getContext()) && mControlContainer != null) {
                 if (mProgressBarDrawingInfo == null) mProgressBarDrawingInfo = new DrawingInfo();
                 mControlContainer.getProgressBarDrawingInfo(mProgressBarDrawingInfo);
             } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayContentDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayContentDelegate.java
index f19c564b..0fec3a6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayContentDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayContentDelegate.java
@@ -41,6 +41,11 @@
     public void onContentLoadFinished() {}
 
     /**
+     * Called when the navigation entry has been committed.
+     */
+    public void onNavigationEntryCommitted() {}
+
+    /**
      * Determine if a particular navigation should be intercepted.
      * @param externalNavHandler External navigation handler for the activity the panel is in.
      * @param navigationParams The navigation params for the current navigation.
@@ -51,6 +56,19 @@
         return true;
     }
 
+    /**
+     * Allows the delegate to intercept the loading of a URL.
+     * If the loading is intercepted, the OverlayPanelContent will not load the URL when
+     * {@link OverlayPanelContent#loadUrl} is called. Instead, it is up to the delegate to load it.
+     * This allows, for example, passing custom HTTP headers when loading a URL.
+     * @param overlayContentViewCore The Overlay.
+     * @param url The URL to load.
+     * @return Whether the load has been intercepted.
+     */
+    public boolean handleInterceptLoadUrl(ContentViewCore overlayContentViewCore, String url) {
+        return false;
+    }
+
     // ============================================================================================
     // ContentViewCore related events.
     // ============================================================================================
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
index c387957..9ace891e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
@@ -67,7 +67,7 @@
 
     /**
      * Whether the ContentViewCore is processing a pending navigation.
-     * NOTE(pedrosimonetti): This is being used to prevent redirections on the SERP to
+     * NOTE(pedrosimonetti): This is being used to prevent redirections on the SERP to be
      * interpreted as a regular navigation, which should cause the Contextual Search Panel
      * to be promoted as a Tab. This was added to work around a server bug that has been fixed.
      * Just checking for whether the Content has been touched is enough to determine whether a
@@ -235,6 +235,11 @@
                     }
 
                     @Override
+                    public void navigationEntryCommitted() {
+                        mContentDelegate.onNavigationEntryCommitted();
+                    }
+
+                    @Override
                     public void didStartProvisionalLoadForFrame(long frameId, long parentFrameId,
                             boolean isMainFrame, String validatedUrl, boolean isErrorPage,
                             boolean isIframeSrcdoc) {
@@ -309,8 +314,10 @@
             mLoadedUrl = url;
             mDidStartLoadingUrl = true;
             mIsProcessingPendingNavigation = true;
-            mContentViewCore.getWebContents().getNavigationController().loadUrl(
-                    new LoadUrlParams(url));
+            if (!mContentDelegate.handleInterceptLoadUrl(mContentViewCore, url)) {
+                mContentViewCore.getWebContents().getNavigationController().loadUrl(
+                        new LoadUrlParams(url));
+            }
         }
     }
 
@@ -374,7 +381,7 @@
         mIsContentViewShowing = isVisible;
 
         if (isVisible) {
-            // If the last call to loadUrl was sepcified to be delayed, load it now.
+            // If the last call to loadUrl was specified to be delayed, load it now.
             if (!TextUtils.isEmpty(mPendingUrl)) {
                 loadUrl(mPendingUrl, true);
             }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java
index 02c6cd3..da07d0f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java
@@ -1120,7 +1120,9 @@
      */
     public EventFilter findInterceptingEventFilter(
             MotionEvent e, Point offsets, boolean isKeyboardShowing) {
-        for (int i = 0; i < mSceneOverlays.size(); i++) {
+        // The last added overlay will be drawn on top of everything else, therefore the last
+        // filter added should have the first chance to intercept any touch events.
+        for (int i = mSceneOverlays.size() - 1; i >= 0; i--) {
             EventFilter eventFilter = mSceneOverlays.get(i).getEventFilter();
             if (offsets != null) eventFilter.setCurrentMotionEventOffsets(offsets.x, offsets.y);
             if (eventFilter.onInterceptTouchEvent(e, isKeyboardShowing)) return eventFilter;
@@ -1173,6 +1175,10 @@
      * @return Whether or not to force the top controls Android view to hide.
      */
     public boolean forceHideTopControlsAndroidView() {
+        for (int i = 0; i < mSceneOverlays.size(); i++) {
+            // If any overlay wants to hide tha Android version of the top controls, hide them.
+            if (mSceneOverlays.get(i).shouldHideAndroidTopControls()) return true;
+        }
         return false;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/SceneOverlay.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/SceneOverlay.java
index 4054eb1..79648802 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/SceneOverlay.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/SceneOverlay.java
@@ -49,6 +49,11 @@
     void getVirtualViews(List<VirtualView> views);
 
     /**
+     * @return True if the overlay requires the Android top controls view to be hidden.
+     */
+    boolean shouldHideAndroidTopControls();
+
+    /**
      * Helper-specific updates. Cascades the values updated by the animations and flings.
      * @param time The current time of the app in ms.
      * @param dt   The delta time between update frames in ms.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
index 3b181676..cbc6054d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelperManager.java
@@ -154,6 +154,11 @@
         getActiveStripLayoutHelper().getVirtualViews(views);
     }
 
+    @Override
+    public boolean shouldHideAndroidTopControls() {
+        return false;
+    }
+
     /**
      * @return The brightness of background tabs in the tabstrip.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
index 79c6db48..d0ad74c5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
@@ -26,8 +26,9 @@
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.IntentHandler;
-import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
+import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.util.IntentUtils;
 import org.chromium.chrome.browser.widget.TintedDrawable;
 
@@ -422,7 +423,11 @@
      * @param context Context for the package.
      */
     private void parseHerbExtras(Intent intent, Context context) {
-        if (TextUtils.isEmpty(ChromePreferenceManager.getHerbFlavor())) return;
+        String herbFlavor = FeatureUtilities.getHerbFlavor();
+        if (TextUtils.isEmpty(herbFlavor)
+                || TextUtils.equals(ChromeSwitches.HERB_FLAVOR_DISABLED, herbFlavor)) {
+            return;
+        }
         if (!IntentHandler.isIntentChromeOrFirstParty(intent, context)) return;
 
         mFinishAfterOpeningInBrowser = IntentUtils.safeGetBooleanExtra(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
index 8201ade..0eed196 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
@@ -181,10 +181,11 @@
             System.exit(-1);
         }
         final Context context = app.getApplicationContext();
+        final ChromeApplication chrome = (ChromeApplication) context;
         new AsyncTask<Void, Void, Void>() {
             @Override
             protected Void doInBackground(Void... params) {
-                ChildProcessLauncher.warmUp(context);
+                ChildProcessLauncher.warmUp(context, chrome.getChildProcessCreationParams());
                 return null;
             }
         }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
index aa47784..70d93139 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
@@ -322,8 +322,9 @@
         if (!canBeHijackedByHerb(getIntent())) return false;
 
         // Different Herb flavors handle incoming intents differently.
-        String flavor = ChromePreferenceManager.getHerbFlavor();
-        if (TextUtils.isEmpty(flavor)) {
+        String flavor = FeatureUtilities.getHerbFlavor();
+        if (TextUtils.isEmpty(flavor)
+                || TextUtils.equals(ChromeSwitches.HERB_FLAVOR_DISABLED, flavor)) {
             return false;
         } else if (TextUtils.equals(flavor, ChromeSwitches.HERB_FLAVOR_ANISE)
                 || TextUtils.equals(flavor, ChromeSwitches.HERB_FLAVOR_BASIL)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java
index 4d0b017..f9b18e8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java
@@ -19,12 +19,10 @@
 import android.util.Pair;
 import android.view.View;
 import android.webkit.MimeTypeMap;
-import android.webkit.URLUtil;
 import android.widget.TextView;
 
 import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
-import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.infobar.InfoBarIdentifier;
@@ -177,64 +175,16 @@
     }
 
     /**
-     * Decide the file name of the final download. The file extension is derived
-     * from the MIME type.
-     * @param url The full URL to the content that should be downloaded.
-     * @param mimeType The MIME type of the content reported by the server.
-     * @param contentDisposition Content-Disposition HTTP header, if present.
-     * @return The best guess of the file name for the downloaded object.
-     */
-    @VisibleForTesting
-    public static String fileName(String url, String mimeType, String contentDisposition) {
-        // URLUtil#guessFileName will prefer the MIME type extension over
-        // the file extension only if the latter is of a known MIME type.
-        // Therefore for things like "file.php" with Content-Type PDF, it will
-        // still generate file names like "file.php" instead of "file.pdf".
-        // If that's the case, rebuild the file extension from the MIME type.
-        String fileName = URLUtil.guessFileName(url, contentDisposition, mimeType);
-        int dotIndex = fileName.lastIndexOf('.');
-        if (mimeType != null
-                && !mimeType.isEmpty()
-                && dotIndex > 1  // at least one char before the '.'
-                && dotIndex < fileName.length()) { // '.' should not be the last char
-            MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
-
-            String fileRoot = fileName.substring(0, dotIndex);
-            String fileExtension = fileName.substring(dotIndex + 1);
-            String fileExtensionMimeType =
-                    mimeTypeMap.getMimeTypeFromExtension(fileExtension);
-
-            // If the file extension's official MIME type and {@code mimeType}
-            // are the same, simply use the file extension.
-            // If not, extension derived from {@code mimeType} is preferred.
-            if (mimeType.equals(fileExtensionMimeType)) {
-                fileName = fileRoot + "." + fileExtension;
-            } else {
-                String mimeExtension =
-                        mimeTypeMap.getExtensionFromMimeType(mimeType);
-
-                if (mimeExtension != null && !mimeExtension.equals(fileExtension)) {
-                    fileName = fileRoot + "." + mimeExtension;
-                }
-            }
-        }
-        return fileName;
-    }
-
-    /**
      * Notify the host application a download should be done, even if there is a
      * streaming viewer available for this type.
      *
      * @param downloadInfo Information about the download.
      */
     protected void onDownloadStartNoStream(final DownloadInfo downloadInfo) {
-        final String newMimeType = remapGenericMimeType(
-                downloadInfo.getMimeType(),
-                downloadInfo.getUrl(),
-                downloadInfo.getFileName());
-        final String fileName = TextUtils.isEmpty(downloadInfo.getFileName())
-                ? fileName(downloadInfo.getUrl(), newMimeType, downloadInfo.getContentDisposition())
-                : downloadInfo.getFileName();
+        final String fileName = downloadInfo.getFileName();
+        assert !TextUtils.isEmpty(fileName);
+        final String newMimeType =
+                remapGenericMimeType(downloadInfo.getMimeType(), downloadInfo.getUrl(), fileName);
         new AsyncTask<Void, Void, Object[]>() {
             @Override
             protected Object[] doInBackground(Void... params) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/UpdatePasswordInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/UpdatePasswordInfoBar.java
new file mode 100644
index 0000000..9d45806
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/UpdatePasswordInfoBar.java
@@ -0,0 +1,130 @@
+// Copyright 2016 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.
+
+package org.chromium.chrome.browser.infobar;
+
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.TextUtils;
+import android.text.style.ClickableSpan;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.PopupMenu;
+import android.widget.TextView;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ResourceId;
+
+/**
+ * The Update Password infobar offers the user the ability to update a password for the site.
+ */
+public class UpdatePasswordInfoBar
+        extends ConfirmInfoBar implements PopupMenu.OnMenuItemClickListener {
+    private final long mNativePtr;
+    private final String[] mUsernames;
+    private final boolean mShowMultipleAccounts;
+    private final boolean mIsSmartLockEnabled;
+    private final SpannableString mBrandingSpan;
+    private int mSelectedUsername;
+    private TextView mMessageView;
+
+    @CalledByNative
+    private static InfoBar show(long nativePtr, int enumeratedIconId, String[] usernames,
+            String primaryButtonText, String secondaryButtonText, String branding,
+            boolean showMultipleAccounts, boolean isSmartLockEnabled) {
+        return new UpdatePasswordInfoBar(nativePtr, ResourceId.mapToDrawableId(enumeratedIconId),
+                usernames, primaryButtonText, secondaryButtonText, branding, showMultipleAccounts,
+                isSmartLockEnabled);
+    }
+
+    private UpdatePasswordInfoBar(long nativePtr, int iconDrawbleId, String[] usernames,
+            String primaryButtonText, String secondaryButtonText, String branding,
+            boolean showMultipleAccounts, boolean isSmartLockEnabled) {
+        super(iconDrawbleId, null, null, null, primaryButtonText, secondaryButtonText);
+        mNativePtr = nativePtr;
+        mUsernames = usernames;
+        mShowMultipleAccounts = showMultipleAccounts;
+        mIsSmartLockEnabled = isSmartLockEnabled;
+        mBrandingSpan = new SpannableString(branding);
+    }
+
+    private void onUsernameLinkClicked(View v) {
+        PopupMenu popup = new PopupMenu(getContext(), v);
+        for (int i = 0; i < mUsernames.length; ++i) {
+            MenuItem item = popup.getMenu().add(Menu.NONE, i, i, mUsernames[i]);
+        }
+        popup.setOnMenuItemClickListener(this);
+        popup.show();
+    }
+
+    /**
+     * Returns the infobar message for the case when PasswordManager has a guess which credentials
+     * pair should be updated. There are two cases possible: there is only one credential pair that
+     * should be updated and there several guesses available. In the first case user is presented
+     * with the username of the credentials that should be updated in the second case user is able
+     * to choose which of the available credentials to update.
+     * It also remembered the choice made.
+     */
+    private CharSequence createUsernameMessageText(int selectedUsername) {
+        CharSequence message;
+        mSelectedUsername = selectedUsername;
+        final String template = getContext().getString(R.string.update_password_for_account);
+        final String usernameToDisplay = mUsernames[mSelectedUsername];
+        if (mShowMultipleAccounts) {
+            final String downPointingArrow = " \u25BE";
+            SpannableString usernameSelector =
+                    new SpannableString(usernameToDisplay + downPointingArrow);
+            usernameSelector.setSpan(new ClickableSpan() {
+                @Override
+                public void onClick(View view) {
+                    onUsernameLinkClicked(view);
+                }
+            }, 0, usernameSelector.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
+            message = TextUtils.expandTemplate(template, mBrandingSpan, usernameSelector);
+        } else {
+            message = TextUtils.expandTemplate(template, mBrandingSpan, usernameToDisplay);
+        }
+        return message;
+    }
+
+    /**
+     * If user have chosen different than was shown username to update, then we need to change the
+     * infobar message in order to reflect this choice.
+     */
+    public boolean onMenuItemClick(MenuItem item) {
+        mMessageView.setText(
+                createUsernameMessageText(item.getItemId()), TextView.BufferType.SPANNABLE);
+        return false;
+    }
+
+    @Override
+    public void createContent(InfoBarLayout layout) {
+        super.createContent(layout);
+        CharSequence message;
+        if (mIsSmartLockEnabled) {
+            mBrandingSpan.setSpan(new ClickableSpan() {
+                @Override
+                public void onClick(View view) {
+                    onLinkClicked();
+                }
+            }, 0, mBrandingSpan.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        }
+        if (mShowMultipleAccounts || mUsernames.length != 0) {
+            message = createUsernameMessageText(0);
+        } else {
+            String template = getContext().getString(R.string.update_password);
+            message = TextUtils.expandTemplate(template, mBrandingSpan);
+        }
+
+        mMessageView = layout.getMessageTextView();
+        mMessageView.setText(message, TextView.BufferType.SPANNABLE);
+    }
+
+    @CalledByNative
+    private int getSelectedUsername() {
+        return mSelectedUsername;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
index 90ebf03e..4dc01149 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
@@ -5,7 +5,9 @@
 package org.chromium.chrome.browser.init;
 
 import android.app.Activity;
+import android.content.Context;
 import android.content.Intent;
+import android.content.res.Configuration;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
@@ -13,6 +15,7 @@
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.support.v7.app.AppCompatActivity;
+import android.util.DisplayMetrics;
 import android.view.Display;
 import android.view.Surface;
 import android.view.View;
@@ -67,6 +70,29 @@
         super.onDestroy();
     }
 
+    @SuppressWarnings("cast")
+    @Override
+    protected void attachBaseContext(Context newBase) {
+        super.attachBaseContext(newBase);
+
+        // On N, Chrome should always retain the tab strip layout on tablets. Normally in
+        // multi-window, if Chrome is launched into a smaller screen Android will load the tab
+        // switcher resources. Overriding the smallestScreenWidthDp in the Configuration ensures
+        // Android will load the tab strip resources. See crbug.com/588838.
+        if (Build.VERSION.CODENAME.equals("N")) {
+            DisplayMetrics metrics = new DisplayMetrics();
+            ((WindowManager) getApplicationContext().getSystemService(
+                    Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(metrics);
+            int smallestDeviceWidthDp = DeviceFormFactor.getSmallestDeviceWidthDp(metrics);
+
+            if (smallestDeviceWidthDp >= DeviceFormFactor.MINIMUM_TABLET_WIDTH_DP) {
+                Configuration overrideConfiguration = new Configuration();
+                overrideConfiguration.smallestScreenWidthDp = smallestDeviceWidthDp;
+                applyOverrideConfiguration(overrideConfiguration);
+            }
+        }
+    }
+
     @Override
     public void preInflationStartup() {
         mIsTablet = DeviceFormFactor.isTablet(this);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
index 9352f016..91f0dee 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
@@ -13,6 +13,8 @@
 import android.preference.PreferenceManager;
 import android.text.TextUtils;
 
+import com.squareup.leakcanary.LeakCanary;
+
 import org.chromium.base.ActivityState;
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.ApplicationStatus.ActivityStateListener;
@@ -23,6 +25,7 @@
 import org.chromium.base.ResourceExtractor;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.TraceEvent;
+import org.chromium.base.annotations.RemovableInRelease;
 import org.chromium.base.library_loader.LibraryLoader;
 import org.chromium.base.library_loader.LibraryProcessType;
 import org.chromium.base.library_loader.ProcessInitException;
@@ -93,6 +96,14 @@
     private ChromeBrowserInitializer(Context context) {
         mApplication = (ChromeApplication) context.getApplicationContext();
         mHandler = new Handler(Looper.getMainLooper());
+        initLeakCanary();
+    }
+
+    @RemovableInRelease
+    private void initLeakCanary() {
+        // Watch that Activity objects are not retained after their onDestroy() has been called.
+        // This is a no-op in release builds.
+        LeakCanary.install(mApplication);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/NativeInitializationController.java b/chrome/android/java/src/org/chromium/chrome/browser/init/NativeInitializationController.java
index 2fd5fa0..c5e6f36d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/NativeInitializationController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/NativeInitializationController.java
@@ -100,9 +100,7 @@
                     return;
                 }
                 ChromeApplication chrome = (ChromeApplication) mContext;
-                ChildProcessLauncher.setChildProcessCreationParams(
-                        chrome.getChildProcessCreationParams());
-                ChildProcessLauncher.warmUp(mContext);
+                ChildProcessLauncher.warmUp(mContext, chrome.getChildProcessCreationParams());
                 ThreadUtils.runOnUiThread(new Runnable() {
                     @Override
                     public void run() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedItem.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedItem.java
index 64b6b0c..3e83b9e2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedItem.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedItem.java
@@ -49,6 +49,7 @@
     private MostVisitedItemManager mManager;
     private String mTitle;
     private String mUrl;
+    private boolean mOfflineAvailable;
     private int mIndex;
     private int mTileType;
     private View mView;
@@ -59,12 +60,15 @@
      * @param manager The NewTabPageManager used to handle clicks and context menu events.
      * @param title The title of the page.
      * @param url The URL of the page.
+     * @param offlineAvailable Whether there is an offline copy of the URL available.
      * @param index The index of this item in the list of most visited items.
      */
-    public MostVisitedItem(MostVisitedItemManager manager, String title, String url, int index) {
+    public MostVisitedItem(MostVisitedItemManager manager, String title, String url,
+            boolean offlineAvailable, int index) {
         mManager = manager;
         mTitle = title;
         mUrl = url;
+        mOfflineAvailable = offlineAvailable;
         mIndex = index;
         mTileType = MostVisitedTileType.NONE;
     }
@@ -102,6 +106,13 @@
     }
 
     /**
+     * @return Whether this item is available offline.
+     */
+    public boolean isOfflineAvailable() {
+        return mOfflineAvailable;
+    }
+
+    /**
      * @return The index of this MostVisitedItem in the list of MostVisitedItems.
      */
     public int getIndex() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
index ace8a12..ad242f2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -47,6 +47,7 @@
 import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager;
 import org.chromium.chrome.browser.ntp.interests.InterestsPage;
 import org.chromium.chrome.browser.ntp.interests.InterestsPage.InterestsClickListener;
+import org.chromium.chrome.browser.ntp.snippets.SnippetsManager;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
 import org.chromium.chrome.browser.preferences.DocumentModeManager;
 import org.chromium.chrome.browser.preferences.DocumentModePreference;
@@ -120,6 +121,7 @@
     private String mAnimatedLogoUrl;
     private FakeboxDelegate mFakeboxDelegate;
     private OfflinePageBridge mOfflinePageBridge;
+    private SnippetsManager mSnippetsManager;
 
     // The timestamp at which the constructor was called.
     private final long mConstructedTimeNs;
@@ -135,8 +137,6 @@
     // Whether destroy() has been called.
     private boolean mIsDestroyed;
 
-    private boolean mIsTablet;
-
     /**
      * Allows clients to listen for updates to the scroll changes of the search box on the
      * NTP.
@@ -529,6 +529,16 @@
             }
             mMostVisitedSites.recordTileTypeMetrics(tileTypes);
 
+            if (isNtpOfflinePagesEnabled()) {
+                final int maxNumTiles = 12;
+                for (int i = 0; i < items.length; i++) {
+                    if (items[i].isOfflineAvailable()) {
+                        RecordHistogram.recordEnumeratedHistogram(
+                                "NewTabPage.TileOfflineAvailable", i, maxNumTiles);
+                    }
+                }
+            }
+
             SyncSessionsMetrics.recordYoungestForeignTabAgeOnNTP();
         }
     };
@@ -577,12 +587,12 @@
         mLogoBridge = new LogoBridge(mProfile);
         updateSearchProviderHasLogo();
 
+        mSnippetsManager = new SnippetsManager(mNewTabPageManager, mProfile);
+
         LayoutInflater inflater = LayoutInflater.from(activity);
         mNewTabPageView = (NewTabPageView) inflater.inflate(R.layout.new_tab_page, null);
         mNewTabPageView.initialize(mNewTabPageManager, isInSingleUrlBarMode(activity),
-                mSearchProviderHasLogo);
-
-        mIsTablet = DeviceFormFactor.isTablet(activity);
+                mSearchProviderHasLogo, mSnippetsManager);
 
         RecordHistogram.recordBooleanHistogram(
                 "NewTabPage.MobileIsUserOnline", NetworkChangeNotifier.isOnline());
@@ -633,14 +643,14 @@
     }
 
     private boolean isInSingleUrlBarMode(Context context) {
-        if (mIsTablet) return false;
+        if (DeviceFormFactor.isTablet(context)) return false;
         if (mOptOutPromoShown) return false;
 
         return mSearchProviderHasLogo;
     }
 
     private void updateSearchProviderHasLogo() {
-        if (CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_NTP_SNIPPETS)) {
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_SNIPPETS)) {
             mSearchProviderHasLogo = false;
             if (mNewTabPageView != null) mNewTabPageView.setSearchProviderHasLogo(false);
         } else {
@@ -762,6 +772,10 @@
             mLogoBridge.destroy();
             mLogoBridge = null;
         }
+        if (mSnippetsManager != null) {
+            mSnippetsManager.destroy();
+            mSnippetsManager = null;
+        }
         if (mMostVisitedItemRemovedController != null) {
             mTab.getSnackbarManager().dismissSnackbars(mMostVisitedItemRemovedController);
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
index 072c320f..2cca3fb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -34,12 +34,11 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
-import org.chromium.base.CommandLine;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback;
 import org.chromium.chrome.browser.favicon.FaviconHelper.IconAvailabilityCallback;
 import org.chromium.chrome.browser.favicon.LargeIconBridge.LargeIconCallback;
@@ -87,7 +86,6 @@
     private NewTabPageManager mManager;
     private MostVisitedDesign mMostVisitedDesign;
     private MostVisitedItem[] mMostVisitedItems;
-    private SnippetsManager mSnippetsManager;
     private boolean mFirstShow = true;
     private boolean mSearchProviderHasLogo = true;
     private boolean mHasReceivedMostVisitedSites;
@@ -250,7 +248,7 @@
      * @param searchProviderHasLogo Whether the search provider has a logo.
      */
     public void initialize(NewTabPageManager manager, boolean isSingleUrlBarMode,
-            boolean searchProviderHasLogo) {
+            boolean searchProviderHasLogo, SnippetsManager snippetsManager) {
         mManager = manager;
 
         mScrollView = (NewTabScrollView) findViewById(R.id.ntp_scrollview);
@@ -334,13 +332,12 @@
         if (mManager.shouldShowOptOutPromo()) showOptOutPromo();
 
         // Set up snippets
-        if (CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_NTP_SNIPPETS)) {
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_SNIPPETS)) {
             mSnippetsView = (RecyclerView) findViewById(R.id.snippets_card_list);
             mSnippetsView.setVisibility(View.VISIBLE);
             RecordHistogram.recordEnumeratedHistogram(SnippetsManager.SNIPPETS_STATE_HISTOGRAM,
                     SnippetsManager.SNIPPETS_SHOWN, SnippetsManager.NUM_SNIPPETS_ACTIONS);
             mSnippetsView.setLayoutManager(new LinearLayoutManager(getContext()));
-            mSnippetsManager = new SnippetsManager(mManager, mSnippetsView);
             mSnippetsView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                 private boolean mScrolledOnce = false;
                 @Override
@@ -355,6 +352,7 @@
                             SnippetsManager.NUM_SNIPPETS_ACTIONS);
                 }
             });
+            snippetsManager.setSnippetsView(mSnippetsView);
         }
 
         // Set up interests
@@ -783,13 +781,15 @@
         for (int i = 0; i < titles.length; i++) {
             final String url = urls[i];
             final String title = titles[i];
+            boolean offlineAvailable = mManager.isOfflineAvailable(url);
 
             // Look for an existing item to reuse.
             MostVisitedItem item = null;
             for (int j = 0; j < oldItemCount; j++) {
                 MostVisitedItem oldItem = oldItems[j];
                 if (oldItem != null && TextUtils.equals(url, oldItem.getUrl())
-                        && TextUtils.equals(title, oldItem.getTitle())) {
+                        && TextUtils.equals(title, oldItem.getTitle())
+                        && offlineAvailable == oldItem.isOfflineAvailable()) {
                     item = oldItem;
                     item.setIndex(i);
                     oldItems[j] = null;
@@ -799,10 +799,9 @@
 
             // If nothing can be reused, create a new item.
             if (item == null) {
-                String displayTitle = getTitleForDisplay(title, url);
-                item = new MostVisitedItem(mManager, title, url, i);
-                View view = mMostVisitedDesign.createMostVisitedItemView(inflater, url,
-                        displayTitle, item, isInitialLoad);
+                item = new MostVisitedItem(mManager, title, url, offlineAvailable, i);
+                View view =
+                        mMostVisitedDesign.createMostVisitedItemView(inflater, item, isInitialLoad);
                 item.initView(view);
             }
 
@@ -963,17 +962,16 @@
             }
         }
 
-        public View createMostVisitedItemView(LayoutInflater inflater, final String url,
-                String displayTitle, MostVisitedItem item,
-                final boolean isInitialLoad) {
+        public View createMostVisitedItemView(
+                LayoutInflater inflater, MostVisitedItem item, boolean isInitialLoad) {
             final MostVisitedItemView view = (MostVisitedItemView) inflater.inflate(
                     R.layout.most_visited_item, mMostVisitedLayout, false);
-            view.setTitle(displayTitle);
-            view.setOfflineAvailable(mManager.isOfflineAvailable(url));
+            view.setTitle(getTitleForDisplay(item.getTitle(), item.getUrl()));
+            view.setOfflineAvailable(item.isOfflineAvailable());
 
             LargeIconCallback iconCallback = new LargeIconCallbackImpl(item, isInitialLoad);
             if (isInitialLoad) mPendingLoadTasks++;
-            mManager.getLargeIconForUrl(url, mMinIconSize, iconCallback);
+            mManager.getLargeIconForUrl(item.getUrl(), mMinIconSize, iconCallback);
 
             return view;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsExpandableListView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsExpandableListView.java
index 905b40a0..8614c905 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsExpandableListView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsExpandableListView.java
@@ -21,14 +21,12 @@
     private int mMaxListViewWidth;
     private int mSavedListPosition = 0;
     private int mSavedListTop = 0;
-    private boolean mIsTablet;
 
     /**
      * Constructor for inflating from XML.
      */
     public RecentTabsExpandableListView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mIsTablet = DeviceFormFactor.isTablet(context);
     }
 
     @Override
@@ -40,7 +38,7 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        if (!mIsTablet) {
+        if (!DeviceFormFactor.isTablet(getContext())) {
             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
             return;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetCardItemViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetCardItemViewHolder.java
index 14adb83..d032d52 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetCardItemViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetCardItemViewHolder.java
@@ -102,7 +102,7 @@
 
         mHeadlineTextView.setText(item.mTitle);
         mPublisherTextView.setText(item.mPublisher);
-        mArticleSnippetTextView.setText(item.mSnippet);
+        mArticleSnippetTextView.setText(item.mPreviewText);
         mUrl = item.mUrl;
         mPosition = item.mPosition;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
new file mode 100644
index 0000000..db0b5ad
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
@@ -0,0 +1,54 @@
+// Copyright 2016 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.
+
+package org.chromium.chrome.browser.ntp.snippets;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.chrome.browser.profiles.Profile;
+
+/**
+ * Provides access to the snippets to display on the NTP using the C++ NTP Snippets Service
+ */
+public class SnippetsBridge {
+    private static final String TAG = "SnippetsBridge";
+
+    private long mNativeSnippetsBridge;
+
+    /**
+     * An observer for notifying when new snippets are loaded
+     */
+    public interface SnippetsObserver {
+        @CalledByNative("SnippetsObserver")
+        public void onSnippetsAvailable(
+                String[] titles, String[] urls, String[] thumbnailUrls, String[] previewText);
+    }
+
+    /**
+     * Creates a SnippetsBridge for getting snippet data for the current user
+     *
+     * @param profile Profile of the user that we will retrieve snippets for.
+     */
+    public SnippetsBridge(Profile profile, final SnippetsObserver observer) {
+        SnippetsObserver wrappedObserver = new SnippetsObserver() {
+            @Override
+            public void onSnippetsAvailable(
+                    String[] titles, String[] urls, String[] thumbnailUrls, String[] previewText) {
+                // Don't notify observer if we've already been destroyed.
+                if (mNativeSnippetsBridge != 0) {
+                    observer.onSnippetsAvailable(titles, urls, thumbnailUrls, previewText);
+                }
+            }
+        };
+        mNativeSnippetsBridge = nativeInit(profile, wrappedObserver);
+    }
+
+    void destroy() {
+        assert mNativeSnippetsBridge != 0;
+        nativeDestroy(mNativeSnippetsBridge);
+        mNativeSnippetsBridge = 0;
+    }
+
+    private native long nativeInit(Profile profile, SnippetsObserver observer);
+    private native void nativeDestroy(long nativeNTPSnippetsBridge);
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsController.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsController.java
new file mode 100644
index 0000000..55dd84cd
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsController.java
@@ -0,0 +1,59 @@
+// Copyright 2016 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.
+
+package org.chromium.chrome.browser.ntp.snippets;
+
+import android.content.Context;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.signin.SigninManager;
+import org.chromium.chrome.browser.signin.SigninManager.SignInStateObserver;
+
+/**
+ * The main controller for calling into the native snippets component to fetch snippets
+ */
+public class SnippetsController implements SignInStateObserver {
+    private static SnippetsController sInstance;
+
+    private long mNativeSnippetsController;
+
+    public SnippetsController(Context applicationContext) {
+        SigninManager.get(applicationContext).addSignInStateObserver(this);
+    }
+
+    /**
+     * Fetches new snippets
+     *
+     * @param overwrite true if an update to the current snippets should be forced, and false if
+     * snippets should be downloaded only if there are no existing ones.
+     */
+    public void fetchSnippets(boolean overwrite) {
+        nativeFetchSnippets(Profile.getLastUsedProfile(), overwrite);
+    }
+
+    /**
+     * Retrieve the singleton instance of this class.
+     *
+     * @param context the current context.
+     * @return the singleton instance.
+     */
+    public static SnippetsController get(Context context) {
+        ThreadUtils.assertOnUiThread();
+        if (sInstance == null) {
+            sInstance = new SnippetsController(context.getApplicationContext());
+        }
+        return sInstance;
+    }
+
+    @Override
+    public void onSignedIn() {
+        fetchSnippets(true);
+    }
+
+    @Override
+    public void onSignedOut() {}
+
+    private native void nativeFetchSnippets(Profile profile, boolean overwrite);
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsManager.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsManager.java
index eb90180..7faf17a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsManager.java
@@ -6,21 +6,19 @@
 
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
-import android.os.Environment;
 import android.support.v7.widget.RecyclerView;
-import android.util.JsonReader;
 import android.widget.ImageView;
 
 import org.chromium.base.Log;
 import org.chromium.base.StreamUtil;
-import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager;
+import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge.SnippetsObserver;
+import org.chromium.chrome.browser.profiles.Profile;
 
-import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -51,6 +49,7 @@
 
     private NewTabPageManager mNewTabPageManager;
     private SnippetsAdapter mDataAdapter;
+    private SnippetsBridge mSnippetsBridge;
 
     /** Base type for anything to add to the snippets view
      */
@@ -86,15 +85,15 @@
     public static class SnippetArticle implements SnippetListItem {
         public final String mTitle;
         public final String mPublisher;
-        public final String mSnippet;
+        public final String mPreviewText;
         public final String mUrl;
         public final String mThumbnailPath;
         public final int mPosition;
 
         private ThumbnailRenderingTask mThumbnailRenderingTask;
 
-        // Async task to create the thumbnail from a local file
-        // TODO(maybelle): This task to retrieve the thumbnail from local disk is temporary while
+        // Async task to create the thumbnail from a URL
+        // TODO(maybelle): This task to retrieve the thumbnail from the web is temporary while
         // we are prototyping this feature for clank. For the real production feature, we
         // will likely have to download/decode the thumbnail on the native side.
         private static class ThumbnailRenderingTask extends AsyncTask<String, Void, Drawable> {
@@ -106,8 +105,18 @@
 
             @Override
             protected Drawable doInBackground(String... params) {
-                String thumbnailPath = params[0];
-                return Drawable.createFromPath(thumbnailPath);
+                InputStream is = null;
+                try {
+                    is = (InputStream) new URL(params[0]).getContent();
+                    return Drawable.createFromStream(is, "thumbnail");
+                } catch (MalformedURLException e) {
+                    Log.e(TAG, "Could not get image thumbnail due to malformed URL", e);
+                } catch (IOException e) {
+                    Log.e(TAG, "Could not get image thumbnail", e);
+                } finally {
+                    StreamUtil.closeQuietly(is);
+                }
+                return null;
             }
 
             @Override
@@ -116,11 +125,11 @@
             }
         }
 
-        public SnippetArticle(String title, String publisher, String snippet, String url,
+        public SnippetArticle(String title, String publisher, String previewText, String url,
                 String thumbnailPath, int position) {
             mTitle = title;
             mPublisher = publisher;
-            mSnippet = snippet;
+            mPreviewText = previewText;
             mUrl = url;
             mThumbnailPath = thumbnailPath;
             mPosition = position;
@@ -146,117 +155,33 @@
         }
     }
 
-    private class ReadFileTask extends AsyncTask<Void, Void, List<SnippetListItem>> {
-        private int mNumArticles;
-
-        @Override
-        protected List<SnippetListItem> doInBackground(Void... params) {
-            FileInputStream fis = null;
-            try {
-                fis = new FileInputStream(
-                        new File(Environment.getExternalStorageDirectory().getPath()
-                                + "/chrome/reading_list.json"));
-                List<SnippetListItem> listSnippetsGroups = readJsonStream(fis);
-                return listSnippetsGroups;
-            } catch (IOException ex) {
-                Log.e(TAG, "Exception reading file: %s ", ex);
-            } finally {
-                StreamUtil.closeQuietly(fis);
-            }
-            return null;
-        }
-
-        @Override
-        protected void onPostExecute(List<SnippetListItem> listSnippetsGroups) {
-            if (listSnippetsGroups == null) return;
-
-            mDataAdapter.setSnippetListItems(listSnippetsGroups);
-        }
-
-        private List<SnippetListItem> readJsonStream(InputStream in) throws IOException {
-            JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
-            try {
-                return readRecommendationsArray(reader);
-            } finally {
-                reader.close();
-            }
-        }
-
-        private List<SnippetListItem> readRecommendationsArray(JsonReader reader)
-                throws IOException {
-            List<SnippetListItem> listSnippetItems = new ArrayList<SnippetListItem>();
-            mNumArticles = 0;
-            reader.beginArray();
-            while (reader.hasNext()) {
-                readSnippetGroup(listSnippetItems, reader);
-            }
-            reader.endArray();
-            RecordHistogram.recordSparseSlowlyHistogram(
-                    "NewTabPage.Snippets.NumArticles", mNumArticles);
-            return listSnippetItems;
-        }
-
-        private void readSnippetGroup(List<SnippetListItem> listSnippetItems, JsonReader reader)
-                throws IOException {
-            reader.beginObject();
-            while (reader.hasNext()) {
-                String name = reader.nextName();
-                if (name.equals("recommendation_basis")) {
-                    listSnippetItems.add(new SnippetHeader(reader.nextString()));
-                } else if (name.equals("articles")) {
-                    readArticlesArray(listSnippetItems, reader);
-                }
-            }
-            reader.endObject();
-        }
-
-        private void readArticlesArray(List<SnippetListItem> listSnippetItems, JsonReader reader)
-                throws IOException {
-            reader.beginArray();
-            while (reader.hasNext()) {
-                listSnippetItems.add(readArticleDetails(reader));
-            }
-            reader.endArray();
-        }
-
-        private SnippetArticle readArticleDetails(JsonReader reader) throws IOException {
-            String headline = "";
-            String publisher = "";
-            String snippets = "";
-            String url = "";
-            String thumbnail = "";
-
-            reader.beginObject();
-            while (reader.hasNext()) {
-                String name = reader.nextName();
-                if (name.equals("headline")) {
-                    headline = reader.nextString();
-                } else if (name.equals("publisher")) {
-                    publisher = reader.nextString();
-                } else if (name.equals("snippet")) {
-                    snippets = reader.nextString();
-                } else if (name.equals("url")) {
-                    url = reader.nextString();
-                } else if (name.equals("thumbnail")) {
-                    thumbnail = reader.nextString();
-                } else {
-                    reader.skipValue();
-                }
-            }
-            reader.endObject();
-            return new SnippetsManager.SnippetArticle(
-                    headline, publisher, snippets, url, thumbnail, mNumArticles++);
-        }
-    }
-
-    public SnippetsManager(NewTabPageManager tabManager, RecyclerView mSnippetsView) {
+    public SnippetsManager(NewTabPageManager tabManager, Profile profile) {
         mNewTabPageManager = tabManager;
         mDataAdapter = new SnippetsAdapter(this);
+        mSnippetsBridge = new SnippetsBridge(profile, new SnippetsObserver() {
+            @Override
+            public void onSnippetsAvailable(
+                    String[] titles, String[] urls, String[] thumbnailUrls, String[] previewText) {
+                List<SnippetListItem> listItems = new ArrayList<SnippetListItem>();
+                for (int i = 0; i < titles.length; ++i) {
+                    SnippetArticle article = new SnippetArticle(
+                            titles[i], "", previewText[i], urls[i], thumbnailUrls[i], i);
+                    listItems.add(article);
+                }
+                mDataAdapter.setSnippetListItems(listItems);
+            }
+        });
+    }
+
+    public void setSnippetsView(RecyclerView mSnippetsView) {
         mSnippetsView.setAdapter(mDataAdapter);
-        new ReadFileTask().execute();
     }
 
     public void loadUrl(String url) {
         mNewTabPageManager.open(url);
     }
+
+    public void destroy() {
+        mSnippetsBridge.destroy();
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageConnectivityListener.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageConnectivityListener.java
index ea0dd10..38514fd8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageConnectivityListener.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageConnectivityListener.java
@@ -8,7 +8,6 @@
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarController;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.net.ConnectionType;
 import org.chromium.net.NetworkChangeNotifier;
 
 /**
@@ -42,8 +41,7 @@
         Log.d(TAG, "Got connectivity event, connectionType: " + connectionType + ", controller "
                         + mSnackbarController);
 
-        boolean connected = (connectionType != ConnectionType.CONNECTION_NONE
-                && connectionType != ConnectionType.CONNECTION_BLUETOOTH);
+        boolean connected = NetworkChangeNotifier.isOnline();
         Log.d(TAG, "Connection changed, connected " + connected);
 
         // TODO(petewil): We should consider using the connection quality monitor instead
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteController.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteController.java
index 8ce1108d..188cfd92 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteController.java
@@ -229,16 +229,17 @@
      *                           native NTP. This should be false on all other pages.
      * @param elapsedTimeSinceModified The number of ms that passed between the user first
      *                                 modifying text in the omnibox and selecting a suggestion.
+     * @param completedLength The length of the default match's inline autocompletion if any.
      * @param webContents The web contents for the tab where the selected suggestion will be shown.
      */
     public void onSuggestionSelected(int selectedIndex, int type,
             String currentPageUrl, boolean isQueryInOmnibox, boolean focusedFromFakebox,
-            long elapsedTimeSinceModified, WebContents webContents) {
+            long elapsedTimeSinceModified, int completedLength, WebContents webContents) {
         // Don't natively log voice suggestion results as we add them in Java.
         if (type == OmniboxSuggestionType.VOICE_SUGGEST) return;
         nativeOnSuggestionSelected(mNativeAutocompleteControllerAndroid, selectedIndex,
                 currentPageUrl, isQueryInOmnibox, focusedFromFakebox, elapsedTimeSinceModified,
-                webContents);
+                completedLength, webContents);
     }
 
     /**
@@ -323,7 +324,8 @@
     private native void nativeResetSession(long nativeAutocompleteControllerAndroid);
     private native void nativeOnSuggestionSelected(long nativeAutocompleteControllerAndroid,
             int selectedIndex, String currentPageUrl, boolean isQueryInOmnibox,
-            boolean focusedFromFakebox, long elapsedTimeSinceModified, WebContents webContents);
+            boolean focusedFromFakebox, long elapsedTimeSinceModified,
+            int completedLength, WebContents webContents);
     private native void nativeOnOmniboxFocused(long nativeAutocompleteControllerAndroid,
             String omniboxText, String currentUrl, boolean isQueryInOmnibox,
             boolean focusedFromFakebox);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
index 45682da8..d7311a3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -242,8 +242,6 @@
 
     private Runnable mShowSuggestions;
 
-    private boolean mIsTablet;
-
     /**
      * Listener for receiving the messages related with interacting with the omnibox during startup.
      */
@@ -672,12 +670,11 @@
     public LocationBarLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
 
-        mIsTablet = DeviceFormFactor.isTablet(context);
-
         LayoutInflater.from(context).inflate(R.layout.location_bar, this, true);
         mNavigationButton = (ImageView) findViewById(R.id.navigation_button);
         assert mNavigationButton != null : "Missing navigation type view.";
-        mNavigationButtonType = mIsTablet ? NavigationButtonType.PAGE : NavigationButtonType.EMPTY;
+        mNavigationButtonType = DeviceFormFactor.isTablet(context)
+                ? NavigationButtonType.PAGE : NavigationButtonType.EMPTY;
 
         mSecurityButton = (ImageButton) findViewById(R.id.security_button);
         mSecurityIconType = ConnectionSecurityLevel.NONE;
@@ -956,7 +953,7 @@
         updateDeleteButtonVisibility();
         Tab currentTab = getCurrentTab();
         if (hasFocus) {
-            RecordUserAction.record("FocusLocation");
+            if (mNativeInitialized) RecordUserAction.record("FocusLocation");
             mUrlBar.deEmphasizeUrl();
         } else {
             mUrlFocusedFromFakebox = false;
@@ -975,7 +972,8 @@
         }
 
         if (mUrlFocusChangeListener != null) mUrlFocusChangeListener.onUrlFocusChange(hasFocus);
-        changeLocationBarIcon((!mIsTablet || !hasFocus) && isSecurityButtonShown());
+        changeLocationBarIcon(
+                (!DeviceFormFactor.isTablet(getContext()) || !hasFocus) && isSecurityButtonShown());
         mUrlBar.setCursorVisible(hasFocus);
         if (mQueryInTheOmnibox) mUrlBar.setSelection(mUrlBar.getSelectionEnd());
 
@@ -1134,14 +1132,15 @@
 
     // Updates the navigation button based on the URL string
     private void updateNavigationButton() {
+        boolean isTablet = DeviceFormFactor.isTablet(getContext());
         NavigationButtonType type = NavigationButtonType.EMPTY;
-        if (mIsTablet && !mSuggestionItems.isEmpty()) {
+        if (isTablet && !mSuggestionItems.isEmpty()) {
             // If there are suggestions showing, show the icon for the default suggestion.
             type = suggestionTypeToNavigationButtonType(
                     mSuggestionItems.get(0).getSuggestion());
         } else if (mQueryInTheOmnibox) {
             type = NavigationButtonType.MAGNIFIER;
-        } else if (mIsTablet) {
+        } else if (isTablet) {
             type = NavigationButtonType.PAGE;
         }
 
@@ -1247,7 +1246,8 @@
      * @param enabled Whether the security button should be displayed.
      */
     private void updateSecurityButton(boolean enabled) {
-        changeLocationBarIcon(enabled && (!mIsTablet || !mUrlHasFocus));
+        changeLocationBarIcon(enabled
+                && (!DeviceFormFactor.isTablet(getContext()) || !mUrlHasFocus));
         mSecurityButtonShown = enabled;
         updateLocationBarIconContainerVisibility();
     }
@@ -2021,7 +2021,7 @@
                 ? (SystemClock.elapsedRealtime() - mNewOmniboxEditSessionTimestamp) : -1;
         mAutocomplete.onSuggestionSelected(matchPosition, type, currentPageUrl,
                 mQueryInTheOmnibox, mUrlFocusedFromFakebox, elapsedTimeSinceModified,
-                webContents);
+                mUrlBar.getAutocompleteLength(), webContents);
         loadUrl(url, transition);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java
index ce0a9b5..91f8f79 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java
@@ -391,6 +391,8 @@
         mShowMenuBadge = true;
         mMenuBadge.setImageResource(shouldUseLightDrawables()
                 ? R.drawable.badge_update_light : R.drawable.badge_update_dark);
+        mMenuButton.setContentDescription(getResources().getString(
+                R.string.accessibility_toolbar_btn_menu_update));
 
         if (!animate || mIsMenuBadgeAnimationRunning) {
             mMenuBadge.setVisibility(View.VISIBLE);
@@ -430,6 +432,9 @@
     public void removeAppMenuUpdateBadge(boolean animate) {
         boolean wasShowingMenuBadge = mShowMenuBadge;
         mShowMenuBadge = false;
+        mMenuButton.setContentDescription(getResources().getString(
+                R.string.accessibility_toolbar_btn_menu));
+
         if (!animate || !wasShowingMenuBadge) {
             if (showMenuButtonInOmnibox()) {
                 mMenuBadge.setVisibility(View.GONE);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SuggestionView.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SuggestionView.java
index a238a0a..6ee89bb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SuggestionView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SuggestionView.java
@@ -93,8 +93,6 @@
     private final int mPhoneUrlBarLeftOffsetPx;
     private final int mPhoneUrlBarLeftOffsetRtlPx;
 
-    private boolean mIsTablet;
-
     /**
      * Constructs a new omnibox suggestion view.
      *
@@ -179,8 +177,6 @@
                 TypedValue.COMPLEX_UNIT_DIP,
                 PHONE_URL_BAR_LEFT_OFFSET_RTL_DP,
                 getContext().getResources().getDisplayMetrics()));
-
-        mIsTablet = DeviceFormFactor.isTablet(context);
     }
 
     @Override
@@ -489,7 +485,7 @@
                 }
                 classifications.add(0, new MatchClassification(0, MatchClassificationStyle.NONE));
 
-                if (mIsTablet) {
+                if (DeviceFormFactor.isTablet(getContext())) {
                     TextPaint tp = mContentsView.mTextLine1.getPaint();
                     mContentsView.mRequiredWidth =
                             tp.measureText(fillIntoEdit, 0, fillIntoEdit.length());
@@ -692,7 +688,7 @@
         protected void onDraw(Canvas canvas) {
             super.onDraw(canvas);
 
-            if (mIsTablet) {
+            if (DeviceFormFactor.isTablet(getContext())) {
                 // Use the same image transform matrix as the navigation icon to ensure the same
                 // scaling, which requires centering vertically based on the height of the
                 // navigation icon view and not the image itself.
@@ -772,7 +768,7 @@
             mTextLeft = getSuggestionTextLeftPosition();
             mTextRight = getSuggestionTextRightPosition();
             boolean isRTL = ApiCompatibilityUtils.isLayoutRtl(this);
-            if (mIsTablet) {
+            if (DeviceFormFactor.isTablet(getContext())) {
                 int textWidth = isRTL ? mTextRight : (r - l - mTextLeft);
                 final float maxRequiredWidth = mSuggestionDelegate.getMaxRequiredWidth();
                 final float maxMatchContentsWidth = mSuggestionDelegate.getMaxMatchContentsWidth();
@@ -810,7 +806,7 @@
         }
 
         private int getUrlBarLeftOffset() {
-            if (mIsTablet) {
+            if (DeviceFormFactor.isTablet(getContext())) {
                 mUrlBar.getLocationOnScreen(mViewPositionHolder);
                 return mViewPositionHolder[0];
             } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
index e96ebbd..dd5a109 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
@@ -739,6 +739,16 @@
     }
 
     /**
+     * Returns the length of the autocomplete text currently displayed, zero if none is
+     * currently displayed.
+     */
+    public int getAutocompleteLength() {
+        int autoCompleteIndex = getText().getSpanStart(mAutocompleteSpan);
+        if (autoCompleteIndex < 0) return 0;
+        return getText().length() - autoCompleteIndex;
+    }
+
+    /**
      * Overrides the text announced when focusing on the field for accessibility.  This value will
      * be cleared automatically when the text content changes for this view.
      * @param accessibilityOverride The text to be announced instead of the current text value
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/AccountChooserDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/AccountChooserDialog.java
index e83e361..71bb371 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/AccountChooserDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/AccountChooserDialog.java
@@ -153,6 +153,7 @@
                 @Override
                 public void onClick(View view) {
                     nativeOnLinkClicked(mNativeAccountChooserDialog);
+                    mDialog.dismiss();
                 }
             }, mTitleLinkStart, mTitleLinkEnd, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
             titleMessageText.setText(spanableTitle, TextView.BufferType.SPANNABLE);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java
index 6a120de..8eb0dc7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/ListUrlsActivity.java
@@ -69,6 +69,7 @@
     private boolean mIsInitialDisplayRecorded;
     private boolean mIsRefreshing;
     private boolean mIsRefreshUserInitiated;
+    private PhysicalWebBleClient mPhysicalWebBleClient;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -119,6 +120,8 @@
         mIsInitialDisplayRecorded = false;
         mIsRefreshing = false;
         mIsRefreshUserInitiated = false;
+        mPhysicalWebBleClient =
+            PhysicalWebBleClient.getInstance((ChromeApplication) getApplicationContext());
     }
 
     @Override
@@ -152,6 +155,14 @@
         return true;
     }
 
+    private void foregroundSubscribe() {
+        mPhysicalWebBleClient.foregroundSubscribe(this);
+    }
+
+    private void foregroundUnsubscribe() {
+        mPhysicalWebBleClient.foregroundUnsubscribe();
+    }
+
     @Override
     protected void onStart() {
         super.onStart();
@@ -161,6 +172,7 @@
     @Override
     protected void onResume() {
         super.onResume();
+        foregroundSubscribe();
         startRefresh(false, false);
 
         int bottomBarDisplayCount = getBottomBarDisplayCount();
@@ -171,6 +183,12 @@
     }
 
     @Override
+    protected void onPause() {
+        foregroundUnsubscribe();
+        super.onPause();
+    }
+
+    @Override
     public void onRefresh() {
         startRefresh(true, true);
     }
@@ -268,9 +286,6 @@
 
             resolve(urls);
         }
-
-        // Clear stored URLs and resubscribe to Nearby.
-        PhysicalWeb.startPhysicalWeb((ChromeApplication) getApplicationContext());
     }
 
     private void finishRefresh() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWeb.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWeb.java
index 230d7959..0ae107c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWeb.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWeb.java
@@ -73,7 +73,7 @@
      */
     public static void startPhysicalWeb(ChromeApplication application) {
         PhysicalWebBleClient physicalWebBleClient = PhysicalWebBleClient.getInstance(application);
-        physicalWebBleClient.subscribe();
+        physicalWebBleClient.backgroundSubscribe();
         clearUrlsAsync(application);
     }
 
@@ -84,7 +84,7 @@
      */
     public static void stopPhysicalWeb(ChromeApplication application) {
         PhysicalWebBleClient physicalWebBleClient = PhysicalWebBleClient.getInstance(application);
-        physicalWebBleClient.unsubscribe();
+        physicalWebBleClient.backgroundUnsubscribe();
         clearUrlsAsync(application);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebBleClient.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebBleClient.java
index a0b68c0..b1caf76 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebBleClient.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebBleClient.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.physicalweb;
 
+import android.app.Activity;
+
 import org.chromium.base.Log;
 import org.chromium.chrome.browser.ChromeApplication;
 
@@ -32,18 +34,35 @@
     }
 
     /**
-     * Begin subscribing to URLs broadcasted from BLE beacons.
+     * Begin a background subscription to URLs broadcasted from BLE beacons.
      * This currently does nothing and should be overridden by a subclass.
      */
-    void subscribe() {
-        Log.d(TAG, "subscribing in empty client");
+    void backgroundSubscribe() {
+        Log.d(TAG, "background subscribing in empty client");
     }
 
     /**
-     * Cancel subscription to URLs broadcasted from BLE beacons.
+     * Cancel a background subscription to URLs broadcasted from BLE beacons.
      * This currently does nothing and should be overridden by a subclass.
      */
-    void unsubscribe() {
-        Log.d(TAG, "unsubscribing in empty client");
+    void backgroundUnsubscribe() {
+        Log.d(TAG, "background unsubscribing in empty client");
+    }
+
+    /**
+     * Begin a foreground subscription to URLs broadcasted from BLE beacons.
+     * This currently does nothing and should be overridden by a subclass.
+     * @param activity The Activity that is performing the scan.
+     */
+    void foregroundSubscribe(Activity activity) {
+        Log.d(TAG, "foreground subscribing in empty client");
+    }
+
+    /**
+     * Cancel a foreground subscription to URLs broadcasted from BLE beacons.
+     * This currently does nothing and should be overridden by a subclass.
+     */
+    void foregroundUnsubscribe() {
+        Log.d(TAG, "foreground unsubscribing in empty client");
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebDiagnosticsPage.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebDiagnosticsPage.java
index 31dfdd90..bf019ad 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebDiagnosticsPage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebDiagnosticsPage.java
@@ -300,4 +300,4 @@
     public void updateForUrl(String url) {
         // nothing to do
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java
index f79c9379..231c090 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java
@@ -14,9 +14,11 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.SystemClock;
+import android.preference.PreferenceManager;
 import android.support.v4.app.NotificationCompat;
 
 import org.chromium.base.Log;
@@ -48,12 +50,12 @@
  */
 class UrlManager {
     private static final String TAG = "PhysicalWeb";
-    private static final String PREFS_NAME = "org.chromium.chrome.browser.physicalweb.URL_CACHE";
-    private static final String PREFS_VERSION_KEY = "version";
-    private static final String PREFS_NEARBY_URLS_KEY = "nearby_urls";
-    private static final String PREFS_RESOLVED_URLS_KEY = "resolved_urls";
-    private static final String DEPRECATED_PREFS_URLS_KEY = "urls";
-    private static final int PREFS_VERSION = 2;
+    private static final String DEPRECATED_PREFS_NAME =
+            "org.chromium.chrome.browser.physicalweb.URL_CACHE";
+    private static final String PREFS_VERSION_KEY = "physicalweb_version";
+    private static final String PREFS_NEARBY_URLS_KEY = "physicalweb_nearby_urls";
+    private static final String PREFS_RESOLVED_URLS_KEY = "physicalweb_resolved_urls";
+    private static final int PREFS_VERSION = 3;
     private static final long STALE_NOTIFICATION_TIMEOUT_MILLIS = 30 * 60 * 1000;
     private static UrlManager sInstance = null;
     private final Context mContext;
@@ -249,7 +251,7 @@
     }
 
     private void initSharedPreferences() {
-        SharedPreferences prefs = mContext.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
+        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
         int prefsVersion = prefs.getInt(PREFS_VERSION_KEY, 0);
 
         // Check the version.
@@ -258,24 +260,29 @@
         }
 
         // Stored preferences are old, upgrade to the current version.
-        SharedPreferences.Editor editor = prefs.edit();
-        editor.remove(DEPRECATED_PREFS_URLS_KEY);
-        editor.putInt(PREFS_VERSION_KEY, PREFS_VERSION);
-        editor.apply();
-
-        clearUrls();
+        // TODO(cco3): This code may be deleted around m53.
+        prefs.edit().putInt(PREFS_VERSION_KEY, PREFS_VERSION);
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                SharedPreferences oldPrefs =
+                        mContext.getSharedPreferences(DEPRECATED_PREFS_NAME, Context.MODE_PRIVATE);
+                oldPrefs.edit().clear().commit();
+                return null;
+            }
+        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     }
 
     private Set<String> getStringSetFromSharedPreferences(String preferenceName) {
         // Check the version.
-        SharedPreferences prefs = mContext.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
+        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
         return prefs.getStringSet(preferenceName, new HashSet<String>());
     }
 
     private void setStringSetInSharedPreferences(String preferenceName,
                                                  Set<String> preferenceValue) {
         // Write the version.
-        SharedPreferences prefs = mContext.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
+        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
         SharedPreferences.Editor editor = prefs.edit();
         editor.putStringSet(preferenceName, preferenceValue);
         editor.apply();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
index 5424939..b7450d8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
@@ -6,19 +6,13 @@
 
 import android.content.Context;
 import android.content.SharedPreferences;
-import android.os.StrictMode;
 import android.preference.PreferenceManager;
-import android.text.TextUtils;
 
-import org.chromium.base.ApplicationStatus;
-import org.chromium.base.CommandLine;
-import org.chromium.base.Log;
 import org.chromium.base.annotations.SuppressFBWarnings;
 import org.chromium.chrome.browser.ChromeSwitches;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.crash.MinidumpUploadService.ProcessType;
 import org.chromium.chrome.browser.signin.SigninPromoUma;
-import org.chromium.ui.base.DeviceFormFactor;
+import org.chromium.chrome.browser.util.FeatureUtilities;
 
 import java.util.Locale;
 
@@ -59,8 +53,6 @@
     private static final long MILLISECONDS_IN_DAY = 1000 * 60 * 60 * 24;
 
     private static ChromePreferenceManager sPrefs;
-    private static String sCachedHerbFlavor;
-    private static boolean sIsHerbFlavorCached;
 
     private final SharedPreferences mSharedPreferences;
     private final Context mContext;
@@ -333,51 +325,18 @@
     }
 
     /**
-     * @return Which flavor of Herb is active, or null if a prototype isn't being tested.
+     * @return Which UI prototype the user is testing. This is cached from native via
+     *         {@link FeatureUtilities#cacheHerbFlavor}.
      */
-    public static String getHerbFlavor() {
-        if (!sIsHerbFlavorCached) {
-            Context context = ApplicationStatus.getApplicationContext();
-            if (ChromeVersionInfo.isStableBuild() || ChromeVersionInfo.isBetaBuild()) return null;
-            if (DeviceFormFactor.isTablet(context)) return null;
-
-            // Allowing disk access for preferences while prototyping.
-            sCachedHerbFlavor = null;
-            StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-            try {
-                sCachedHerbFlavor =
-                        ChromePreferenceManager.getInstance(context).getHerbFlavorInternal();
-            } finally {
-                StrictMode.setThreadPolicy(oldPolicy);
-            }
-
-            sIsHerbFlavorCached = true;
-            Log.d(TAG, "Retrieved Herb flavor: " + sCachedHerbFlavor);
-        }
-
-        return sCachedHerbFlavor;
-    }
-
-    private String getHerbFlavorInternal() {
-        return mSharedPreferences.getString(HERB_FLAVOR_KEY, null);
+    public String getCachedHerbFlavor() {
+        return mSharedPreferences.getString(HERB_FLAVOR_KEY, ChromeSwitches.HERB_FLAVOR_DISABLED);
     }
 
     /**
-     * Caches which flavor of Herb the user prefers from native.
+     * Caches which UI prototype the user is testing.
      */
-    public static boolean cacheHerbFlavor() {
-        String oldFlavor = getHerbFlavor();
-        String newFlavor =
-                CommandLine.getInstance().getSwitchValue(ChromeSwitches.HERB_FLAVOR, null);
-        sCachedHerbFlavor = newFlavor;
-        Log.d(TAG, "Caching Herb flavor: " + sCachedHerbFlavor);
-
-        if (!TextUtils.equals(oldFlavor, newFlavor)) {
-            Context context = ApplicationStatus.getApplicationContext();
-            ChromePreferenceManager.getInstance(context).writeString(HERB_FLAVOR_KEY, newFlavor);
-            return true;
-        }
-        return false;
+    public void setCachedHerbFlavor(String flavor) {
+        writeString(HERB_FLAVOR_KEY, flavor);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/Preferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/Preferences.java
index 44ed46bc..82d9ccf6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/Preferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/Preferences.java
@@ -191,7 +191,7 @@
         super.onCreateOptionsMenu(menu);
         // By default, every screen in Settings shows a "Help & feedback" menu item.
         MenuItem help = menu.add(
-                Menu.NONE, R.id.menu_id_help_general, Menu.CATEGORY_SECONDARY, R.string.menu_help);
+                Menu.NONE, R.id.menu_id_general_help, Menu.CATEGORY_SECONDARY, R.string.menu_help);
         help.setIcon(R.drawable.ic_help_and_feedback);
         return true;
     }
@@ -210,7 +210,7 @@
         if (item.getItemId() == android.R.id.home) {
             finish();
             return true;
-        } else if (item.getItemId() == R.id.menu_id_help_general) {
+        } else if (item.getItemId() == R.id.menu_id_general_help) {
             HelpAndFeedback.getInstance(this).show(this, getString(R.string.help_context_settings),
                     Profile.getLastUsedProfile(), null);
             return true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPreferences.java
index 2254f2c..c4a7b603 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPreferences.java
@@ -14,14 +14,19 @@
 import android.preference.PreferenceFragment;
 import android.preference.PreferenceManager;
 import android.text.format.DateUtils;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
 
 import org.chromium.base.CommandLine;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.firstrun.FirstRunStatus;
+import org.chromium.chrome.browser.help.HelpAndFeedback;
 import org.chromium.chrome.browser.infobar.DataReductionProxyInfoBar;
 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
 import org.chromium.chrome.browser.preferences.ChromeSwitchPreference;
 import org.chromium.chrome.browser.preferences.ManagedPreferenceDelegate;
+import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.third_party.android.datausagechart.NetworkStats;
 import org.chromium.third_party.android.datausagechart.NetworkStatsHistory;
@@ -90,6 +95,25 @@
         DataReductionProxyUma.dataReductionProxyUIAction(statusChange);
     }
 
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        menu.clear();
+        MenuItem help = menu.add(
+                Menu.NONE, R.id.menu_id_targeted_help, Menu.NONE, R.string.menu_help);
+        help.setIcon(R.drawable.ic_help_and_feedback);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == R.id.menu_id_targeted_help) {
+            HelpAndFeedback.getInstance(getActivity())
+                    .show(getActivity(), getString(R.string.help_context_data_reduction),
+                            Profile.getLastUsedProfile(), null);
+            return true;
+        }
+        return false;
+    }
+
     /**
      * Switches preference screens depending on whether data reduction is enabled/disabled.
      * @param isEnabled Indicates whether data reduction is enabled.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java
index 49fb94d..54e1914 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/ClearBrowsingDataPreferences.java
@@ -83,7 +83,7 @@
 
         @Override
         public void onCounterFinished(String result) {
-            mCheckbox.setSummaryOn(result);
+            if (mCheckbox != null) mCheckbox.setSummaryOn(result);
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java
index d1a32a6..0db853b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/privacy/PrivacyPreferences.java
@@ -276,13 +276,13 @@
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
         menu.clear();
         MenuItem help = menu.add(
-                Menu.NONE, R.id.menu_id_help_privacy, Menu.NONE, R.string.menu_help);
+                Menu.NONE, R.id.menu_id_targeted_help, Menu.NONE, R.string.menu_help);
         help.setIcon(R.drawable.ic_help_and_feedback);
     }
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
-        if (item.getItemId() == R.id.menu_id_help_privacy) {
+        if (item.getItemId() == R.id.menu_id_targeted_help) {
             HelpAndFeedback.getInstance(getActivity())
                     .show(getActivity(), getString(R.string.help_context_privacy),
                             Profile.getLastUsedProfile(), null);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/LanguagePreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/LanguagePreferences.java
index dbb1503..2d142ab 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/LanguagePreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/LanguagePreferences.java
@@ -79,32 +79,27 @@
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
         menu.clear();
         MenuItem help = menu.add(
-                Menu.NONE, R.id.menu_id_translate_help, Menu.NONE, R.string.menu_help);
+                Menu.NONE, R.id.menu_id_targeted_help, Menu.NONE, R.string.menu_help);
         help.setIcon(R.drawable.ic_help_and_feedback);
         help.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
 
-        MenuItem reset = menu.add(Menu.NONE, Menu.NONE, Menu.NONE,
-                R.string.reset_translate_defaults);
-        reset.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
-            @Override
-            public boolean onMenuItemClick(MenuItem menuItem) {
-                PrefServiceBridge.getInstance().resetTranslateDefaults();
-                Toast.makeText(getActivity(), getString(
-                        R.string.translate_prefs_toast_description),
-                        Toast.LENGTH_SHORT).show();
-                return true;
-            }
-        });
+        menu.add(Menu.NONE, R.id.menu_id_reset, Menu.NONE, R.string.reset_translate_defaults);
     }
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         int itemId = item.getItemId();
-        if (itemId == R.id.menu_id_translate_help) {
+        if (itemId == R.id.menu_id_targeted_help) {
             HelpAndFeedback.getInstance(getActivity())
                     .show(getActivity(), getString(R.string.help_context_translate),
                             Profile.getLastUsedProfile(), null);
             return true;
+        } else if (itemId == R.id.menu_id_reset) {
+            PrefServiceBridge.getInstance().resetTranslateDefaults();
+            Toast.makeText(getActivity(), getString(
+                    R.string.translate_prefs_toast_description),
+                    Toast.LENGTH_SHORT).show();
+            return true;
         }
         return false;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleCategoryPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleCategoryPreferences.java
index 66663e6..b686e02 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleCategoryPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleCategoryPreferences.java
@@ -21,6 +21,7 @@
 import android.widget.TextView;
 
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.help.HelpAndFeedback;
 import org.chromium.chrome.browser.media.cdm.MediaDrmCredentialManager;
 import org.chromium.chrome.browser.media.cdm.MediaDrmCredentialManager.MediaDrmCredentialManagerCallback;
 import org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference;
@@ -32,6 +33,7 @@
 import org.chromium.chrome.browser.preferences.ManagedPreferencesUtils;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.browser.preferences.ProtectedContentResetCredentialConfirmDialogFragment;
+import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.widget.TintedDrawable;
 import org.chromium.ui.widget.Toast;
 
@@ -302,6 +304,7 @@
 
     @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        menu.clear();
         inflater.inflate(R.menu.website_preferences_menu, menu);
 
         MenuItem searchItem = menu.findItem(R.id.search);
@@ -328,7 +331,7 @@
         if (mCategory.showProtectedMediaSites()) {
             // Add a menu item to reset protected media identifier device credentials.
             MenuItem resetMenu =
-                    menu.add(Menu.NONE, Menu.NONE, Menu.FIRST, R.string.reset_device_credentials);
+                    menu.add(Menu.NONE, Menu.NONE, Menu.NONE, R.string.reset_device_credentials);
             resetMenu.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
                 @Override
                 public boolean onMenuItemClick(MenuItem menuItem) {
@@ -339,6 +342,24 @@
                 }
             });
         }
+
+        MenuItem help = menu.add(
+                Menu.NONE, R.id.menu_id_targeted_help, Menu.NONE, R.string.menu_help);
+        help.setIcon(R.drawable.ic_help_and_feedback);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == R.id.menu_id_targeted_help) {
+            int helpContextResId = R.string.help_context_settings;
+            if (mCategory.showProtectedMediaSites()) {
+                helpContextResId = R.string.help_context_protected_content;
+            }
+            HelpAndFeedback.getInstance(getActivity()).show(
+                    getActivity(), getString(helpContextResId), Profile.getLastUsedProfile(), null);
+            return true;
+        }
+        return false;
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/prerender/ChromePrerenderService.java b/chrome/android/java/src/org/chromium/chrome/browser/prerender/ChromePrerenderService.java
index a258b7e..1e37e779c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/prerender/ChromePrerenderService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/prerender/ChromePrerenderService.java
@@ -19,6 +19,7 @@
 import org.chromium.base.library_loader.ProcessInitException;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ApplicationInitialization;
+import org.chromium.chrome.browser.ChromeApplication;
 import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.WarmupManager;
 import org.chromium.chrome.browser.externalauth.ExternalAuthUtils;
@@ -37,10 +38,22 @@
     public static final String KEY_PRERENDER_HEIGHT = "prerender_height";
     public static final String KEY_REFERRER = "referrer";
 
-    private static class LauncherWarmUpTask extends AsyncTask<Context, Void, Void> {
+    private static class LauncherWarmUpTaskParams {
+        final Context mContext;
+        final ChildProcessLauncher.ChildProcessCreationParams mParams;
+
+        LauncherWarmUpTaskParams(
+                Context context, ChildProcessLauncher.ChildProcessCreationParams params) {
+            mContext = context;
+            mParams = params;
+        }
+    }
+
+    private static class LauncherWarmUpTask
+            extends AsyncTask<LauncherWarmUpTaskParams, Void, Void> {
         @Override
-        protected Void doInBackground(Context... args) {
-            ChildProcessLauncher.warmUp(args[0]);
+        protected Void doInBackground(LauncherWarmUpTaskParams... args) {
+            ChildProcessLauncher.warmUp(args[0].mContext, args[0].mParams);
             return null;
         }
     }
@@ -75,7 +88,10 @@
         mMessenger = new Messenger(new IncomingHandler(getApplicationContext()));
 
         try {
-            new LauncherWarmUpTask().execute(getApplicationContext());
+            final Context context = getApplicationContext();
+            final ChromeApplication chrome = (ChromeApplication) context;
+            new LauncherWarmUpTask().execute(new LauncherWarmUpTaskParams(
+                            context, chrome.getChildProcessCreationParams()));
             ChromeBrowserInitializer.getInstance(this).handleSynchronousStartup();
 
             ApplicationInitialization.enableFullscreenFlags(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/ConfirmAccountChangeFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/ConfirmAccountChangeFragment.java
index 9d7a251..48a70f6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/ConfirmAccountChangeFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/ConfirmAccountChangeFragment.java
@@ -38,6 +38,9 @@
     private static final String KEY_OLD_ACCOUNT_NAME = "lastAccountName";
     private static final String KEY_NEW_ACCOUNT_NAME = "newAccountName";
 
+    // Tracks whether to abort signin in onDismiss.
+    private boolean mAbortSignin = true;
+
     public static ConfirmAccountChangeFragment newInstance(String accountName) {
         ConfirmAccountChangeFragment dialogFragment = new ConfirmAccountChangeFragment();
         Bundle args = new Bundle();
@@ -85,8 +88,17 @@
         if (which == AlertDialog.BUTTON_POSITIVE) {
             RecordUserAction.record("Signin_ImportDataPrompt_ImportData");
             SigninManager.get(getActivity()).progressInteractiveSignInFlowAccountConfirmed();
+            mAbortSignin = false;
         } else if (which == AlertDialog.BUTTON_NEGATIVE) {
             RecordUserAction.record("Signin_ImportDataPrompt_Cancel");
+        }
+    }
+
+    @Override
+    public void onDismiss(DialogInterface dialogInterface) {
+        super.onDismiss(dialogInterface);
+        if (mAbortSignin) {
+            // Something other than BUTTON_POSITIVE is dismissing this fragment; abort signin.
             SigninManager.get(getActivity()).abortSignIn();
         }
     }
@@ -96,10 +108,7 @@
                 ClearSyncDataPreferences.class.getName());
         startActivity(intent);
 
-        // Cancel out of current sign in.
-        SigninManager.get(getActivity()).abortSignIn();
-        dismiss();
-
         RecordUserAction.record("Signin_ImportDataPrompt_DontImport");
+        dismiss();
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/ConfirmManagedSigninFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/ConfirmManagedSigninFragment.java
index c2e585f..41a4f97d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/ConfirmManagedSigninFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/ConfirmManagedSigninFragment.java
@@ -22,6 +22,9 @@
     private static final String TAG = "ConfirmManagedSignin";
     private static final String KEY_MANAGEMENT_DOMAIN = "managementDomain";
 
+    // Tracks whether to abort signin in onDismiss.
+    private boolean mAbortSignin = true;
+
     public static ConfirmManagedSigninFragment newInstance(String managementDomain) {
         ConfirmManagedSigninFragment dialogFragment = new ConfirmManagedSigninFragment();
         Bundle args = new Bundle();
@@ -51,17 +54,16 @@
         if (which == AlertDialog.BUTTON_POSITIVE) {
             Log.d(TAG, "Accepted policy management, proceeding with sign-in.");
             SigninManager.get(getActivity()).progressInteractiveSignInFlowManagedConfirmed();
-        } else {
-            Log.d(TAG, "Policy confirmation rejected; abort sign-in.");
-            SigninManager.get(getActivity()).abortSignIn();
+            mAbortSignin = false;
         }
     }
 
     @Override
     public void onDismiss(DialogInterface dialogInterface) {
         super.onDismiss(dialogInterface);
-        // This makes dismissing the dialog equivalent to cancelling sign-in, and
-        // allows the listener to clean up any pending state.
-        onClick(dialogInterface, AlertDialog.BUTTON_NEGATIVE);
+        if (mAbortSignin) {
+            Log.d(TAG, "Policy confirmation rejected; abort sign-in.");
+            SigninManager.get(getActivity()).abortSignIn();
+        }
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninHelper.java
index 2bf32943..b01572db 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninHelper.java
@@ -375,6 +375,12 @@
         }
     }
 
+    @VisibleForTesting
+    public static void resetAccountRenameEventIndex(Context context) {
+        PreferenceManager.getDefaultSharedPreferences(context)
+                .edit().putInt(ACCOUNT_RENAME_EVENT_INDEX_PREFS_KEY, 0).apply();
+    }
+
     public static boolean checkAndClearAccountsChangedPref(Context context) {
         if (PreferenceManager.getDefaultSharedPreferences(context)
                 .getBoolean(ACCOUNTS_CHANGED_PREFS_KEY, false)) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
index 33b3ad4..9c4ac524 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -121,6 +121,9 @@
         View.OnSystemUiVisibilityChangeListener {
     public static final int INVALID_TAB_ID = -1;
 
+    /** Return value from {@link #getBookmarkId()} if this tab is not bookmarked. */
+    public static final long INVALID_BOOKMARK_ID = -1;
+
     /** The maximum amount of time to wait for a page to load before entering fullscreen.  -1 means
      *  wait until the page finishes loading. */
     private static final long MAX_FULLSCREEN_LOAD_DELAY_MS = 3000;
@@ -1794,7 +1797,8 @@
     }
 
     /**
-     * @return Whether or not this Tab has a live native component.
+     * @return Whether or not this Tab has a live native component.  This will be true prior to
+     *         {@link #initializeNative()} being called or after {@link #destroy()}.
      */
     public boolean isInitialized() {
         return mIsInitialized;
@@ -2590,11 +2594,11 @@
     }
 
     /**
-     * @return The ID of the bookmark associated with the current URL (or -1 if no such bookmark
-     *         exists).
+     * @return The ID of the bookmark associated with the current URL, or
+     *         {@link #INVALID_BOOKMARK_ID} if no such bookmark exists.
      */
     public long getBookmarkId() {
-        return isFrozen() ? -1 : nativeGetBookmarkId(mNativeTabAndroid, false);
+        return isFrozen() ? INVALID_BOOKMARK_ID : nativeGetBookmarkId(mNativeTabAndroid, false);
     }
 
     /**
@@ -2602,7 +2606,7 @@
      * that can't be edited by the user.
      */
     public long getUserBookmarkId() {
-        return isFrozen() ? -1 : nativeGetBookmarkId(mNativeTabAndroid, true);
+        return isFrozen() ? INVALID_BOOKMARK_ID : nativeGetBookmarkId(mNativeTabAndroid, true);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUma.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUma.java
index 2da957ae..02128af 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUma.java
@@ -264,6 +264,13 @@
                 } else {
                     RecordHistogram.recordEnumeratedHistogram("Tab.BackgroundLoadStatus",
                             TAB_BACKGROUND_LOAD_LOST, TAB_BACKGROUND_LOAD_LIM);
+
+                    if (previousTimestampMillis > 0) {
+                        RecordHistogram.recordMediumTimesHistogram(
+                                "Tab.LostTabAgeWhenSwitchedToForeground",
+                                System.currentTimeMillis() - previousTimestampMillis,
+                                TimeUnit.MILLISECONDS);
+                    }
                 }
             } else if (mTabCreationState == TabCreationState.FROZEN_FOR_LAZY_LOAD) {
                 assert mRestoreStartedAtMillis == -1;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java
index 1d01279..cc90675 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java
@@ -205,19 +205,8 @@
     @Override
     public void showRepostFormWarningDialog() {
         mTab.resetSwipeRefreshHandler();
-        RepostFormWarningDialog warningDialog = new RepostFormWarningDialog(
-                new Runnable() {
-                    @Override
-                    public void run() {
-                        mTab.getWebContents().getNavigationController().cancelPendingReload();
-                    }
-                }, new Runnable() {
-                    @Override
-                    public void run() {
-                        mTab.getWebContents().getNavigationController().continuePendingReload();
-                    }
-                });
         if (mTab.getActivity() == null) return;
+        RepostFormWarningDialog warningDialog = new RepostFormWarningDialog(mTab);
         warningDialog.show(mTab.getActivity().getFragmentManager(), null);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelImpl.java
index abcae375..f12c8f16 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelImpl.java
@@ -176,8 +176,8 @@
         mInitializationObservers = new ObserverList<InitializationObserver>();
         mObservers = new ObserverList<TabModelObserver>();
 
-        long time = SystemClock.elapsedRealtime();
         SharedPreferences prefs = mContext.getSharedPreferences(PREF_PACKAGE, Context.MODE_PRIVATE);
+        long time = SystemClock.elapsedRealtime();
         mLastShownTabId = prefs.getInt(
                 isIncognito() ? PREF_LAST_SHOWN_TAB_ID_INCOGNITO : PREF_LAST_SHOWN_TAB_ID_REGULAR,
                 Tab.INVALID_TAB_ID);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
index f3d918b..8c00780 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
@@ -652,6 +652,8 @@
     public void removeAppMenuUpdateBadge(boolean animate) {
         boolean wasShowingMenuBadge = mShowMenuBadge;
         mShowMenuBadge = false;
+        setMenuButtonContentDescription(false);
+
         if (!animate || !wasShowingMenuBadge) {
             mMenuBadge.setVisibility(View.GONE);
             return;
@@ -692,6 +694,7 @@
      * bitmap.
      */
     protected void setAppMenuUpdateBadgeToVisible(boolean animate) {
+        setMenuButtonContentDescription(true);
         if (!animate || mIsMenuBadgeAnimationRunning) {
             mMenuBadge.setVisibility(View.VISIBLE);
             return;
@@ -739,6 +742,20 @@
                 : R.drawable.badge_update_dark);
     }
 
+    /**
+     * Sets the content description for the menu button.
+     * @param isUpdateBadgeVisible Whether the update menu badge is visible.
+     */
+    protected void setMenuButtonContentDescription(boolean isUpdateBadgeVisible) {
+        if (isUpdateBadgeVisible) {
+            mMenuButton.setContentDescription(getResources().getString(
+                    R.string.accessibility_toolbar_btn_menu_update));
+        } else {
+            mMenuButton.setContentDescription(getResources().getString(
+                    R.string.accessibility_toolbar_btn_menu));
+        }
+    }
+
     @Override
     public void setReturnButtonListener(View.OnClickListener listener) {
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index 7cde469..90d07ee 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -47,7 +47,6 @@
 import org.chromium.chrome.browser.partnercustomizations.HomepageManager;
 import org.chromium.chrome.browser.partnercustomizations.HomepageManager.HomepageStateListener;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.provider.ChromeBrowserProviderClient;
 import org.chromium.chrome.browser.search_engines.TemplateUrlService;
 import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrl;
 import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrlServiceObserver;
@@ -1018,7 +1017,7 @@
     private void updateBookmarkButtonStatus() {
         Tab currentTab = mToolbarModel.getTab();
         boolean isBookmarked = currentTab != null
-                && currentTab.getBookmarkId() != ChromeBrowserProviderClient.INVALID_BOOKMARK_ID;
+                && currentTab.getBookmarkId() != Tab.INVALID_BOOKMARK_ID;
         boolean editingAllowed = currentTab == null || mBookmarkBridge == null
                 || mBookmarkBridge.isEditBookmarksEnabled();
         mToolbar.updateBookmarkButton(isBookmarked, editingAllowed);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
index 2b06dc80..61fa4f62 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
@@ -54,7 +54,6 @@
 import org.chromium.chrome.browser.omnibox.LocationBarPhone;
 import org.chromium.chrome.browser.omnibox.UrlContainer;
 import org.chromium.chrome.browser.partnercustomizations.HomepageManager;
-import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.chrome.browser.util.FeatureUtilities;
@@ -1429,6 +1428,9 @@
         for (View view : mBrowsingModeViews) {
             view.setVisibility(browsingViewsVisibility);
         }
+        if (mShowMenuBadge) {
+            setMenuButtonContentDescription(!isInTabSwitcherMode);
+        }
         getProgressBar().setVisibility(
                 isInTabSwitcherMode || isTabSwitcherAnimationRunning() ? INVISIBLE : VISIBLE);
         updateVisualsForToolbarState(isInTabSwitcherMode);
@@ -2147,7 +2149,7 @@
     }
 
     private boolean isReturnButtonVisible() {
-        String herbFlavor = ChromePreferenceManager.getHerbFlavor();
+        String herbFlavor = FeatureUtilities.getHerbFlavor();
         if (!TextUtils.equals(ChromeSwitches.HERB_FLAVOR_BASIL, herbFlavor)
                 && !TextUtils.equals(ChromeSwitches.HERB_FLAVOR_CHIVE, herbFlavor)) {
             return false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java
index f687616e..c8a4322 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java
@@ -370,6 +370,7 @@
             mLocationBar.getContainerView().setVisibility(View.INVISIBLE);
             if (mShowMenuBadge) {
                 mMenuBadge.setVisibility(View.GONE);
+                setMenuButtonContentDescription(false);
             }
         } else {
             mIsInTabSwitcherMode = false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
index 2089a3b..f1cdf130 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
@@ -12,13 +12,20 @@
 import android.content.pm.ResolveInfo;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.StrictMode;
 import android.os.UserManager;
 import android.speech.RecognizerIntent;
+import android.text.TextUtils;
 
+import org.chromium.base.ApplicationStatus;
 import org.chromium.base.CommandLine;
+import org.chromium.base.FieldTrialList;
+import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.ChromeVersionInfo;
+import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
 import org.chromium.chrome.browser.preferences.DocumentModeManager;
 import org.chromium.sync.signin.AccountManagerHelper;
 import org.chromium.ui.base.DeviceFormFactor;
@@ -30,9 +37,17 @@
  * this device.
  */
 public class FeatureUtilities {
+    private static final String TAG = "FeatureUtilities";
+    private static final String HERB_EXPERIMENT_NAME = "TabManagementExperiment";
+    private static final String HERB_EXPERIMENT_FLAVOR_PARAM = "type";
+
     private static Boolean sHasGoogleAccountAuthenticator;
     private static Boolean sHasRecognitionIntentHandler;
     private static Boolean sDocumentModeDisabled;
+
+    private static String sCachedHerbFlavor;
+    private static boolean sIsHerbFlavorCached;
+
     /** Used to track if cached command line flags should be refreshed. */
     private static CommandLine.ResetListener sResetListener = null;
 
@@ -171,6 +186,83 @@
         CommandLine.addResetListener(sResetListener);
     }
 
+    /**
+     * @return Which flavor of Herb is being tested.  See {@link ChromeSwitches#HERB_FLAVOR_ANISE}
+     *         and its related switches.
+     */
+    public static String getHerbFlavor() {
+        if (!sIsHerbFlavorCached) {
+            sCachedHerbFlavor = null;
+
+            Context context = ApplicationStatus.getApplicationContext();
+            if (isDocumentMode(context) || ChromeVersionInfo.isStableBuild()
+                    || ChromeVersionInfo.isBetaBuild() || DeviceFormFactor.isTablet(context)) {
+                // Disable Herb.
+                sCachedHerbFlavor = ChromeSwitches.HERB_FLAVOR_DISABLED;
+            } else {
+                // Allowing disk access for preferences while prototyping.
+                StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+                try {
+                    sCachedHerbFlavor =
+                            ChromePreferenceManager.getInstance(context).getCachedHerbFlavor();
+                } finally {
+                    StrictMode.setThreadPolicy(oldPolicy);
+                }
+            }
+
+            sIsHerbFlavorCached = true;
+            Log.d(TAG, "Retrieved cached Herb flavor: " + sCachedHerbFlavor);
+        }
+
+        return sCachedHerbFlavor;
+    }
+
+    /**
+     * Caches which flavor of Herb the user prefers from native.
+     */
+    public static void cacheHerbFlavor() {
+        String oldFlavor = getHerbFlavor();
+
+        // Check the experiment value before the command line to put the user in the correct group.
+        // The first clause does the null checks so so we can freely use the startsWith() function.
+        String newFlavor = FieldTrialList.findFullName(HERB_EXPERIMENT_NAME);
+        Log.d(TAG, "Experiment flavor: " + newFlavor);
+        if (TextUtils.isEmpty(newFlavor)
+                || newFlavor.startsWith(ChromeSwitches.HERB_FLAVOR_CONTROL)
+                || newFlavor.startsWith(ChromeSwitches.HERB_FLAVOR_DEFAULT)) {
+            newFlavor = ChromeSwitches.HERB_FLAVOR_DISABLED;
+        } else if (newFlavor.startsWith(ChromeSwitches.HERB_FLAVOR_ANISE)) {
+            newFlavor = ChromeSwitches.HERB_FLAVOR_ANISE;
+        } else if (newFlavor.startsWith(ChromeSwitches.HERB_FLAVOR_BASIL)) {
+            newFlavor = ChromeSwitches.HERB_FLAVOR_BASIL;
+        } else if (newFlavor.startsWith(ChromeSwitches.HERB_FLAVOR_CHIVE)) {
+            newFlavor = ChromeSwitches.HERB_FLAVOR_CHIVE;
+        } else if (newFlavor.startsWith(ChromeSwitches.HERB_FLAVOR_DILL)) {
+            newFlavor = ChromeSwitches.HERB_FLAVOR_DILL;
+        }
+
+        CommandLine instance = CommandLine.getInstance();
+        if (instance.hasSwitch(ChromeSwitches.HERB_FLAVOR_DISABLED_SWITCH)) {
+            newFlavor = ChromeSwitches.HERB_FLAVOR_DISABLED;
+        } else if (instance.hasSwitch(ChromeSwitches.HERB_FLAVOR_ANISE_SWITCH)) {
+            newFlavor = ChromeSwitches.HERB_FLAVOR_ANISE;
+        } else if (instance.hasSwitch(ChromeSwitches.HERB_FLAVOR_BASIL_SWITCH)) {
+            newFlavor = ChromeSwitches.HERB_FLAVOR_BASIL;
+        } else if (instance.hasSwitch(ChromeSwitches.HERB_FLAVOR_CHIVE_SWITCH)) {
+            newFlavor = ChromeSwitches.HERB_FLAVOR_CHIVE;
+        } else if (instance.hasSwitch(ChromeSwitches.HERB_FLAVOR_DILL_SWITCH)) {
+            newFlavor = ChromeSwitches.HERB_FLAVOR_DILL;
+        }
+
+        Log.d(TAG, "Caching flavor: " + newFlavor);
+        sCachedHerbFlavor = newFlavor;
+
+        if (!TextUtils.equals(oldFlavor, newFlavor)) {
+            Context context = ApplicationStatus.getApplicationContext();
+            ChromePreferenceManager.getInstance(context).setCachedHerbFlavor(newFlavor);
+        }
+    }
+
     private static native void nativeSetDocumentModeEnabled(boolean enabled);
     private static native void nativeSetCustomTabVisible(boolean visible);
     public static native void nativeSetSqlMmapDisabledByDefault();
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 5ece304..bb8ed707 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -418,9 +418,12 @@
 
 For example, some websites may respond to this request by showing you ads that aren’t based on other websites you’ve visited. Many websites will still collect and use your browsing data — for example to improve security, to provide content, ads and recommendations, and to generate reporting statistics.
       </message>
-      <message name="IDS_CLEAR_BROWSING_DATA_TITLE" desc="Button to Clear Browsing Data [CHAR-LIMIT=24]">
+      <message name="IDS_CLEAR_BROWSING_DATA_TITLE" desc="Title of the Clear Browsing Data screen. [CHAR-LIMIT=32]">
         Clear browsing data
       </message>
+      <message name="IDS_CLEAR_BROWSING_DATA_SUMMARY" desc="Summary of the settings item that opens the Clear Browsing Data dialog.">
+        Clear history, cookies, site data, cache…
+      </message>
       <message name="IDS_CLEAR_BROWSING_DATA_FOOTNOTE" desc="A summary string at the bottom of the Clear Browsing Data dialog, informing the user that not all data can be cleared through this dialog.">
         Saved site settings will not be deleted and may reflect your browsing habits.
       </message>
@@ -2172,6 +2175,9 @@
       <message name="IDS_ACCESSIBILITY_TOOLBAR_BTN_MENU" desc="Content description for the settings menu button.">
         More options
       </message>
+      <message name="IDS_ACCESSIBILITY_TOOLBAR_BTN_MENU_UPDATE" desc="Content description for the menu button when it is covered by the update icon that is displayed when a newer version of Chrome is available.">
+        Update available. More options
+      </message>
       <message name="IDS_ACCESSIBILITY_TOOLBAR_BTN_SITE_INFO" desc="Content description for the page icon that gives more site information when clicked.  The icon can be a lock for secure pages, a magnifier for search result pages, or other icons representing the page state.">
         Site information
       </message>
@@ -2380,6 +2386,14 @@
       <message name="IDS_PHYSICAL_WEB_BOTTOM_BAR" desc="A message displayed in the nearby URLs list activity informing the user that a notification will appear whenever devices broadcasting URLs are nearby">
         Future nearby Physical Web pages will show up in your notifications list
       </message>
+
+    <!-- Password Manager strings -->
+      <message name="IDS_UPDATE_PASSWORD" desc="A message shown to users to allow updating a saved password for a site, shown in an infobar that appears after the user uses a different password to sign in to the site or uses a password change form.">
+        Do you want <ph name="PASSWORD_MANAGER_BRAND">^1<ex>Google Chrome</ex></ph> to update your password for this site?
+      </message>
+      <message name="IDS_UPDATE_PASSWORD_FOR_ACCOUNT" desc="A message shown to users to allow updating a saved password for a site, where user has multiple credentials saved, shown in an infobar that appears after user uses new password to sign in to the site or uses a password change form.">
+        Do you want <ph name="PASSWORD_MANAGER_BRAND">^1<ex>Google Chrome</ex></ph> to update the password for <ph name="USERNAME">^2<ex>don.john.lemon@example.com</ex></ph> for this site?
+      </message>
     </messages>
   </release>
 </grit>
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/AudioTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/AudioTest.java
index 6451373c..79f5a41 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/AudioTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/AudioTest.java
@@ -24,7 +24,6 @@
 
     public AudioTest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerIntegrationTest.java
index 484464c..609bd3ef 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerIntegrationTest.java
@@ -173,7 +173,6 @@
 
     public BindingManagerIntegrationTest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ChromeActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ChromeActivityTest.java
index 4524038..fe5b3d0e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ChromeActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ChromeActivityTest.java
@@ -27,10 +27,6 @@
 
     private EmbeddedTestServer mTestServer;
 
-    public ChromeActivityTest() {
-        mSkipCheckHttpServer = true;
-    }
-
     @Override
     protected void setUp() throws Exception {
         super.setUp();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/FocusedEditableTextFieldZoomTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/FocusedEditableTextFieldZoomTest.java
index 069887c..e49afef 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/FocusedEditableTextFieldZoomTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/FocusedEditableTextFieldZoomTest.java
@@ -33,7 +33,6 @@
 
     public FocusedEditableTextFieldZoomTest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/GeolocationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/GeolocationTest.java
index a220a27f..1bbc8115 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/GeolocationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/GeolocationTest.java
@@ -65,7 +65,6 @@
 
     public GeolocationTest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/HistoryUITest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/HistoryUITest.java
index c0fd264..2b909c3 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/HistoryUITest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/HistoryUITest.java
@@ -43,7 +43,6 @@
 
     public HistoryUITest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/MainActivityWithURLTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/MainActivityWithURLTest.java
index b434b45..f675102 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/MainActivityWithURLTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/MainActivityWithURLTest.java
@@ -18,10 +18,6 @@
  */
 public class MainActivityWithURLTest extends ChromeTabbedActivityTestBase {
 
-    public MainActivityWithURLTest() {
-        mSkipCheckHttpServer = true;
-    }
-
     @Override
     public void startMainActivity() {
         // Don't launch activity automatically.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
index affccda..36f1495 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
@@ -54,10 +54,6 @@
 
     private EmbeddedTestServer mTestServer;
 
-    public NavigateTest() {
-        mSkipCheckHttpServer = true;
-    }
-
     @Override
     protected void setUp() throws Exception {
         super.setUp();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/PopularUrlsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/PopularUrlsTest.java
index d803195..10cd2a75 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/PopularUrlsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/PopularUrlsTest.java
@@ -67,7 +67,6 @@
 
     @Override
     protected void setUp() throws Exception {
-        mSkipCheckHttpServer = true;
         mStatus = new RunStatus(STATUS_FILE);
         mFailed = false;
         mDoShortWait = checkDoShortWait();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/PopupTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/PopupTest.java
index e8e6714..cb53bfb 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/PopupTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/PopupTest.java
@@ -36,7 +36,6 @@
 
     public PopupTest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     private int getNumInfobarsShowing() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/PrerenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/PrerenderTest.java
index e928941..2ea23ed 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/PrerenderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/PrerenderTest.java
@@ -10,20 +10,16 @@
 import android.test.FlakyTest;
 import android.test.MoreAsserts;
 import android.test.suitebuilder.annotation.LargeTest;
-import android.view.KeyEvent;
 
 import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.Restriction;
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.omnibox.UrlBar;
 import org.chromium.chrome.browser.prerender.ExternalPrerenderHandler;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.test.ChromeTabbedActivityTestBase;
-import org.chromium.chrome.test.util.ChromeTabUtils;
 import org.chromium.chrome.test.util.PrerenderTestHelper;
 import org.chromium.chrome.test.util.browser.TabTitleObserver;
-import org.chromium.content.browser.test.util.KeyUtils;
 import org.chromium.net.test.EmbeddedTestServer;
 import org.chromium.ui.base.PageTransition;
 
@@ -38,10 +34,6 @@
 
     private EmbeddedTestServer mTestServer;
 
-    public PrerenderTest() {
-        mSkipCheckHttpServer = true;
-    }
-
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -90,16 +82,15 @@
     public void testPrerenderNotDead() throws InterruptedException, TimeoutException {
         String testUrl = mTestServer.getURL(
                 "/chrome/test/data/android/prerender/google.html");
-        PrerenderTestHelper.prerenderUrlAndFocusOmnibox(testUrl, this);
         final Tab tab = getActivity().getActivityTab();
+        PrerenderTestHelper.prerenderUrl(testUrl, tab);
         // Navigate should use the prerendered version.
-        assertEquals(TabLoadStatus.FULL_PRERENDERED_PAGE_LOAD,
-                loadUrlInTab(testUrl, PageTransition.TYPED | PageTransition.FROM_ADDRESS_BAR, tab));
+        assertEquals(TabLoadStatus.FULL_PRERENDERED_PAGE_LOAD, loadUrl(testUrl));
 
         // Prerender again with new text; make sure we get something different.
         String newTitle = "Welcome to the YouTube";
         testUrl = mTestServer.getURL("/chrome/test/data/android/prerender/youtube.html");
-        PrerenderTestHelper.prerenderUrlAndFocusOmnibox(testUrl, this);
+        PrerenderTestHelper.prerenderUrl(testUrl, tab);
 
         // Make sure the current tab title is NOT from the prerendered page.
         MoreAsserts.assertNotEqual(newTitle, tab.getTitle());
@@ -107,9 +98,7 @@
         TabTitleObserver observer = new TabTitleObserver(tab, newTitle);
 
         // Now commit and see the new title.
-        final UrlBar urlBar = (UrlBar) getActivity().findViewById(R.id.url_bar);
-        assertNotNull("urlBar is null", urlBar);
-        KeyUtils.singleKeyEventView(getInstrumentation(), urlBar, KeyEvent.KEYCODE_ENTER);
+        loadUrl(testUrl);
 
         observer.waitForTitleUpdate(5);
         assertEquals(newTitle, tab.getTitle());
@@ -124,18 +113,8 @@
     @Feature({"TabContents"})
     public void testPageLoadFinishNotification() throws InterruptedException {
         String url = mTestServer.getURL("/chrome/test/data/android/prerender/google.html");
-        PrerenderTestHelper.prerenderUrlAndFocusOmnibox(url, this);
-        // Now let's press enter to validate the suggestion. The prerendered page should be
-        // committed and we should get a page load finished notification (which would trigger the
-        // page load).
-        ChromeTabUtils.waitForTabPageLoaded(getActivity().getActivityTab(), new Runnable() {
-            @Override
-            public void run() {
-                final UrlBar urlBar = (UrlBar) getActivity().findViewById(R.id.url_bar);
-                assertNotNull("urlBar is null", urlBar);
-                KeyUtils.singleKeyEventView(getInstrumentation(), urlBar, KeyEvent.KEYCODE_ENTER);
-            }
-        });
+        PrerenderTestHelper.prerenderUrl(url, getActivity().getActivityTab());
+        loadUrl(url);
     }
 
     /**
@@ -144,24 +123,23 @@
      * Note that this bug happened with the instant code. Now that we use Wicked Fast, we don't
      * deal with infobars ourselves.
      */
+    /*
     @LargeTest
     @Restriction({RESTRICTION_TYPE_NON_LOW_END_DEVICE})
     @Feature({"TabContents"})
+    */
+    @DisabledTest  // Prerenderer disables infobars. crbug.com/588808
     public void testInfoBarDismissed() throws InterruptedException {
         final String url = mTestServer.getURL(
                 "/chrome/test/data/geolocation/geolocation_on_load.html");
-        final ExternalPrerenderHandler handler = PrerenderTestHelper.prerenderUrlAndFocusOmnibox(
-                url, this);
+        final ExternalPrerenderHandler handler =
+                PrerenderTestHelper.prerenderUrl(url, getActivity().getActivityTab());
 
-        // Let's clear the URL bar, this will discard the prerendered WebContents and close the
+        // Cancel the prerender. This will discard the prerendered WebContents and close the
         // infobars.
-        final UrlBar urlBar = (UrlBar) getActivity().findViewById(R.id.url_bar);
-        assertNotNull(urlBar);
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                urlBar.requestFocus();
-                urlBar.setText("");
                 handler.cancelCurrentPrerender();
             }
         });
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/RepostFormWarningTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/RepostFormWarningTest.java
index 89926d7..3aa4aa5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/RepostFormWarningTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/RepostFormWarningTest.java
@@ -35,7 +35,6 @@
 
     public RepostFormWarningTest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     @Override
@@ -70,7 +69,7 @@
 
         // Verify that the form resubmission warning was not shown.
         assertNull("Form resubmission warning shown upon first load.",
-                RepostFormWarningDialog.getCurrentDialog());
+                RepostFormWarningDialog.getCurrentDialogForTesting());
     }
 
     /** Verifies that confirming the form reload performs the reload. */
@@ -91,7 +90,7 @@
 
         // Verify that the reference to the dialog in RepostFormWarningDialog was cleared.
         assertNull("Form resubmission warning dialog was not dismissed correctly.",
-                RepostFormWarningDialog.getCurrentDialog());
+                RepostFormWarningDialog.getCurrentDialogForTesting());
     }
 
     /**
@@ -122,7 +121,37 @@
 
         // Verify that the reference to the dialog in RepostFormWarningDialog was cleared.
         assertNull("Form resubmission warning dialog was not dismissed correctly.",
-                RepostFormWarningDialog.getCurrentDialog());
+                RepostFormWarningDialog.getCurrentDialogForTesting());
+    }
+
+    /**
+     * Verifies that destroying the Tab dismisses the form resubmission dialog.
+     */
+    @SmallTest
+    @Feature({"Navigation"})
+    public void testFormResubmissionTabDestroyed() throws Throwable {
+        // Load the url posting data for the first time.
+        postNavigation();
+        mCallbackHelper.getOnPageFinishedHelper().waitForCallback(0);
+
+        // Trigger a reload and wait for the warning to be displayed.
+        reload();
+        waitForRepostFormWarningDialog();
+
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                getActivity().getCurrentTabModel().closeTab(mTab);
+            }
+        });
+
+        CriteriaHelper.pollForUIThreadCriteria(
+                new Criteria("Form resubmission dialog not dismissed correctly") {
+                    @Override
+                    public boolean isSatisfied() {
+                        return RepostFormWarningDialog.getCurrentDialogForTesting() == null;
+                    }
+                });
     }
 
     private AlertDialog waitForRepostFormWarningDialog() throws InterruptedException {
@@ -130,13 +159,13 @@
                 new Criteria("Form resubmission warning not shown") {
                     @Override
                     public boolean isSatisfied() {
-                        return RepostFormWarningDialog.getCurrentDialog() != null;
+                        return RepostFormWarningDialog.getCurrentDialogForTesting() != null;
                     }
                 });
         return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<AlertDialog>() {
             @Override
             public AlertDialog call() throws Exception {
-                return (AlertDialog) RepostFormWarningDialog.getCurrentDialog();
+                return (AlertDialog) RepostFormWarningDialog.getCurrentDialogForTesting();
             }
         });
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java
index ee492387..8e0ccfe 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java
@@ -153,10 +153,6 @@
 
     private EmbeddedTestServer mTestServer;
 
-    public TabsOpenedFromExternalAppTest() {
-        mSkipCheckHttpServer = true;
-    }
-
     @Override
     public void startMainActivity() {
         // We'll start the activity explicitly in the tests, as we need to start it with an intent
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
index 19c4d94..bd5031c0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
@@ -120,10 +120,6 @@
             + "  <div id=\"test\">No resize event has been received yet.</div>"
             + "</body></html>");
 
-    public TabsTest() {
-        mSkipCheckHttpServer = true;
-    }
-
     @Override
     protected void tearDown() throws Exception {
         if (mTestServer != null) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
index 50092868..75419df 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
@@ -163,10 +163,6 @@
     private EmbeddedTestServer mTestServer;
     private String mWebAppUrl;
 
-    public AppBannerManagerTest() {
-        mSkipCheckHttpServer = true;
-    }
-
     @Override
     public void startMainActivity() throws InterruptedException {
         startMainActivityOnBlankPage();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java
index 3203783b..d2775bf 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java
@@ -43,7 +43,6 @@
 
     public BookmarkTest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     private static final String TEST_PAGE = "/chrome/test/data/android/google.html";
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java
index 59b059e..f895f80 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java
@@ -46,10 +46,6 @@
     private EmbeddedTestServer mTestServer;
     private String mTestUrl;
 
-    public ContextMenuTest() {
-        mSkipCheckHttpServer = true;
-    }
-
     @Override
     protected void setUp() throws Exception {
         mTestServer = EmbeddedTestServer.createAndStartFileServer(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
index 83b733d..c1ec9ac 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -102,7 +102,6 @@
 
     public ContextualSearchManagerTest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
index cb65925..ef2799e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -106,10 +106,6 @@
     private String mTestPage2;
     private EmbeddedTestServer mTestServer;
 
-    public CustomTabActivityTest() {
-        mSkipCheckHttpServer = true;
-    }
-
     @Override
     protected void setUp() throws Exception {
         super.setUp();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabExternalNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabExternalNavigationTest.java
index a24286a..c550b64 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabExternalNavigationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabExternalNavigationTest.java
@@ -49,10 +49,6 @@
     private EmbeddedTestServer mTestServer;
     private ExternalNavigationHandler mUrlHandler;
 
-    public CustomTabExternalNavigationTest() {
-        mSkipCheckHttpServer = true;
-    }
-
     @Override
     public void setUp() throws Exception {
         mTestServer = EmbeddedTestServer.createAndStartFileServer(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/ChromeDownloadDelegateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/ChromeDownloadDelegateTest.java
index e16201d..0c12de9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/ChromeDownloadDelegateTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/ChromeDownloadDelegateTest.java
@@ -41,53 +41,6 @@
     }
 
     /**
-     * Test to make sure {@link ChromeDownloadDelegate#fileName} returns the
-     * right file for different URLs and MIME types.
-     */
-    @SmallTest
-    @Feature({"Download"})
-    public void testFileName() {
-        String testUrl = "http://server.com/file.pdf";
-        assertEquals("file.pdf", ChromeDownloadDelegate.fileName(testUrl, "application/pdf", ""));
-        assertEquals("file.pdf", ChromeDownloadDelegate.fileName(testUrl, "", ""));
-
-        // .php is an unknown MIME format extension.
-        // This used to generate file.php even when the MIME type was set.
-        // http://code.google.com/p/chromium/issues/detail?id=134396
-        testUrl = "http://server.com/file.php";
-
-        assertEquals("file.pdf", ChromeDownloadDelegate.fileName(testUrl, "application/pdf", ""));
-        assertEquals("file.php", ChromeDownloadDelegate.fileName(testUrl, "", ""));
-
-        // .xml is a known MIME format extension.
-        testUrl = "http://server.com/file.xml";
-        assertEquals("file.xml", ChromeDownloadDelegate.fileName(testUrl, "", ""));
-
-        assertEquals("file.pdf", ChromeDownloadDelegate.fileName(testUrl, "application/pdf", ""));
-
-        // If the file's extension and HTTP header's MIME type are the same, use
-        // the former to derive the final extension.
-        // https://code.google.com/p/chromium/issues/detail?id=170852
-        testUrl = "http://server.com/file.mp3";
-        assertEquals("file.mp3", ChromeDownloadDelegate.fileName(testUrl, "audio/mpeg", ""));
-
-        testUrl = "http://server.com/";
-        assertEquals("downloadfile.bin", ChromeDownloadDelegate.fileName(testUrl, "", ""));
-        assertEquals("downloadfile.pdf",
-                ChromeDownloadDelegate.fileName(testUrl, "application/pdf", ""));
-
-        // Fails to match the filename pattern from header; uses one from url.
-        // Note that header itself is a valid one.
-        testUrl = "http://server.com/file.pdf";
-        assertEquals("file.pdf", ChromeDownloadDelegate.fileName(testUrl, "application/pdf",
-                "attachment; name=\"foo\"; filename=\"bar\""));
-        assertEquals("file.pdf", ChromeDownloadDelegate.fileName(testUrl, "application/pdf",
-                "attachment; filename=\"bar\"; name=\"foo\""));
-        assertEquals("file.pdf", ChromeDownloadDelegate.fileName(testUrl, "application/pdf",
-                "attachment; filename=\"bar\"; filename*=utf-8''baz"));
-    }
-
-    /**
      * Test to make sure {@link ChromeDownloadDelegate#shouldInterceptContextMenuDownload}
      * returns true only for ".dd" or ".dm" extensions with http/https scheme.
      */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTest.java
index b7fe7d03..5551d68 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTest.java
@@ -38,10 +38,6 @@
 
     private EmbeddedTestServer mTestServer;
 
-    public DownloadTest() {
-        mSkipCheckHttpServer = true;
-    }
-
     @Override
     protected void setUp() throws Exception {
         super.setUp();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java
index 084a60d0..7159f16 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java
@@ -108,7 +108,6 @@
 
     public UrlOverridingTest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java
index 61c0050e..dca5582 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java
@@ -82,10 +82,6 @@
             + "</body>"
             + "</html>");
 
-    public FullscreenManagerTest() {
-        mSkipCheckHttpServer = true;
-    }
-
     @MediumTest
     @Feature({"Fullscreen"})
     public void testTogglePersistentFullscreen() throws InterruptedException {
@@ -306,7 +302,7 @@
             final Tab tab = getActivity().getActivityTab();
             final String testUrl = testServer.getURL(
                     "/chrome/test/data/android/very_long_google.html");
-            PrerenderTestHelper.prerenderUrlAndFocusOmnibox(testUrl, this);
+            PrerenderTestHelper.prerenderUrl(testUrl, tab);
             assertTrue("loadUrl did not use pre-rendered page.",
                     PrerenderTestHelper.isLoadUrlResultPrerendered(loadUrl(testUrl)));
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarContainerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarContainerTest.java
index e1745da..6ba20df 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarContainerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarContainerTest.java
@@ -61,7 +61,6 @@
 
     public InfoBarContainerTest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest.java
index 4fc2be8..f4f6cdd 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest.java
@@ -47,7 +47,6 @@
 
     public InfoBarTest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/PermissionUpdateInfobarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/PermissionUpdateInfobarTest.java
index 53ea54a..6697902 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/PermissionUpdateInfobarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/PermissionUpdateInfobarTest.java
@@ -43,10 +43,6 @@
     private InfoBarTestAnimationListener mListener;
     private EmbeddedTestServer mTestServer;
 
-    public PermissionUpdateInfobarTest() {
-        mSkipCheckHttpServer = true;
-    }
-
     @Override
     public void startMainActivity() throws InterruptedException {
         startMainActivityOnBlankPage();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/RouterTestUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/RouterTestUtils.java
new file mode 100644
index 0000000..7a1ea95
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/RouterTestUtils.java
@@ -0,0 +1,160 @@
+// Copyright 2016 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.
+
+package org.chromium.chrome.browser.media;
+
+import android.app.Instrumentation;
+import android.os.SystemClock;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.app.FragmentManager;
+import android.view.MotionEvent;
+import android.view.View;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.content.browser.test.util.Criteria;
+import org.chromium.content.browser.test.util.CriteriaHelper;
+import org.chromium.content.browser.test.util.TestTouchUtils;
+
+import java.util.ArrayList;
+import java.util.concurrent.Callable;
+
+/**
+ * Test utils shared by MediaRouter and MediaRemote.
+ */
+public class RouterTestUtils {
+    public static View waitForRouteButton(
+            final ChromeActivity activity, final String chromecastName,
+            int maxTimeoutMs, int intervalMs) {
+        return waitForView(new Callable<View>() {
+            @Override
+            public View call() {
+                DialogFragment mediaRouteListFragment = getDialogFragment(activity);
+                if (mediaRouteListFragment == null || mediaRouteListFragment.getDialog() == null) {
+                    return null;
+                }
+                View mediaRouteList =
+                        mediaRouteListFragment.getDialog().findViewById(R.id.mr_chooser_list);
+                if (mediaRouteList == null) return null;
+                ArrayList<View> routesWanted = new ArrayList<View>();
+                mediaRouteList.findViewsWithText(routesWanted, chromecastName,
+                        View.FIND_VIEWS_WITH_TEXT);
+                if (routesWanted.size() == 0) return null;
+
+                return routesWanted.get(0);
+            }
+            }, maxTimeoutMs, intervalMs);
+    }
+
+    public static DialogFragment getDialogFragment(ChromeActivity activity) {
+        FragmentManager fm = activity.getSupportFragmentManager();
+        if (fm == null) return null;
+        return (DialogFragment) fm.findFragmentByTag(
+            "android.support.v7.mediarouter:MediaRouteChooserDialogFragment");
+    }
+
+    public static View waitForView(
+            final Callable<View> getViewCallable, int maxTimeoutMs, int intervalMs) {
+        try {
+            CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+                    @Override
+                    public boolean isSatisfied() {
+                        try {
+                            return getViewCallable.call() != null;
+                        } catch (Exception e) {
+                            return false;
+                        }
+                    }
+                }, maxTimeoutMs, intervalMs);
+            return getViewCallable.call();
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    /**
+     * Click a button. Unlike {@link RouterTestUtils#mouseSingleClickView} this directly accesses
+     * the view and does not send motion events though the message queue. As such it doesn't require
+     * the view to have been created by the instrumented activity, but gives less flexibility than
+     * mouseSingleClickView. For example, if the view is hierachical, then clickButton will always
+     * act on specified view, whereas mouseSingleClickView will send the events to the appropriate
+     * child view. It is hence only really appropriate for simple views such as buttons.
+     *
+     * @param button the button to be clicked.
+     */
+    public static void clickButton(final View button) {
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+                @Override
+            public void run() {
+                // Post the actual click to the button's message queue, to ensure that it has been
+                // inflated before the click is received.
+                button.post(new Runnable() {
+                        @Override
+                    public void run() {
+                        button.performClick();
+                    }
+                });
+            }
+        });
+    }
+
+    private static void sendMouseAction(Instrumentation instrumentation, int action, long downTime,
+            float x, float y) {
+        long eventTime = SystemClock.uptimeMillis();
+        MotionEvent.PointerCoords coords[] = new MotionEvent.PointerCoords[1];
+        coords[0] = new MotionEvent.PointerCoords();
+        coords[0].x = x;
+        coords[0].y = y;
+        MotionEvent.PointerProperties properties[] = new MotionEvent.PointerProperties[1];
+        properties[0] = new MotionEvent.PointerProperties();
+        properties[0].id = 0;
+        properties[0].toolType = MotionEvent.TOOL_TYPE_MOUSE;
+        MotionEvent event = MotionEvent.obtain(downTime, eventTime, action, 1, properties, coords,
+                0, 0, 0.0f, 0.0f, 0, 0, 0, 0);
+        instrumentation.sendPointerSync(event);
+        instrumentation.waitForIdleSync();
+    }
+
+    /**
+     * Sends (synchronously) a single mosue click to an absolute screen coordinates.
+     *
+     * @param instrumentation Instrumentation object used by the test.
+     * @param x Screen absolute x location.
+     * @param y Screen absolute y location.
+     */
+    private static void mouseSingleClick(Instrumentation instrumentation, float x, float y) {
+        long downTime = SystemClock.uptimeMillis();
+        sendMouseAction(instrumentation, MotionEvent.ACTION_DOWN, downTime, x, y);
+        sendMouseAction(instrumentation, MotionEvent.ACTION_UP, downTime, x, y);
+    }
+
+    /**
+     * Sends (synchronously) a single mouse click to the View at the specified coordinates.
+     *
+     * @param instrumentation Instrumentation object used by the test.
+     * @param v The view the coordinates are relative to.
+     * @param x Relative x location to the view.
+     * @param y Relative y location to the view.
+     */
+    public static void mouseSingleClickView(Instrumentation instrumentation, View v, int x,
+            int y) {
+        int location[] = TestTouchUtils.getAbsoluteLocationFromRelative(v, x, y);
+        int absoluteX = location[0];
+        int absoluteY = location[1];
+        mouseSingleClick(instrumentation, absoluteX, absoluteY);
+    }
+
+    /**
+     * Sends (synchronously) a single mouse click to the center of the View.
+     *
+     * @param instrumentation Instrumentation object used by the test.
+     * @param v The view the coordinates are relative to.
+     */
+    public static void mouseSingleClickView(Instrumentation instrumentation, View v) {
+        int x = v.getWidth() / 2;
+        int y = v.getHeight() / 2;
+        mouseSingleClickView(instrumentation, v, x, y);
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastTestBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastTestBase.java
index 0480ea8..f1f642a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastTestBase.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastTestBase.java
@@ -5,34 +5,29 @@
 package org.chromium.chrome.browser.media.remote;
 
 import android.app.Dialog;
-import android.app.Instrumentation;
 import android.graphics.Rect;
 import android.os.Environment;
 import android.os.StrictMode;
-import android.os.SystemClock;
 import android.support.v4.app.DialogFragment;
 import android.support.v4.app.FragmentManager;
-import android.view.MotionEvent;
 import android.view.View;
 
 import junit.framework.Assert;
 
 import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
-import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.media.RouterTestUtils;
 import org.chromium.chrome.browser.media.remote.RemoteVideoInfo.PlayerState;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.test.ChromeActivityTestCaseBase;
 import org.chromium.content.browser.ContentViewCore;
 import org.chromium.content.browser.test.util.DOMUtils;
 import org.chromium.content.browser.test.util.JavaScriptUtils;
-import org.chromium.content.browser.test.util.TestTouchUtils;
 import org.chromium.content.browser.test.util.UiUtils;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.net.test.EmbeddedTestServer;
 
-import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.concurrent.Callable;
@@ -130,7 +125,6 @@
 
     public CastTestBase() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     @Override
@@ -315,34 +309,11 @@
             fail();
         }
 
-        View testRouteButton = waitForRouteButton(chromecastName);
+        View testRouteButton = RouterTestUtils.waitForRouteButton(
+                getActivity(), chromecastName, MAX_VIEW_TIME_MS, VIEW_RETRY_MS);
         assertNotNull("Test route not found", testRouteButton);
 
-        mouseSingleClickView(getInstrumentation(), testRouteButton);
-    }
-
-    protected View waitForRouteButton(final String chromecastName) {
-        return waitForView(new Callable<View>() {
-            @Override
-            public View call() {
-                FragmentManager fm = getActivity().getSupportFragmentManager();
-                if (fm == null) return null;
-                DialogFragment mediaRouteListFragment = (DialogFragment) fm.findFragmentByTag(
-                        "android.support.v7.mediarouter:MediaRouteChooserDialogFragment");
-                if (mediaRouteListFragment == null || mediaRouteListFragment.getDialog() == null) {
-                    return null;
-                }
-                View mediaRouteList =
-                        mediaRouteListFragment.getDialog().findViewById(R.id.mr_chooser_list);
-                if (mediaRouteList == null) return null;
-                ArrayList<View> routesWanted = new ArrayList<View>();
-                mediaRouteList.findViewsWithText(routesWanted, chromecastName,
-                        View.FIND_VIEWS_WITH_TEXT);
-                if (routesWanted.size() == 0) return null;
-
-                return routesWanted.get(0);
-            }
-        }, MAX_VIEW_TIME_MS);
+        RouterTestUtils.mouseSingleClickView(getInstrumentation(), testRouteButton);
     }
 
     protected void checkDisconnected() {
@@ -366,7 +337,7 @@
         tapCastButton(tab, videoRect);
 
         // Wait for the disconnect button
-        final View disconnectButton = waitForView(new Callable<View>() {
+        final View disconnectButton = RouterTestUtils.waitForView(new Callable<View>() {
             @Override
             public View call() {
                 FragmentManager fm = getActivity().getSupportFragmentManager();
@@ -383,11 +354,11 @@
                 //               https://crbug/548599
                 return dialog.findViewById(android.R.id.button1);
             }
-        }, MAX_VIEW_TIME_MS);
+        }, MAX_VIEW_TIME_MS, VIEW_RETRY_MS);
 
         assertNotNull("No disconnect button", disconnectButton);
 
-        clickButton(disconnectButton);
+        RouterTestUtils.clickButton(disconnectButton);
     }
 
     /*
@@ -414,32 +385,6 @@
                 .getCurrentlyPlayingMediaRouteController() instanceof DefaultMediaRouteController));
     }
 
-    /**
-     * Click a button. Unlike {@link CastTestBase#mouseSingleClickView} this directly accesses the
-     * view and does not send motion events though the message queue. As such it doesn't require the
-     * view to have been created by the instrumented activity, but gives less flexibility than
-     * mouseSingleClickView. For example, if the view is hierachical, then clickButton will always
-     * act on specified view, whereas mouseSingleClickView will send the events to the appropriate
-     * child view. It is hence only really appropriate for simple views such as buttons.
-     *
-     * @param button the button to be clicked.
-     */
-    protected void clickButton(final View button) {
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-                @Override
-            public void run() {
-                // Post the actual click to the button's message queue, to ensure that it has been
-                // inflated before the click is received.
-                button.post(new Runnable() {
-                        @Override
-                    public void run() {
-                        button.performClick();
-                    }
-                });
-            }
-        });
-    }
-
     protected void sleepNoThrow(long timeout) {
         try {
             Thread.sleep(timeout);
@@ -460,19 +405,6 @@
         tapButton(tab, playPauseButton(videoRect));
     }
 
-    protected View waitForView(Callable<View> getViewCallable, int timeoutMs) {
-        for (int time = 0; time < timeoutMs; time += VIEW_RETRY_MS) {
-            try {
-                View result = ThreadUtils.runOnUiThreadBlocking(getViewCallable);
-                if (result != null) return result;
-            } catch (Exception e) {
-                fail(e.toString());
-            }
-            sleepNoThrow(VIEW_RETRY_MS);
-        }
-        return null;
-    }
-
     protected CastNotificationControl waitForCastNotification() {
         for (int time = 0; time < MAX_VIEW_TIME_MS; time += VIEW_RETRY_MS) {
             CastNotificationControl result = ThreadUtils.runOnUiThreadBlockingNoException(
@@ -627,65 +559,8 @@
                         ((float) (rect.top + rect.bottom)) / 2)
                 + core.getTopControlsHeightPix();
         // Click using a virtual mouse, since a touch may result in a disambiguation pop-up.
-        mouseSingleClickView(getInstrumentation(), tab.getView(), clickX, clickY);
+        RouterTestUtils.mouseSingleClickView(getInstrumentation(), tab.getView(), clickX, clickY);
     }
 
-    private static void sendMouseAction(Instrumentation instrumentation, int action, long downTime,
-            float x, float y) {
-        long eventTime = SystemClock.uptimeMillis();
-        MotionEvent.PointerCoords coords[] = new MotionEvent.PointerCoords[1];
-        coords[0] = new MotionEvent.PointerCoords();
-        coords[0].x = x;
-        coords[0].y = y;
-        MotionEvent.PointerProperties properties[] = new MotionEvent.PointerProperties[1];
-        properties[0] = new MotionEvent.PointerProperties();
-        properties[0].id = 0;
-        properties[0].toolType = MotionEvent.TOOL_TYPE_MOUSE;
-        MotionEvent event = MotionEvent.obtain(downTime, eventTime, action, 1, properties, coords,
-                0, 0, 0.0f, 0.0f, 0, 0, 0, 0);
-        instrumentation.sendPointerSync(event);
-        instrumentation.waitForIdleSync();
-    }
-
-    /**
-     * Sends (synchronously) a single mosue click to an absolute screen coordinates.
-     *
-     * @param instrumentation Instrumentation object used by the test.
-     * @param x Screen absolute x location.
-     * @param y Screen absolute y location.
-     */
-    private static void mouseSingleClick(Instrumentation instrumentation, float x, float y) {
-        long downTime = SystemClock.uptimeMillis();
-        sendMouseAction(instrumentation, MotionEvent.ACTION_DOWN, downTime, x, y);
-        sendMouseAction(instrumentation, MotionEvent.ACTION_UP, downTime, x, y);
-    }
-
-    /**
-     * Sends (synchronously) a single mouse click to the View at the specified coordinates.
-     *
-     * @param instrumentation Instrumentation object used by the test.
-     * @param v The view the coordinates are relative to.
-     * @param x Relative x location to the view.
-     * @param y Relative y location to the view.
-     */
-    private static void mouseSingleClickView(Instrumentation instrumentation, View v, int x,
-            int y) {
-        int location[] = TestTouchUtils.getAbsoluteLocationFromRelative(v, x, y);
-        int absoluteX = location[0];
-        int absoluteY = location[1];
-        mouseSingleClick(instrumentation, absoluteX, absoluteY);
-    }
-
-    /**
-     * Sends (synchronously) a single mouse click to the center of the View.
-     *
-     * @param instrumentation Instrumentation object used by the test.
-     * @param v The view the coordinates are relative to.
-     */
-    private static void mouseSingleClickView(Instrumentation instrumentation, View v) {
-        int x = v.getWidth() / 2;
-        int y = v.getHeight() / 2;
-        mouseSingleClickView(instrumentation, v, x, y);
-    }
 
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/PauseOnHeadsetUnplugTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/PauseOnHeadsetUnplugTest.java
index e02f9c4..eb9a243 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/PauseOnHeadsetUnplugTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/PauseOnHeadsetUnplugTest.java
@@ -35,7 +35,6 @@
 
     public PauseOnHeadsetUnplugTest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     @SmallTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationTestBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationTestBase.java
index 88c6c80b..035a796 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationTestBase.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationTestBase.java
@@ -37,10 +37,6 @@
     private MockNotificationManagerProxy mMockNotificationManager;
     private EmbeddedTestServer mTestServer;
 
-    public NotificationTestBase() {
-        mSkipCheckHttpServer = true;
-    }
-
     @Override
     protected void setUp() throws Exception {
         super.setUp();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageNavigationTest.java
index 9e05d68..3458b7d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageNavigationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageNavigationTest.java
@@ -22,10 +22,6 @@
 
     private EmbeddedTestServer mTestServer;
 
-    public NewTabPageNavigationTest() {
-        mSkipCheckHttpServer = true;
-    }
-
     @Override
     protected void setUp() throws Exception {
         super.setUp();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java
index 7a87132..46a3b945 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java
@@ -46,7 +46,6 @@
 
     public OfflinePageBridgeTest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsTest.java
index 880fa0a..7e7a2c0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsTest.java
@@ -45,7 +45,6 @@
 
     public OfflinePageUtilsTest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
index 76fa1f6c..34fb7bd 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
@@ -58,7 +58,6 @@
 
     public OmniboxTest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     private void clearUrlBar() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/QueryInOmniboxTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/QueryInOmniboxTest.java
index 1f4475d..7f91a64f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/QueryInOmniboxTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/QueryInOmniboxTest.java
@@ -56,7 +56,6 @@
 
     public QueryInOmniboxTest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeIntegrationTest.java
index 8e83289..bf1865b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeIntegrationTest.java
@@ -31,10 +31,6 @@
 public class PartnerDisableIncognitoModeIntegrationTest extends
         BasePartnerBrowserCustomizationIntegrationTest {
 
-    public PartnerDisableIncognitoModeIntegrationTest() {
-        mSkipCheckHttpServer = true;
-    }
-
     @Override
     public void startMainActivity() throws InterruptedException {
         // Each test will launch main activity, so purposefully omit here.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageIntegrationTest.java
index c616b619..4db649dd 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageIntegrationTest.java
@@ -44,10 +44,6 @@
 public class PartnerHomepageIntegrationTest extends BasePartnerBrowserCustomizationIntegrationTest {
     private static final String TEST_PAGE = "/chrome/test/data/android/about.html";
 
-    public PartnerHomepageIntegrationTest() {
-        mSkipCheckHttpServer = true;
-    }
-
     @Override
     public void startMainActivity() throws InterruptedException {
         ThreadUtils.runOnUiThreadBlocking(new Runnable(){
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/website/SiteSettingsPreferencesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/website/SiteSettingsPreferencesTest.java
index e0e73eb7..58a1a13c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/website/SiteSettingsPreferencesTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/website/SiteSettingsPreferencesTest.java
@@ -42,7 +42,6 @@
 
     public SiteSettingsPreferencesTest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/prerender/ExternalPrerenderRequestTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/prerender/ExternalPrerenderRequestTest.java
index ddbe3fe..de527e95 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/prerender/ExternalPrerenderRequestTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/prerender/ExternalPrerenderRequestTest.java
@@ -40,7 +40,6 @@
 
     public ExternalPrerenderRequestTest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateTest.java
index b7e3332..3b5d2d8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateTest.java
@@ -59,7 +59,6 @@
 
     public InterceptNavigationDelegateTest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabUmaTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabUmaTest.java
index b11a283..3598ec7 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabUmaTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/TabUmaTest.java
@@ -34,7 +34,6 @@
 
     public TabUmaTest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreatorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreatorTest.java
index 59acd123..44052aea 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreatorTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreatorTest.java
@@ -31,10 +31,6 @@
 
     private EmbeddedTestServer mTestServer;
 
-    public ChromeTabCreatorTest() {
-        mSkipCheckHttpServer = true;
-    }
-
     @Override
     protected void setUp() throws Exception {
         super.setUp();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ContextMenuLoadUrlParamsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ContextMenuLoadUrlParamsTest.java
index 4ddbb66..d447a95af 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ContextMenuLoadUrlParamsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/ContextMenuLoadUrlParamsTest.java
@@ -52,10 +52,6 @@
         }
     }
 
-    public ContextMenuLoadUrlParamsTest() {
-        mSkipCheckHttpServer = true;
-    }
-
     @Override
     protected void setUp() throws Exception {
         // Plant RecordingTabModelSelector as the TabModelSelector used in Main. The factory has to
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateInfoBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateInfoBarTest.java
index c02c565..1de6882 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateInfoBarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateInfoBarTest.java
@@ -40,7 +40,6 @@
 
     public TranslateInfoBarTest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/video/FullscreenVideoTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/video/FullscreenVideoTest.java
index 2ad03bc..4c27465 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/video/FullscreenVideoTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/video/FullscreenVideoTest.java
@@ -34,7 +34,6 @@
 
     public FullscreenVideoTest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/video/VideoTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/video/VideoTest.java
index 8393d50..a0b1e6b5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/video/VideoTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/video/VideoTest.java
@@ -25,7 +25,6 @@
 
     public VideoTest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     @DisableIf.Build(sdk_is_less_than = 19, message = "crbug.com/582067")
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenDialogHelperTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenDialogHelperTest.java
index 142f250f..764e4af9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenDialogHelperTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenDialogHelperTest.java
@@ -108,7 +108,6 @@
 
     public AddToHomescreenDialogHelperTest() {
         super(ChromeActivity.class);
-        mSkipCheckHttpServer = true;
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/findinpage/FindTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/findinpage/FindTest.java
index 79bde2e7..2a67ce64 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/findinpage/FindTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/findinpage/FindTest.java
@@ -43,10 +43,6 @@
 
     private EmbeddedTestServer mTestServer;
 
-    public FindTest() {
-        mSkipCheckHttpServer = true;
-    }
-
     @Override
     protected void setUp() throws Exception {
         super.setUp();
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/BookmarkUtilsTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/BookmarkUtilsTest.java
index a83f662f..7a136c751 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/BookmarkUtilsTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/BookmarkUtilsTest.java
@@ -6,29 +6,43 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
 
+
+import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
 
+import org.chromium.base.ApplicationStatus;
+import org.chromium.base.BaseChromiumApplication;
 import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.browser.snackbar.SnackbarManager;
+import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.components.bookmarks.BookmarkId;
 import org.chromium.components.bookmarks.BookmarkType;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.testing.local.LocalRobolectricTestRunner;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.robolectric.Robolectric;
 import org.robolectric.annotation.Config;
 
 /**
  * Robolectric tests for {@link BookmarkUtils}.
  */
 @RunWith(LocalRobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
+@Config(manifest = Config.NONE, application = BaseChromiumApplication.class)
 public class BookmarkUtilsTest {
     @Mock private Context mContext;
     @Mock private BookmarkModel mBookmarkModel;
@@ -66,4 +80,65 @@
         assertEquals(mWebContents, intentArgumentCaptor.getValue()
                 .getParcelableExtra(BookmarkEditActivity.INTENT_WEB_CONTENTS));
     }
+
+    @Test
+    @Feature({"Bookmark"})
+    public void testSaveBookmarkOfflineNoBookmark() {
+        ApplicationStatus.initialize((BaseChromiumApplication) Robolectric.application);
+        Tab tab = new Tab(0, true, null);
+        BookmarkModel model = mock(BookmarkModel.class);
+        SnackbarManager snackbarManager = mock(SnackbarManager.class);
+        Activity activity = mock(Activity.class);
+
+        when(model.doesBookmarkExist(new BookmarkId(12345L, BookmarkType.NORMAL)))
+                .thenReturn(false);
+        BookmarkUtils.saveBookmarkOffline(12345L, model, tab, snackbarManager, activity);
+        verify(model).doesBookmarkExist(new BookmarkId(12345L, BookmarkType.NORMAL));
+
+        verifyNoMoreInteractions(model);
+        verifyNoMoreInteractions(snackbarManager);
+        verifyNoMoreInteractions(activity);
+    }
+
+    @Test
+    @Feature({"Bookmark"})
+    public void testSaveBookmarkOfflineSadTab() {
+        ApplicationStatus.initialize((BaseChromiumApplication) Robolectric.application);
+        Tab tab = new Tab(0, true, null);
+        BookmarkModel model = mock(BookmarkModel.class);
+        SnackbarManager snackbarManager = mock(SnackbarManager.class);
+        Activity activity = mock(Activity.class);
+
+        tab.setIsShowingErrorPage(true);
+
+        when(model.doesBookmarkExist(new BookmarkId(12345L, BookmarkType.NORMAL))).thenReturn(true);
+        BookmarkUtils.saveBookmarkOffline(12345L, model, tab, snackbarManager, activity);
+        verify(model).doesBookmarkExist(new BookmarkId(12345L, BookmarkType.NORMAL));
+
+        verifyNoMoreInteractions(model);
+        verifyNoMoreInteractions(snackbarManager);
+        verifyNoMoreInteractions(activity);
+    }
+
+    @Test
+    @Feature({"Bookmark"})
+    public void testSaveBookmarkOffline() {
+        ApplicationStatus.initialize((BaseChromiumApplication) Robolectric.application);
+        Tab tab = new Tab(0, true, null);
+        BookmarkModel model = mock(BookmarkModel.class);
+        SnackbarManager snackbarManager = mock(SnackbarManager.class);
+        Activity activity = mock(Activity.class);
+        BookmarkId id = new BookmarkId(12345L, BookmarkType.NORMAL);
+        when(model.doesBookmarkExist(id)).thenReturn(true);
+        doNothing().when(model).saveOfflinePage(eq(id), any(WebContents.class),
+                any(BookmarkModel.AddBookmarkCallback.class));
+        BookmarkUtils.saveBookmarkOffline(12345L, model, tab, snackbarManager, activity);
+        verify(model).doesBookmarkExist(id);
+        verify(model).saveOfflinePage(eq(id), any(WebContents.class),
+                any(BookmarkModel.AddBookmarkCallback.class));
+
+        verifyNoMoreInteractions(model);
+        verifyNoMoreInteractions(snackbarManager);
+        verifyNoMoreInteractions(activity);
+    }
 }
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java
index fe143b7..e2e7fa1a 100644
--- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java
+++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java
@@ -11,7 +11,6 @@
 import org.chromium.base.ActivityState;
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.ThreadUtils;
-import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.signin.AccountIdProvider;
@@ -62,9 +61,8 @@
         SyncTestUtil.verifySyncIsActiveForAccount(mContext, account);
     }
 
-    // @LargeTest
-    // @Feature({"Sync"})
-    @DisabledTest
+    @LargeTest
+    @Feature({"Sync"})
     public void testRename() throws InterruptedException {
         // The two accounts object that would represent the account rename.
         final Account oldAccount = setUpTestAccountAndSignInToSync();
@@ -78,6 +76,7 @@
                 // real account rename events instead of the mocks.
                 MockChangeEventChecker eventChecker = new MockChangeEventChecker();
                 eventChecker.insertRenameEvent(oldAccount.name, newAccount.name);
+                SigninHelper.resetAccountRenameEventIndex(mContext);
                 SigninHelper.updateAccountRenameData(mContext, eventChecker);
 
                 // Tell the fake content resolver that a rename had happen and copy over the sync
@@ -88,8 +87,9 @@
                 // Inform the AccountTracker, these would normally be done by account validation
                 // or signin. We will only be calling the testing versions of it.
                 AccountIdProvider provider = AccountIdProvider.getInstance();
-                String[] accountNames = {newAccount.name};
-                String[] accountIds = {provider.getAccountId(mContext, accountNames[0])};
+                String[] accountNames = {oldAccount.name, newAccount.name};
+                String[] accountIds = {provider.getAccountId(mContext, accountNames[0]),
+                                       provider.getAccountId(mContext, accountNames[1])};
                 AccountTrackerService.get(mContext).syncForceRefreshForTest(
                         accountIds, accountNames);
 
diff --git a/chrome/app/DEPS b/chrome/app/DEPS
index 6587f5b..a672a05 100644
--- a/chrome/app/DEPS
+++ b/chrome/app/DEPS
@@ -3,6 +3,7 @@
   "+chrome/browser",
   "+chrome/child",
   "+chrome/chrome_watcher",
+  "+chrome/common/chrome_features.h",
   "+chrome/grit",  # For generated headers
   "+chrome/installer",
   "+chrome/plugin/chrome_content_plugin_client.h",
diff --git a/chrome/app/chrome_crash_reporter_client.cc b/chrome/app/chrome_crash_reporter_client.cc
index 5ffda19..7e43daf 100644
--- a/chrome/app/chrome_crash_reporter_client.cc
+++ b/chrome/app/chrome_crash_reporter_client.cc
@@ -33,7 +33,7 @@
 #include "policy/policy_constants.h"
 #endif
 
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
 #include "components/upload_list/crash_upload_list.h"
 #include "components/version_info/version_info_values.h"
 #endif
@@ -252,7 +252,7 @@
 }
 #endif  // defined(OS_WIN)
 
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
 void ChromeCrashReporterClient::GetProductNameAndVersion(
     const char** product_name,
     const char** version) {
diff --git a/chrome/app/chrome_crash_reporter_client.h b/chrome/app/chrome_crash_reporter_client.h
index 32a1684..5cdeac26 100644
--- a/chrome/app/chrome_crash_reporter_client.h
+++ b/chrome/app/chrome_crash_reporter_client.h
@@ -48,7 +48,7 @@
                                     bool succeeded) override;
 #endif
 
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
   void GetProductNameAndVersion(const char** product_name,
                                 const char** version) override;
   base::FilePath GetReporterLogFilename() override;
diff --git a/chrome/app/chrome_main.cc b/chrome/app/chrome_main.cc
index 041ecc4..0ad602a 100644
--- a/chrome/app/chrome_main.cc
+++ b/chrome/app/chrome_main.cc
@@ -5,8 +5,14 @@
 #include "chrome/app/chrome_main_delegate.h"
 
 #include "build/build_config.h"
+#include "chrome/common/features.h"
 #include "content/public/app/content_main.h"
 
+#if BUILDFLAG(ENABLE_PACKAGE_MASH_SERVICES)
+#include "base/command_line.h"
+#include "chrome/app/mash/mash_runner.h"
+#endif
+
 #if defined(OS_WIN)
 #include "base/debug/dump_without_crashing.h"
 #include "base/win/win_util.h"
@@ -64,6 +70,17 @@
   params.argv = argv;
 #endif
 
+#if BUILDFLAG(ENABLE_PACKAGE_MASH_SERVICES)
+#if !defined(OS_WIN)
+  base::CommandLine::Init(params.argc, params.argv);
+#endif
+  const base::CommandLine& command_line =
+      *base::CommandLine::ForCurrentProcess();
+  // TODO(sky): only do this for dev builds and if on canary channel.
+  if (command_line.HasSwitch("mash"))
+    return MashMain();
+#endif
+
   int rv = content::ContentMain(params);
 
 #if defined(OS_WIN)
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 3417d4e..ec38ffa 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -1579,6 +1579,19 @@
   <message name="IDS_LOGIN_PREVIOUS_PASSWORD" desc="Password field text on the password changed dialog">
     Previous password
   </message>
+  <message name="IDS_LOGIN_UNRECOVERABLE_CRYPTOHOME_ERROR_MESSAGE" desc="Message text for the fatal cryptohome error dialog box">
+    A serious error has occurred and we're unable to access your data. We'd like to collect system information so we can figure out what went wrong and prevent such problems in the future.<ph name="BR">&lt;br&gt;</ph>
+    <ph name="BR">&lt;br&gt;</ph>
+    Any data stored in Drive or otherwise online should be safe, but, unfortunately, any local data, including data in your Downloads folder has been lost.<ph name="BR">&lt;br&gt;</ph>
+    <ph name="BR">&lt;br&gt;</ph>
+    We'll need to recreate your profile to continue.
+  </message>
+  <message name="IDS_LOGIN_UNRECOVERABLE_CRYPTOHOME_ERROR_CONTINUE" desc="Label of the button to continue with re-creating cryptohome for the fatal cryptohome error dialog box">
+    Continue
+  </message>
+  <message name="IDS_LOGIN_UNRECOVERABLE_CRYPTOHOME_ERROR_SEND_FEEDBACK" desc="Label of the button to send feedback then continue with re-creating cryptohome for the fatal cryptohome error dialog box">
+    Send feedback &amp; continue
+  </message>
   <message name="IDS_LOGIN_SAML_NOTICE" desc="Text message displayed above SAML portal to early indicate that the user is being redirected to another sign-in provider. This is the version of the string used in the GAIA flow.">
     This sign-in service is hosted by <ph name="SAML_DOMAIN">$1<ex>saml.com</ex></ph>
   </message>
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 171306cc..82e068a 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5530,15 +5530,7 @@
       </message>
       <message name="IDS_FLAGS_WEBVR_DESCRIPTION" desc="Description for the flag to enable WebVR APIs.">
         Enabling this option allows web applications to access experimental Virtual Reality APIs.
-      </message>
-      <if expr="is_android">
-        <message name="IDS_FLAGS_WEBAUDIO_NAME" desc="Name of the 'Disable WebAudio' lab.">
-          WebAudio
-        </message>
-        <message name="IDS_FLAGS_WEBAUDIO_DESCRIPTION" desc="Description for the flag for WebAudio.">
-          Allows web sites to access the WebAudio API.
-        </message>
-      </if>
+      </message>     
       <message name="IDS_FLAGS_COMPOSITING_FOR_FIXED_POSITION_NAME" desc="Name of the 'Compositing for fixed position elements' lab.">
         Compositing for fixed position elements.
       </message>
@@ -7270,6 +7262,9 @@
       </message>
 
       <!-- Password Manager -->
+      <message name="IDS_PASSWORD_MANAGER_CANCEL_BUTTON" desc="Label for the 'dismiss' button in the Manage Password bubble/Update Password infobar. These UIs ask the user if they wish to perform some action with saved passwords, e.g. updating or deleting them; the button dismisses the UI without taking the suggested action.">
+        Nope
+      </message>
       <message name="IDS_FILL_ON_ACCOUNT_SELECT_NAME" desc="Name of the experiment for the password manager to fill on account selection rather than page load">
         Fill passwords on account selection
       </message>
@@ -7295,9 +7290,6 @@
         <message name="IDS_PASSWORD_MANAGER_BUBBLE_BLACKLIST_BUTTON" desc="Button text for the 'Save Password' bubble's 'Never remember for this site' option">
           Never
         </message>
-        <message name="IDS_PASSWORD_MANAGER_CANCEL_BUTTON" desc="Text for the 'Manage Passwords' bubble's 'Not now' option">
-          Nope
-        </message>
         <message name="IDS_PASSWORD_MANAGER_TOOLTIP_SAVE" desc="Text for the 'Manage Passwords' icon's 'password to be saved' state">
           Save your password
         </message>
@@ -7312,6 +7304,9 @@
         <message name="IDS_PASSWORD_MANAGER_BLACKLIST_BUTTON" desc="Mobile: Button text for the 'Save Password' infobar's 'Never remember for this site' option">
           Never
         </message>
+        <message name="IDS_PASSWORD_MANAGER_UPDATE_BUTTON" desc="Label for the 'update' button in the Update Password infobar. This infobar asks if the user wishes to update the saved password for a site to a new password the user has just entered; the button applies the suggested update.">
+          Update
+        </message>
       </if>
 
       <!-- Android uses custom UI for Bookmark importing -->
@@ -12214,10 +12209,16 @@
         <ph name="PASSWORD_MANAGER_BRAND">$1<ex>Google Chrome</ex></ph> remembers your passwords and signs you in to sites automatically on this device.
       </message>
       <message name="IDS_AUTO_SIGNIN_FIRST_RUN_TITLE_MANY_DEVICES" desc="The title of the dialog during the autosign-in first run experience for the Chrome syncing users.">
-        Automatically sign in across your devices
+        Sign in easily across devices
+      </message>
+      <message name="IDS_AUTO_SIGNIN_FIRST_RUN_TITLE_MANY_DEVICES_1" desc="The alternative title of the dialog during the autosign-in first run experience for the Chrome syncing users.">
+        Automatically sign in across devices
       </message>
       <message name="IDS_AUTO_SIGNIN_FIRST_RUN_TITLE_LOCAL_DEVICE" desc="The title of the dialog during the autosign-in first run experience for the Chrome signed out users.">
-        Automatically sign in to sites on this device
+        Sign in easily on this device
+      </message>
+      <message name="IDS_AUTO_SIGNIN_FIRST_RUN_TITLE_LOCAL_DEVICE_1" desc="The alternative title of the dialog during the autosign-in first run experience for the Chrome signed out users.">
+        Automatically sign in on this device
       </message>
       <message name="IDS_AUTO_SIGNIN_FIRST_RUN_SMART_LOCK_TEXT" desc="The text of the dialog during the autosign-in first run experience for the Chrome syncing users.">
         <ph name="PASSWORD_MANAGER_BRAND">$1<ex>Google Smart Lock</ex></ph> automatically signs you in to eligible sites and apps with passwords you saved.
@@ -14510,6 +14511,14 @@
       <message name="IDS_CHOOSER_BUBBLE_CANCEL_BUTTON_TEXT" desc="The text that is shown on the cancel button in the chooser popup.">
         Cancel
       </message>
+      <!-- Chooser Bubble Footnote Text -->
+      <message name="IDS_CHOOSER_BUBBLE_FOOTNOTE_TEXT" desc="This text is shown at the bottom of the chooser popup with a link to part of its text.">
+        Not seeing your device? <ph name="GET_HELP_LINK">$1<ex>Get help</ex></ph>
+      </message>
+      <!-- Chooser Bubble Get Help Link Text -->
+      <message name="IDS_CHOOSER_BUBBLE_GET_HELP_LINK_TEXT" desc="Text of the 'Get help' link at the bottom of the chooser popup.">
+        Get help
+      </message>
     </if>
 
     <if expr="is_android">
@@ -14579,6 +14588,15 @@
       </message>
     </if>
 
+    <if expr="is_android">
+      <message name="IDS_FLAGS_ENABLE_NTP_SNIPPETS_NAME" desc="Name for the flag to enable snippets on the New Tab page." translateable="false">
+        Show content snippets on the New Tab page
+      </message>
+      <message name="IDS_FLAGS_ENABLE_NTP_SNIPPETS_DESCRIPTION" desc="Description for the flag to enable snippets on the New Tab page." translateable="false">
+        If enabled, the New Tab page will show a list of content snippets
+      </message>
+    </if>
+
     </messages>
   </release>
 </grit>
diff --git a/chrome/app/mash/BUILD.gn b/chrome/app/mash/BUILD.gn
new file mode 100644
index 0000000..654b512
--- /dev/null
+++ b/chrome/app/mash/BUILD.gn
@@ -0,0 +1,64 @@
+# Copyright 2016 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("//mojo/public/mojo_application_manifest.gni")
+
+source_set("mash") {
+  sources = [
+    "mash_runner.cc",
+    "mash_runner.h",
+  ]
+  deps = [
+    ":manifest",
+    "//ash/mus:lib",
+    "//ash/resources",
+    "//base:i18n",
+    "//components/mus:lib",
+    "//components/resource_provider:lib",
+    "//content/public/common",
+    "//mash/quick_launch:lib",
+    "//mash/shell:lib",
+    "//mash/wm:lib",
+    "//mojo/common:mojo_scheme_register",
+    "//mojo/shell",
+    "//mojo/shell/background:lib",
+    "//mojo/shell/public/cpp",
+    "//mojo/shell/public/interfaces",
+    "//mojo/shell/runner/common",
+    "//mojo/shell/runner/host:child_process_base",
+    "//mojo/shell/runner/host:lib",
+    "//url",
+  ]
+
+  if (is_linux && !is_android) {
+    deps += [ "//components/font_service:lib" ]
+  }
+}
+
+mojo_application_manifest("manifest") {
+  type = "exe"
+  application_name = "chrome_mash"
+  source = "chrome_mash_manifest.json"
+  deps = [
+    "//ash/mus:manifest",
+    "//components/mus:manifest",
+    "//components/resource_provider:manifest",
+    "//mash/quick_launch:manifest",
+    "//mash/shell:manifest",
+    "//mash/wm:manifest",
+  ]
+  packaged_applications = [
+    "ash_sysui",
+    "desktop_wm",
+    "mash_shell",
+    "mus",
+    "quick_launch",
+    "resource_provider",
+  ]
+
+  if (is_linux && !is_android) {
+    deps += [ "//components/font_service:manifest" ]
+    packaged_applications += [ "font_service" ]
+  }
+}
diff --git a/chrome/app/mash/DEPS b/chrome/app/mash/DEPS
new file mode 100644
index 0000000..8c027b2
--- /dev/null
+++ b/chrome/app/mash/DEPS
@@ -0,0 +1,8 @@
+include_rules = [
+  "+ash",
+  "+components/font_service",
+  "+components/mus",
+  "+components/resource_provider",
+  "+mash",
+  "+mojo/shell",
+]
diff --git a/chrome/app/mash/chrome_mash_manifest.json b/chrome/app/mash/chrome_mash_manifest.json
new file mode 100644
index 0000000..282e897f
--- /dev/null
+++ b/chrome/app/mash/chrome_mash_manifest.json
@@ -0,0 +1,5 @@
+{
+  "url": "exe://chrome_mash/",
+  "name": "Chrome",
+  "capabilities": { "*": [ "*" ] }
+}
diff --git a/chrome/app/mash/mash_runner.cc b/chrome/app/mash/mash_runner.cc
new file mode 100644
index 0000000..c49780cd
--- /dev/null
+++ b/chrome/app/mash/mash_runner.cc
@@ -0,0 +1,239 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/app/mash/mash_runner.h"
+
+#include "ash/mus/sysui_application.h"
+#include "base/at_exit.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/debug/debugger.h"
+#include "base/i18n/icu_util.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/process/launch.h"
+#include "components/mus/mus_app.h"
+#include "components/resource_provider/resource_provider_app.h"
+#include "content/public/common/content_switches.h"
+#include "mash/quick_launch/quick_launch_application.h"
+#include "mash/shell/shell_application_delegate.h"
+#include "mash/wm/window_manager_application.h"
+#include "mojo/common/mojo_scheme_register.h"
+#include "mojo/public/cpp/bindings/weak_binding_set.h"
+#include "mojo/shell/background/background_shell.h"
+#include "mojo/shell/identity.h"
+#include "mojo/shell/native_runner_delegate.h"
+#include "mojo/shell/public/cpp/shell_client.h"
+#include "mojo/shell/public/cpp/shell_connection.h"
+#include "mojo/shell/public/interfaces/shell_client_factory.mojom.h"
+#include "mojo/shell/runner/common/switches.h"
+#include "mojo/shell/runner/host/child_process_base.h"
+#include "url/gurl.h"
+#include "url/url_util.h"
+
+#if defined(OS_LINUX)
+#include "components/font_service/font_service_app.h"
+#endif
+
+using mojo::shell::mojom::ShellClientFactory;
+
+namespace {
+
+// kProcessType used to identify child processes.
+const char* kMashChild = "mash-child";
+
+// ShellClient responsible for starting the appropriate app.
+class DefaultShellClient : public mojo::ShellClient,
+                           public ShellClientFactory,
+                           public mojo::InterfaceFactory<ShellClientFactory> {
+ public:
+  DefaultShellClient() {}
+  ~DefaultShellClient() override {}
+
+  // mojo::ShellClient:
+  bool AcceptConnection(mojo::Connection* connection) override {
+    connection->AddInterface<ShellClientFactory>(this);
+    return true;
+  }
+
+  // mojo::InterfaceFactory<ShellClientFactory>
+  void Create(mojo::Connection* connection,
+              mojo::InterfaceRequest<ShellClientFactory> request) override {
+    shell_client_factory_bindings_.AddBinding(this, std::move(request));
+  }
+
+  // ShellClientFactory:
+  void CreateShellClient(mojo::shell::mojom::ShellClientRequest request,
+                         const mojo::String& mojo_url) override {
+    const GURL url = GURL(std::string(mojo_url));
+    if (shell_client_) {
+      LOG(ERROR) << "request to create additional app " << url;
+      return;
+    }
+    shell_client_ = CreateShellClient(url);
+    if (shell_client_) {
+      shell_connection_.reset(
+          new mojo::ShellConnection(shell_client_.get(), std::move(request)));
+      return;
+    }
+    LOG(ERROR) << "unknown url " << url;
+    NOTREACHED();
+  }
+
+ private:
+  // TODO(sky): move this into mash.
+  scoped_ptr<mojo::ShellClient> CreateShellClient(const GURL& url) {
+    if (url == GURL("mojo:ash_sysui"))
+      return make_scoped_ptr(new ash::sysui::SysUIApplication);
+    if (url == GURL("mojo:desktop_wm"))
+      return make_scoped_ptr(new mash::wm::WindowManagerApplication);
+    if (url == GURL("mojo:mash_shell"))
+      return make_scoped_ptr(new mash::shell::ShellApplicationDelegate);
+    if (url == GURL("mojo:mus"))
+      return make_scoped_ptr(new mus::MandolineUIServicesApp);
+    if (url == GURL("mojo:quick_launch"))
+      return make_scoped_ptr(new mash::quick_launch::QuickLaunchApplication);
+    if (url == GURL("mojo:resource_provider")) {
+      return make_scoped_ptr(
+          new resource_provider::ResourceProviderApp("mojo:resource_provider"));
+    }
+#if defined(OS_LINUX)
+    if (url == GURL("mojo:font_service"))
+      return make_scoped_ptr(new font_service::FontServiceApp);
+#endif
+    return nullptr;
+  }
+
+  mojo::WeakBindingSet<ShellClientFactory> shell_client_factory_bindings_;
+  scoped_ptr<mojo::ShellClient> shell_client_;
+  scoped_ptr<mojo::ShellConnection> shell_connection_;
+
+  DISALLOW_COPY_AND_ASSIGN(DefaultShellClient);
+};
+
+bool IsChild() {
+  return base::CommandLine::ForCurrentProcess()->HasSwitch(
+             switches::kProcessType) &&
+         base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+             switches::kProcessType) == kMashChild;
+}
+
+// Convert the command line program from chrome_mash to chrome. This is
+// necessary as the shell will attempt to start chrome_mash. We want chrome.
+void ChangeChromeMashToChrome(base::CommandLine* command_line) {
+  base::FilePath exe_path(command_line->GetProgram());
+#if defined(OS_WIN)
+  exe_path = exe_path.DirName().Append(FILE_PATH_LITERAL("chrome.exe"));
+#else
+  exe_path = exe_path.DirName().Append(FILE_PATH_LITERAL("chrome"));
+#endif
+  command_line->SetProgram(exe_path);
+}
+
+class NativeRunnerDelegateImpl : public mojo::shell::NativeRunnerDelegate {
+ public:
+  NativeRunnerDelegateImpl() {}
+  ~NativeRunnerDelegateImpl() override {}
+
+ private:
+  // mojo::shell::NativeRunnerDelegate:
+  void AdjustCommandLineArgumentsForTarget(
+      const mojo::shell::Identity& target,
+      base::CommandLine* command_line) override {
+    if (target.url() != GURL("exe:chrome")) {
+      if (target.url() == GURL("exe:chrome_mash"))
+        ChangeChromeMashToChrome(command_line);
+      command_line->AppendSwitchASCII(switches::kProcessType, kMashChild);
+#if defined(OS_WIN)
+      command_line->AppendArg(switches::kPrefetchArgumentOther);
+#endif
+      return;
+    }
+
+    base::CommandLine::StringVector argv(command_line->argv());
+    auto iter =
+        std::find(argv.begin(), argv.end(), FILE_PATH_LITERAL("--mash"));
+    if (iter != argv.end())
+      argv.erase(iter);
+    *command_line = base::CommandLine(argv);
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(NativeRunnerDelegateImpl);
+};
+
+}  // namespace
+
+MashRunner::MashRunner() {}
+
+MashRunner::~MashRunner() {}
+
+void MashRunner::Run() {
+  if (IsChild())
+    RunChild();
+  else
+    RunMain();
+}
+
+void MashRunner::RunMain() {
+  // TODO(sky): refactor backgroundshell so can supply own context, we
+  // shouldn't we using context as it has a lot of stuff we don't really want
+  // in chrome.
+  NativeRunnerDelegateImpl native_runner_delegate;
+  mojo::shell::BackgroundShell background_shell;
+  scoped_ptr<mojo::shell::BackgroundShell::InitParams> init_params(
+      new mojo::shell::BackgroundShell::InitParams);
+  init_params->native_runner_delegate = &native_runner_delegate;
+  background_shell.Init(std::move(init_params));
+  shell_client_.reset(new DefaultShellClient);
+  shell_connection_.reset(new mojo::ShellConnection(
+      shell_client_.get(),
+      background_shell.CreateShellClientRequest(GURL("exe:chrome_mash"))));
+  shell_connection_->WaitForInitialize();
+  static_cast<mojo::Shell*>(shell_connection_.get())
+      ->Connect("mojo:mash_shell");
+  base::MessageLoop::current()->Run();
+}
+
+void MashRunner::RunChild() {
+  base::i18n::InitializeICU();
+  mojo::shell::ChildProcessMain(
+      base::Bind(&MashRunner::StartChildApp, base::Unretained(this)));
+}
+
+void MashRunner::StartChildApp(
+    mojo::shell::mojom::ShellClientRequest client_request) {
+  // TODO(sky): use MessagePumpMojo.
+  base::MessageLoop message_loop(base::MessageLoop::TYPE_UI);
+  shell_client_.reset(new DefaultShellClient);
+  shell_connection_.reset(new mojo::ShellConnection(shell_client_.get(),
+                                                    std::move(client_request)));
+  message_loop.Run();
+}
+
+int MashMain() {
+#if defined(OS_WIN)
+  base::RouteStdioToConsole(false);
+#endif
+  // TODO(sky): wire this up correctly.
+  logging::LoggingSettings settings;
+  settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
+  logging::InitLogging(settings);
+  // To view log output with IDs and timestamps use "adb logcat -v threadtime".
+  logging::SetLogItems(false,   // Process ID
+                       false,   // Thread ID
+                       false,   // Timestamp
+                       false);  // Tick count
+
+  mojo::RegisterMojoSchemes();
+  // TODO(sky): use MessagePumpMojo.
+  scoped_ptr<base::MessageLoop> message_loop;
+#if defined(OS_LINUX)
+  base::AtExitManager exit_manager;
+#endif
+  if (!IsChild())
+    message_loop.reset(new base::MessageLoop(base::MessageLoop::TYPE_UI));
+  MashRunner mash_runner;
+  mash_runner.Run();
+  return 0;
+}
diff --git a/chrome/app/mash/mash_runner.h b/chrome/app/mash/mash_runner.h
new file mode 100644
index 0000000..0658077c
--- /dev/null
+++ b/chrome/app/mash/mash_runner.h
@@ -0,0 +1,39 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_APP_MASH_MASH_RUNNER_H_
+#define CHROME_APP_MASH_MASH_RUNNER_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "mojo/shell/public/interfaces/shell_client.mojom.h"
+
+namespace mojo {
+class ShellClient;
+class ShellConnection;
+}
+
+// Responsible for running mash, both child and main processes.
+class MashRunner {
+ public:
+  MashRunner();
+  ~MashRunner();
+
+  void Run();
+
+ private:
+  void RunMain();
+  void RunChild();
+
+  void StartChildApp(mojo::shell::mojom::ShellClientRequest client_request);
+
+  scoped_ptr<mojo::ShellClient> shell_client_;
+  scoped_ptr<mojo::ShellConnection> shell_connection_;
+
+  DISALLOW_COPY_AND_ASSIGN(MashRunner);
+};
+
+int MashMain();
+
+#endif  // CHROME_APP_MASH_MASH_RUNNER_H_
diff --git a/chrome/app/settings_chromium_strings.grdp b/chrome/app/settings_chromium_strings.grdp
index e5c40fc9..9d6cc81a 100644
--- a/chrome/app/settings_chromium_strings.grdp
+++ b/chrome/app/settings_chromium_strings.grdp
@@ -4,10 +4,7 @@
   <!-- Default Browser Page -->
   <if expr="not chromeos">
     <message name="IDS_SETTINGS_DEFAULT_BROWSER_DEFAULT" desc="The text displayed when Chrome is not the default browser">
-      The default browser is currently Chromium.
-    </message>
-    <message name="IDS_SETTINGS_DEFAULT_BROWSER_NOT_DEFAULT" desc="The text displayed when Chrome is not the default browser">
-      Chromium is not currently your default browser.
+      Chromium is your default browser. Yay!
     </message>
     <message name="IDS_SETTINGS_DEFAULT_BROWSER_MAKE_DEFAULT" desc="Default browser checkbox label">
       Make Chromium the default browser
diff --git a/chrome/app/settings_google_chrome_strings.grdp b/chrome/app/settings_google_chrome_strings.grdp
index 19a0626c..68abc441 100644
--- a/chrome/app/settings_google_chrome_strings.grdp
+++ b/chrome/app/settings_google_chrome_strings.grdp
@@ -4,10 +4,7 @@
   <!-- Default Browser Page -->
   <if expr="not chromeos">
     <message name="IDS_SETTINGS_DEFAULT_BROWSER_DEFAULT" desc="The text displayed when Chrome is not the default browser">
-      The default browser is currently Google Chrome.
-    </message>
-    <message name="IDS_SETTINGS_DEFAULT_BROWSER_NOT_DEFAULT" desc="The text displayed when Chrome is not the default browser">
-      Google Chrome is not currently your default browser.
+      Google Chrome is your default browser. Yay!
     </message>
     <message name="IDS_SETTINGS_DEFAULT_BROWSER_MAKE_DEFAULT" desc="Default browser checkbox label">
       Make Google Chrome the default browser
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 90a1f72..98018ee4 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -232,7 +232,7 @@
 
   <!-- Clear Browsing Data -->
   <message name="IDS_SETTINGS_CLEAR_FOLLOWING_ITEMS_FROM" desc="Label at the top of the client area of the dialog, preceding the period combo box">
-    Obliterate the following items from:
+    Clear the following items from
   </message>
   <message name="IDS_SETTINGS_CLEAR_BROWSING_HISTORY" desc="Checkbox for deleting Browsing History">
     Browsing history
@@ -404,8 +404,8 @@
   <message name="IDS_SETTINGS_SUGGEST_PREF" desc="The documentation string of the 'Use Suggest' preference">
     Use a prediction service to help complete searches and URLs typed in the address bar or the app launcher search box
   </message>
-  <message name="IDS_SETTINGS_NETWORK_PREDICTION_ENABLED_DESCRIPTION" desc="In the advanced options tab, the text next to the checkbox that enables prediction of network actions.  Actions include DNS prefetching, TCP and SSL preconnection, and prerendering of webpages.">
-    Prefetch resources to load pages more quickly
+  <message name="IDS_SETTINGS_NETWORK_PREDICTION_ENABLED_DESCRIPTION" desc="In the advanced options tab, the text next to the checkbox that enables prediction of network actions.  Actions include browser-initiated DNS prefetching, TCP and SSL preconnection, and prerendering of webpages.">
+    Use a prediction service to load pages more quickly
   </message>
   <message name="IDS_SETTINGS_SAFEBROWSING_ENABLEPROTECTION" desc="The label of the 'Enable phishing and malware protection' checkbox">
     Enable phishing and malware protection
@@ -471,9 +471,15 @@
   <message name="IDS_SETTINGS_SEARCH_ENGINES_NOT_VALID" desc="Text indicating that the input to a given text field in the add/edit search engine dialog is not invalid.">
    Not valid
   </message>
+  <message name="IDS_SETTINGS_SEARCH_ENGINES_DEFAULT_ENGINES" desc="Label for 'default' Search Engines section">
+    Default search engines
+  </message>
   <message name="IDS_SETTINGS_SEARCH_ENGINES_OTHER_ENGINES" desc="Label for 'other' Search Engines section">
     Other search engines
   </message>
+  <message name="IDS_SETTINGS_SEARCH_ENGINES_EXTENSION_ENGINES" desc="Label for a section that displays search engines added by extensions">
+    Search engines added by extensions
+  </message>
   <message name="IDS_SETTINGS_SEARCH_ENGINES_SEARCH_ENGINE" desc="Label for a table column that holds the name of a search engine">
     Search engine
   </message>
@@ -495,6 +501,9 @@
   <message name="IDS_SETTINGS_SEARCH_ENGINES_REMOVE_FROM_LIST" desc="Label for a button that removes a search engine from the list of search engines">
     Remove from list
   </message>
+  <message name="IDS_SETTINGS_SEARCH_ENGINES_MANAGE_EXTENSION" desc="Text displayed for a button that allows the user to manage a Chrome extension">
+    Manage
+  </message>
 
   <!-- Site Settings Page -->
   <message name="IDS_SETTINGS_SITE_SETTINGS" desc="Name of the settings page which allows users to modify site settings.">
@@ -812,10 +821,10 @@
     Web content
   </message>
   <message name="IDS_SETTINGS_PAGE_ZOOM_LABEL" desc="Label for the page zoom dropdown menu in settings.">
-    Page zoom:
+    Page zoom
   </message>
   <message name="IDS_SETTINGS_FONT_SIZE_LABEL" desc="Label for the font size dropdown menu in settings.">
-    Font size:
+    Font size
   </message>
   <message name="IDS_SETTINGS_VERY_SMALL_FONT" desc="The very small choice in the font size dropdown menu in settings.">
     Very small
@@ -842,22 +851,22 @@
     Fonts and encoding
   </message>
   <message name="IDS_SETTINGS_STANDARD_FONT_LABEL" desc="Label for the standard font dropdown menu in settings.">
-    Standard font:
+    Standard font
   </message>
   <message name="IDS_SETTINGS_SERIF_FONT_LABEL" desc="Label for the serif font dropdown menu in settings.">
-    Serif font:
+    Serif font
   </message>
   <message name="IDS_SETTINGS_SANS_SERIF_FONT_LABEL" desc="Label for the sans serif font dropdown menu in settings.">
-    Sans-serif font:
+    Sans-serif font
   </message>
   <message name="IDS_SETTINGS_FIXED_WIDTH_FONT_LABEL" desc="Label for the fixed width font dropdown menu in settings.">
-    Fixed-width font:
+    Fixed-width font
   </message>
   <message name="IDS_SETTINGS_MINIMUM_FONT_SIZE_LABEL" desc="Label for the minimum font size slider in settings.">
-    Minimum font size:
+    Minimum font size
   </message>
   <message name="IDS_SETTINGS_ENCODING_LABEL" desc="Label for the text encoding in settings.">
-    Encoding:
+    Encoding
   </message>
   <message name="IDS_SETTINGS_TINY_FONT_SIZE" desc="The small end of the minimum font size slider in settings.">
     Tiny
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 7a315a1e..b1dbcce 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -528,15 +528,17 @@
 };
 
 const FeatureEntry::Choice kHerbPrototypeChoices[] = {
-    {IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED, "", ""},
+    {IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", ""},
+    {IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
+     switches::kTabManagementExperimentTypeDisabled, ""},
     {IDS_FLAGS_HERB_PROTOTYPE_FLAVOR_ANISE,
-     switches::kTabManagementExperimentType, "anise"},
+     switches::kTabManagementExperimentTypeAnise, ""},
     {IDS_FLAGS_HERB_PROTOTYPE_FLAVOR_BASIL,
-     switches::kTabManagementExperimentType, "basil"},
+     switches::kTabManagementExperimentTypeBasil, ""},
     {IDS_FLAGS_HERB_PROTOTYPE_FLAVOR_CHIVE,
-     switches::kTabManagementExperimentType, "chive"},
+     switches::kTabManagementExperimentTypeChive, ""},
     {IDS_FLAGS_HERB_PROTOTYPE_FLAVOR_DILL,
-     switches::kTabManagementExperimentType, "dill"},
+     switches::kTabManagementExperimentTypeDill, ""},
 };
 #endif  // defined(OS_ANDROID)
 
@@ -622,11 +624,6 @@
      IDS_FLAGS_WEBRTC_STUN_ORIGIN_DESCRIPTION, kOsAll,
      SINGLE_VALUE_TYPE(switches::kEnableWebRtcStunOrigin)},
 #endif
-#if defined(OS_ANDROID)
-    {"disable-webaudio", IDS_FLAGS_WEBAUDIO_NAME,
-     IDS_FLAGS_WEBAUDIO_DESCRIPTION, kOsAndroid,
-     SINGLE_DISABLE_VALUE_TYPE(switches::kDisableWebAudio)},
-#endif
   // Native client is compiled out when DISABLE_NACL is defined.
 #if !defined(DISABLE_NACL)
     {"enable-nacl",  // FLAGS:RECORD_UMA
@@ -983,12 +980,10 @@
     {"trace-upload-url", IDS_FLAGS_TRACE_UPLOAD_URL,
      IDS_FLAGS_TRACE_UPLOAD_URL_DESCRIPTION, kOsAll,
      MULTI_VALUE_TYPE(kTraceUploadURL)},
-#if !defined(OS_IOS)
     {"enable-stale-while-revalidate",
      IDS_FLAGS_ENABLE_STALE_WHILE_REVALIDATE_NAME,
      IDS_FLAGS_ENABLE_STALE_WHILE_REVALIDATE_DESCRIPTION, kOsAll,
      SINGLE_VALUE_TYPE(switches::kEnableStaleWhileRevalidate)},
-#endif
     {"enable-suggestions-with-substring-match",
      IDS_FLAGS_SUGGESTIONS_WITH_SUB_STRING_MATCH_NAME,
      IDS_FLAGS_SUGGESTIONS_WITH_SUB_STRING_MATCH_DESCRIPTION, kOsAll,
@@ -1398,7 +1393,7 @@
      SINGLE_VALUE_TYPE(switches::kEnableTabAudioMuting)},
     {"enable-credential-manager-api", IDS_FLAGS_CREDENTIAL_MANAGER_API_NAME,
      IDS_FLAGS_CREDENTIAL_MANAGER_API_DESCRIPTION, kOsAll,
-     SINGLE_VALUE_TYPE(switches::kEnableCredentialManagerAPI)},
+     FEATURE_VALUE_TYPE(features::kCredentialManagementAPI)},
     {"reduced-referrer-granularity",
      IDS_FLAGS_REDUCED_REFERRER_GRANULARITY_NAME,
      IDS_FLAGS_REDUCED_REFERRER_GRANULARITY_DESCRIPTION, kOsAll,
@@ -1810,6 +1805,11 @@
      IDS_FLAG_ENABLE_TAB_FOR_DESKTOP_SHARE_DESCRIPTION, kOsAll,
      SINGLE_VALUE_TYPE(extensions::switches::kEnableTabForDesktopShare)}
 #endif
+#if defined(OS_ANDROID)
+    {"enable-ntp-snippets", IDS_FLAGS_ENABLE_NTP_SNIPPETS_NAME,
+     IDS_FLAGS_ENABLE_NTP_SNIPPETS_DESCRIPTION, kOsAndroid,
+     FEATURE_VALUE_TYPE(chrome::android::kNTPSnippetsFeature)},
+#endif  // defined(OS_ANDROID)
     // NOTE: Adding new command-line switches requires adding corresponding
     // entries to enum "LoginCustomFlags" in histograms.xml. See note in
     // histograms.xml and don't forget to run AboutFlagsHistogramTest unit test.
diff --git a/chrome/browser/android/DEPS b/chrome/browser/android/DEPS
index 5894717..4fc151f 100644
--- a/chrome/browser/android/DEPS
+++ b/chrome/browser/android/DEPS
@@ -2,6 +2,7 @@
   "-components/devtools_bridge",
   "+components/devtools_discovery",
   "+components/devtools_http_handler",
+  "+components/ntp_snippets",
   "+components/service_tab_launcher",
   "+components/toolbar",
   "+components/web_contents_delegate_android",
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index 8b44469..eeefab1 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -25,6 +25,7 @@
 // other locations in the code base (e.g. chrome/, components/, etc).
 const base::Feature* kFeaturesExposedToJava[] = {
     &kNTPOfflinePagesFeature,
+    &kNTPSnippetsFeature,
     &kPhysicalWebFeature,
 };
 
@@ -34,6 +35,10 @@
   "NTPOfflinePages", base::FEATURE_DISABLED_BY_DEFAULT
 };
 
+const base::Feature kNTPSnippetsFeature {
+  "NTPSnippets", base::FEATURE_DISABLED_BY_DEFAULT
+};
+
 const base::Feature kPhysicalWebFeature {
   "PhysicalWeb", base::FEATURE_DISABLED_BY_DEFAULT
 };
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index 17ca186..f13d6e5 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -13,6 +13,7 @@
 namespace android {
 
 extern const base::Feature kNTPOfflinePagesFeature;
+extern const base::Feature kNTPSnippetsFeature;
 extern const base::Feature kPhysicalWebFeature;
 
 bool RegisterChromeFeatureListJni(JNIEnv* env);
diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc
index d52c26bb..8aca352 100644
--- a/chrome/browser/android/chrome_jni_registrar.cc
+++ b/chrome/browser/android/chrome_jni_registrar.cc
@@ -60,6 +60,8 @@
 #include "chrome/browser/android/most_visited_sites.h"
 #include "chrome/browser/android/net/external_estimate_provider_android.h"
 #include "chrome/browser/android/new_tab_page_prefs.h"
+#include "chrome/browser/android/ntp_snippets_bridge.h"
+#include "chrome/browser/android/ntp_snippets_controller.h"
 #include "chrome/browser/android/offline_pages/offline_page_bridge.h"
 #include "chrome/browser/android/omnibox/answers_image_bridge.h"
 #include "chrome/browser/android/omnibox/autocomplete_controller_android.h"
@@ -145,6 +147,7 @@
 #include "chrome/browser/ui/android/infobars/save_password_infobar.h"
 #include "chrome/browser/ui/android/infobars/simple_confirm_infobar_builder.h"
 #include "chrome/browser/ui/android/infobars/translate_infobar.h"
+#include "chrome/browser/ui/android/infobars/update_password_infobar.h"
 #include "chrome/browser/ui/android/javascript_app_modal_dialog_android.h"
 #include "chrome/browser/ui/android/omnibox/omnibox_url_emphasizer.h"
 #include "chrome/browser/ui/android/omnibox/omnibox_view_util.h"
@@ -305,6 +308,8 @@
     {"NewTabPagePrefs", NewTabPagePrefs::RegisterNewTabPagePrefs},
     {"NotificationUIManager",
      NotificationUIManagerAndroid::RegisterNotificationUIManager},
+    {"NTPSnippetsBridge", NTPSnippetsBridge::Register},
+    {"NTPSnippetsController", NTPSnippetsController::Register},
     {"OAuth2TokenServiceDelegateAndroid",
      OAuth2TokenServiceDelegateAndroid::Register},
     {"OfflinePageBridge", offline_pages::android::RegisterOfflinePageBridge},
@@ -366,6 +371,7 @@
     {"TranslateInfoBarDelegate", RegisterTranslateInfoBarDelegate},
     {"TtsPlatformImpl", TtsPlatformImplAndroid::Register},
     {"UmaSessionStats", RegisterUmaSessionStats},
+    {"UpdatePasswordInfoBar", UpdatePasswordInfoBar::Register},
     {"UrlUtilities", RegisterUrlUtilities},
     {"Variations", variations::android::RegisterVariations},
     {"VariationsSeedBridge", variations::android::RegisterVariationsSeedBridge},
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate.cc b/chrome/browser/android/contextualsearch/contextual_search_delegate.cc
index 5fd6c5f..2e58411 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_delegate.cc
+++ b/chrome/browser/android/contextualsearch/contextual_search_delegate.cc
@@ -12,6 +12,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/android/contextualsearch/contextual_search_field_trial.h"
 #include "chrome/browser/android/contextualsearch/resolved_search_term.h"
 #include "chrome/browser/android/proto/client_discourse_context.pb.h"
 #include "chrome/browser/profiles/profile.h"
@@ -34,12 +35,6 @@
 
 namespace {
 
-const char kContextualSearchFieldTrialName[] = "ContextualSearch";
-const char kContextualSearchSurroundingSizeParamName[] = "surrounding_size";
-const char kContextualSearchIcingSurroundingSizeParamName[] =
-    "icing_surrounding_size";
-const char kContextualSearchResolverURLParamName[] = "resolver_url";
-const char kContextualSearchDoNotSendURLParamName[] = "do_not_send_url";
 const char kContextualSearchResponseDisplayTextParam[] = "display_text";
 const char kContextualSearchResponseSelectedTextParam[] = "selected_text";
 const char kContextualSearchResponseSearchTermParam[] = "search_term";
@@ -49,12 +44,6 @@
 const char kContextualSearchMentions[] = "mentions";
 const char kContextualSearchServerEndpoint[] = "_/contextualsearch?";
 const int kContextualSearchRequestVersion = 2;
-const char kContextualSearchResolverUrl[] =
-    "contextual-search-resolver-url";
-// The default size of the content surrounding the selection to gather, allowing
-// room for other parameters.
-const int kContextualSearchDefaultContentSize = 1536;
-const int kContextualSearchDefaultIcingSurroundingSize = 400;
 const int kContextualSearchMaxSelection = 100;
 // The maximum length of a URL to build.
 const int kMaxURLSize = 2048;
@@ -84,6 +73,7 @@
       search_term_callback_(search_term_callback),
       surrounding_callback_(surrounding_callback),
       icing_callback_(icing_callback) {
+  field_trial_.reset(new ContextualSearchFieldTrial());
 }
 
 ContextualSearchDelegate::~ContextualSearchDelegate() {
@@ -239,17 +229,7 @@
           NULL));
 
   // The switch/param should be the URL up to and including the endpoint.
-  std::string replacement_url;
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-      kContextualSearchResolverUrl)) {
-    replacement_url =
-        base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-            kContextualSearchResolverUrl);
-  } else {
-    std::string param_value = variations::GetVariationParamValue(
-        kContextualSearchFieldTrialName, kContextualSearchResolverURLParamName);
-    if (!param_value.empty()) replacement_url = param_value;
-  }
+  std::string replacement_url = field_trial_->GetResolverURLPrefix();
 
   // If a replacement URL was specified above, do the substitution.
   if (!replacement_url.empty()) {
@@ -283,7 +263,7 @@
   context_.reset(new ContextualSearchContext(
       selection, use_resolved_search_term, url_to_send, encoding));
   content_view_core->RequestTextSurroundingSelection(
-      GetSearchTermSurroundingSize(), callback);
+      field_trial_->GetSurroundingSize(), callback);
 }
 
 void ContextualSearchDelegate::StartSearchTermRequestFromSelection(
@@ -327,7 +307,7 @@
       std::min(surrounding_length, std::max(0, context_->end_offset));
 
   // Call the Icing callback with a shortened copy of the surroundings.
-  int icing_surrounding_size = GetIcingSurroundingSize();
+  int icing_surrounding_size = field_trial_->GetIcingSurroundingSize();
   size_t selection_start = context_->start_offset;
   size_t selection_end = context_->end_offset;
   if (icing_surrounding_size >= 0 && selection_start < selection_end) {
@@ -388,9 +368,7 @@
     TemplateURLService* template_url_service) {
   // Check whether there is a Finch parameter preventing us from sending the
   // page URL.
-  std::string param_value = variations::GetVariationParamValue(
-      kContextualSearchFieldTrialName, kContextualSearchDoNotSendURLParamName);
-  if (!param_value.empty())
+  if (field_trial_->IsSendBasePageURLDisabled())
     return false;
 
   // Ensure that the default search provider is Google.
@@ -468,10 +446,12 @@
       *display_text = *search_term;
     }
     // Extract mentions for selection expansion.
-    base::ListValue* mentions_list = NULL;
-    dict->GetList(kContextualSearchMentions, &mentions_list);
-    if (mentions_list != NULL && mentions_list->GetSize() >= 2)
-      ExtractMentionsStartEnd(*mentions_list, mention_start, mention_end);
+    if (!field_trial_->IsDecodeMentionsDisabled()) {
+      base::ListValue* mentions_list = NULL;
+      dict->GetList(kContextualSearchMentions, &mentions_list);
+      if (mentions_list != NULL && mentions_list->GetSize() >= 2)
+        ExtractMentionsStartEnd(*mentions_list, mention_start, mention_end);
+    }
     // If either the selected text or the resolved term is not the search term,
     // use it as the alternate term.
     std::string selected_text;
@@ -489,18 +469,6 @@
   }
 }
 
-// Returns the size of the surroundings to be sent to the server for search term
-// resolution.
-int ContextualSearchDelegate::GetSearchTermSurroundingSize() {
-  const std::string param_value = variations::GetVariationParamValue(
-      kContextualSearchFieldTrialName,
-      kContextualSearchSurroundingSizeParamName);
-  int param_length;
-  if (!param_value.empty() && base::StringToInt(param_value, &param_length))
-    return param_length;
-  return kContextualSearchDefaultContentSize;
-}
-
 // Extract the Start/End of the mentions in the surrounding text
 // for selection-expansion.
 void ContextualSearchDelegate::ExtractMentionsStartEnd(
@@ -514,22 +482,6 @@
     *endResult = std::max(0, int_value);
 }
 
-// Returns the size of the surroundings to be sent to Icing.
-int ContextualSearchDelegate::GetIcingSurroundingSize() {
-  std::string param_string = variations::GetVariationParamValue(
-      kContextualSearchFieldTrialName,
-      kContextualSearchIcingSurroundingSizeParamName);
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          kContextualSearchIcingSurroundingSizeParamName)) {
-    param_string = base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-        kContextualSearchIcingSurroundingSizeParamName);
-  }
-  int param_value;
-  if (!param_string.empty() && base::StringToInt(param_string, &param_value))
-    return param_value;
-  return kContextualSearchDefaultIcingSurroundingSize;
-}
-
 base::string16 ContextualSearchDelegate::SurroundingTextForIcing(
     const base::string16& surrounding_text,
     int padding_each_side,
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate.h b/chrome/browser/android/contextualsearch/contextual_search_delegate.h
index 9208f80f..f926b5d 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_delegate.h
+++ b/chrome/browser/android/contextualsearch/contextual_search_delegate.h
@@ -24,6 +24,7 @@
 
 class Profile;
 class TemplateURLService;
+class ContextualSearchFieldTrial;
 
 // Handles tasks for the ContextualSearchManager in a separable and testable
 // way, without the complication of being connected to a Java object.
@@ -169,13 +170,6 @@
                                int* startResult,
                                int* endResult);
 
-  // Returns the surrounding size to use for the search term resolution
-  // request.
-  int GetSearchTermSurroundingSize();
-
-  // Returns the size of the surroundings to be sent to Icing.
-  int GetIcingSurroundingSize();
-
   // Generates a subset of the given surrounding_text string, for Icing
   // integration.
   // |surrounding_text| the entire text context that contains the selection.
@@ -202,6 +196,9 @@
   // Holds the TemplateURLService. Not owned.
   TemplateURLService* template_url_service_;
 
+  // The field trial helper instance, always set up by the constructor.
+  scoped_ptr<ContextualSearchFieldTrial> field_trial_;
+
   // The callback for notifications of completed URL fetches.
   SearchTermResolutionCallback search_term_callback_;
 
diff --git a/chrome/browser/android/contextualsearch/contextual_search_field_trial.cc b/chrome/browser/android/contextualsearch/contextual_search_field_trial.cc
new file mode 100644
index 0000000..35a50183
--- /dev/null
+++ b/chrome/browser/android/contextualsearch/contextual_search_field_trial.cc
@@ -0,0 +1,134 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/android/contextualsearch/contextual_search_field_trial.h"
+
+#include "base/command_line.h"
+#include "base/strings/string_number_conversions.h"
+#include "components/variations/variations_associated_data.h"
+
+namespace {
+
+const char kContextualSearchFieldTrialName[] = "ContextualSearch";
+const char kFalseValue[] = "false";
+const char kAnyNonEmptyValue[] = "1";
+const char kContextualSearchResolverUrl[] = "contextual-search-resolver-url";
+const char kContextualSearchSurroundingSizeParamName[] = "surrounding_size";
+const char kContextualSearchIcingSurroundingSizeParamName[] =
+    "icing_surrounding_size";
+const char kContextualSearchSendURLDisabledParamName[] = "disable_send_url";
+const char kContextualSearchDecodeMentionsDisabledParamName[] =
+    "disable_decode_mentions";
+// The default size of the content surrounding the selection to gather, allowing
+// room for other parameters.
+const int kContextualSearchDefaultContentSize = 1536;
+
+}  // namespace
+
+// static
+const int
+    ContextualSearchFieldTrial::kContextualSearchDefaultIcingSurroundingSize =
+        400;
+
+ContextualSearchFieldTrial::ContextualSearchFieldTrial()
+    : is_resolver_url_prefix_cached_(false),
+      is_surrounding_size_cached_(false),
+      surrounding_size_(0),
+      is_icing_surrounding_size_cached_(false),
+      icing_surrounding_size_(0),
+      is_send_base_page_url_disabled_cached_(false),
+      is_send_base_page_url_disabled_(false),
+      is_decode_mentions_disabled_cached_(false),
+      is_decode_mentions_disabled_(false) {}
+
+ContextualSearchFieldTrial::~ContextualSearchFieldTrial() {}
+
+std::string ContextualSearchFieldTrial::GetResolverURLPrefix() {
+  if (!is_resolver_url_prefix_cached_) {
+    is_resolver_url_prefix_cached_ = true;
+    resolver_url_prefix_ = GetSwitch(kContextualSearchResolverUrl);
+    if (resolver_url_prefix_.empty())
+      resolver_url_prefix_ = GetParam(kContextualSearchResolverUrl);
+  }
+  return resolver_url_prefix_;
+}
+
+int ContextualSearchFieldTrial::GetSurroundingSize() {
+  return GetIntParamValueOrDefault(kContextualSearchSurroundingSizeParamName,
+                                   kContextualSearchDefaultContentSize,
+                                   &is_surrounding_size_cached_,
+                                   &surrounding_size_);
+}
+
+int ContextualSearchFieldTrial::GetIcingSurroundingSize() {
+  return GetIntParamValueOrDefault(
+      kContextualSearchIcingSurroundingSizeParamName,
+      kContextualSearchDefaultIcingSurroundingSize,
+      &is_icing_surrounding_size_cached_, &icing_surrounding_size_);
+}
+
+bool ContextualSearchFieldTrial::IsSendBasePageURLDisabled() {
+  return GetBooleanParam(kContextualSearchSendURLDisabledParamName,
+                         &is_send_base_page_url_disabled_cached_,
+                         &is_send_base_page_url_disabled_);
+}
+
+bool ContextualSearchFieldTrial::IsDecodeMentionsDisabled() {
+  return GetBooleanParam(kContextualSearchDecodeMentionsDisabledParamName,
+                         &is_decode_mentions_disabled_cached_,
+                         &is_decode_mentions_disabled_);
+}
+
+bool ContextualSearchFieldTrial::GetBooleanParam(const std::string& name,
+                                                 bool* is_value_cached,
+                                                 bool* cached_value) {
+  if (!*is_value_cached) {
+    *is_value_cached = true;
+    std::string string_value = GetSwitch(name);
+    // A switch with an empty value is true.
+    bool has_switch = HasSwitch(name);
+    if (has_switch && string_value.empty())
+      string_value = kAnyNonEmptyValue;
+    if (!has_switch)
+      string_value = GetParam(name);
+    *cached_value = !string_value.empty() && string_value != kFalseValue;
+  }
+  return *cached_value;
+}
+
+int ContextualSearchFieldTrial::GetIntParamValueOrDefault(
+    const std::string& name,
+    const int default_value,
+    bool* is_value_cached,
+    int* cached_value) {
+  if (!*is_value_cached) {
+    *is_value_cached = true;
+    std::string param_string = GetSwitch(name);
+    if (param_string.empty())
+      param_string = GetParam(name);
+
+    int param_int;
+    if (!param_string.empty() && base::StringToInt(param_string, &param_int))
+      *cached_value = param_int;
+    else
+      *cached_value = default_value;
+  }
+  return *cached_value;
+}
+
+bool ContextualSearchFieldTrial::HasSwitch(const std::string& name) {
+  return base::CommandLine::ForCurrentProcess()->HasSwitch(name);
+}
+
+std::string ContextualSearchFieldTrial::GetSwitch(const std::string& name) {
+  if (!HasSwitch(name))
+    return std::string();
+  else
+    return base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(name);
+}
+
+std::string ContextualSearchFieldTrial::GetParam(const std::string& name) {
+  return variations::GetVariationParamValue(kContextualSearchFieldTrialName,
+                                            name);
+}
diff --git a/chrome/browser/android/contextualsearch/contextual_search_field_trial.h b/chrome/browser/android/contextualsearch/contextual_search_field_trial.h
new file mode 100644
index 0000000..deadf9f5
--- /dev/null
+++ b/chrome/browser/android/contextualsearch/contextual_search_field_trial.h
@@ -0,0 +1,86 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ANDROID_CONTEXTUALSEARCH_CONTEXTUAL_SEARCH_FIELD_TRIAL_H_
+#define CHROME_BROWSER_ANDROID_CONTEXTUALSEARCH_CONTEXTUAL_SEARCH_FIELD_TRIAL_H_
+
+#include <stddef.h>
+
+#include "base/values.h"
+
+// This class manages the Contextual Search native field trials.
+class ContextualSearchFieldTrial {
+ public:
+  ContextualSearchFieldTrial();
+  ~ContextualSearchFieldTrial();
+
+  // Returns a partial URL to use for a Contextual Search Resolve request, or
+  // an empty string if no override is required.  The returned value is a prefix
+  // of a URL -- from the beginning up through the GWS end-point in the path,
+  // which consists of the authority and the beginning of the path.
+  std::string GetResolverURLPrefix();
+
+  // Gets the size of the surrounding text to return for normal Resolve requests
+  // when a Contextual Search is being performed.
+  int GetSurroundingSize();
+
+  // Gets the size of the surrounding text to return for Icing when a Contextual
+  // Search is being performed.
+  int GetIcingSurroundingSize();
+
+  // Gets whether sending the URL of the base page is disabled.
+  bool IsSendBasePageURLDisabled();
+
+  // Gets whether decoding the mentions fields in the Resolve is disabled.
+  bool IsDecodeMentionsDisabled();
+
+  // Disables the cache.
+  void DisableCache();
+
+  // Constant used in tests.
+  static const int kContextualSearchDefaultIcingSurroundingSize;
+
+ protected:
+  // Checks if command-line switch of the given name exists.
+  virtual bool HasSwitch(const std::string& name);
+
+  // Gets a command-line switch of the given name, returns the empty string
+  // if the switch does not exist.
+  virtual std::string GetSwitch(const std::string& name);
+
+  // Gets a Variation parameter by the given name.
+  virtual std::string GetParam(const std::string& name);
+
+ private:
+  // Gets a boolean param value of the given name from the Contextual Search
+  // field trial.  Default is false if no param is present.
+  bool GetBooleanParam(const std::string& param_name,
+                       bool* is_value_cached,
+                       bool* cached_value);
+
+  // Gets an int param value of the given name from the Contextual Search
+  // field trial.  Returns the |default_value| if no switch or param is present.
+  // Caches the result pointed to by the given |cached_value|, using the given
+  // |is_value_cached| to remember if the value has been cached or not.
+  int GetIntParamValueOrDefault(const std::string& param_name,
+                                const int default_value,
+                                bool* is_value_cached,
+                                int* cached_value);
+
+  // Cached values.
+  bool is_resolver_url_prefix_cached_;
+  std::string resolver_url_prefix_;
+  bool is_surrounding_size_cached_;
+  int surrounding_size_;
+  bool is_icing_surrounding_size_cached_;
+  int icing_surrounding_size_;
+  bool is_send_base_page_url_disabled_cached_;
+  bool is_send_base_page_url_disabled_;
+  bool is_decode_mentions_disabled_cached_;
+  bool is_decode_mentions_disabled_;
+
+  DISALLOW_COPY_AND_ASSIGN(ContextualSearchFieldTrial);
+};
+
+#endif  // CHROME_BROWSER_ANDROID_CONTEXTUALSEARCH_CONTEXTUAL_SEARCH_FIELD_TRIAL_H_
diff --git a/chrome/browser/android/contextualsearch/contextual_search_field_trial_unittest.cc b/chrome/browser/android/contextualsearch/contextual_search_field_trial_unittest.cc
new file mode 100644
index 0000000..6dc7795
--- /dev/null
+++ b/chrome/browser/android/contextualsearch/contextual_search_field_trial_unittest.cc
@@ -0,0 +1,151 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/android/contextualsearch/contextual_search_field_trial.h"
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Tests ContextualSearchFieldTrail class.
+class ContextualSearchFieldTrailTest : public testing::Test {
+ public:
+  ContextualSearchFieldTrailTest() {}
+  ~ContextualSearchFieldTrailTest() override {}
+
+  // Inner class that stubs out access to Variations and command-line switches.
+  class ContextualSearchFieldTrailStubbed : public ContextualSearchFieldTrial {
+   public:
+    // Use these to set a non-empty value to override return of a Get method.
+    void SetSwitchValue(const std::string& value);
+    void SetParamValue(const std::string& value);
+
+   protected:
+    // These are overridden to return the Set value above.
+    bool HasSwitch(const std::string& name) override;
+    std::string GetSwitch(const std::string& name) override;
+    std::string GetParam(const std::string& name) override;
+
+   private:
+    bool does_have_switch_;
+    std::string switch_value_;
+    std::string param_value_;
+  };
+
+  // The class under test.
+  scoped_ptr<ContextualSearchFieldTrailStubbed> field_trial_;
+
+ protected:
+  void SetUp() override {
+    field_trial_.reset(new ContextualSearchFieldTrailStubbed());
+  }
+
+  void TearDown() override {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ContextualSearchFieldTrailTest);
+};
+
+bool ContextualSearchFieldTrailTest::ContextualSearchFieldTrailStubbed::
+    HasSwitch(const std::string& name) {
+  return does_have_switch_;
+}
+
+void ContextualSearchFieldTrailTest::ContextualSearchFieldTrailStubbed::
+    SetSwitchValue(const std::string& value) {
+  switch_value_ = value;
+  does_have_switch_ = true;
+}
+
+std::string
+ContextualSearchFieldTrailTest::ContextualSearchFieldTrailStubbed::GetSwitch(
+    const std::string& name) {
+  return switch_value_;
+}
+
+void ContextualSearchFieldTrailTest::ContextualSearchFieldTrailStubbed::
+    SetParamValue(const std::string& value) {
+  param_value_ = value;
+}
+
+std::string
+ContextualSearchFieldTrailTest::ContextualSearchFieldTrailStubbed::GetParam(
+    const std::string& name) {
+  return param_value_;
+}
+
+TEST_F(ContextualSearchFieldTrailTest, IntegerDefaultValue) {
+  // Should return this default value.
+  EXPECT_EQ(
+      ContextualSearchFieldTrial::kContextualSearchDefaultIcingSurroundingSize,
+      field_trial_->GetIcingSurroundingSize());
+}
+
+TEST_F(ContextualSearchFieldTrailTest, IntegerParamOverrides) {
+  // Params override defaults.
+  field_trial_->SetParamValue("500");
+  EXPECT_EQ(500, field_trial_->GetIcingSurroundingSize());
+}
+
+TEST_F(ContextualSearchFieldTrailTest, IntegerSwitchOverrides) {
+  field_trial_->SetParamValue("500");
+  // Switches override params.
+  field_trial_->SetSwitchValue("200");
+  EXPECT_EQ(200, field_trial_->GetIcingSurroundingSize());
+}
+
+TEST_F(ContextualSearchFieldTrailTest, IntegerJunkIgnored) {
+  // A junk value effectively resets the switch.
+  field_trial_->SetSwitchValue("foo");
+  EXPECT_EQ(
+      ContextualSearchFieldTrial::kContextualSearchDefaultIcingSurroundingSize,
+      field_trial_->GetIcingSurroundingSize());
+}
+
+TEST_F(ContextualSearchFieldTrailTest, BooleanDefaultValue) {
+  // Should return this default value.
+  EXPECT_FALSE(field_trial_->IsSendBasePageURLDisabled());
+}
+
+TEST_F(ContextualSearchFieldTrailTest, BooleanParamOverrides) {
+  // Params override defaults.
+  field_trial_->SetParamValue("any");
+  EXPECT_TRUE(field_trial_->IsSendBasePageURLDisabled());
+}
+
+TEST_F(ContextualSearchFieldTrailTest, BooleanFalseParam) {
+  field_trial_->SetParamValue("false");
+  EXPECT_FALSE(field_trial_->IsSendBasePageURLDisabled());
+}
+
+TEST_F(ContextualSearchFieldTrailTest, BooleanSwitchOverrides) {
+  field_trial_->SetParamValue("false");
+  // Switches override params.
+  field_trial_->SetSwitchValue("any");
+  EXPECT_TRUE(field_trial_->IsSendBasePageURLDisabled());
+}
+
+TEST_F(ContextualSearchFieldTrailTest, BooleanEmptySwitch) {
+  // An empty switch that's present should return true;
+  field_trial_->SetSwitchValue("");
+  EXPECT_TRUE(field_trial_->IsSendBasePageURLDisabled());
+}
+
+TEST_F(ContextualSearchFieldTrailTest, StringDefaultEmpty) {
+  // Default should return an empty string.
+  EXPECT_TRUE(field_trial_->GetResolverURLPrefix().empty());
+}
+
+TEST_F(ContextualSearchFieldTrailTest, StringParamOverrides) {
+  // Params override.
+  field_trial_->SetParamValue("param");
+  EXPECT_EQ("param", field_trial_->GetResolverURLPrefix());
+}
+
+TEST_F(ContextualSearchFieldTrailTest, StringSwitchOverrides) {
+  field_trial_->SetParamValue("param");
+  // Switches override params.
+  field_trial_->SetSwitchValue("switch");
+  EXPECT_EQ("switch", field_trial_->GetResolverURLPrefix());
+}
diff --git a/chrome/browser/android/download/download_manager_service.cc b/chrome/browser/android/download/download_manager_service.cc
index b52fe1ee..0e0ed61 100644
--- a/chrome/browser/android/download/download_manager_service.cc
+++ b/chrome/browser/android/download/download_manager_service.cc
@@ -8,10 +8,12 @@
 #include "base/message_loop/message_loop.h"
 #include "base/time/time.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/grit/generated_resources.h"
 #include "content/public/browser/android/download_controller_android.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/download_item.h"
 #include "jni/DownloadManagerService_jni.h"
+#include "ui/base/l10n/l10n_util.h"
 
 using base::android::JavaParamRef;
 using base::android::ConvertJavaStringToUTF8;
@@ -45,6 +47,8 @@
     jobject obj,
     content::DownloadManager* manager)
     : java_ref_(env, obj), manager_(manager) {
+  content::DownloadControllerAndroid::Get()->SetDefaultDownloadFileName(
+      l10n_util::GetStringUTF8(IDS_DEFAULT_DOWNLOAD_FILENAME));
   manager_->AddObserver(this);
 }
 
diff --git a/chrome/browser/android/download/download_manager_service_unittest.cc b/chrome/browser/android/download/download_manager_service_unittest.cc
index c400c8a..7b26c2a 100644
--- a/chrome/browser/android/download/download_manager_service_unittest.cc
+++ b/chrome/browser/android/download/download_manager_service_unittest.cc
@@ -115,8 +115,10 @@
   MOCK_CONST_METHOD0(GetDelegate, content::DownloadManagerDelegate*());
   MOCK_METHOD0(Shutdown, void());
   MOCK_METHOD1(GetAllDownloads, void(DownloadVector*));
-  MOCK_METHOD3(RemoveDownloadsByOriginAndTime,
-               int(const url::Origin&, base::Time, base::Time));
+  MOCK_METHOD3(RemoveDownloadsByURLAndTime,
+               int(const base::Callback<bool(const GURL&)>& url_filter,
+                   base::Time,
+                   base::Time));
   MOCK_METHOD2(RemoveDownloadsBetween, int(base::Time, base::Time));
   MOCK_METHOD1(RemoveDownloads, int(base::Time));
   MOCK_METHOD0(RemoveAllDownloads, int());
diff --git a/chrome/browser/android/history_report/usage_report_util.cc b/chrome/browser/android/history_report/usage_report_util.cc
index c2c696e..f6c9efdc 100644
--- a/chrome/browser/android/history_report/usage_report_util.cc
+++ b/chrome/browser/android/history_report/usage_report_util.cc
@@ -9,7 +9,7 @@
 #include <sstream>
 
 #include "chrome/browser/android/proto/delta_file.pb.h"
-#include "net/base/net_util.h"
+#include "net/base/url_util.h"
 #include "url/gurl.h"
 
 namespace history_report {
diff --git a/chrome/browser/android/ntp_snippets_bridge.cc b/chrome/browser/android/ntp_snippets_bridge.cc
new file mode 100644
index 0000000..1613ae42
--- /dev/null
+++ b/chrome/browser/android/ntp_snippets_bridge.cc
@@ -0,0 +1,84 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/android/ntp_snippets_bridge.h"
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_array.h"
+#include "base/android/scoped_java_ref.h"
+#include "chrome/browser/ntp_snippets/ntp_snippets_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_android.h"
+#include "components/ntp_snippets/ntp_snippet.h"
+#include "components/ntp_snippets/ntp_snippets_service.h"
+#include "jni/SnippetsBridge_jni.h"
+
+using base::android::JavaParamRef;
+using base::android::ToJavaArrayOfStrings;
+using ntp_snippets::NTPSnippetsService;
+using ntp_snippets::NTPSnippetsServiceObserver;
+
+static jlong Init(JNIEnv* env,
+                  const JavaParamRef<jobject>& obj,
+                  const JavaParamRef<jobject>& j_profile,
+                  const JavaParamRef<jobject>& j_observer) {
+  NTPSnippetsBridge* snippets_bridge =
+      new NTPSnippetsBridge(env, j_profile, j_observer);
+  return reinterpret_cast<intptr_t>(snippets_bridge);
+}
+
+NTPSnippetsBridge::NTPSnippetsBridge(JNIEnv* env,
+                                     jobject j_profile,
+                                     jobject j_observer)
+    : snippet_service_observer_(this) {
+  observer_.Reset(env, j_observer);
+
+  Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
+  ntp_snippets_service_ = NTPSnippetsServiceFactory::GetForProfile(profile);
+  snippet_service_observer_.Add(ntp_snippets_service_);
+  if (ntp_snippets_service_->is_loaded())
+    NTPSnippetsServiceLoaded(ntp_snippets_service_);
+}
+
+NTPSnippetsBridge::~NTPSnippetsBridge() {}
+
+void NTPSnippetsBridge::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) {
+  delete this;
+}
+
+void NTPSnippetsBridge::NTPSnippetsServiceLoaded(NTPSnippetsService* service) {
+  if (observer_.is_null())
+    return;
+
+  std::vector<std::string> titles;
+  std::vector<std::string> urls;
+  std::vector<std::string> thumbnail_urls;
+  std::vector<std::string> snippets;
+  for (const ntp_snippets::NTPSnippet& snippet : *service) {
+    titles.push_back(snippet.title());
+    urls.push_back(snippet.url().spec());
+    thumbnail_urls.push_back(snippet.salient_image_url().spec());
+    snippets.push_back(snippet.snippet());
+  }
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_SnippetsObserver_onSnippetsAvailable(
+      env, observer_.obj(), ToJavaArrayOfStrings(env, titles).obj(),
+      ToJavaArrayOfStrings(env, urls).obj(),
+      ToJavaArrayOfStrings(env, thumbnail_urls).obj(),
+      ToJavaArrayOfStrings(env, snippets).obj());
+}
+
+void NTPSnippetsBridge::NTPSnippetsServiceShutdown(
+    NTPSnippetsService* service) {
+  observer_.Reset();
+  snippet_service_observer_.Remove(ntp_snippets_service_);
+}
+
+// static
+bool NTPSnippetsBridge::Register(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
diff --git a/chrome/browser/android/ntp_snippets_bridge.h b/chrome/browser/android/ntp_snippets_bridge.h
new file mode 100644
index 0000000..727cd27
--- /dev/null
+++ b/chrome/browser/android/ntp_snippets_bridge.h
@@ -0,0 +1,44 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ANDROID_NTP_SNIPPETS_BRIDGE_H_
+#define CHROME_BROWSER_ANDROID_NTP_SNIPPETS_BRIDGE_H_
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/scoped_observer.h"
+#include "components/ntp_snippets/ntp_snippets_service.h"
+
+// The C++ counterpart to NTPSnippetsBridge.java. Enables Java code to access
+// the list of snippets to show on the NTP
+class NTPSnippetsBridge : public ntp_snippets::NTPSnippetsServiceObserver {
+ public:
+  explicit NTPSnippetsBridge(JNIEnv* env,
+                             jobject j_profile,
+                             jobject j_observer);
+  void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
+
+  static bool Register(JNIEnv* env);
+
+ private:
+  ~NTPSnippetsBridge() override;
+
+  // NTPSnippetsServiceObserver overrides
+  void NTPSnippetsServiceLoaded(
+      ntp_snippets::NTPSnippetsService* service) override;
+  void NTPSnippetsServiceShutdown(
+      ntp_snippets::NTPSnippetsService* service) override;
+
+  ntp_snippets::NTPSnippetsService* ntp_snippets_service_;
+
+  base::android::ScopedJavaGlobalRef<jobject> observer_;
+  ScopedObserver<ntp_snippets::NTPSnippetsService,
+                 ntp_snippets::NTPSnippetsServiceObserver>
+      snippet_service_observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(NTPSnippetsBridge);
+};
+
+#endif  // CHROME_BROWSER_ANDROID_NTP_SNIPPETS_BRIDGE_H_
diff --git a/chrome/browser/android/ntp_snippets_controller.cc b/chrome/browser/android/ntp_snippets_controller.cc
new file mode 100644
index 0000000..a252d52d
--- /dev/null
+++ b/chrome/browser/android/ntp_snippets_controller.cc
@@ -0,0 +1,34 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/android/ntp_snippets_controller.h"
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "chrome/browser/ntp_snippets/ntp_snippets_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_android.h"
+#include "components/ntp_snippets/ntp_snippets_service.h"
+#include "jni/SnippetsController_jni.h"
+
+using base::android::JavaParamRef;
+
+static void FetchSnippets(JNIEnv* env,
+                          const JavaParamRef<jobject>& obj,
+                          const JavaParamRef<jobject>& jprofile,
+                          jboolean overwrite) {
+  Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile);
+  if (profile) {
+    ntp_snippets::NTPSnippetsService* ntp_snippets_service =
+        NTPSnippetsServiceFactory::GetForProfile(profile);
+    ntp_snippets_service->FetchSnippets(overwrite);
+  }
+}
+
+// static
+bool NTPSnippetsController::Register(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
diff --git a/chrome/browser/android/ntp_snippets_controller.h b/chrome/browser/android/ntp_snippets_controller.h
new file mode 100644
index 0000000..d5bc137
--- /dev/null
+++ b/chrome/browser/android/ntp_snippets_controller.h
@@ -0,0 +1,21 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ANDROID_NTP_SNIPPETS_CONTROLLER_H_
+#define CHROME_BROWSER_ANDROID_NTP_SNIPPETS_CONTROLLER_H_
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+
+// The C++ counterpart to SnippetsController.java. Enables Java code to fetch
+// snippets from the server
+class NTPSnippetsController {
+ public:
+  static bool Register(JNIEnv* env);
+
+  DISALLOW_COPY_AND_ASSIGN(NTPSnippetsController);
+};
+
+#endif  // CHROME_BROWSER_ANDROID_NTP_SNIPPETS_CONTROLLER_H_
diff --git a/chrome/browser/android/omnibox/autocomplete_controller_android.cc b/chrome/browser/android/omnibox/autocomplete_controller_android.cc
index ebbc4ff4..2551d59 100644
--- a/chrome/browser/android/omnibox/autocomplete_controller_android.cc
+++ b/chrome/browser/android/omnibox/autocomplete_controller_android.cc
@@ -221,6 +221,7 @@
     jboolean is_query_in_omnibox,
     jboolean focused_from_fakebox,
     jlong elapsed_time_since_first_modified,
+    jint completed_length,
     const JavaParamRef<jobject>& j_web_contents) {
   base::string16 url = ConvertJavaStringToUTF16(env, j_current_url);
   const GURL current_url = GURL(url);
@@ -242,7 +243,7 @@
       SessionTabHelper::IdForTab(web_contents),
       current_page_classification,
       base::TimeDelta::FromMilliseconds(elapsed_time_since_first_modified),
-      base::string16::npos,
+      completed_length,
       now - autocomplete_controller_->last_time_default_match_changed(),
       autocomplete_controller_->result());
   autocomplete_controller_->AddProvidersInfo(&log.providers_info);
diff --git a/chrome/browser/android/omnibox/autocomplete_controller_android.h b/chrome/browser/android/omnibox/autocomplete_controller_android.h
index b4c1e9e..f08856bb 100644
--- a/chrome/browser/android/omnibox/autocomplete_controller_android.h
+++ b/chrome/browser/android/omnibox/autocomplete_controller_android.h
@@ -67,6 +67,7 @@
       jboolean is_query_in_omnibox,
       jboolean focused_from_fakebox,
       jlong elapsed_time_since_first_modified,
+      jint completed_length,
       const base::android::JavaParamRef<jobject>& j_web_contents);
   void DeleteSuggestion(JNIEnv* env,
                         const base::android::JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc b/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc
index 61e5f32..bf15ceb6 100644
--- a/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc
+++ b/chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.cc
@@ -9,7 +9,6 @@
 #include "chrome/browser/external_protocol/external_protocol_handler.h"
 #include "chrome/browser/profiles/profile_io_data.h"
 #include "content/public/common/url_constants.h"
-#include "net/base/net_util.h"
 #include "url/url_util.h"
 
 ChromeAutocompleteSchemeClassifier::ChromeAutocompleteSchemeClassifier(
diff --git a/chrome/browser/autocomplete/in_memory_url_index_factory.cc b/chrome/browser/autocomplete/in_memory_url_index_factory.cc
index c9fbc44..4d12989e 100644
--- a/chrome/browser/autocomplete/in_memory_url_index_factory.cc
+++ b/chrome/browser/autocomplete/in_memory_url_index_factory.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/common/pref_names.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/keyed_service/core/service_access_type.h"
@@ -34,6 +35,7 @@
           BrowserContextDependencyManager::GetInstance()) {
   DependsOn(BookmarkModelFactory::GetInstance());
   DependsOn(HistoryServiceFactory::GetInstance());
+  DependsOn(TemplateURLServiceFactory::GetInstance());
 }
 
 InMemoryURLIndexFactory::~InMemoryURLIndexFactory() {
@@ -49,6 +51,7 @@
       BookmarkModelFactory::GetForProfile(profile),
       HistoryServiceFactory::GetForProfile(profile,
                                            ServiceAccessType::IMPLICIT_ACCESS),
+      TemplateURLServiceFactory::GetForProfile(profile),
       content::BrowserThread::GetBlockingPool(), profile->GetPath(),
       profile->GetPrefs()->GetString(prefs::kAcceptLanguages),
       chrome_schemes_to_whitelist);
diff --git a/chrome/browser/bookmarks/bookmark_model_factory.cc b/chrome/browser/bookmarks/bookmark_model_factory.cc
index 8a86b71..cece0df9 100644
--- a/chrome/browser/bookmarks/bookmark_model_factory.cc
+++ b/chrome/browser/bookmarks/bookmark_model_factory.cc
@@ -81,11 +81,11 @@
                        content::BrowserThread::GetMessageLoopProxyForThread(
                            content::BrowserThread::UI));
   bool register_bookmark_undo_service_as_observer = true;
-#if !defined(OS_IOS) && !BUILDFLAG(ANDROID_JAVA_UI)
+#if !BUILDFLAG(ANDROID_JAVA_UI)
   register_bookmark_undo_service_as_observer =
       base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kEnableBookmarkUndo);
-#endif  // !defined(OS_IOS) && !BUILDFLAG(ANDROID_JAVA_UI)
+#endif  // !BUILDFLAG(ANDROID_JAVA_UI)
   if (register_bookmark_undo_service_as_observer)
     BookmarkUndoServiceFactory::GetForProfile(profile)->Start(bookmark_model);
 
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 9f17e38..1e26f78 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -829,9 +829,9 @@
 
   registry->RegisterBooleanPref(prefs::kAllowCrossOriginAuthPrompt, false);
 
-#if defined(OS_CHROMEOS) || defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
   registry->RegisterBooleanPref(prefs::kEulaAccepted, false);
-#endif  // defined(OS_CHROMEOS) || defined(OS_ANDROID) || defined(OS_IOS)
+#endif  // defined(OS_CHROMEOS) || defined(OS_ANDROID)
 #if defined(OS_WIN)
   if (base::win::GetVersion() >= base::win::VERSION_WIN7) {
     registry->RegisterStringPref(prefs::kRelaunchMode,
@@ -1027,7 +1027,7 @@
 
   // This preference must be kept in sync with external values; update them
   // whenever the preference or its controlling policy changes.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   pref_change_registrar_.Add(
       metrics::prefs::kMetricsReportingEnabled,
       base::Bind(&BrowserProcessImpl::ApplyMetricsReportingPolicy,
@@ -1066,7 +1066,7 @@
   if (local_state_->IsManagedPreference(prefs::kDefaultBrowserSettingEnabled))
     ApplyDefaultBrowserPolicy();
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   ApplyMetricsReportingPolicy();
 #endif
 
@@ -1096,7 +1096,7 @@
 #endif
 #endif  // defined(ENABLE_PLUGINS)
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   storage_monitor::StorageMonitor::Create();
 #endif
 
@@ -1227,7 +1227,7 @@
 }
 
 void BrowserProcessImpl::ApplyMetricsReportingPolicy() {
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   CHECK(BrowserThread::PostTask(
       BrowserThread::FILE, FROM_HERE,
       base::Bind(
@@ -1239,7 +1239,7 @@
 void BrowserProcessImpl::CacheDefaultWebClientState() {
 #if defined(OS_CHROMEOS)
   cached_default_web_client_state_ = shell_integration::IS_DEFAULT;
-#elif !defined(OS_ANDROID) && !defined(OS_IOS)
+#elif !defined(OS_ANDROID)
   cached_default_web_client_state_ = shell_integration::GetDefaultBrowser();
 #endif
 }
diff --git a/chrome/browser/browser_process_platform_part.h b/chrome/browser/browser_process_platform_part.h
index 08d1eda5..fed32627 100644
--- a/chrome/browser/browser_process_platform_part.h
+++ b/chrome/browser/browser_process_platform_part.h
@@ -12,7 +12,7 @@
 #include "chrome/browser/browser_process_platform_part_android.h"
 #elif defined(OS_CHROMEOS)
 #include "chrome/browser/browser_process_platform_part_chromeos.h"
-#elif defined(OS_MACOSX) && !defined(OS_IOS)
+#elif defined(OS_MACOSX)
 #include "chrome/browser/browser_process_platform_part_mac.h"
 #else
 #include "chrome/browser/browser_process_platform_part_base.h"
diff --git a/chrome/browser/browser_process_platform_part_base.cc b/chrome/browser/browser_process_platform_part_base.cc
index 8e56a0e53..c7b19926 100644
--- a/chrome/browser/browser_process_platform_part_base.cc
+++ b/chrome/browser/browser_process_platform_part_base.cc
@@ -8,10 +8,8 @@
 #include "chrome/browser/lifetime/application_lifetime.h"
 
 #if defined(ENABLE_CONFIGURATION_POLICY)
-#include "components/policy/core/browser/browser_policy_connector.h"
-#if !defined(OS_IOS)
 #include "chrome/browser/policy/chrome_browser_policy_connector.h"
-#endif
+#include "components/policy/core/browser/browser_policy_connector.h"
 #endif
 
 BrowserProcessPlatformPartBase::BrowserProcessPlatformPartBase() {
@@ -28,9 +26,9 @@
 }
 
 void BrowserProcessPlatformPartBase::AttemptExit() {
-// chrome::CloseAllBrowsers() doesn't link on OS_IOS and OS_ANDROID, but
-// OS_ANDROID overrides this method already and OS_IOS never calls this.
-#if defined(OS_IOS) || defined(OS_ANDROID)
+// chrome::CloseAllBrowsers() doesn't link on OS_ANDROID, but it overrides this
+// method already.
+#if defined(OS_ANDROID)
   NOTREACHED();
 #else
   // On most platforms, closing all windows causes the application to exit.
@@ -44,12 +42,7 @@
 #if defined(ENABLE_CONFIGURATION_POLICY)
 scoped_ptr<policy::BrowserPolicyConnector>
 BrowserProcessPlatformPartBase::CreateBrowserPolicyConnector() {
-#if defined(OS_IOS)
-  NOTREACHED();
-  return scoped_ptr<policy::BrowserPolicyConnector>();
-#else
   return scoped_ptr<policy::BrowserPolicyConnector>(
       new policy::ChromeBrowserPolicyConnector());
-#endif
 }
 #endif
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index f0593ce..5379443 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -202,6 +202,7 @@
         <include name="IDR_MD_HISTORY_HISTORY_LIST_JS" file="resources\md_history\history_list.js" type="BINDATA" />
         <include name="IDR_MD_HISTORY_HISTORY_TOOLBAR_HTML" file="resources\md_history\history_toolbar.html" type="BINDATA" />
         <include name="IDR_MD_HISTORY_HISTORY_TOOLBAR_JS" file="resources\md_history\history_toolbar.js" type="BINDATA" />
+        <include name="IDR_MD_HISTORY_SHARED_STYLE_HTML" file="resources\md_history\shared_style.html" type="BINDATA" />
       </if>
 
       <include name="IDR_OTHER_DEVICES_JS" file="resources\history\other_devices.js" flattenhtml="true" type="BINDATA" />
diff --git a/chrome/browser/browsing_data/browsing_data_counter_utils.cc b/chrome/browser/browsing_data/browsing_data_counter_utils.cc
index e485a181..d40ee0f 100644
--- a/chrome/browser/browsing_data/browsing_data_counter_utils.cc
+++ b/chrome/browser/browsing_data/browsing_data_counter_utils.cc
@@ -27,13 +27,8 @@
     return false;
   }
 
-  // Enabled by default on desktop. Disabled on Android until the feature
-  // is finished.
-#if defined(OS_ANDROID)
-  return false;
-#else
+  // Enabled by default.
   return true;
-#endif
 }
 
 // A helper function to display the size of cache in units of MB or higher.
diff --git a/chrome/browser/browsing_data/browsing_data_remover.cc b/chrome/browser/browsing_data/browsing_data_remover.cc
index ca6d7b3..1fab3eaf2 100644
--- a/chrome/browser/browsing_data/browsing_data_remover.cc
+++ b/chrome/browser/browsing_data/browsing_data_remover.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browsing_data/browsing_data_helper.h"
 #include "chrome/browser/browsing_data/browsing_data_remover_factory.h"
+#include "chrome/browser/browsing_data/origin_filter_builder.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/domain_reliability/service_factory.h"
@@ -343,7 +344,19 @@
   delete_end_ = time_range.end;
   remove_mask_ = remove_mask;
   origin_type_mask_ = origin_type_mask;
+
+  // TODO(msramek): Replace |remove_origin| with |filter| in all backends.
   const url::Origin remove_origin(remove_url);
+  OriginFilterBuilder builder(OriginFilterBuilder::BLACKLIST);
+  if (!remove_url.is_empty()) {
+    // Make sure that only URLs representing origins, with no extra components,
+    // are passed to this class.
+    DCHECK_EQ(remove_url, remove_url.GetOrigin());
+    builder.SetMode(OriginFilterBuilder::WHITELIST);
+    builder.AddOrigin(url::Origin(remove_origin));
+  }
+  base::Callback<bool(const GURL& url)> same_origin_filter =
+      builder.BuildSameOriginFilter();
 
   PrefService* prefs = profile_->GetPrefs();
   bool may_delete_history = prefs->GetBoolean(
@@ -379,6 +392,12 @@
         HistoryServiceFactory::GetForProfile(
             profile_, ServiceAccessType::EXPLICIT_ACCESS);
     if (history_service) {
+      // Selective history deletion is currently done through HistoryUI ->
+      // HistoryBackend -> HistoryService, and that is for individual URLs,
+      // not origins. The code below is currently unused, as the only callsite
+      // supplying |remove_url| is the unittest.
+      // TODO(msramek): Make it possible to delete history per origin, not just
+      // per URL, and use that functionality here.
       std::set<GURL> restrict_urls;
       if (!remove_url.is_empty())
         restrict_urls.insert(remove_url);
@@ -559,12 +578,8 @@
     content::RecordAction(UserMetricsAction("ClearBrowsingData_Downloads"));
     content::DownloadManager* download_manager =
         BrowserContext::GetDownloadManager(profile_);
-    if (remove_url.is_empty()) {
-      download_manager->RemoveDownloadsBetween(delete_begin_, delete_end_);
-    } else {
-      download_manager->RemoveDownloadsByOriginAndTime(
-          remove_origin, delete_begin_, delete_end_);
-    }
+    download_manager->RemoveDownloadsByURLAndTime(
+        same_origin_filter, delete_begin_, delete_end_);
     DownloadPrefs* download_prefs = DownloadPrefs::FromDownloadManager(
         download_manager);
     download_prefs->SetSaveFilePath(download_prefs->DownloadPath());
diff --git a/chrome/browser/browsing_data/browsing_data_remover_unittest.cc b/chrome/browser/browsing_data/browsing_data_remover_unittest.cc
index 6aa8694..4661b55 100644
--- a/chrome/browser/browsing_data/browsing_data_remover_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_remover_unittest.cc
@@ -28,6 +28,7 @@
 #include "chrome/browser/browsing_data/browsing_data_helper.h"
 #include "chrome/browser/browsing_data/browsing_data_remover_factory.h"
 #include "chrome/browser/browsing_data/browsing_data_remover_test_util.h"
+#include "chrome/browser/browsing_data/origin_filter_builder.h"
 #include "chrome/browser/domain_reliability/service_factory.h"
 #include "chrome/browser/download/chrome_download_manager_delegate.h"
 #include "chrome/browser/favicon/favicon_service_factory.h"
@@ -263,6 +264,9 @@
 // origin.
 // (We cannot use equality-based matching because operator== is not defined for
 // Origin, and we in fact want to rely on IsSameOrigin for matching purposes.)
+// TODO(msramek): This is only used for backends that take url::Origin instead
+// of an url filter predicate to match URLs. Remove this when we fully switch
+// to url filter predicates.
 class SameOriginMatcher : public MatcherInterface<const url::Origin&> {
  public:
   explicit SameOriginMatcher(const url::Origin& reference)
@@ -289,6 +293,55 @@
   return MakeMatcher(new SameOriginMatcher(reference));
 }
 
+// Custom matcher to test the equivalence of two URL filters. Since those are
+// blackbox predicates, we can only approximate the equivalence by testing
+// whether the filter give the same answer for several URLs. This is currently
+// good enough for our testing purposes, to distinguish whitelists
+// and blacklists, empty and non-empty filters and such.
+// TODO(msramek): BrowsingDataRemover and some of its backends support URL
+// filters, but its constructor currently only takes a single URL and constructs
+// its own url filter. If an url filter was directly passed to
+// BrowsingDataRemover (what should eventually be the case), we can use the same
+// instance in the test as well, and thus simply test base::Callback::Equals()
+// in this matcher.
+class ProbablySameFilterMatcher
+    : public MatcherInterface<const base::Callback<bool(const GURL&)>&> {
+ public:
+  explicit ProbablySameFilterMatcher(
+      const base::Callback<bool(const GURL&)>& filter)
+      : to_match_(filter) {
+  }
+
+  virtual bool MatchAndExplain(const base::Callback<bool(const GURL&)>& filter,
+                               MatchResultListener* listener) const {
+    const GURL urls_to_test_[] =
+        {kOrigin1, kOrigin2, kOrigin3, GURL("invalid spec")};
+    for (GURL url : urls_to_test_) {
+      if (filter.Run(url) != to_match_.Run(url)) {
+        *listener << "The filters differ on the URL " << url;
+        return false;
+      }
+    }
+    return true;
+  }
+
+  virtual void DescribeTo(::std::ostream* os) const {
+    *os << "is probably the same url filter as " << &to_match_;
+  }
+
+  virtual void DescribeNegationTo(::std::ostream* os) const {
+    *os << "is definitely NOT the same url filter as " << &to_match_;
+  }
+
+ private:
+  const base::Callback<bool(const GURL&)>& to_match_;
+};
+
+inline Matcher<const base::Callback<bool(const GURL&)>&> ProbablySameFilter(
+    const base::Callback<bool(const GURL&)>& filter) {
+  return MakeMatcher(new ProbablySameFilterMatcher(filter));
+}
+
 }  // namespace
 
 // Testers -------------------------------------------------------------------
@@ -2170,8 +2223,12 @@
 
 TEST_F(BrowsingDataRemoverTest, RemoveDownloadsByTimeOnly) {
   RemoveDownloadsTester tester(GetProfile());
+  base::Callback<bool(const GURL&)> filter =
+      OriginFilterBuilder::BuildNoopFilter();
 
-  EXPECT_CALL(*tester.download_manager(), RemoveDownloadsBetween(_, _));
+  EXPECT_CALL(
+      *tester.download_manager(),
+      RemoveDownloadsByURLAndTime(ProbablySameFilter(filter), _, _));
 
   BlockUntilBrowsingDataRemoved(BrowsingDataRemover::EVERYTHING,
                                 BrowsingDataRemover::REMOVE_DOWNLOADS, false);
@@ -2179,10 +2236,13 @@
 
 TEST_F(BrowsingDataRemoverTest, RemoveDownloadsByOrigin) {
   RemoveDownloadsTester tester(GetProfile());
-  const url::Origin expectedOrigin(kOrigin1);
+  OriginFilterBuilder builder(OriginFilterBuilder::WHITELIST);
+  builder.AddOrigin(url::Origin(kOrigin1));
+  base::Callback<bool(const GURL&)> filter = builder.BuildSameOriginFilter();
 
-  EXPECT_CALL(*tester.download_manager(),
-              RemoveDownloadsByOriginAndTime(SameOrigin(expectedOrigin), _, _));
+  EXPECT_CALL(
+      *tester.download_manager(),
+      RemoveDownloadsByURLAndTime(ProbablySameFilter(filter), _, _));
 
   BlockUntilOriginDataRemoved(BrowsingDataRemover::EVERYTHING,
                               BrowsingDataRemover::REMOVE_DOWNLOADS, kOrigin1);
diff --git a/chrome/browser/browsing_data/origin_filter_builder.cc b/chrome/browser/browsing_data/origin_filter_builder.cc
new file mode 100644
index 0000000..900b01831
--- /dev/null
+++ b/chrome/browser/browsing_data/origin_filter_builder.cc
@@ -0,0 +1,111 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/browsing_data/origin_filter_builder.h"
+
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+
+namespace {
+
+bool NoopFilter(const GURL& url) {
+  return true;
+}
+
+}  // namespace
+
+OriginFilterBuilder::OriginFilterBuilder(Mode mode)
+    : mode_(mode) {
+}
+
+OriginFilterBuilder::~OriginFilterBuilder() {
+}
+
+void OriginFilterBuilder::AddOrigin(const url::Origin& origin) {
+  // TODO(msramek): Optimize OriginFilterBuilder for larger filters if needed.
+  DCHECK_LE(origin_list_.size(), 10U) << "OriginFilterBuilder is only suitable "
+                                         "for creating small filters.";
+
+  // By limiting the filter to non-unique origins, we can guarantee that
+  // origin1 < origin2 && origin1 > origin2 <=> origin1.isSameOrigin(origin2).
+  // This means that std::set::find() will use the same semantics for
+  // origin comparison as Origin::IsSameOriginWith(). Furthermore, this
+  // means that two filters are equal iff they are equal element-wise.
+  DCHECK(!origin.unique()) << "Invalid origin passed into OriginFilter.";
+
+  // TODO(msramek): All urls with file scheme currently map to the same
+  // origin. This is currently not a problem, but if it becomes one,
+  // consider recognizing the URL path.
+
+  origin_list_.insert(origin);
+}
+
+void OriginFilterBuilder::SetMode(Mode mode) {
+  mode_ = mode;
+}
+
+base::Callback<bool(const GURL&)>
+    OriginFilterBuilder::BuildSameOriginFilter() const {
+  std::set<url::Origin>* origins = new std::set<url::Origin>(origin_list_);
+  return base::Bind(&OriginFilterBuilder::MatchesURL,
+                    base::Owned(origins), mode_);
+}
+
+base::Callback<bool(const GURL&)>
+    OriginFilterBuilder::BuildDomainFilter() const {
+  std::set<url::Origin>* origins = new std::set<url::Origin>(origin_list_);
+  return base::Bind(&OriginFilterBuilder::MatchesURLWithSubdomains,
+                    base::Owned(origins), mode_);
+}
+
+// static
+base::Callback<bool(const GURL&)> OriginFilterBuilder::BuildNoopFilter() {
+  return base::Bind(&NoopFilter);
+}
+
+// static
+bool OriginFilterBuilder::MatchesURL(
+    std::set<url::Origin>* origins, Mode mode, const GURL& url) {
+  return ((origins->find(url::Origin(url)) != origins->end()) ==
+          (mode == WHITELIST));
+}
+
+// static
+bool OriginFilterBuilder::MatchesURLWithSubdomains(
+    std::set<url::Origin>* origins, Mode mode, const GURL& url) {
+  if (origins->empty())
+    return mode == BLACKLIST;
+
+  // If there is no concept of subdomains, simply delegate to MatchesURL().
+  if (url.HostIsIPAddress())
+    return MatchesURL(origins, mode, url);
+
+  // TODO(msramek): We do not expect filters to be particularly large.
+  // If they are, replace std::set with a trie for faster searching.
+  int port = url.EffectiveIntPort();
+  base::StringPiece host_piece = url.host_piece();
+  for (size_t i = 0; i < host_piece.length(); ++i) {
+    if (i != 0 && host_piece[i - 1] != '.')
+      continue;
+
+    url::Origin origin_with_removed_subdomain =
+        url::Origin::UnsafelyCreateOriginWithoutNormalization(
+            url.scheme_piece(),
+            host_piece.substr(i),
+            port);
+
+    // If we recognize the origin, return true for whitelist and false
+    // for blacklist.
+    if (origins->find(url::Origin(origin_with_removed_subdomain))
+        != origins->end()) {
+      return mode == WHITELIST;
+    }
+  }
+
+  // We do not recognize the URL. Return false for whitelist mode and true
+  // for blacklist mode.
+  return mode == BLACKLIST;
+}
diff --git a/chrome/browser/browsing_data/origin_filter_builder.h b/chrome/browser/browsing_data/origin_filter_builder.h
new file mode 100644
index 0000000..092ec42
--- /dev/null
+++ b/chrome/browser/browsing_data/origin_filter_builder.h
@@ -0,0 +1,70 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_BROWSING_DATA_ORIGIN_FILTER_BUILDER_H_
+#define CHROME_BROWSER_BROWSING_DATA_ORIGIN_FILTER_BUILDER_H_
+
+#include <ostream>
+#include <set>
+#include <vector>
+
+#include "base/callback.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+// A class that constructs URL deletion filters (represented as GURL->bool
+// predicates) that match certain origins.
+class OriginFilterBuilder {
+ public:
+  enum Mode {
+    WHITELIST,
+    BLACKLIST
+  };
+
+  // Constructs a filter with the given |mode| - whitelist or blacklist.
+  explicit OriginFilterBuilder(Mode mode);
+
+  ~OriginFilterBuilder();
+
+  // Adds the |origin| to the (white- or black-) list.
+  void AddOrigin(const url::Origin& origin);
+
+  // Sets the |mode| of the filter.
+  void SetMode(Mode mode);
+
+  // Builds a filter that matches URLs whose origins are in the whitelist,
+  // or aren't in the blacklist.
+  base::Callback<bool(const GURL&)> BuildSameOriginFilter() const;
+
+  // Build a filter that matches URLs whose origins, or origins obtained by
+  // replacing the host with any superdomain, are listed in the whitelist,
+  // or are not listed in the blacklist.
+  base::Callback<bool(const GURL&)> BuildDomainFilter() const;
+
+  // A convenience method to produce an empty blacklist, a filter that matches
+  // everything.
+  static base::Callback<bool(const GURL&)> BuildNoopFilter();
+
+ private:
+  // True if the origin of |url| is in the whitelist, or isn't in the blacklist.
+  // The whitelist or blacklist is represented as |origins| and |mode|.
+  static bool MatchesURL(
+      std::set<url::Origin>* origins, Mode mode, const GURL& url);
+
+  // True if any origin [scheme, host, port], such that |url| has the same
+  // scheme and port, and |url|'s host is the same or a subdomain of that host,
+  // is in the whitelist, or isn't in the blacklist. The whitelist or blacklist
+  // is represented as |origins| and |mode|.
+  static bool MatchesURLWithSubdomains(
+      std::set<url::Origin>* origins, Mode mode, const GURL& url);
+
+  // The list of origins and whether they should be interpreted as a whitelist
+  // or blacklist.
+  std::set<url::Origin> origin_list_;
+  Mode mode_;
+
+  DISALLOW_COPY_AND_ASSIGN(OriginFilterBuilder);
+};
+
+#endif  // CHROME_BROWSER_BROWSING_DATA_ORIGIN_FILTER_BUILDER_H_
diff --git a/chrome/browser/browsing_data/origin_filter_builder_unittest.cc b/chrome/browser/browsing_data/origin_filter_builder_unittest.cc
new file mode 100644
index 0000000..32fef25
--- /dev/null
+++ b/chrome/browser/browsing_data/origin_filter_builder_unittest.cc
@@ -0,0 +1,140 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/browsing_data/origin_filter_builder.h"
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace url {
+
+namespace {
+
+struct TestCase {
+  std::string url;
+  bool should_match;
+};
+
+void RunTestCase(
+    TestCase test_case, const base::Callback<bool(const GURL&)>& filter) {
+  if (test_case.should_match)
+    EXPECT_TRUE(filter.Run(GURL(test_case.url)));
+  else
+    EXPECT_FALSE(filter.Run(GURL(test_case.url)));
+}
+
+}  // namespace
+
+TEST(OriginFilterBuilderTest, Noop) {
+  // An no-op filter matches everything.
+  base::Callback<bool(const GURL&)> filter =
+      OriginFilterBuilder::BuildNoopFilter();
+
+  TestCase test_cases[] = {
+      { "https://www.google.com", true },
+      { "https://www.chrome.com", true },
+      { "invalid url spec", true }
+  };
+
+  for (TestCase test_case : test_cases)
+    RunTestCase(test_case, filter);
+}
+
+TEST(OriginFilterBuilderTest, Whitelist) {
+  OriginFilterBuilder builder(OriginFilterBuilder::WHITELIST);
+  builder.AddOrigin(Origin(GURL("https://www.google.com")));
+  builder.AddOrigin(Origin(GURL("http://www.example.com")));
+  base::Callback<bool(const GURL&)> filter = builder.BuildSameOriginFilter();
+
+  TestCase test_cases[] = {
+      // Whitelist matches any URL on the specified origins.
+      { "https://www.google.com", true },
+      { "https://www.google.com/?q=test", true },
+      { "http://www.example.com", true },
+      { "http://www.example.com/index.html", true },
+      { "http://www.example.com/foo/bar", true },
+
+      // Subdomains are different origins.
+      { "https://test.www.google.com", false },
+
+      // Different scheme or port is a different origin.
+      { "https://www.google.com:8000", false },
+      { "https://www.example.com/index.html", false },
+
+      // Different host is a different origin.
+      { "https://www.youtube.com", false },
+      { "https://www.chromium.org", false },
+  };
+
+  for (TestCase test_case : test_cases)
+    RunTestCase(test_case, filter);
+}
+
+TEST(OriginFilterBuilderTest, Blacklist) {
+  OriginFilterBuilder builder(OriginFilterBuilder::BLACKLIST);
+  builder.AddOrigin(Origin(GURL("https://www.google.com")));
+  builder.AddOrigin(Origin(GURL("http://www.example.com")));
+  base::Callback<bool(const GURL&)> filter = builder.BuildSameOriginFilter();
+
+  TestCase test_cases[] = {
+      // URLS on explicitly specified origins are not matched.
+      { "https://www.google.com", false },
+      { "https://www.google.com/?q=test", false },
+      { "http://www.example.com", false },
+      { "http://www.example.com/index.html", false },
+      { "http://www.example.com/foo/bar", false },
+
+      // Subdomains are different origins.
+      { "https://test.www.google.com", true },
+
+      // The same hosts but with different schemes and ports
+      // are not blacklisted.
+      { "https://www.google.com:8000", true },
+      { "https://www.example.com/index.html", true },
+
+      // Different hosts are not blacklisted.
+      { "https://www.chrome.com", true },
+      { "https://www.youtube.com", true },
+  };
+
+  for (TestCase test_case : test_cases)
+    RunTestCase(test_case, filter);
+}
+
+TEST(OriginFilterBuilderTest, MatchesURLWithSubdomain) {
+  OriginFilterBuilder builder(OriginFilterBuilder::WHITELIST);
+  builder.AddOrigin(Origin(GURL("https://www.google.com")));
+  base::Callback<bool(const GURL&)> filter = builder.BuildDomainFilter();
+
+  TestCase test_cases[] = {
+      // Any URL on the specified origin is matched.
+      { "https://www.google.com", true },
+      { "https://www.google.com/test.html", true },
+
+      // Subdomains are also matched.
+      { "https://foo.www.google.com", true },
+      { "https://foo.www.google.com/?q=test", true },
+      { "https://foo.bar.www.google.com", true },
+      { "https://foo.bar.www.google.com/test.html", true },
+      { "https://foo.bar.baz.www.google.com", true },
+
+      // Superdomains are not matched.
+      { "https://google.com", false },
+
+      // Different hosts are not matched.
+      { "https://www.chrome.com", false },
+      { "https://www.youtube.com", false },
+  };
+
+  for (TestCase test_case : test_cases)
+    RunTestCase(test_case, filter);
+}
+
+}  // namespace url
diff --git a/chrome/browser/chrome_browser_field_trials.cc b/chrome/browser/chrome_browser_field_trials.cc
index 760dd13..682271f 100644
--- a/chrome/browser/chrome_browser_field_trials.cc
+++ b/chrome/browser/chrome_browser_field_trials.cc
@@ -17,7 +17,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "components/metrics/metrics_pref_names.h"
 
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_ANDROID)
 #include "chrome/browser/chrome_browser_field_trials_mobile.h"
 #else
 #include "chrome/browser/chrome_browser_field_trials_desktop.h"
@@ -56,7 +56,7 @@
   // Field trials that are shared by all platforms.
   InstantiateDynamicTrials();
 
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_ANDROID)
   chrome::SetupMobileFieldTrials(parsed_command_line_);
 #else
   chrome::SetupDesktopFieldTrials(parsed_command_line_);
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 3138e4f..f43eb5d 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -80,6 +80,7 @@
 #include "chrome/browser/tracing/navigation_tracing.h"
 #include "chrome/browser/translate/translate_service.h"
 #include "chrome/browser/ui/app_list/app_list_service.h"
+#include "chrome/browser/ui/app_modal/chrome_javascript_native_dialog_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/host_desktop.h"
@@ -97,6 +98,7 @@
 #include "chrome/common/env_vars.h"
 #include "chrome/common/features.h"
 #include "chrome/common/logging_chrome.h"
+#include "chrome/common/media/media_resource_provider.h"
 #include "chrome/common/net/net_resource_provider.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/profiling.h"
@@ -143,6 +145,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/common/main_function_params.h"
 #include "grit/platform_locale_settings.h"
+#include "media/base/media_resources.h"
 #include "net/base/net_module.h"
 #include "net/cookies/cookie_monster.h"
 #include "net/http/http_network_layer.h"
@@ -201,7 +204,6 @@
 #include "chrome/installer/util/module_util_win.h"
 #include "chrome/installer/util/shell_util.h"
 #include "components/startup_metric_utils/common/pre_read_field_trial_utils_win.h"
-#include "net/base/net_util.h"
 #include "ui/base/l10n/l10n_util_win.h"
 #include "ui/gfx/win/dpi.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
@@ -214,12 +216,6 @@
 #include "chrome/browser/mac/keystone_glue.h"
 #endif  // defined(OS_MACOSX)
 
-#if !defined(OS_IOS)
-#include "chrome/browser/ui/app_modal/chrome_javascript_native_dialog_factory.h"
-#include "chrome/common/media/media_resource_provider.h"
-#include "media/base/media_resources.h"
-#endif  // !defined(OS_IOS)
-
 #if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
 #include "chrome/browser/first_run/upgrade_util.h"
 #endif
@@ -253,7 +249,7 @@
 #include "ui/aura/env.h"
 #endif  // defined(USE_AURA)
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 #include "chrome/browser/chrome_webusb_browser_client.h"
 #include "components/webusb/webusb_detector.h"
 #endif
@@ -1170,9 +1166,7 @@
   javascript_dialog_extensions_client::InstallClient();
 #endif  // defined(ENABLE_EXTENSIONS)
 
-#if !defined(OS_IOS)
   InstallChromeJavaScriptNativeDialogFactory();
-#endif  // !defined(OS_IOS)
 }
 
 void ChromeBrowserMainParts::PostProfileInit() {
@@ -1224,7 +1218,7 @@
       base::TimeDelta::FromMinutes(1));
 #endif  // defined(ENABLE_WEBRTC)
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   // WebUSB is an experimental web API. The sites these notifications will link
   // to will only work if the experiment is enabled.
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -1574,10 +1568,8 @@
 
   // Configure modules that need access to resources.
   net::NetModule::SetResourceProvider(chrome_common_net::NetResourceProvider);
-#if !defined(OS_IOS)
   media::SetLocalizedStringProvider(
       chrome_common_media::LocalizedStringProvider);
-#endif
 
   // In unittest mode, this will do nothing.  In normal mode, this will create
   // the global IntranetRedirectDetector instance, which will promptly go to
@@ -1841,10 +1833,8 @@
   // shut down.
   process_power_collector_.reset();
 
-#if !defined(OS_IOS)
   webusb_detector_.reset();
   webusb_browser_client_.reset();
-#endif
 
   for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
     chrome_extra_parts_[i]->PostMainMessageLoopRun();
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 4af0317..0f05ef87 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -288,7 +288,7 @@
 #include "chrome/browser/media/router/presentation_service_delegate_impl.h"
 #endif
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 #include "components/webusb/public/interfaces/webusb_permission_bubble.mojom.h"
 #endif
 
@@ -678,7 +678,7 @@
   tab_helper->CreateDeviceManager(render_frame_host, std::move(request));
 }
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 void CreateWebUsbPermissionBubble(
     RenderFrameHost* render_frame_host,
     mojo::InterfaceRequest<webusb::WebUsbPermissionBubble> request) {
@@ -693,7 +693,7 @@
       UsbTabHelper::GetOrCreateForWebContents(web_contents);
   tab_helper->CreatePermissionBubble(render_frame_host, std::move(request));
 }
-#endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif  // !defined(OS_ANDROID)
 
 bool GetDataSaverEnabledPref(const PrefService* prefs) {
   // Enable data saver only when data saver pref is enabled and not part of
@@ -1628,13 +1628,15 @@
 #if !defined(DISABLE_NACL)
       switches::kEnableNaClDebug,
       switches::kEnableNaClNonSfiMode,
-      switches::kEnablePNaClSubzero,
 #endif
       switches::kEnableNetBenchmarking,
       switches::kEnableNewBookmarkApps,
 #if defined(OS_ANDROID)
       switches::kEnableOfflinePagesAsBookmarks,
 #endif
+#if !defined(DISABLE_NACL)
+      switches::kForcePNaClSubzero,
+#endif
       switches::kJavaScriptHarmony,
       switches::kMessageLoopHistogrammer,
       switches::kPpapiFlashArgs,
@@ -1678,7 +1680,7 @@
 #if !defined(DISABLE_NACL)
       switches::kEnableNaClDebug,
       switches::kEnableNaClNonSfiMode,
-      switches::kEnablePNaClSubzero,
+      switches::kForcePNaClSubzero,
       switches::kNaClDangerousNoSandboxNonSfi,
 #endif
       switches::kPpapiFlashPath,
@@ -2727,10 +2729,10 @@
     content::ServiceRegistry* registry,
     content::RenderFrameHost* render_frame_host) {
   registry->AddService(base::Bind(&CreateUsbDeviceManager, render_frame_host));
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   registry->AddService(
       base::Bind(&CreateWebUsbPermissionBubble, render_frame_host));
-#endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif  // !defined(OS_ANDROID)
 }
 
 void ChromeContentBrowserClient::RegisterInProcessMojoApplications(
@@ -2758,7 +2760,7 @@
 #if BUILDFLAG(ANDROID_JAVA_UI)
   service_tab_launcher::ServiceTabLauncher::GetInstance()->LaunchTab(
       browser_context, params, callback);
-#elif !defined(OS_IOS)
+#else
   chrome::NavigateParams nav_params(
       Profile::FromBrowserContext(browser_context),
       params.url,
@@ -2768,8 +2770,6 @@
 
   Navigate(&nav_params);
   callback.Run(nav_params.target_contents);
-#else
-  NOTIMPLEMENTED();
 #endif
 }
 
diff --git a/chrome/browser/chrome_content_browser_client_unittest.cc b/chrome/browser/chrome_content_browser_client_unittest.cc
index e4b60d6..45ecd0a3 100644
--- a/chrome/browser/chrome_content_browser_client_unittest.cc
+++ b/chrome/browser/chrome_content_browser_client_unittest.cc
@@ -25,7 +25,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
@@ -41,8 +41,8 @@
   EXPECT_TRUE(client.ShouldAssignSiteForURL(GURL("https://www.google.com")));
 }
 
-// BrowserWithTestWindowTest doesn't work on iOS and Android.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+// BrowserWithTestWindowTest doesn't work on Android.
+#if !defined(OS_ANDROID)
 
 using ChromeContentBrowserClientWindowTest = BrowserWithTestWindowTest;
 
@@ -90,7 +90,7 @@
   EXPECT_EQ(previous_count + 2, browser()->tab_strip_model()->count());
 }
 
-#endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif  // !defined(OS_ANDROID)
 
 #if defined(ENABLE_WEBRTC)
 
@@ -325,7 +325,7 @@
             command_line().GetSwitchValueASCII(switches::kBlinkSettings));
 }
 
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
+#if !defined(OS_ANDROID)
 namespace content {
 
 class InstantNTPURLRewriteTest : public BrowserWithTestWindowTest {
@@ -374,4 +374,4 @@
 }
 
 }  // namespace content
-#endif  // !defined(OS_IOS) && !defined(OS_ANDROID)
+#endif  // !defined(OS_ANDROID)
diff --git a/chrome/browser/chromeos/display/display_preferences.cc b/chrome/browser/chromeos/display/display_preferences.cc
index bd23885b..e9d21c7 100644
--- a/chrome/browser/chromeos/display/display_preferences.cc
+++ b/chrome/browser/chromeos/display/display_preferences.cc
@@ -124,17 +124,19 @@
     }
 
     if (it.key().find(",") != std::string::npos) {
-      std::vector<std::string> ids = base::SplitString(
+      std::vector<std::string> ids_str = base::SplitString(
           it.key(), ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
       int64_t id1 = gfx::Display::kInvalidDisplayID;
       int64_t id2 = gfx::Display::kInvalidDisplayID;
-      if (!base::StringToInt64(ids[0], &id1) ||
-          !base::StringToInt64(ids[1], &id2) ||
+      if (!base::StringToInt64(ids_str[0], &id1) ||
+          !base::StringToInt64(ids_str[1], &id2) ||
           id1 == gfx::Display::kInvalidDisplayID ||
           id2 == gfx::Display::kInvalidDisplayID) {
         continue;
       }
-      ash::DisplayIdList list = ash::CreateDisplayIdList(id1, id2);
+      int64_t ids[] = {id1, id2};
+      ash::DisplayIdList list =
+          ash::GenerateDisplayIdList(std::begin(ids), std::end(ids));
       layout_store->RegisterLayoutForDisplayIdList(list, std::move(layout));
     }
   }
@@ -390,10 +392,9 @@
 }
 
 // Stores the display layout for given display pairs.
-void StoreDisplayLayoutPrefForTest(int64_t id1,
-                                   int64_t id2,
+void StoreDisplayLayoutPrefForTest(const ash::DisplayIdList& list,
                                    const ash::DisplayLayout& layout) {
-  StoreDisplayLayoutPref(ash::CreateDisplayIdList(id1, id2), layout);
+  StoreDisplayLayoutPref(list, layout);
 }
 
 // Stores the given |power_state|.
diff --git a/chrome/browser/chromeos/display/display_preferences.h b/chrome/browser/chromeos/display/display_preferences.h
index 1b05c583..ec14e96e 100644
--- a/chrome/browser/chromeos/display/display_preferences.h
+++ b/chrome/browser/chromeos/display/display_preferences.h
@@ -7,6 +7,7 @@
 
 #include <stdint.h>
 
+#include "ash/display/display_layout.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
 class PrefRegistrySimple;
@@ -40,8 +41,7 @@
 void LoadDisplayPreferences(bool first_run_after_boot);
 
 // Stores the display layout for given display pairs for tests.
-void StoreDisplayLayoutPrefForTest(int64_t id1,
-                                   int64_t id2,
+void StoreDisplayLayoutPrefForTest(const ash::DisplayIdList& list,
                                    const ash::DisplayLayout& layout);
 
 // Stores the given |power_state| for tests.
diff --git a/chrome/browser/chromeos/display/display_preferences_unittest.cc b/chrome/browser/chromeos/display/display_preferences_unittest.cc
index c146cd1e..bd6edd1 100644
--- a/chrome/browser/chromeos/display/display_preferences_unittest.cc
+++ b/chrome/browser/chromeos/display/display_preferences_unittest.cc
@@ -107,8 +107,8 @@
     std::string name = ash::DisplayIdListToString(list);
     DictionaryPrefUpdate update(&local_state_, prefs::kSecondaryDisplays);
     ash::DisplayLayout display_layout;
-    display_layout.placement.position = position;
-    display_layout.placement.offset = offset;
+    display_layout.placement_list.push_back(
+        new ash::DisplayPlacement(position, offset));
     display_layout.primary_id = primary_id;
 
     DCHECK(!name.empty());
@@ -190,12 +190,13 @@
     pref_data->SetInteger("orientation", static_cast<int>(rotation));
   }
 
-  std::string GetRegisteredDisplayLayoutStr(const ash::DisplayIdList& list) {
+  std::string GetRegisteredDisplayPlacementStr(const ash::DisplayIdList& list) {
     return ash::Shell::GetInstance()
         ->display_manager()
         ->layout_store()
         ->GetRegisteredDisplayLayout(list)
-        .ToString();
+        .placement_list[0]
+        ->ToString();
   }
 
   PrefService* local_state() { return &local_state_; }
@@ -218,7 +219,7 @@
 
   ash::DisplayIdList list = display_manager->GetCurrentDisplayIdList();
   ash::DisplayIdList dummy_list =
-      ash::CreateDisplayIdList(list[0], list[1] + 1);
+      ash::test::CreateDisplayIdList2(list[0], list[1] + 1);
   ASSERT_NE(list[0], dummy_list[1]);
 
   StoreDisplayLayoutPrefForList(list, ash::DisplayPlacement::TOP, 20);
@@ -238,11 +239,15 @@
   // The new layout overrides old layout.
   // Inverted one of for specified pair (id1, id2).  Not used for the list
   // (id1, dummy_id) since dummy_id is not connected right now.
-  EXPECT_EQ("top, 20, default_unified",
-            shell->display_manager()->GetCurrentDisplayLayout().ToString());
-  EXPECT_EQ("top, 20, default_unified", GetRegisteredDisplayLayoutStr(list));
-  EXPECT_EQ("left, 30, default_unified",
-            GetRegisteredDisplayLayoutStr(dummy_list));
+  EXPECT_EQ("id=2200000001, parent=2200000000, top, 20",
+            shell->display_manager()
+                ->GetCurrentDisplayLayout()
+                .placement_list[0]
+                ->ToString());
+  EXPECT_EQ("id=2200000001, parent=2200000000, top, 20",
+            GetRegisteredDisplayPlacementStr(list));
+  EXPECT_EQ("id=2200000002, parent=2200000000, left, 30",
+            GetRegisteredDisplayPlacementStr(dummy_list));
 }
 
 TEST_F(DisplayPreferencesTest, BasicStores) {
@@ -272,14 +277,15 @@
   display_manager->SetLayoutForCurrentDisplays(
       ash::test::CreateDisplayLayout(ash::DisplayPlacement::TOP, 10));
   const ash::DisplayLayout& layout = display_manager->GetCurrentDisplayLayout();
-  EXPECT_EQ(ash::DisplayPlacement::TOP, layout.placement.position);
-  EXPECT_EQ(10, layout.placement.offset);
+  EXPECT_EQ(ash::DisplayPlacement::TOP, layout.placement_list[0]->position);
+  EXPECT_EQ(10, layout.placement_list[0]->offset);
 
   ash::DisplayLayoutBuilder dummy_layout_builder(id1);
   dummy_layout_builder.SetSecondaryPlacement(dummy_id,
                                              ash::DisplayPlacement::LEFT, 20);
   scoped_ptr<ash::DisplayLayout> dummy_layout(dummy_layout_builder.Build());
-  StoreDisplayLayoutPrefForTest(id1, dummy_id, *dummy_layout);
+  ash::DisplayIdList list = ash::test::CreateDisplayIdList2(id1, dummy_id);
+  StoreDisplayLayoutPrefForTest(list, *dummy_layout);
 
   // Can't switch to a display that does not exist.
   window_tree_host_manager->SetPrimaryDisplayId(dummy_id);
@@ -295,7 +301,6 @@
       local_state()->GetDictionary(prefs::kSecondaryDisplays);
   const base::DictionaryValue* layout_value = nullptr;
   std::string key = base::Int64ToString(id1) + "," + base::Int64ToString(id2);
-
   std::string dummy_key =
       base::Int64ToString(id1) + "," + base::Int64ToString(dummy_id);
   EXPECT_TRUE(displays->GetDictionary(dummy_key, &layout_value));
@@ -303,8 +308,12 @@
   ash::DisplayLayout stored_layout;
   EXPECT_TRUE(ash::DisplayLayout::ConvertFromValue(*layout_value,
                                                    &stored_layout));
-  EXPECT_EQ(dummy_layout->placement.position, stored_layout.placement.position);
-  EXPECT_EQ(dummy_layout->placement.offset, stored_layout.placement.offset);
+  ASSERT_EQ(1u, stored_layout.placement_list.size());
+
+  EXPECT_EQ(dummy_layout->placement_list[0]->position,
+            stored_layout.placement_list[0]->position);
+  EXPECT_EQ(dummy_layout->placement_list[0]->offset,
+            stored_layout.placement_list[0]->offset);
 
   bool mirrored = true;
   EXPECT_TRUE(layout_value->GetBoolean(kMirroredKey, &mirrored));
@@ -368,6 +377,8 @@
 
   window_tree_host_manager->SetPrimaryDisplayId(id2);
 
+  EXPECT_EQ(id2, gfx::Screen::GetScreen()->GetPrimaryDisplay().id());
+
   EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id1), &property));
   width = 0;
   height = 0;
@@ -389,14 +400,21 @@
 
   // The layout is swapped.
   EXPECT_TRUE(displays->GetDictionary(key, &layout_value));
+
   EXPECT_TRUE(ash::DisplayLayout::ConvertFromValue(*layout_value,
                                                    &stored_layout));
-  EXPECT_EQ(ash::DisplayPlacement::BOTTOM, stored_layout.placement.position);
-  EXPECT_EQ(-10, stored_layout.placement.offset);
-  EXPECT_EQ(id1, stored_layout.placement.display_id);
-  EXPECT_EQ(id2, stored_layout.placement.parent_display_id);
+  ASSERT_EQ(1u, stored_layout.placement_list.size());
+  const ash::DisplayPlacement& stored_placement =
+      *stored_layout.placement_list[0];
+  EXPECT_EQ(ash::DisplayPlacement::BOTTOM, stored_placement.position);
+  EXPECT_EQ(-10, stored_placement.offset);
+  EXPECT_EQ(id1, stored_placement.display_id);
+  EXPECT_EQ(id2, stored_placement.parent_display_id);
   EXPECT_EQ(id2, stored_layout.primary_id);
 
+  if (true)
+    return;
+
   mirrored = true;
   EXPECT_TRUE(layout_value->GetBoolean(kMirroredKey, &mirrored));
   EXPECT_FALSE(mirrored);
@@ -563,10 +581,13 @@
     ash::DisplayLayout stored_layout;
     EXPECT_TRUE(
         ash::DisplayLayout::ConvertFromValue(*new_value, &stored_layout));
-    EXPECT_EQ(ash::DisplayPlacement::LEFT, stored_layout.placement.position);
-    EXPECT_EQ(0, stored_layout.placement.offset);
-    EXPECT_EQ(id1, stored_layout.placement.display_id);
-    EXPECT_EQ(id2, stored_layout.placement.parent_display_id);
+    ASSERT_EQ(1u, stored_layout.placement_list.size());
+    const ash::DisplayPlacement& stored_placement =
+        *stored_layout.placement_list[0];
+    EXPECT_EQ(ash::DisplayPlacement::LEFT, stored_placement.position);
+    EXPECT_EQ(0, stored_placement.offset);
+    EXPECT_EQ(id1, stored_placement.display_id);
+    EXPECT_EQ(id2, stored_placement.parent_display_id);
     EXPECT_EQ(id2, stored_layout.primary_id);
   }
 
@@ -579,10 +600,13 @@
     ash::DisplayLayout stored_layout;
     EXPECT_TRUE(
         ash::DisplayLayout::ConvertFromValue(*new_value, &stored_layout));
-    EXPECT_EQ(ash::DisplayPlacement::TOP, stored_layout.placement.position);
-    EXPECT_EQ(10, stored_layout.placement.offset);
-    EXPECT_EQ(id1, stored_layout.placement.display_id);
-    EXPECT_EQ(id2, stored_layout.placement.parent_display_id);
+    ASSERT_EQ(1u, stored_layout.placement_list.size());
+    const ash::DisplayPlacement& stored_placement =
+        *stored_layout.placement_list[0];
+    EXPECT_EQ(ash::DisplayPlacement::TOP, stored_placement.position);
+    EXPECT_EQ(10, stored_placement.offset);
+    EXPECT_EQ(id1, stored_placement.display_id);
+    EXPECT_EQ(id2, stored_placement.parent_display_id);
     EXPECT_EQ(id2, stored_layout.primary_id);
   }
 
@@ -596,10 +620,13 @@
     EXPECT_TRUE(displays->GetDictionary(key, &new_value));
     EXPECT_TRUE(
         ash::DisplayLayout::ConvertFromValue(*new_value, &stored_layout));
-    EXPECT_EQ(ash::DisplayPlacement::BOTTOM, stored_layout.placement.position);
-    EXPECT_EQ(-10, stored_layout.placement.offset);
-    EXPECT_EQ(id2, stored_layout.placement.display_id);
-    EXPECT_EQ(id1, stored_layout.placement.parent_display_id);
+    ASSERT_EQ(1u, stored_layout.placement_list.size());
+    const ash::DisplayPlacement& stored_placement =
+        *stored_layout.placement_list[0];
+    EXPECT_EQ(ash::DisplayPlacement::BOTTOM, stored_placement.position);
+    EXPECT_EQ(-10, stored_placement.offset);
+    EXPECT_EQ(id2, stored_placement.display_id);
+    EXPECT_EQ(id1, stored_placement.parent_display_id);
     EXPECT_EQ(id1, stored_layout.primary_id);
   }
 }
@@ -664,9 +691,10 @@
   // Settings are still notified to the system.
   gfx::Screen* screen = gfx::Screen::GetScreen();
   EXPECT_EQ(id2, screen->GetPrimaryDisplay().id());
-  EXPECT_EQ(ash::DisplayPlacement::BOTTOM,
-            display_manager->GetCurrentDisplayLayout().placement.position);
-  EXPECT_EQ(-10, display_manager->GetCurrentDisplayLayout().placement.offset);
+  const ash::DisplayPlacement& placement =
+      *display_manager->GetCurrentDisplayLayout().placement_list[0];
+  EXPECT_EQ(ash::DisplayPlacement::BOTTOM, placement.position);
+  EXPECT_EQ(-10, placement.offset);
   const gfx::Display& primary_display = screen->GetPrimaryDisplay();
   EXPECT_EQ("178x176", primary_display.bounds().size().ToString());
   EXPECT_EQ(gfx::Display::ROTATE_90, primary_display.rotation());
@@ -991,7 +1019,7 @@
 
 TEST_F(DisplayPreferencesTest, RestoreUnifiedMode) {
   int64_t id1 = gfx::Screen::GetScreen()->GetPrimaryDisplay().id();
-  ash::DisplayIdList list = ash::CreateDisplayIdList(id1, id1 + 1);
+  ash::DisplayIdList list = ash::test::CreateDisplayIdList2(id1, id1 + 1);
   StoreDisplayBoolPropertyForList(list, "default_unified", true);
   StoreDisplayPropertyForList(
       list, "primary-id",
diff --git a/chrome/browser/chromeos/enrollment_dialog_view.cc b/chrome/browser/chromeos/enrollment_dialog_view.cc
index 5e635f4..f5ec1fd 100644
--- a/chrome/browser/chromeos/enrollment_dialog_view.cc
+++ b/chrome/browser/chromeos/enrollment_dialog_view.cc
@@ -53,12 +53,12 @@
   // views::DialogDelegateView overrides
   int GetDialogButtons() const override;
   bool Accept() override;
-  void OnClosed() override;
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
 
   // views::WidgetDelegate overrides
   ui::ModalType GetModalType() const override;
   base::string16 GetWindowTitle() const override;
+  void WindowClosing() override;
 
   // views::View overrides
   gfx::Size GetPreferredSize() const override;
@@ -120,17 +120,6 @@
   return true;
 }
 
-void EnrollmentDialogView::OnClosed() {
-  if (!accepted_)
-    return;
-  chrome::NavigateParams params(profile_,
-                                GURL(target_uri_),
-                                ui::PAGE_TRANSITION_LINK);
-  params.disposition = NEW_FOREGROUND_TAB;
-  params.window_action = chrome::NavigateParams::SHOW_WINDOW;
-  chrome::Navigate(&params);
-}
-
 base::string16 EnrollmentDialogView::GetDialogButtonLabel(
     ui::DialogButton button) const {
   if (button == ui::DIALOG_BUTTON_OK)
@@ -146,6 +135,16 @@
   return l10n_util::GetStringUTF16(IDS_NETWORK_ENROLLMENT_HANDLER_TITLE);
 }
 
+void EnrollmentDialogView::WindowClosing() {
+  if (!accepted_)
+    return;
+  chrome::NavigateParams params(profile_, GURL(target_uri_),
+                                ui::PAGE_TRANSITION_LINK);
+  params.disposition = NEW_FOREGROUND_TAB;
+  params.window_action = chrome::NavigateParams::SHOW_WINDOW;
+  chrome::Navigate(&params);
+}
+
 gfx::Size EnrollmentDialogView::GetPreferredSize() const {
   return gfx::Size(kDefaultWidth, kDefaultHeight);
 }
diff --git a/chrome/browser/chromeos/extensions/OWNERS b/chrome/browser/chromeos/extensions/OWNERS
index 6b10de6..87d43ca4 100644
--- a/chrome/browser/chromeos/extensions/OWNERS
+++ b/chrome/browser/chromeos/extensions/OWNERS
@@ -17,6 +17,7 @@
 # input method related reviewers. shuchen@ is primary, and nona@ is backup.
 per-file input_method*=shuchen@chromium.org
 per-file input_method*=nona@chromium.org
+per-file ime_menu*=shuchen@chromium.org
 
 # DeviceLocalAccount reviewers. bartfab@ is primary, atwilson@ is backup.
 per-file device_local_account*=atwilson@chromium.org
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc
index e52205fa..0d39a2a 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc
@@ -13,11 +13,13 @@
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
 #include "chrome/browser/chromeos/fileapi/file_system_backend.h"
+#include "chrome/browser/extensions/api/file_handlers/directory_util.h"
 #include "chrome/browser/extensions/api/file_handlers/mime_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/extensions/api/file_manager_private.h"
 #include "chrome/common/extensions/api/file_manager_private_internal.h"
 #include "content/public/browser/browser_thread.h"
+#include "extensions/browser/entry_info.h"
 #include "net/base/filename_util.h"
 #include "storage/browser/fileapi/file_system_context.h"
 #include "storage/browser/fileapi/file_system_url.h"
@@ -149,8 +151,9 @@
     local_paths_.push_back(file_system_url.path());
   }
 
-  collector_.reset(new app_file_handler_util::MimeTypeCollector(GetProfile()));
-  collector_->CollectForLocalPaths(
+  mime_type_collector_.reset(
+      new app_file_handler_util::MimeTypeCollector(GetProfile()));
+  mime_type_collector_->CollectForLocalPaths(
       local_paths_,
       base::Bind(
           &FileManagerPrivateInternalGetFileTasksFunction::OnMimeTypesCollected,
@@ -161,15 +164,29 @@
 
 void FileManagerPrivateInternalGetFileTasksFunction::OnMimeTypesCollected(
     scoped_ptr<std::vector<std::string>> mime_types) {
-  app_file_handler_util::PathAndMimeTypeSet path_mime_set;
+  is_directory_collector_.reset(
+      new app_file_handler_util::IsDirectoryCollector(GetProfile()));
+  is_directory_collector_->CollectForEntriesPaths(
+      local_paths_, base::Bind(&FileManagerPrivateInternalGetFileTasksFunction::
+                                   OnAreDirectoriesAndMimeTypesCollected,
+                               this, base::Passed(std::move(mime_types))));
+}
+
+void FileManagerPrivateInternalGetFileTasksFunction::
+    OnAreDirectoriesAndMimeTypesCollected(
+        scoped_ptr<std::vector<std::string>> mime_types,
+        scoped_ptr<std::set<base::FilePath>> directory_paths) {
+  std::vector<EntryInfo> entries;
   for (size_t i = 0; i < local_paths_.size(); ++i) {
-    path_mime_set.insert(std::make_pair(local_paths_[i], (*mime_types)[i]));
+    entries.push_back(EntryInfo(
+        local_paths_[i], (*mime_types)[i],
+        directory_paths->find(local_paths_[i]) != directory_paths->end()));
   }
 
   std::vector<file_manager::file_tasks::FullTaskDescriptor> tasks;
   file_manager::file_tasks::FindAllTypesOfTasks(
       GetProfile(), drive::util::GetDriveAppRegistryByProfile(GetProfile()),
-      path_mime_set, urls_, &tasks);
+      entries, urls_, &tasks);
 
   // Convert the tasks into JSON compatible objects.
   using api::file_manager_private::FileTask;
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.h b/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.h
index 25087a0..80b4b67 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.h
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.h
@@ -7,6 +7,8 @@
 #ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_PRIVATE_API_TASKS_H_
 #define CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_MANAGER_PRIVATE_API_TASKS_H_
 
+#include <set>
+#include <string>
 #include <vector>
 
 #include "base/memory/scoped_ptr.h"
@@ -20,6 +22,7 @@
 namespace extensions {
 
 namespace app_file_handler_util {
+class IsDirectoryCollector;
 class MimeTypeCollector;
 }  // namespace app_file_handler_util
 
@@ -59,11 +62,13 @@
  private:
   void OnMimeTypesCollected(scoped_ptr<std::vector<std::string> > mime_types);
 
-  void OnSniffingMimeTypeCompleted(
-      scoped_ptr<app_file_handler_util::PathAndMimeTypeSet> path_mime_set,
-      scoped_ptr<std::vector<GURL>> urls);
+  void OnAreDirectoriesAndMimeTypesCollected(
+      scoped_ptr<std::vector<std::string>> mime_types,
+      scoped_ptr<std::set<base::FilePath>> path_directory_set);
 
-  scoped_ptr<app_file_handler_util::MimeTypeCollector> collector_;
+  scoped_ptr<app_file_handler_util::IsDirectoryCollector>
+      is_directory_collector_;
+  scoped_ptr<app_file_handler_util::MimeTypeCollector> mime_type_collector_;
   std::vector<GURL> urls_;
   std::vector<base::FilePath> local_paths_;
 };
diff --git a/chrome/browser/chromeos/extensions/ime_menu_event_router.cc b/chrome/browser/chromeos/extensions/ime_menu_event_router.cc
index 2d8fc6a2..df8e6f7 100644
--- a/chrome/browser/chromeos/extensions/ime_menu_event_router.cc
+++ b/chrome/browser/chromeos/extensions/ime_menu_event_router.cc
@@ -12,6 +12,8 @@
 
 namespace OnImeMenuActivationChanged =
     extensions::api::input_method_private::OnImeMenuActivationChanged;
+namespace OnImeMenuListChanged =
+    extensions::api::input_method_private::OnImeMenuListChanged;
 
 namespace chromeos {
 
@@ -42,4 +44,20 @@
   router->BroadcastEvent(std::move(event));
 }
 
+void ExtensionImeMenuEventRouter::ImeMenuListChanged() {
+  extensions::EventRouter* router = extensions::EventRouter::Get(context_);
+
+  if (!router->HasEventListener(OnImeMenuListChanged::kEventName))
+    return;
+
+  scoped_ptr<base::ListValue> args(new base::ListValue());
+
+  // The router will only send the event to extensions that are listening.
+  scoped_ptr<extensions::Event> event(new extensions::Event(
+      extensions::events::INPUT_METHOD_PRIVATE_ON_IME_MENU_LIST_CHANGED,
+      OnImeMenuListChanged::kEventName, std::move(args)));
+  event->restrict_to_browser_context = context_;
+  router->BroadcastEvent(std::move(event));
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/extensions/ime_menu_event_router.h b/chrome/browser/chromeos/extensions/ime_menu_event_router.h
index d6508d5..e4c25f8 100644
--- a/chrome/browser/chromeos/extensions/ime_menu_event_router.h
+++ b/chrome/browser/chromeos/extensions/ime_menu_event_router.h
@@ -25,6 +25,7 @@
 
   // input_method::InputMethodManager::ImeMenuObserver:
   void ImeMenuActivationChanged(bool activation) override;
+  void ImeMenuListChanged() override;
 
  private:
   content::BrowserContext* context_;
diff --git a/chrome/browser/chromeos/extensions/input_method_api.cc b/chrome/browser/chromeos/extensions/input_method_api.cc
index 4c918a0..b22b837c 100644
--- a/chrome/browser/chromeos/extensions/input_method_api.cc
+++ b/chrome/browser/chromeos/extensions/input_method_api.cc
@@ -47,6 +47,8 @@
     extensions::api::input_method_private::OnDictionaryLoaded;
 namespace OnImeMenuActivationChanged =
     extensions::api::input_method_private::OnImeMenuActivationChanged;
+namespace OnImeMenuListChanged =
+    extensions::api::input_method_private::OnImeMenuListChanged;
 
 namespace {
 
@@ -232,6 +234,8 @@
       ->RegisterObserver(this, OnDictionaryLoaded::kEventName);
   EventRouter::Get(context_)
       ->RegisterObserver(this, OnImeMenuActivationChanged::kEventName);
+  EventRouter::Get(context_)
+      ->RegisterObserver(this, OnImeMenuListChanged::kEventName);
   ExtensionFunctionRegistry* registry =
       ExtensionFunctionRegistry::GetInstance();
   registry->RegisterFunction<InputMethodPrivateGetInputMethodConfigFunction>();
@@ -275,7 +279,8 @@
     if (details.event_name == OnDictionaryLoaded::kEventName) {
       dictionary_event_router_->DispatchLoadedEventIfLoaded();
     }
-  } else if (details.event_name == OnImeMenuActivationChanged::kEventName &&
+  } else if ((details.event_name == OnImeMenuActivationChanged::kEventName ||
+              details.event_name == OnImeMenuListChanged::kEventName) &&
              !ime_menu_event_router_.get()) {
     ime_menu_event_router_.reset(
         new chromeos::ExtensionImeMenuEventRouter(context_));
diff --git a/chrome/browser/chromeos/file_manager/file_tasks.cc b/chrome/browser/chromeos/file_manager/file_tasks.cc
index d2a0746..b1d4cee 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks.cc
+++ b/chrome/browser/chromeos/file_manager/file_tasks.cc
@@ -6,6 +6,8 @@
 
 #include <stddef.h>
 
+#include <map>
+
 #include "apps/launcher.h"
 #include "base/bind.h"
 #include "base/macros.h"
@@ -32,6 +34,7 @@
 #include "components/mime_util/mime_util.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
+#include "extensions/browser/entry_info.h"
 #include "extensions/browser/extension_host.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
@@ -41,7 +44,7 @@
 #include "storage/browser/fileapi/file_system_url.h"
 
 using extensions::Extension;
-using extensions::app_file_handler_util::FindFileHandlersForFiles;
+using extensions::app_file_handler_util::FindFileHandlersForEntries;
 using storage::FileSystemURL;
 
 namespace file_manager {
@@ -91,10 +94,9 @@
     arraysize(kDriveTaskExtensionPrefix) - 1;
 
 // Returns true if path_mime_set contains a Google document.
-bool ContainsGoogleDocument(const PathAndMimeTypeSet& path_mime_set) {
-  for (PathAndMimeTypeSet::const_iterator iter = path_mime_set.begin();
-       iter != path_mime_set.end(); ++iter) {
-    if (drive::util::HasHostedDocumentExtension(iter->first))
+bool ContainsGoogleDocument(const std::vector<extensions::EntryInfo>& entries) {
+  for (const auto& it : entries) {
+    if (drive::util::HasHostedDocumentExtension(it.path))
       return true;
   }
   return false;
@@ -302,20 +304,19 @@
   return false;
 }
 
-void FindDriveAppTasks(
-    const drive::DriveAppRegistry& drive_app_registry,
-    const PathAndMimeTypeSet& path_mime_set,
-    std::vector<FullTaskDescriptor>* result_list) {
+void FindDriveAppTasks(const drive::DriveAppRegistry& drive_app_registry,
+                       const std::vector<extensions::EntryInfo>& entries,
+                       std::vector<FullTaskDescriptor>* result_list) {
   DCHECK(result_list);
 
   bool is_first = true;
   typedef std::map<std::string, drive::DriveAppInfo> DriveAppInfoMap;
   DriveAppInfoMap drive_app_map;
 
-  for (PathAndMimeTypeSet::const_iterator it = path_mime_set.begin();
-       it != path_mime_set.end(); ++it) {
-    const base::FilePath& file_path = it->first;
-    const std::string& mime_type = it->second;
+  for (std::vector<extensions::EntryInfo>::const_iterator it = entries.begin();
+       it != entries.end(); ++it) {
+    const base::FilePath& file_path = it->path;
+    const std::string& mime_type = it->mime_type;
     // Return immediately if a file not on Drive is found, as Drive app tasks
     // work only if all files are on Drive.
     if (!drive::util::IsUnderDriveMountPoint(file_path))
@@ -369,7 +370,7 @@
 
 bool IsGoodMatchFileHandler(
     const extensions::FileHandlerInfo& file_handler_info,
-    const PathAndMimeTypeSet& path_mime_set) {
+    const std::vector<extensions::EntryInfo>& entries) {
   if (file_handler_info.extensions.count("*") > 0 ||
       file_handler_info.types.count("*") > 0 ||
       file_handler_info.types.count("*/*") > 0)
@@ -378,20 +379,24 @@
   // If text/* file handler matches with unsupported text mime type, we don't
   // regard it as good match.
   if (file_handler_info.types.count("text/*")) {
-    for (const auto& path_mime : path_mime_set) {
-      if (mime_util::IsUnsupportedTextMimeType(path_mime.second))
+    for (const auto& entry : entries) {
+      if (mime_util::IsUnsupportedTextMimeType(entry.mime_type))
         return false;
     }
   }
 
+  // We consider it a good match if no directories are selected.
+  for (const auto& entry : entries) {
+    if (entry.is_directory)
+      return false;
+  }
   return true;
 }
 
-void FindFileHandlerTasks(
-    Profile* profile,
-    const PathAndMimeTypeSet& path_mime_set,
-    std::vector<FullTaskDescriptor>* result_list) {
-  DCHECK(!path_mime_set.empty());
+void FindFileHandlerTasks(Profile* profile,
+                          const std::vector<extensions::EntryInfo>& entries,
+                          std::vector<FullTaskDescriptor>* result_list) {
+  DCHECK(!entries.empty());
   DCHECK(result_list);
 
   const extensions::ExtensionSet& enabled_extensions =
@@ -414,7 +419,7 @@
 
     typedef std::vector<const extensions::FileHandlerInfo*> FileHandlerList;
     FileHandlerList file_handlers =
-        FindFileHandlersForFiles(*extension, path_mime_set);
+        FindFileHandlersForEntries(*extension, entries);
     if (file_handlers.empty())
       continue;
 
@@ -430,7 +435,7 @@
     // such handler, show the first matching handler of the app.
     const extensions::FileHandlerInfo* file_handler = file_handlers.front();
     for (auto handler : file_handlers) {
-      if (IsGoodMatchFileHandler(*handler, path_mime_set)) {
+      if (IsGoodMatchFileHandler(*handler, entries)) {
         file_handler = handler;
         break;
       }
@@ -449,7 +454,7 @@
     // If file handler doesn't match as good match, regards it as generic file
     // handler.
     const bool is_generic_file_handler =
-        !IsGoodMatchFileHandler(*file_handler, path_mime_set);
+        !IsGoodMatchFileHandler(*file_handler, entries);
     result_list->push_back(FullTaskDescriptor(
         TaskDescriptor(extension->id(), file_tasks::TASK_TYPE_FILE_HANDLER,
                        file_handler->id),
@@ -501,23 +506,22 @@
   }
 }
 
-void FindAllTypesOfTasks(
-    Profile* profile,
-    const drive::DriveAppRegistry* drive_app_registry,
-    const PathAndMimeTypeSet& path_mime_set,
-    const std::vector<GURL>& file_urls,
-    std::vector<FullTaskDescriptor>* result_list) {
+void FindAllTypesOfTasks(Profile* profile,
+                         const drive::DriveAppRegistry* drive_app_registry,
+                         const std::vector<extensions::EntryInfo>& entries,
+                         const std::vector<GURL>& file_urls,
+                         std::vector<FullTaskDescriptor>* result_list) {
   DCHECK(profile);
   DCHECK(result_list);
 
   // Find Drive app tasks, if the drive app registry is present.
   if (drive_app_registry)
-    FindDriveAppTasks(*drive_app_registry, path_mime_set, result_list);
+    FindDriveAppTasks(*drive_app_registry, entries, result_list);
 
   // Find and append file handler tasks. We know there aren't duplicates
   // because Drive apps and platform apps are entirely different kinds of
   // tasks.
-  FindFileHandlerTasks(profile, path_mime_set, result_list);
+  FindFileHandlerTasks(profile, entries, result_list);
 
   // Find and append file browser handler tasks. We know there aren't
   // duplicates because "file_browser_handlers" and "file_handlers" shouldn't
@@ -525,21 +529,21 @@
   FindFileBrowserHandlerTasks(profile, file_urls, result_list);
 
   // Google documents can only be handled by internal handlers.
-  if (ContainsGoogleDocument(path_mime_set))
+  if (ContainsGoogleDocument(entries))
     KeepOnlyFileManagerInternalTasks(result_list);
 
-  ChooseAndSetDefaultTask(*profile->GetPrefs(), path_mime_set, result_list);
+  ChooseAndSetDefaultTask(*profile->GetPrefs(), entries, result_list);
 }
 
 void ChooseAndSetDefaultTask(const PrefService& pref_service,
-                             const PathAndMimeTypeSet& path_mime_set,
+                             const std::vector<extensions::EntryInfo>& entries,
                              std::vector<FullTaskDescriptor>* tasks) {
   // Collect the task IDs of default tasks from the preferences into a set.
   std::set<std::string> default_task_ids;
-  for (PathAndMimeTypeSet::const_iterator it = path_mime_set.begin();
-       it != path_mime_set.end(); ++it) {
-    const base::FilePath& file_path = it->first;
-    const std::string& mime_type = it->second;
+  for (std::vector<extensions::EntryInfo>::const_iterator it = entries.begin();
+       it != entries.end(); ++it) {
+    const base::FilePath& file_path = it->path;
+    const std::string& mime_type = it->mime_type;
     std::string task_id = file_tasks::GetDefaultTaskIdFromPrefs(
         pref_service, mime_type, file_path.Extension());
     default_task_ids.insert(task_id);
diff --git a/chrome/browser/chromeos/file_manager/file_tasks.h b/chrome/browser/chromeos/file_manager/file_tasks.h
index 984347cfe..b357cc2 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks.h
+++ b/chrome/browser/chromeos/file_manager/file_tasks.h
@@ -126,6 +126,10 @@
 class DriveAppRegistry;
 }
 
+namespace extensions {
+struct EntryInfo;
+}
+
 namespace storage {
 class FileSystemURL;
 }
@@ -254,26 +258,23 @@
                      const std::vector<storage::FileSystemURL>& file_urls,
                      const FileTaskFinishedCallback& done);
 
-typedef extensions::app_file_handler_util::PathAndMimeTypeSet
-    PathAndMimeTypeSet;
-
-// Finds the Drive app tasks that can be used with the given |path_mime_set|
+// Finds the Drive app tasks that can be used with the given |entries|
 // from |drive_app_registry|, and append them to the |result_list|.
 // Drive app tasks will be found only if all of the files are on Drive.
 void FindDriveAppTasks(const drive::DriveAppRegistry& drive_app_registry,
-                       const PathAndMimeTypeSet& path_mime_set,
+                       const std::vector<extensions::EntryInfo>& entries,
                        std::vector<FullTaskDescriptor>* result_list);
 
-// Returns true if a file handler matches with files as good match.
+// Returns true if a file handler matches with entries as good match.
 bool IsGoodMatchFileHandler(
     const extensions::FileHandlerInfo& file_handler_info,
-    const PathAndMimeTypeSet& path_mime_set);
+    const std::vector<extensions::EntryInfo>& entries);
 
 // Finds the file handler tasks (apps declaring "file_handlers" in
-// manifest.json) that can be used with the given files, appending them to
+// manifest.json) that can be used with the given entries, appending them to
 // the |result_list|.
 void FindFileHandlerTasks(Profile* profile,
-                          const PathAndMimeTypeSet& path_mime_set,
+                          const std::vector<extensions::EntryInfo>& entries,
                           std::vector<FullTaskDescriptor>* result_list);
 
 // Finds the file browser handler tasks (app/extensions declaring
@@ -290,23 +291,22 @@
 // |drive_app_registry| can be NULL if the drive app registry is not
 // present.
 //
-// If |path_mime_set| contains a Google document, only the internal tasks of
+// If |entries| contains a Google document, only the internal tasks of
 // Files.app (i.e., tasks having the app ID of Files.app) are listed.
 // This is to avoid dups between Drive app tasks and an internal handler that
 // Files.app provides, and to avoid listing normal file handler and file browser
 // handler tasks, which can handle only normal files.
-void FindAllTypesOfTasks(
-    Profile* profile,
-    const drive::DriveAppRegistry* drive_app_registry,
-    const PathAndMimeTypeSet& path_mime_set,
-    const std::vector<GURL>& file_urls,
-    std::vector<FullTaskDescriptor>* result_list);
+void FindAllTypesOfTasks(Profile* profile,
+                         const drive::DriveAppRegistry* drive_app_registry,
+                         const std::vector<extensions::EntryInfo>& entries,
+                         const std::vector<GURL>& file_urls,
+                         std::vector<FullTaskDescriptor>* result_list);
 
 // Chooses the default task in |tasks| and sets it as default, if the default
 // task is found (i.e. the default task may not exist in |tasks|). No tasks
 // should be set as default before calling this function.
 void ChooseAndSetDefaultTask(const PrefService& pref_service,
-                             const PathAndMimeTypeSet& path_mime_set,
+                             const std::vector<extensions::EntryInfo>& entries,
                              std::vector<FullTaskDescriptor>* tasks);
 
 }  // namespace file_tasks
diff --git a/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc b/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
index 3ecee79..caa2b6c 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/chromeos/file_manager/file_tasks.h"
 
 #include <algorithm>
+#include <set>
 #include <utility>
 
 #include "base/command_line.h"
@@ -22,6 +23,7 @@
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/testing_pref_service.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "extensions/browser/entry_info.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/common/extension_builder.h"
@@ -201,15 +203,12 @@
   drive_app_registry.UpdateFromAppList(app_list);
 
   // Find apps for a "text/plain" file. Foo.app and Bar.app should be found.
-  PathAndMimeTypeSet path_mime_set;
-  path_mime_set.insert(
-      std::make_pair(
-          drive::util::GetDriveMountPointPath(&profile).AppendASCII("foo.txt"),
-          "text/plain"));
+  std::vector<extensions::EntryInfo> entries;
+  entries.push_back(extensions::EntryInfo(
+      drive::util::GetDriveMountPointPath(&profile).AppendASCII("foo.txt"),
+      "text/plain", false));
   std::vector<FullTaskDescriptor> tasks;
-  FindDriveAppTasks(drive_app_registry,
-                    path_mime_set,
-                    &tasks);
+  FindDriveAppTasks(drive_app_registry, entries, &tasks);
   ASSERT_EQ(2U, tasks.size());
   // Sort the app IDs, as the order is not guaranteed.
   std::vector<std::string> app_ids;
@@ -222,31 +221,24 @@
 
   // Find apps for "text/plain" and "text/html" files. Only Foo.app should be
   // found.
-  path_mime_set.clear();
-  path_mime_set.insert(
-      std::make_pair(
-          drive::util::GetDriveMountPointPath(&profile).AppendASCII("foo.txt"),
-          "text/plain"));
-  path_mime_set.insert(
-      std::make_pair(
-          drive::util::GetDriveMountPointPath(&profile).AppendASCII("foo.html"),
-          "text/html"));
+  entries.clear();
+  entries.push_back(extensions::EntryInfo(
+      drive::util::GetDriveMountPointPath(&profile).AppendASCII("foo.txt"),
+      "text/plain", false));
+  entries.push_back(extensions::EntryInfo(
+      drive::util::GetDriveMountPointPath(&profile).AppendASCII("foo.html"),
+      "text/html", false));
   tasks.clear();
-  FindDriveAppTasks(drive_app_registry,
-                    path_mime_set,
-                    &tasks);
+  FindDriveAppTasks(drive_app_registry, entries, &tasks);
   ASSERT_EQ(1U, tasks.size());
   // Confirm that only Foo.app is found.
   EXPECT_EQ("foo_app_id", tasks[0].task_descriptor().app_id);
 
   // Add a "text/plain" file not on Drive. No tasks should be found.
-  path_mime_set.insert(
-      std::make_pair(base::FilePath::FromUTF8Unsafe("not_on_drive.txt"),
-                     "text/plain"));
+  entries.push_back(extensions::EntryInfo(
+      base::FilePath::FromUTF8Unsafe("not_on_drive.txt"), "text/plain", false));
   tasks.clear();
-  FindDriveAppTasks(drive_app_registry,
-                    path_mime_set,
-                    &tasks);
+  FindDriveAppTasks(drive_app_registry, entries, &tasks);
   // Confirm no tasks are found.
   ASSERT_TRUE(tasks.empty());
 }
@@ -277,14 +269,13 @@
       GURL("http://example.com/nice_app.png"),
       false /* is_default */,
       false /* is_generic_file_handler */));
-  PathAndMimeTypeSet path_mime_set;
-  path_mime_set.insert(std::make_pair(
-      base::FilePath::FromUTF8Unsafe("foo.txt"),
-      "text/plain"));
+  std::vector<extensions::EntryInfo> entries;
+  entries.push_back(extensions::EntryInfo(
+      base::FilePath::FromUTF8Unsafe("foo.txt"), "text/plain", false));
 
   // None of them should be chosen as default, as nothing is set in the
   // preferences.
-  ChooseAndSetDefaultTask(pref_service, path_mime_set, &tasks);
+  ChooseAndSetDefaultTask(pref_service, entries, &tasks);
   EXPECT_FALSE(tasks[0].is_default());
   EXPECT_FALSE(tasks[1].is_default());
 
@@ -297,7 +288,7 @@
   UpdateDefaultTaskPreferences(&pref_service, mime_types, empty);
 
   // Text.app should be chosen as default.
-  ChooseAndSetDefaultTask(pref_service, path_mime_set, &tasks);
+  ChooseAndSetDefaultTask(pref_service, entries, &tasks);
   EXPECT_TRUE(tasks[0].is_default());
   EXPECT_FALSE(tasks[1].is_default());
 
@@ -306,7 +297,7 @@
 
   // Clear the preferences and make sure none of them are default.
   UpdateDefaultTaskPreferences(&pref_service, empty, empty);
-  ChooseAndSetDefaultTask(pref_service, path_mime_set, &tasks);
+  ChooseAndSetDefaultTask(pref_service, entries, &tasks);
   EXPECT_FALSE(tasks[0].is_default());
   EXPECT_FALSE(tasks[1].is_default());
 
@@ -318,7 +309,7 @@
   UpdateDefaultTaskPreferences(&pref_service, empty, suffixes);
 
   // Now Nice.app should be chosen as default.
-  ChooseAndSetDefaultTask(pref_service, path_mime_set, &tasks);
+  ChooseAndSetDefaultTask(pref_service, entries, &tasks);
   EXPECT_FALSE(tasks[0].is_default());
   EXPECT_TRUE(tasks[1].is_default());
 }
@@ -340,14 +331,13 @@
       GURL("http://example.com/some_icon.png"),
       false /* is_default */,
       false /* is_generic_file_handler */));
-  PathAndMimeTypeSet path_mime_set;
-  path_mime_set.insert(std::make_pair(
-      base::FilePath::FromUTF8Unsafe("foo.txt"),
-      "text/plain"));
+  std::vector<extensions::EntryInfo> entries;
+  entries.push_back(extensions::EntryInfo(
+      base::FilePath::FromUTF8Unsafe("foo.txt"), "text/plain", false));
 
   // The internal file browser handler should be chosen as default, as it's a
   // fallback file browser handler.
-  ChooseAndSetDefaultTask(pref_service, path_mime_set, &tasks);
+  ChooseAndSetDefaultTask(pref_service, entries, &tasks);
   EXPECT_TRUE(tasks[0].is_default());
 }
 
@@ -355,81 +345,79 @@
 // with files as good match or not.
 TEST(FileManagerFileTasksTest, IsGoodMatchFileHandler) {
   using FileHandlerInfo = extensions::FileHandlerInfo;
-  typedef std::pair<base::FilePath, std::string> PathMime;
 
-  PathAndMimeTypeSet path_and_mime_set_1;
-  path_and_mime_set_1.insert(
-      PathMime(base::FilePath(FILE_PATH_LITERAL("foo.jpg")), "image/jpeg"));
-  path_and_mime_set_1.insert(
-      PathMime(base::FilePath(FILE_PATH_LITERAL("bar.txt")), "text/plain"));
+  std::vector<extensions::EntryInfo> entries_1;
+  entries_1.push_back(extensions::EntryInfo(
+      base::FilePath(FILE_PATH_LITERAL("foo.jpg")), "image/jpeg", false));
+  entries_1.push_back(extensions::EntryInfo(
+      base::FilePath(FILE_PATH_LITERAL("bar.txt")), "text/plain", false));
 
-  PathAndMimeTypeSet path_and_mime_set_2;
-  path_and_mime_set_2.insert(
-      PathMime(base::FilePath(FILE_PATH_LITERAL("foo.ics")), "text/calendar"));
+  std::vector<extensions::EntryInfo> entries_2;
+  entries_2.push_back(extensions::EntryInfo(
+      base::FilePath(FILE_PATH_LITERAL("foo.ics")), "text/calendar", false));
 
   // extensions: ["*"]
   FileHandlerInfo file_handler_info_1;
   file_handler_info_1.extensions.insert("*");
-  EXPECT_FALSE(
-      IsGoodMatchFileHandler(file_handler_info_1, path_and_mime_set_1));
+  EXPECT_FALSE(IsGoodMatchFileHandler(file_handler_info_1, entries_1));
 
   // extensions: ["*", "jpg"]
   FileHandlerInfo file_handler_info_2;
   file_handler_info_2.extensions.insert("*");
   file_handler_info_2.extensions.insert("jpg");
-  EXPECT_FALSE(
-      IsGoodMatchFileHandler(file_handler_info_2, path_and_mime_set_1));
+  EXPECT_FALSE(IsGoodMatchFileHandler(file_handler_info_2, entries_1));
 
   // extensions: ["jpg"]
   FileHandlerInfo file_handler_info_3;
   file_handler_info_3.extensions.insert("jpg");
-  EXPECT_TRUE(IsGoodMatchFileHandler(file_handler_info_3, path_and_mime_set_1));
+  EXPECT_TRUE(IsGoodMatchFileHandler(file_handler_info_3, entries_1));
 
   // types: ["*"]
   FileHandlerInfo file_handler_info_4;
   file_handler_info_4.types.insert("*");
-  EXPECT_FALSE(
-      IsGoodMatchFileHandler(file_handler_info_4, path_and_mime_set_1));
+  EXPECT_FALSE(IsGoodMatchFileHandler(file_handler_info_4, entries_1));
 
   // types: ["*/*"]
   FileHandlerInfo file_handler_info_5;
   file_handler_info_5.types.insert("*/*");
-  EXPECT_FALSE(
-      IsGoodMatchFileHandler(file_handler_info_5, path_and_mime_set_1));
+  EXPECT_FALSE(IsGoodMatchFileHandler(file_handler_info_5, entries_1));
 
   // types: ["image/*"]
   FileHandlerInfo file_handler_info_6;
   file_handler_info_6.types.insert("image/*");
   // Partial wild card is not generic.
-  EXPECT_TRUE(IsGoodMatchFileHandler(file_handler_info_6, path_and_mime_set_1));
+  EXPECT_TRUE(IsGoodMatchFileHandler(file_handler_info_6, entries_1));
 
   // types: ["*", "image/*"]
   FileHandlerInfo file_handler_info_7;
   file_handler_info_7.types.insert("*");
   file_handler_info_7.types.insert("image/*");
-  EXPECT_FALSE(
-      IsGoodMatchFileHandler(file_handler_info_7, path_and_mime_set_1));
+  EXPECT_FALSE(IsGoodMatchFileHandler(file_handler_info_7, entries_1));
 
   // extensions: ["*"], types: ["image/*"]
   FileHandlerInfo file_handler_info_8;
   file_handler_info_8.extensions.insert("*");
   file_handler_info_8.types.insert("image/*");
-  EXPECT_FALSE(
-      IsGoodMatchFileHandler(file_handler_info_8, path_and_mime_set_1));
+  EXPECT_FALSE(IsGoodMatchFileHandler(file_handler_info_8, entries_1));
 
   // types: ["text/*"] and target files contain unsupported text mime type, e.g.
   // text/calendar.
   FileHandlerInfo file_handler_info_9;
   file_handler_info_9.types.insert("text/*");
-  EXPECT_FALSE(
-      IsGoodMatchFileHandler(file_handler_info_9, path_and_mime_set_2));
+  EXPECT_FALSE(IsGoodMatchFileHandler(file_handler_info_9, entries_2));
 
   // types: ["text/*"] and target files don't contain unsupported text mime
   // type.
   FileHandlerInfo file_handler_info_10;
   file_handler_info_10.types.insert("text/*");
-  EXPECT_TRUE(
-      IsGoodMatchFileHandler(file_handler_info_10, path_and_mime_set_1));
+  EXPECT_TRUE(IsGoodMatchFileHandler(file_handler_info_10, entries_1));
+
+  // path_directory_set not empty.
+  FileHandlerInfo file_handler_info_11;
+  std::vector<extensions::EntryInfo> entries_3;
+  entries_3.push_back(extensions::EntryInfo(
+      base::FilePath(FILE_PATH_LITERAL("dir1")), "", true));
+  EXPECT_FALSE(IsGoodMatchFileHandler(file_handler_info_11, entries_3));
 }
 
 // Test using the test extension system, which needs lots of setup.
@@ -514,15 +502,14 @@
   extension_service_->AddExtension(bar_app.Build().get());
 
   // Find apps for a "text/plain" file. Foo.app and Bar.app should be found.
-  PathAndMimeTypeSet path_mime_set;
-  path_mime_set.insert(
-      std::make_pair(
-          drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
-              "foo.txt"),
-          "text/plain"));
+  std::vector<extensions::EntryInfo> entries;
+  entries.push_back(
+      extensions::EntryInfo(drive::util::GetDriveMountPointPath(&test_profile_)
+                                .AppendASCII("foo.txt"),
+                            "text/plain", false));
 
   std::vector<FullTaskDescriptor> tasks;
-  FindFileHandlerTasks(&test_profile_, path_mime_set, &tasks);
+  FindFileHandlerTasks(&test_profile_, entries, &tasks);
   ASSERT_EQ(2U, tasks.size());
   // Sort the app IDs, as the order is not guaranteed.
   std::vector<std::string> app_ids;
@@ -535,29 +522,26 @@
 
   // Find apps for "text/plain" and "text/html" files. Only Foo.app should be
   // found.
-  path_mime_set.clear();
-  path_mime_set.insert(
-      std::make_pair(
-          drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
-              "foo.txt"),
-          "text/plain"));
-  path_mime_set.insert(
-      std::make_pair(
-          drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
-              "foo.html"),
-          "text/html"));
+  entries.clear();
+  entries.push_back(
+      extensions::EntryInfo(drive::util::GetDriveMountPointPath(&test_profile_)
+                                .AppendASCII("foo.txt"),
+                            "text/plain", false));
+  entries.push_back(
+      extensions::EntryInfo(drive::util::GetDriveMountPointPath(&test_profile_)
+                                .AppendASCII("foo.html"),
+                            "text/html", false));
   tasks.clear();
-  FindFileHandlerTasks(&test_profile_, path_mime_set, &tasks);
+  FindFileHandlerTasks(&test_profile_, entries, &tasks);
   ASSERT_EQ(1U, tasks.size());
   // Confirm that only Foo.app is found.
   EXPECT_EQ(kFooId, tasks[0].task_descriptor().app_id);
 
   // Add an "image/png" file. No tasks should be found.
-  path_mime_set.insert(
-      std::make_pair(base::FilePath::FromUTF8Unsafe("foo.png"),
-                     "image/png"));
+  entries.push_back(extensions::EntryInfo(
+      base::FilePath::FromUTF8Unsafe("foo.png"), "image/png", false));
   tasks.clear();
-  FindFileHandlerTasks(&test_profile_, path_mime_set, &tasks);
+  FindFileHandlerTasks(&test_profile_, entries, &tasks);
   // Confirm no tasks are found.
   ASSERT_TRUE(tasks.empty());
 }
@@ -718,20 +702,16 @@
   drive_app_registry.UpdateFromAppList(app_list);
 
   // Find apps for "foo.txt". All apps should be found.
-  PathAndMimeTypeSet path_mime_set;
+  std::vector<extensions::EntryInfo> entries;
   std::vector<GURL> file_urls;
-  path_mime_set.insert(
-      std::make_pair(
-          drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
-              "foo.txt"),
-          "text/plain"));
+  entries.push_back(
+      extensions::EntryInfo(drive::util::GetDriveMountPointPath(&test_profile_)
+                                .AppendASCII("foo.txt"),
+                            "text/plain", false));
   file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.txt"));
 
   std::vector<FullTaskDescriptor> tasks;
-  FindAllTypesOfTasks(&test_profile_,
-                      &drive_app_registry,
-                      path_mime_set,
-                      file_urls,
+  FindAllTypesOfTasks(&test_profile_, &drive_app_registry, entries, file_urls,
                       &tasks);
   ASSERT_EQ(3U, tasks.size());
 
@@ -815,20 +795,16 @@
 
   // Find apps for a ".gdoc file". Only the built-in handler of Files.apps
   // should be found.
-  PathAndMimeTypeSet path_mime_set;
+  std::vector<extensions::EntryInfo> entries;
   std::vector<GURL> file_urls;
-  path_mime_set.insert(
-      std::make_pair(
-          drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
-              "foo.gdoc"),
-          "application/vnd.google-apps.document"));
+  entries.push_back(
+      extensions::EntryInfo(drive::util::GetDriveMountPointPath(&test_profile_)
+                                .AppendASCII("foo.gdoc"),
+                            "application/vnd.google-apps.document", false));
   file_urls.push_back(GURL("filesystem:chrome-extension://id/dir/foo.gdoc"));
 
   std::vector<FullTaskDescriptor> tasks;
-  FindAllTypesOfTasks(&test_profile_,
-                      &drive_app_registry,
-                      path_mime_set,
-                      file_urls,
+  FindAllTypesOfTasks(&test_profile_, &drive_app_registry, entries, file_urls,
                       &tasks);
   ASSERT_EQ(1U, tasks.size());
   EXPECT_EQ(kFileManagerAppId, tasks[0].task_descriptor().app_id);
@@ -871,7 +847,7 @@
   extension_service_->AddExtension(foo_app.Build().get());
 
   // Bar app provides file handler for .txt and not provide generic file
-  // handler.
+  // handler, but handles directories.
   extensions::ExtensionBuilder bar_app;
   bar_app.SetManifest(std::move(
       extensions::DictionaryBuilder()
@@ -884,11 +860,14 @@
                    std::move(extensions::DictionaryBuilder().Set(
                        "scripts", std::move(extensions::ListBuilder().Append(
                                       "background.js")))))))
-          .Set("file_handlers",
-               std::move(extensions::DictionaryBuilder().Set(
-                   "text",
-                   std::move(extensions::DictionaryBuilder().Set(
-                       "extensions", std::move(extensions::ListBuilder().Append(
+          .Set(
+              "file_handlers",
+              std::move(extensions::DictionaryBuilder().Set(
+                  "text",
+                  std::move(extensions::DictionaryBuilder()
+                                .SetBoolean("include_directories", true)
+                                .Set("extensions",
+                                     std::move(extensions::ListBuilder().Append(
                                          "txt")))))))));
   bar_app.SetID(kBarId);
   extension_service_->AddExtension(bar_app.Build().get());
@@ -946,14 +925,13 @@
   extension_service_->AddExtension(qux_app.Build().get());
 
   // Test case with .txt file
-  PathAndMimeTypeSet txt_path_mime_set;
-  txt_path_mime_set.insert(
-      std::make_pair(
-          drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
-              "foo.txt"),
-          "text/plain"));
+  std::vector<extensions::EntryInfo> txt_entries;
+  txt_entries.push_back(
+      extensions::EntryInfo(drive::util::GetDriveMountPointPath(&test_profile_)
+                                .AppendASCII("foo.txt"),
+                            "text/plain", false));
   std::vector<FullTaskDescriptor> txt_result;
-  FindFileHandlerTasks(&test_profile_, txt_path_mime_set, &txt_result);
+  FindFileHandlerTasks(&test_profile_, txt_entries, &txt_result);
   EXPECT_EQ(4U, txt_result.size());
   // Foo app provides a handler for text/plain.
   EXPECT_EQ("Foo", txt_result[0].task_title());
@@ -969,14 +947,13 @@
   EXPECT_TRUE(txt_result[3].is_generic_file_handler());
 
   // Test case with .jpg file
-  PathAndMimeTypeSet jpg_path_mime_set;
-  jpg_path_mime_set.insert(
-      std::make_pair(
-          drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII(
-              "foo.jpg"),
-          "image/jpeg"));
+  std::vector<extensions::EntryInfo> jpg_entries;
+  jpg_entries.push_back(
+      extensions::EntryInfo(drive::util::GetDriveMountPointPath(&test_profile_)
+                                .AppendASCII("foo.jpg"),
+                            "image/jpeg", false));
   std::vector<FullTaskDescriptor> jpg_result;
-  FindFileHandlerTasks(&test_profile_, jpg_path_mime_set, &jpg_result);
+  FindFileHandlerTasks(&test_profile_, jpg_entries, &jpg_result);
   EXPECT_EQ(3U, jpg_result.size());
   // Foo app provides a handler for all types.
   EXPECT_EQ("Foo", jpg_result[0].task_title());
@@ -988,6 +965,18 @@
   // Qux app provides a handler for all types.
   EXPECT_EQ("Qux", jpg_result[2].task_title());
   EXPECT_TRUE(jpg_result[2].is_generic_file_handler());
+
+  // Test case with directories.
+  std::vector<extensions::EntryInfo> dir_entries;
+  dir_entries.push_back(extensions::EntryInfo(
+      drive::util::GetDriveMountPointPath(&test_profile_).AppendASCII("dir"),
+      "", true));
+  std::vector<FullTaskDescriptor> dir_result;
+  FindFileHandlerTasks(&test_profile_, dir_entries, &dir_result);
+  ASSERT_EQ(1U, dir_result.size());
+  // Confirm that only Bar.app is found and that it is a generic file handler.
+  EXPECT_EQ(kBarId, dir_result[0].task_descriptor().app_id);
+  EXPECT_TRUE(dir_result[0].is_generic_file_handler());
 }
 
 }  // namespace file_tasks
diff --git a/chrome/browser/chromeos/file_manager/open_util.cc b/chrome/browser/chromeos/file_manager/open_util.cc
index 4883248..0a3ebc2 100644
--- a/chrome/browser/chromeos/file_manager/open_util.cc
+++ b/chrome/browser/chromeos/file_manager/open_util.cc
@@ -4,6 +4,10 @@
 
 #include "chrome/browser/chromeos/file_manager/open_util.h"
 
+#include <set>
+#include <string>
+#include <vector>
+
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
@@ -14,9 +18,11 @@
 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
 #include "chrome/browser/chromeos/file_manager/path_util.h"
 #include "chrome/browser/chromeos/file_manager/url_util.h"
+#include "chrome/browser/extensions/api/file_handlers/directory_util.h"
 #include "chrome/browser/extensions/api/file_handlers/mime_util.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/user_metrics.h"
+#include "extensions/browser/entry_info.h"
 #include "storage/browser/fileapi/file_system_backend.h"
 #include "storage/browser/fileapi/file_system_context.h"
 #include "storage/browser/fileapi/file_system_operation_runner.h"
@@ -42,9 +48,8 @@
 
   file_tasks::ExecuteFileTask(
       profile,
-      GetFileManagerMainPageUrl(), // Executing the task on behalf of Files.app.
-      task,
-      std::vector<FileSystemURL>(1, file_system_context->CrackURL(url)),
+      GetFileManagerMainPageUrl(),  // Executing task on behalf of Files.app.
+      task, std::vector<FileSystemURL>(1, file_system_context->CrackURL(url)),
       file_tasks::FileTaskFinishedCallback());
 }
 
@@ -74,19 +79,16 @@
                           const GURL& url,
                           const platform_util::OpenOperationCallback& callback,
                           const std::string& mime_type) {
-  extensions::app_file_handler_util::PathAndMimeTypeSet path_mime_set;
-  path_mime_set.insert(std::make_pair(path, mime_type));
+  std::vector<extensions::EntryInfo> entries;
+  entries.push_back(extensions::EntryInfo(path, mime_type, false));
 
   std::vector<GURL> file_urls;
   file_urls.push_back(url);
 
   std::vector<file_tasks::FullTaskDescriptor> tasks;
   file_tasks::FindAllTypesOfTasks(
-      profile,
-      drive::util::GetDriveAppRegistryByProfile(profile),
-      path_mime_set,
-      file_urls,
-      &tasks);
+      profile, drive::util::GetDriveAppRegistryByProfile(profile), entries,
+      file_urls, &tasks);
 
   // Select a default handler. If a default handler is not available, select
   // a non-generic file handler.
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
index 2cb3cb3..289ac785 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
+++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
@@ -481,6 +481,8 @@
     if (contain)
       manager_->MaybeInitializeCandidateWindowController();
   }
+
+  manager_->NotifyImeMenuListChanged();
 }
 
 void InputMethodManagerImpl::StateImpl::RemoveInputMethodExtension(
@@ -1033,6 +1035,8 @@
   // Update input method indicators (e.g. "US", "DV") in Chrome windows.
   FOR_EACH_OBSERVER(InputMethodManager::Observer, observers_,
                     InputMethodChanged(this, profile, show_message));
+  // Update the current input method in IME menu.
+  NotifyImeMenuListChanged();
 }
 
 void InputMethodManagerImpl::LoadNecessaryComponentExtensions(
@@ -1168,6 +1172,11 @@
                     ImeMenuActivationChanged(is_active));
 }
 
+void InputMethodManagerImpl::NotifyImeMenuListChanged() {
+  FOR_EACH_OBSERVER(InputMethodManager::ImeMenuObserver, ime_menu_observers_,
+                    ImeMenuListChanged());
+}
+
 void InputMethodManagerImpl::MaybeInitializeCandidateWindowController() {
   if (candidate_window_controller_.get())
     return;
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.h b/chrome/browser/chromeos/input_method/input_method_manager_impl.h
index bf77997..0e2b525 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager_impl.h
+++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.h
@@ -238,6 +238,10 @@
   // Record input method usage histograms.
   void RecordInputMethodUsage(const std::string& input_method_id);
 
+  // Notifies the current input method or the list of active input method IDs
+  // changed.
+  void NotifyImeMenuListChanged();
+
   scoped_ptr<InputMethodDelegate> delegate_;
 
   // The current UI session status.
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc
index 61e9a4b..d8e0943 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -497,6 +497,23 @@
   login_display_->ShowErrorScreen(LoginDisplay::TPM_ERROR);
 }
 
+void ExistingUserController::ShowPasswordChangedDialog() {
+  VLOG(1) << "Show password changed dialog"
+          << ", count=" << login_performer_->password_changed_callback_count();
+
+  // True if user has already made an attempt to enter old password and failed.
+  bool show_invalid_old_password_error =
+      login_performer_->password_changed_callback_count() > 1;
+
+  // Note: We allow owner using "full sync" mode which will recreate
+  // cryptohome and deal with owner private key being lost. This also allows
+  // us to recover from a lost owner password/homedir.
+  // TODO(gspencer): We shouldn't have to erase stateful data when
+  // doing this.  See http://crosbug.com/9115 http://crosbug.com/7792
+  login_display_->ShowPasswordChangedDialog(show_invalid_old_password_error,
+                                            display_email_);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // ExistingUserController, LoginPerformer::Delegate implementation:
 //
@@ -674,23 +691,23 @@
     return;
   }
 
-  // True if user has already made an attempt to enter old password and failed.
-  bool show_invalid_old_password_error =
-      login_performer_->password_changed_callback_count() > 1;
-
-  VLOG(1) << "Show password changed dialog"
-          << ", count=" << login_performer_->password_changed_callback_count();
-
-  // Note: We allow owner using "full sync" mode which will recreate
-  // cryptohome and deal with owner private key being lost. This also allows
-  // us to recover from a lost owner password/homedir.
-  // TODO(gspencer): We shouldn't have to erase stateful data when
-  // doing this.  See http://crosbug.com/9115 http://crosbug.com/7792
-  login_display_->ShowPasswordChangedDialog(show_invalid_old_password_error,
-                                            display_email_);
-
   if (auth_status_consumer_)
     auth_status_consumer_->OnPasswordChangeDetected();
+
+  // If the password change happens after an online auth, do a TokenHandle check
+  // to find out whether the user password is really changed or not.
+  if (auth_mode() == LoginPerformer::AUTH_MODE_EXTENSION) {
+    token_handle_util_.reset(new TokenHandleUtil);
+    if (token_handle_util_->HasToken(last_login_attempt_account_id_)) {
+      token_handle_util_->CheckToken(
+          last_login_attempt_account_id_,
+          base::Bind(&ExistingUserController::OnTokenHandleChecked,
+                     weak_factory_.GetWeakPtr()));
+      return;
+    }
+  }
+
+  ShowPasswordChangedDialog();
 }
 
 void ExistingUserController::WhiteListCheckFailed(const std::string& email) {
@@ -1213,4 +1230,21 @@
   PerformLogin(user_context, LoginPerformer::AUTH_MODE_EXTENSION);
 }
 
+void ExistingUserController::OnTokenHandleChecked(
+    const AccountId&,
+    TokenHandleUtil::TokenHandleStatus token_handle_status) {
+  // If TokenHandle is invalid or unknown, continue with regular password
+  // changed flow.
+  if (token_handle_status != TokenHandleUtil::VALID) {
+    VLOG(1) << "Checked TokenHandle status=" << token_handle_status;
+    ShowPasswordChangedDialog();
+    return;
+  }
+
+  // Otherwise, show the unrecoverable cryptohome error UI and ask user's
+  // permission to collect a feedback.
+  VLOG(1) << "Show unrecoverable cryptohome error dialog.";
+  login_display_->ShowUnrecoverableCrypthomeErrorDialog(display_email_);
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/existing_user_controller.h b/chrome/browser/chromeos/login/existing_user_controller.h
index b5e4d0f4..2d18cfe 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.h
+++ b/chrome/browser/chromeos/login/existing_user_controller.h
@@ -20,6 +20,7 @@
 #include "base/timer/timer.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
+#include "chrome/browser/chromeos/login/signin/token_handle_util.h"
 #include "chrome/browser/chromeos/login/ui/login_display.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
@@ -193,6 +194,9 @@
   // Shows "critical TPM error" screen.
   void ShowTPMError();
 
+  // Shows "password changed" dialog.
+  void ShowPasswordChangedDialog();
+
   // Creates |login_performer_| if necessary and calls login() on it.
   void PerformLogin(const UserContext& user_context,
                     LoginPerformer::AuthorizationMode auth_mode);
@@ -241,6 +245,11 @@
   // Callback invoked when |oauth2_token_initializer_| has finished.
   void OnOAuth2TokensFetched(bool success, const UserContext& user_context);
 
+  // Callback invoked when |token_handle_util_| finishes token check.
+  void OnTokenHandleChecked(
+      const AccountId&,
+      TokenHandleUtil::TokenHandleStatus token_handle_status);
+
   // Public session auto-login timer.
   scoped_ptr<base::OneShotTimer> auto_login_timer_;
 
@@ -329,6 +338,8 @@
 
   scoped_ptr<OAuth2TokenInitializer> oauth2_token_initializer_;
 
+  scoped_ptr<TokenHandleUtil> token_handle_util_;
+
   FRIEND_TEST_ALL_PREFIXES(ExistingUserControllerTest, ExistingUserLogin);
 
   // Factory of callbacks.
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc
index 3eda1fd93..572d0a5 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -1042,7 +1042,7 @@
     if (has_auth_cookies_) {
       const user_manager::User* user =
           user_manager::UserManager::Get()->FindUser(account_id);
-      if (user->is_affiliated()) {
+      if (user->IsAffiliated()) {
         CrosSettings::Get()->GetBoolean(
             kAccountsPrefTransferSAMLCookies,
             &transfer_saml_auth_cookies_on_subsequent_login);
diff --git a/chrome/browser/chromeos/login/ui/login_display.h b/chrome/browser/chromeos/login/ui/login_display.h
index a650d03..1c5ddc9 100644
--- a/chrome/browser/chromeos/login/ui/login_display.h
+++ b/chrome/browser/chromeos/login/ui/login_display.h
@@ -141,6 +141,10 @@
   // signin but whitelist check fails.
   virtual void ShowWhitelistCheckFailedError() = 0;
 
+  // Show unrecoverable cryptohome error dialog.
+  virtual void ShowUnrecoverableCrypthomeErrorDialog(
+      const std::string& email) = 0;
+
   gfx::Rect background_bounds() const { return background_bounds_; }
   void set_background_bounds(const gfx::Rect& background_bounds) {
     background_bounds_ = background_bounds;
diff --git a/chrome/browser/chromeos/login/ui/mock_login_display.h b/chrome/browser/chromeos/login/ui/mock_login_display.h
index eab108b1..a4eb67e 100644
--- a/chrome/browser/chromeos/login/ui/mock_login_display.h
+++ b/chrome/browser/chromeos/login/ui/mock_login_display.h
@@ -28,8 +28,7 @@
   MOCK_METHOD2(ShowPasswordChangedDialog, void(bool, const std::string&));
   MOCK_METHOD1(ShowSigninUI, void(const std::string&));
   MOCK_METHOD0(ShowWhitelistCheckFailedError, void(void));
-  MOCK_METHOD1(OnBeforeUserRemoved, void(const AccountId&));
-  MOCK_METHOD1(OnUserRemoved, void(const AccountId&));
+  MOCK_METHOD1(ShowUnrecoverableCrypthomeErrorDialog, void(const std::string&));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockLoginDisplay);
diff --git a/chrome/browser/chromeos/login/ui/oobe_display.h b/chrome/browser/chromeos/login/ui/oobe_display.h
index 860f8b3..c75bc0dc 100644
--- a/chrome/browser/chromeos/login/ui/oobe_display.h
+++ b/chrome/browser/chromeos/login/ui/oobe_display.h
@@ -66,6 +66,7 @@
     SCREEN_OOBE_CONTROLLER_PAIRING,
     SCREEN_OOBE_HOST_PAIRING,
     SCREEN_DEVICE_DISABLED,
+    SCREEN_UNRECOVERABLE_CRYPTOHOME_ERROR,
     SCREEN_UNKNOWN
   };
 
diff --git a/chrome/browser/chromeos/login/ui/webui_login_display.cc b/chrome/browser/chromeos/login/ui/webui_login_display.cc
index bd8d9cd..21b36e71 100644
--- a/chrome/browser/chromeos/login/ui/webui_login_display.cc
+++ b/chrome/browser/chromeos/login/ui/webui_login_display.cc
@@ -187,6 +187,12 @@
     webui_handler_->ShowWhitelistCheckFailedError();
 }
 
+void WebUILoginDisplay::ShowUnrecoverableCrypthomeErrorDialog(
+    const std::string& email) {
+  if (webui_handler_)
+    webui_handler_->ShowUnrecoverableCrypthomeErrorDialog(email);
+}
+
 // WebUILoginDisplay, NativeWindowDelegate implementation: ---------------------
 gfx::NativeWindow WebUILoginDisplay::GetNativeWindow() const {
   return parent_window();
diff --git a/chrome/browser/chromeos/login/ui/webui_login_display.h b/chrome/browser/chromeos/login/ui/webui_login_display.h
index 025dd3e..e47e0b9 100644
--- a/chrome/browser/chromeos/login/ui/webui_login_display.h
+++ b/chrome/browser/chromeos/login/ui/webui_login_display.h
@@ -48,6 +48,7 @@
                                  const std::string& email) override;
   void ShowSigninUI(const std::string& email) override;
   void ShowWhitelistCheckFailedError() override;
+  void ShowUnrecoverableCrypthomeErrorDialog(const std::string& email) override;
 
   // NativeWindowDelegate implementation:
   gfx::NativeWindow GetNativeWindow() const override;
diff --git a/chrome/browser/chromeos/login/users/avatar/user_image_loader.cc b/chrome/browser/chromeos/login/users/avatar/user_image_loader.cc
index bd7a266..ed550ef0 100644
--- a/chrome/browser/chromeos/login/users/avatar/user_image_loader.cc
+++ b/chrome/browser/chromeos/login/users/avatar/user_image_loader.cc
@@ -13,6 +13,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/sequenced_task_runner.h"
 #include "base/single_thread_task_runner.h"
+#include "base/task_runner_util.h"
 #include "base/thread_task_runner_handle.h"
 #include "chrome/browser/chromeos/login/helper.h"
 #include "components/user_manager/user_image/user_image.h"
@@ -23,80 +24,52 @@
 
 namespace chromeos {
 
-UserImageLoader::ImageInfo::ImageInfo(const base::FilePath& file_path,
-                                      int pixels_per_side,
-                                      const LoadedCallback& loaded_cb)
-    : file_path(file_path),
-      pixels_per_side(pixels_per_side),
-      loaded_cb(loaded_cb) {}
+namespace {
 
-UserImageLoader::ImageInfo::~ImageInfo() {
-}
+// Contains attributes we need to know about each image we decode.
+struct ImageInfo {
+  ImageInfo(const base::FilePath& file_path,
+            int pixels_per_side,
+            ImageDecoder::ImageCodec image_codec,
+            const UserImageLoader::LoadedCallback& loaded_cb)
+      : file_path(file_path),
+        pixels_per_side(pixels_per_side),
+        image_codec(image_codec),
+        loaded_cb(loaded_cb) {}
+  ~ImageInfo() {}
 
-UserImageLoader::UserImageRequest::UserImageRequest(
-    const ImageInfo& image_info,
-    const std::string& image_data,
-    const scoped_refptr<UserImageLoader>& user_image_loader)
-    : ImageRequest(user_image_loader->background_task_runner_),
-      image_info_(image_info),
-      image_data_(image_data.begin(), image_data.end()),
-      user_image_loader_(user_image_loader) {
-}
+  const base::FilePath file_path;
+  const int pixels_per_side;
+  const ImageDecoder::ImageCodec image_codec;
+  const UserImageLoader::LoadedCallback loaded_cb;
+};
 
-UserImageLoader::UserImageRequest::~UserImageRequest() {
-}
+// Handles the decoded image returned from ImageDecoder through the
+// ImageRequest interface.
+class UserImageRequest : public ImageDecoder::ImageRequest {
+ public:
+  UserImageRequest(
+      const ImageInfo& image_info,
+      const std::string& image_data,
+      scoped_refptr<base::SequencedTaskRunner> background_task_runner)
+      : ImageRequest(background_task_runner),
+        image_info_(image_info),
+        image_data_(image_data.begin(), image_data.end()),
+        foreground_task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
+  ~UserImageRequest() override {}
 
-UserImageLoader::UserImageLoader(
-    ImageDecoder::ImageCodec image_codec,
-    scoped_refptr<base::SequencedTaskRunner> background_task_runner)
-    : foreground_task_runner_(base::ThreadTaskRunnerHandle::Get()),
-      background_task_runner_(background_task_runner),
-      image_codec_(image_codec) {
-}
+  // ImageDecoder::ImageRequest implementation. These callbacks will only be
+  // invoked via user_image_loader_'s background_task_runner_.
+  void OnImageDecoded(const SkBitmap& decoded_image) override;
+  void OnDecodeImageFailed() override;
 
-UserImageLoader::~UserImageLoader() {
-}
+ private:
+  const ImageInfo image_info_;
+  std::vector<unsigned char> image_data_;
+  scoped_refptr<base::SequencedTaskRunner> foreground_task_runner_;
+};
 
-void UserImageLoader::StartWithFilePath(const base::FilePath& file_path,
-                                        int pixels_per_side,
-                                        const LoadedCallback& loaded_cb) {
-  background_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&UserImageLoader::ReadAndDecodeImage, this,
-                            ImageInfo(file_path, pixels_per_side, loaded_cb)));
-}
-
-void UserImageLoader::StartWithData(scoped_ptr<std::string> data,
-                                    int pixels_per_side,
-                                    const LoadedCallback& loaded_cb) {
-  background_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&UserImageLoader::DecodeImage, this, base::Passed(&data),
-                 ImageInfo(base::FilePath(), pixels_per_side, loaded_cb)));
-}
-
-void UserImageLoader::ReadAndDecodeImage(const ImageInfo& image_info) {
-  DCHECK(background_task_runner_->RunsTasksOnCurrentThread());
-
-  scoped_ptr<std::string> data(new std::string);
-  if (!base::ReadFileToString(image_info.file_path, data.get()))
-    LOG(ERROR) << "Failed to read image " << image_info.file_path.value();
-
-  // In case ReadFileToString() fails, |data| is empty and DecodeImage() calls
-  // back to OnDecodeImageFailed().
-  DecodeImage(std::move(data), image_info);
-}
-
-void UserImageLoader::DecodeImage(const scoped_ptr<std::string> data,
-                                  const ImageInfo& image_info) {
-  DCHECK(background_task_runner_->RunsTasksOnCurrentThread());
-
-  UserImageRequest* image_request =
-      new UserImageRequest(image_info, *data, this);
-  ImageDecoder::StartWithOptions(image_request, *data, image_codec_, false);
-}
-
-void UserImageLoader::UserImageRequest::OnImageDecoded(
-    const SkBitmap& decoded_image) {
+void UserImageRequest::OnImageDecoded(const SkBitmap& decoded_image) {
   DCHECK(task_runner()->RunsTasksOnCurrentThread());
 
   const int target_size = image_info_.pixels_per_side;
@@ -129,18 +102,73 @@
   final_image_skia.MakeThreadSafe();
   user_manager::UserImage user_image(final_image_skia, image_data_);
   user_image.set_file_path(image_info_.file_path);
-  if (user_image_loader_->image_codec_ == ImageDecoder::ROBUST_JPEG_CODEC)
+  if (image_info_.image_codec == ImageDecoder::ROBUST_JPEG_CODEC)
     user_image.MarkAsSafe();
-  user_image_loader_->foreground_task_runner_->PostTask(
+  // TODO(satorux): Remove the foreground_task_runner_ stuff.
+  foreground_task_runner_->PostTask(
       FROM_HERE, base::Bind(image_info_.loaded_cb, user_image));
-  delete this;
+  foreground_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(base::Bind(&base::DeletePointer<UserImageRequest>, this)));
 }
 
-void UserImageLoader::UserImageRequest::OnDecodeImageFailed() {
+void UserImageRequest::OnDecodeImageFailed() {
   DCHECK(task_runner()->RunsTasksOnCurrentThread());
-  user_image_loader_->foreground_task_runner_->PostTask(
+  // TODO(satorux): Remove the foreground_task_runner_ stuff.
+  foreground_task_runner_->PostTask(
       FROM_HERE, base::Bind(image_info_.loaded_cb, user_manager::UserImage()));
-  delete this;
+  foreground_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(base::Bind(&base::DeletePointer<UserImageRequest>, this)));
+}
+
+// Starts decoding the image with ImageDecoder for the image |data| if
+// |data_is_ready| is true.
+void DecodeImage(
+    const ImageInfo& image_info,
+    scoped_refptr<base::SequencedTaskRunner> background_task_runner,
+    const std::string* data,
+    bool data_is_ready) {
+  if (!data_is_ready) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(image_info.loaded_cb, user_manager::UserImage()));
+    return;
+  }
+
+  UserImageRequest* image_request =
+      new UserImageRequest(image_info, *data, background_task_runner);
+  ImageDecoder::StartWithOptions(image_request, *data, image_info.image_codec,
+                                 false);
+}
+
+}  // namespace
+
+UserImageLoader::UserImageLoader(
+    scoped_refptr<base::SequencedTaskRunner> background_task_runner)
+    : background_task_runner_(background_task_runner) {}
+
+UserImageLoader::~UserImageLoader() {}
+
+void UserImageLoader::StartWithFilePath(const base::FilePath& file_path,
+                                        ImageDecoder::ImageCodec image_codec,
+                                        int pixels_per_side,
+                                        const LoadedCallback& loaded_cb) {
+  std::string* data = new std::string;
+  base::PostTaskAndReplyWithResult(
+      background_task_runner_.get(), FROM_HERE,
+      base::Bind(&base::ReadFileToString, file_path, data),
+      base::Bind(&DecodeImage,
+                 ImageInfo(file_path, pixels_per_side, image_codec, loaded_cb),
+                 background_task_runner_, base::Owned(data)));
+}
+
+void UserImageLoader::StartWithData(scoped_ptr<std::string> data,
+                                    ImageDecoder::ImageCodec image_codec,
+                                    int pixels_per_side,
+                                    const LoadedCallback& loaded_cb) {
+  DecodeImage(
+      ImageInfo(base::FilePath(), pixels_per_side, image_codec, loaded_cb),
+      background_task_runner_, data.get(), true /* data_is_ready */);
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/users/avatar/user_image_loader.h b/chrome/browser/chromeos/login/users/avatar/user_image_loader.h
index 3f96a9d4..04322a1f 100644
--- a/chrome/browser/chromeos/login/users/avatar/user_image_loader.h
+++ b/chrome/browser/chromeos/login/users/avatar/user_image_loader.h
@@ -8,14 +8,11 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "chrome/browser/image_decoder.h"
 
-class SkBitmap;
-
 namespace base {
 class SequencedTaskRunner;
 }
@@ -36,78 +33,33 @@
 
   // All file I/O, decoding and resizing are done via |background_task_runner|.
   UserImageLoader(
-      ImageDecoder::ImageCodec image_codec,
       scoped_refptr<base::SequencedTaskRunner> background_task_runner);
 
-  // Load an image in the background and call |loaded_cb| with the resulting
-  // UserImage (which may be empty in case of error). If |pixels_per_side| is
-  // positive, the image is cropped to a square and shrunk so that it does not
-  // exceed |pixels_per_side|x|pixels_per_side|. The first variant of this
-  // method reads the image from |file_path| on disk, the second processes
-  // |data| read into memory already.
+  // Load an image with |image_codec| in the background and call |loaded_cb|
+  // with the resulting UserImage (which may be empty in case of error). If
+  // |pixels_per_side| is positive, the image is cropped to a square and
+  // shrunk so that it does not exceed
+  // |pixels_per_side|x|pixels_per_side|. The first variant of this method
+  // reads the image from |file_path| on disk, the second processes |data|
+  // read into memory already.
   void StartWithFilePath(const base::FilePath& file_path,
+                         ImageDecoder::ImageCodec image_codec,
                          int pixels_per_side,
                          const LoadedCallback& loaded_cb);
   void StartWithData(scoped_ptr<std::string> data,
+                     ImageDecoder::ImageCodec image_codec,
                      int pixels_per_side,
                      const LoadedCallback& loaded_cb);
 
  private:
   friend class base::RefCountedThreadSafe<UserImageLoader>;
 
-  // Contains attributes we need to know about each image we decode.
-  struct ImageInfo {
-    ImageInfo(const base::FilePath& file_path,
-              int pixels_per_side,
-              const LoadedCallback& loaded_cb);
-    ~ImageInfo();
-
-    const base::FilePath file_path;
-    const int pixels_per_side;
-    const LoadedCallback loaded_cb;
-  };
-
-  class UserImageRequest : public ImageDecoder::ImageRequest {
-   public:
-    UserImageRequest(const ImageInfo& image_info,
-                     const std::string& image_data,
-                     const scoped_refptr<UserImageLoader>& user_image_loader);
-
-    // ImageDecoder::ImageRequest implementation. These callbacks will only be
-    // invoked via user_image_loader_'s background_task_runner_.
-    void OnImageDecoded(const SkBitmap& decoded_image) override;
-    void OnDecodeImageFailed() override;
-
-   private:
-    ~UserImageRequest() override;
-
-    const ImageInfo image_info_;
-    std::vector<unsigned char> image_data_;
-    scoped_refptr<UserImageLoader> user_image_loader_;
-  };
-
   ~UserImageLoader();
 
-  // Reads the image from |image_info.file_path| and starts the decoding
-  // process. This method may only be invoked via the |background_task_runner_|.
-  void ReadAndDecodeImage(const ImageInfo& image_info);
-
-  // Decodes the image |data|. This method may only be invoked via the
-  // |background_task_runner_|.
-  void DecodeImage(const scoped_ptr<std::string> data,
-                   const ImageInfo& image_info);
-
-  // The foreground task runner on which |this| is instantiated, Start() is
-  // called and LoadedCallbacks are invoked.
-  scoped_refptr<base::SequencedTaskRunner> foreground_task_runner_;
-
   // The background task runner on which file I/O, image decoding and resizing
   // are done.
   scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
 
-  // Specify how the file should be decoded in the utility process.
-  const ImageDecoder::ImageCodec image_codec_;
-
   DISALLOW_COPY_AND_ASSIGN(UserImageLoader);
 };
 
diff --git a/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.cc b/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.cc
index c8192a1d..9123586 100644
--- a/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.cc
+++ b/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.cc
@@ -315,12 +315,13 @@
   } else if (image_index_ == user_manager::User::USER_IMAGE_EXTERNAL ||
              image_index_ == user_manager::User::USER_IMAGE_PROFILE) {
     // Load the user image from a file referenced by |image_path|. This happens
-    // asynchronously. The JPEG image loader can be used here because
+    // asynchronously. ROBUST_JPEG_CODEC can be used here because
     // LoadImage() is called only for users whose user image has previously
     // been set by one of the Set*() methods, which transcode to JPEG format.
     DCHECK(!image_path_.empty());
     parent_->image_loader_->StartWithFilePath(
-        image_path_, 0,  // Do not crop.
+        image_path_, ImageDecoder::ROBUST_JPEG_CODEC,
+        0,  // Do not crop.
         base::Bind(&Job::OnLoadImageDone, weak_factory_.GetWeakPtr(), false));
   } else {
     NOTREACHED();
@@ -366,18 +367,19 @@
 
   image_index_ = user_manager::User::USER_IMAGE_EXTERNAL;
 
-  // This method uses the image_loader_, not the unsafe_image_loader_:
+  // This method uses ROBUST_JPEG_CODEC, not DEFAULT_CODEC:
   // * This is necessary because the method is used to update the user image
   //   whenever the policy for a user is set. In the case of device-local
   //   accounts, policy may change at any time, even if the user is not
-  //   currently logged in (and thus, the unsafe_image_loader_ may not be used).
+  //   currently logged in (and thus, DEFAULT_CODEC may not be used).
   // * This is possible because only JPEG |data| is accepted. No support for
   //   other image file formats is needed.
-  // * This is safe because the image_loader_ employs a hardened JPEG decoder
+  // * This is safe because ROBUST_JPEG_CODEC employs a hardened JPEG decoder
   //   that protects against malicious invalid image data being used to attack
   //   the login screen or another user session currently in progress.
   parent_->image_loader_->StartWithData(
-      std::move(data), login::kMaxUserImageSize,
+      std::move(data), ImageDecoder::ROBUST_JPEG_CODEC,
+      login::kMaxUserImageSize,
       base::Bind(&Job::OnLoadImageDone, weak_factory_.GetWeakPtr(), true));
 }
 
@@ -392,8 +394,8 @@
   image_url_ = image_url;
 
   DCHECK(!path.empty());
-  parent_->unsafe_image_loader_->StartWithFilePath(
-      path, resize ? login::kMaxUserImageSize : 0,
+  parent_->image_loader_->StartWithFilePath(
+      path, ImageDecoder::DEFAULT_CODEC, resize ? login::kMaxUserImageSize : 0,
       base::Bind(&Job::OnLoadImageDone, weak_factory_.GetWeakPtr(), true));
 }
 
@@ -485,10 +487,7 @@
       blocking_pool->GetSequencedTaskRunnerWithShutdownBehavior(
           blocking_pool->GetSequenceToken(),
           base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
-  image_loader_ = new UserImageLoader(ImageDecoder::ROBUST_JPEG_CODEC,
-                                      background_task_runner_);
-  unsafe_image_loader_ = new UserImageLoader(ImageDecoder::DEFAULT_CODEC,
-                                             background_task_runner_);
+  image_loader_ = new UserImageLoader(background_task_runner_);
 }
 
 UserImageManagerImpl::~UserImageManagerImpl() {}
diff --git a/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.h b/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.h
index fdffa19..0ccf9ee 100644
--- a/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.h
+++ b/chrome/browser/chromeos/login/users/avatar/user_image_manager_impl.h
@@ -156,12 +156,9 @@
   // The user manager.
   user_manager::UserManager* user_manager_;
 
-  // Loader for JPEG user images.
+  // Loader for user images.
   scoped_refptr<UserImageLoader> image_loader_;
 
-  // Unsafe loader instance for all user images formats.
-  scoped_refptr<UserImageLoader> unsafe_image_loader_;
-
   // Whether the |profile_downloader_| is downloading the profile image for the
   // currently logged-in user (and not just the full name). Only valid when a
   // download is currently in progress.
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
index 869224e6..4bac334 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
@@ -1192,7 +1192,7 @@
     const bool is_affiliated = chromeos::IsUserAffiliated(
         user_affiliation_ids, connector->GetDeviceAffiliationIDs(),
         account_id.GetUserEmail(), connector->GetEnterpriseDomain());
-    user->set_affiliation(is_affiliated);
+    user->SetAffiliation(is_affiliated);
 
     if (user->GetType() == user_manager::USER_TYPE_REGULAR) {
       if (is_affiliated) {
diff --git a/chrome/browser/chromeos/login/users/fake_chrome_user_manager.cc b/chrome/browser/chromeos/login/users/fake_chrome_user_manager.cc
index 9b739af..8d4f8d7 100644
--- a/chrome/browser/chromeos/login/users/fake_chrome_user_manager.cc
+++ b/chrome/browser/chromeos/login/users/fake_chrome_user_manager.cc
@@ -42,7 +42,7 @@
     const AccountId& account_id,
     bool is_affiliated) {
   user_manager::User* user = user_manager::User::CreateRegularUser(account_id);
-  user->set_affiliation(is_affiliated);
+  user->SetAffiliation(is_affiliated);
   user->set_username_hash(ProfileHelper::GetUserIdHashByUserIdForTesting(
       account_id.GetUserEmail()));
   user->SetStubImage(user_manager::UserImage(
diff --git a/chrome/browser/chromeos/login/users/mock_user_manager.cc b/chrome/browser/chromeos/login/users/mock_user_manager.cc
index 513cb27..c894bd7a 100644
--- a/chrome/browser/chromeos/login/users/mock_user_manager.cc
+++ b/chrome/browser/chromeos/login/users/mock_user_manager.cc
@@ -129,7 +129,7 @@
 void MockUserManager::AddUserWithAffiliation(const AccountId& account_id,
                                              bool is_affiliated) {
   user_manager::User* user = user_manager::User::CreateRegularUser(account_id);
-  user->set_affiliation(is_affiliated);
+  user->SetAffiliation(is_affiliated);
   user_list_.push_back(user);
   ProfileHelper::Get()->SetProfileToUserMappingForTesting(user);
 }
@@ -145,7 +145,7 @@
 bool MockUserManager::ShouldReportUser(const std::string& user_id) const {
   for (const auto& user : user_list_) {
     if (user->email() == user_id)
-      return user->is_affiliated();
+      return user->IsAffiliated();
   }
   NOTREACHED();
   return false;
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
index 17dcda8..1b8fd8c 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
@@ -449,7 +449,7 @@
     return;
 
   wallpaper_loader_->StartWithData(
-      std::move(data),
+      std::move(data), ImageDecoder::ROBUST_JPEG_CODEC,
       0,  // Do not crop.
       base::Bind(&WallpaperManager::SetPolicyControlledWallpaper,
                  weak_factory_.GetWeakPtr(), account_id));
@@ -760,8 +760,7 @@
       BrowserThread::GetBlockingPool()
           ->GetSequencedTaskRunnerWithShutdownBehavior(
               sequence_token_, base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
-  wallpaper_loader_ =
-      new UserImageLoader(ImageDecoder::ROBUST_JPEG_CODEC, task_runner_);
+  wallpaper_loader_ = new UserImageLoader(task_runner_);
 
   user_manager::UserManager::Get()->AddSessionStateObserver(this);
 }
@@ -955,7 +954,7 @@
         CustomWallpaperElement(wallpaper_path, gfx::ImageSkia());
   }
   wallpaper_loader_->StartWithFilePath(
-      wallpaper_path,
+      wallpaper_path, ImageDecoder::ROBUST_JPEG_CODEC,
       0,  // Do not crop.
       base::Bind(&WallpaperManager::OnWallpaperDecoded,
                  weak_factory_.GetWeakPtr(), account_id, info.layout,
@@ -976,7 +975,7 @@
     // Either resized images do not exist or cached version is incorrect.
     // Need to start resize again.
     wallpaper_loader_->StartWithFilePath(
-        downloaded_file,
+        downloaded_file, ImageDecoder::ROBUST_JPEG_CODEC,
         0,  // Do not crop.
         base::Bind(&WallpaperManager::OnCustomizedDefaultWallpaperDecoded,
                    weak_factory_.GetWeakPtr(), wallpaper_url,
@@ -1052,7 +1051,7 @@
     MovableOnDestroyCallbackHolder on_finish,
     scoped_ptr<user_manager::UserImage>* result_out) {
   wallpaper_loader_->StartWithFilePath(
-      path,
+      path, ImageDecoder::ROBUST_JPEG_CODEC,
       0,  // Do not crop.
       base::Bind(&WallpaperManager::OnDefaultWallpaperDecoded,
                  weak_factory_.GetWeakPtr(), path, layout,
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc b/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc
index d1d9877..f210607 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc
@@ -782,7 +782,7 @@
 
   // Use the device-wide system key slot only if the user is affiliated on the
   // device.
-  bool use_system_key_slot = user->is_affiliated();
+  const bool use_system_key_slot = user->IsAffiliated();
 
   scoped_ptr<SelectCertificatesState> state(new SelectCertificatesState(
       user->username_hash(), use_system_key_slot, cert_request_info, callback));
diff --git a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.cc b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.cc
index 3e44c84..d853a887 100644
--- a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.cc
+++ b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.cc
@@ -157,7 +157,7 @@
   }
   const user_manager::User* user =
       chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
-  if (!user || !user->is_affiliated()) {
+  if (!user || !user->IsAffiliated()) {
     // If the Profile belongs to a user who is not affiliated on the device,
     // ignore it.
     return;
diff --git a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
index d228236..fd7dcbe 100644
--- a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
@@ -880,6 +880,16 @@
 
   CheckPublicSessionPresent(account_id_1_);
   CheckPublicSessionPresent(account_id_2_);
+
+  ASSERT_TRUE(user_manager::UserManager::Get()->FindUser(account_id_1_));
+  EXPECT_TRUE(user_manager::UserManager::Get()
+                  ->FindUser(account_id_1_)
+                  ->IsAffiliated());
+
+  ASSERT_TRUE(user_manager::UserManager::Get()->FindUser(account_id_2_));
+  EXPECT_TRUE(user_manager::UserManager::Get()
+                  ->FindUser(account_id_2_)
+                  ->IsAffiliated());
 }
 
 // Flaky: http://crbug.com/512670.
diff --git a/chrome/browser/chromeos/policy/user_affiliation_browsertest.cc b/chrome/browser/chromeos/policy/user_affiliation_browsertest.cc
index c2a3000..4b63296 100644
--- a/chrome/browser/chromeos/policy/user_affiliation_browsertest.cc
+++ b/chrome/browser/chromeos/policy/user_affiliation_browsertest.cc
@@ -84,7 +84,7 @@
   EXPECT_EQ(GetParam().affiliated_,
             user_manager::UserManager::Get()
                 ->FindUser(AccountId::FromUserEmail(kAffiliatedUser))
-                ->is_affiliated());
+                ->IsAffiliated());
 }
 
 INSTANTIATE_TEST_CASE_P(AffiliationCheck,
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.cc b/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.cc
index 96e73e0f..369a494 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.cc
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.cc
@@ -500,7 +500,8 @@
     return;
   }
 
-  const bool read_success = base::ReadFileToString(path, key, kKeySizeLimit);
+  const bool read_success =
+      base::ReadFileToStringWithMaxSize(path, key, kKeySizeLimit);
   // If the read was successful and the file size is 0 or if the read fails
   // due to file size exceeding |kKeySizeLimit|, log error.
   if ((read_success && key->length() == 0) ||
diff --git a/chrome/browser/chromeos/proxy_config_service_impl.cc b/chrome/browser/chromeos/proxy_config_service_impl.cc
index a5bf67f..ca343e7 100644
--- a/chrome/browser/chromeos/proxy_config_service_impl.cc
+++ b/chrome/browser/chromeos/proxy_config_service_impl.cc
@@ -160,7 +160,7 @@
   if (onc_source == ::onc::ONC_SOURCE_DEVICE_POLICY) {
     const user_manager::User* logged_in_user =
         user_manager::UserManager::Get()->GetLoggedInUser();
-    if (logged_in_user->is_affiliated()) {
+    if (logged_in_user->IsAffiliated()) {
       VLOG(1) << "Respecting proxy for network, as logged-in user belongs to "
               << "the domain the device is enrolled to.";
       return false;
diff --git a/chrome/browser/devtools/device/adb/adb_client_socket.cc b/chrome/browser/devtools/device/adb/adb_client_socket.cc
index e65375b..9552ef0 100644
--- a/chrome/browser/devtools/device/adb/adb_client_socket.cc
+++ b/chrome/browser/devtools/device/adb/adb_client_socket.cc
@@ -13,8 +13,8 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "net/base/ip_address.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/socket/tcp_client_socket.h"
 
 namespace {
@@ -173,14 +173,14 @@
 }
 
 void AdbClientSocket::Connect(const net::CompletionCallback& callback) {
-  net::IPAddressNumber ip_number;
-  if (!net::ParseIPLiteralToNumber(host_, &ip_number)) {
+  net::IPAddress ip_address;
+  if (!ip_address.AssignFromIPLiteral(host_)) {
     callback.Run(net::ERR_FAILED);
     return;
   }
 
   net::AddressList address_list =
-      net::AddressList::CreateFromIPAddress(ip_number, port_);
+      net::AddressList::CreateFromIPAddress(ip_address, port_);
   socket_.reset(new net::TCPClientSocket(address_list, NULL,
                                          net::NetLog::Source()));
   int result = socket_->Connect(callback);
diff --git a/chrome/browser/devtools/device/adb/mock_adb_server.cc b/chrome/browser/devtools/device/adb/mock_adb_server.cc
index 333af448..bd0e0fe 100644
--- a/chrome/browser/devtools/device/adb/mock_adb_server.cc
+++ b/chrome/browser/devtools/device/adb/mock_adb_server.cc
@@ -21,6 +21,7 @@
 #include "content/public/test/browser_test.h"
 #include "content/public/test/test_utils.h"
 #include "net/base/io_buffer.h"
+#include "net/base/ip_address.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
 #include "net/socket/stream_socket.h"
@@ -480,9 +481,7 @@
 void StartMockAdbServerOnIOThread(FlushMode flush_mode) {
   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   CHECK(mock_adb_server_ == NULL);
-  net::IPAddressNumber address;
-  net::ParseIPLiteralToNumber("127.0.0.1", &address);
-  net::IPEndPoint endpoint(address, kAdbPort);
+  net::IPEndPoint endpoint(net::IPAddress(127, 0, 0, 1), kAdbPort);
   mock_adb_server_ = new SimpleHttpServer(
       base::Bind(&AdbParser::Create, flush_mode), endpoint);
 }
diff --git a/chrome/browser/devtools/device/port_forwarding_controller.cc b/chrome/browser/devtools/device/port_forwarding_controller.cc
index 182b987..76f983a 100644
--- a/chrome/browser/devtools/device/port_forwarding_controller.cc
+++ b/chrome/browser/devtools/device/port_forwarding_controller.cc
@@ -27,7 +27,6 @@
 #include "net/base/address_list.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/dns/host_resolver.h"
 #include "net/socket/tcp_client_socket.h"
 
diff --git a/chrome/browser/devtools/device/usb/android_usb_socket.cc b/chrome/browser/devtools/device/usb/android_usb_socket.cc
index 501e543a..76fd0507 100644
--- a/chrome/browser/devtools/device/usb/android_usb_socket.cc
+++ b/chrome/browser/devtools/device/usb/android_usb_socket.cc
@@ -10,6 +10,7 @@
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
 #include "net/base/io_buffer.h"
+#include "net/base/ip_address.h"
 #include "net/base/net_errors.h"
 
 namespace {
@@ -191,8 +192,7 @@
 }
 
 int AndroidUsbSocket::GetPeerAddress(net::IPEndPoint* address) const {
-  net::IPAddressNumber ip(net::kIPv4AddressSize);
-  *address = net::IPEndPoint(ip, 0);
+  *address = net::IPEndPoint(net::IPAddress(0, 0, 0, 0), 0);
   return net::OK;
 }
 
diff --git a/chrome/browser/devtools/devtools_auto_opener.cc b/chrome/browser/devtools/devtools_auto_opener.cc
index e21c35e..5b51e16 100644
--- a/chrome/browser/devtools/devtools_auto_opener.cc
+++ b/chrome/browser/devtools/devtools_auto_opener.cc
@@ -20,5 +20,6 @@
     content::WebContents* contents,
     int index,
     bool foreground) {
-  DevToolsWindow::OpenDevToolsWindow(contents);
+  if (!DevToolsWindow::IsDevToolsWindow(contents))
+    DevToolsWindow::OpenDevToolsWindow(contents);
 }
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc
index 5edac67..62b3284 100644
--- a/chrome/browser/devtools/devtools_sanity_browsertest.cc
+++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -1029,32 +1029,32 @@
  public:
   void SetUpCommandLine(base::CommandLine* command_line) override {
     command_line->AppendSwitch(switches::kAutoOpenDevToolsForTabs);
+    observer_.reset(new DevToolsWindowCreationObserver());
   }
+ protected:
+  scoped_ptr<DevToolsWindowCreationObserver> observer_;
 };
 
 IN_PROC_BROWSER_TEST_F(DevToolsAutoOpenerTest, TestAutoOpenForTabs) {
   {
-    scoped_refptr<content::DevToolsAgentHost> agent(
-        content::DevToolsAgentHost::GetOrCreateFor(GetInspectedTab()));
-    DevToolsWindow* window = DevToolsWindow::FindDevToolsWindow(agent.get());
-    ASSERT_TRUE(window);
-    DevToolsWindowTesting::CloseDevToolsWindowSync(window);
-  }
-  {
     DevToolsWindowCreationObserver observer;
     AddTabAtIndexToBrowser(browser(), 0, GURL("about:blank"),
         ui::PAGE_TRANSITION_AUTO_TOPLEVEL, false);
     observer.WaitForLoad();
-    DevToolsWindowTesting::CloseDevToolsWindowSync(observer.devtools_window());
+  }
+  Browser* new_browser = nullptr;
+  {
+    DevToolsWindowCreationObserver observer;
+    new_browser = CreateBrowser(browser()->profile());
+    observer.WaitForLoad();
   }
   {
     DevToolsWindowCreationObserver observer;
-    Browser* new_browser = CreateBrowser(browser()->profile());
     AddTabAtIndexToBrowser(new_browser, 0, GURL("about:blank"),
         ui::PAGE_TRANSITION_AUTO_TOPLEVEL, false);
     observer.WaitForLoad();
-    DevToolsWindowTesting::CloseDevToolsWindowSync(observer.devtools_window());
   }
+  observer_->CloseAllSync();
 }
 
 class DevToolsReattachAfterCrashTest : public DevToolsSanityTest {
diff --git a/chrome/browser/devtools/devtools_window.cc b/chrome/browser/devtools/devtools_window.cc
index 2d7a3c6..8ba43421 100644
--- a/chrome/browser/devtools/devtools_window.cc
+++ b/chrome/browser/devtools/devtools_window.cc
@@ -312,6 +312,17 @@
   g_creation_callbacks.Get().push_back(callback);
 }
 
+// static
+void DevToolsWindow::RemoveCreationCallbackForTest(
+    const CreationCallback& callback) {
+  for (size_t i = 0; i < g_creation_callbacks.Get().size(); ++i) {
+    if (g_creation_callbacks.Get().at(i).Equals(callback)) {
+      g_creation_callbacks.Get().erase(g_creation_callbacks.Get().begin() + i);
+      return;
+    }
+  }
+}
+
 DevToolsWindow::~DevToolsWindow() {
   life_stage_ = kClosing;
 
@@ -751,8 +762,8 @@
   task_management::WebContentsTags::CreateForDevToolsContents(
       main_web_contents_);
 
-  std::vector<base::Callback<void(DevToolsWindow*)>> copy;
-  g_creation_callbacks.Get().swap(copy);
+  std::vector<base::Callback<void(DevToolsWindow*)>> copy(
+      g_creation_callbacks.Get());
   for (const auto& callback : copy)
     callback.Run(this);
 }
diff --git a/chrome/browser/devtools/devtools_window.h b/chrome/browser/devtools/devtools_window.h
index 16e337cd..fc17c12 100644
--- a/chrome/browser/devtools/devtools_window.h
+++ b/chrome/browser/devtools/devtools_window.h
@@ -217,6 +217,7 @@
 
   using CreationCallback = base::Callback<void(DevToolsWindow*)>;
   static void AddCreationCallbackForTest(const CreationCallback& callback);
+  static void RemoveCreationCallbackForTest(const CreationCallback& callback);
 
   // DevTools lifecycle typically follows this way:
   // - Toggle/Open: client call;
diff --git a/chrome/browser/devtools/devtools_window_testing.cc b/chrome/browser/devtools/devtools_window_testing.cc
index abc8043..0f27344 100644
--- a/chrome/browser/devtools/devtools_window_testing.cc
+++ b/chrome/browser/devtools/devtools_window_testing.cc
@@ -156,17 +156,18 @@
 // DevToolsWindowCreationObserver ---------------------------------------------
 
 DevToolsWindowCreationObserver::DevToolsWindowCreationObserver()
-    : devtools_window_(nullptr) {
-  DevToolsWindow::AddCreationCallbackForTest(base::Bind(
-      &DevToolsWindowCreationObserver::DevToolsWindowCreated,
-      base::Unretained(this)));
+    : creation_callback_(base::Bind(
+          &DevToolsWindowCreationObserver::DevToolsWindowCreated,
+          base::Unretained(this))) {
+  DevToolsWindow::AddCreationCallbackForTest(creation_callback_);
 }
 
 DevToolsWindowCreationObserver::~DevToolsWindowCreationObserver() {
+  DevToolsWindow::RemoveCreationCallbackForTest(creation_callback_);
 }
 
 void DevToolsWindowCreationObserver::Wait() {
-  if (devtools_window_)
+  if (devtools_windows_.size())
     return;
   runner_ = new content::MessageLoopRunner();
   runner_->Run();
@@ -174,13 +175,27 @@
 
 void DevToolsWindowCreationObserver::WaitForLoad() {
   Wait();
-  if (devtools_window_)
-    DevToolsWindowTesting::WaitForDevToolsWindowLoad(devtools_window_);
+  if (devtools_window())
+    DevToolsWindowTesting::WaitForDevToolsWindowLoad(devtools_window());
 }
 
 void DevToolsWindowCreationObserver::DevToolsWindowCreated(
     DevToolsWindow* devtools_window) {
-  devtools_window_ = devtools_window;
-  if (runner_.get())
-      runner_->QuitClosure().Run();
+  devtools_windows_.push_back(devtools_window);
+  if (runner_.get()) {
+    runner_->QuitClosure().Run();
+    runner_ = nullptr;
+  }
+}
+
+DevToolsWindow* DevToolsWindowCreationObserver::devtools_window() {
+  if (!devtools_windows_.size())
+    return nullptr;
+  return devtools_windows_[devtools_windows_.size() - 1];
+}
+
+void DevToolsWindowCreationObserver::CloseAllSync() {
+  for (DevToolsWindow* window : devtools_windows_)
+    DevToolsWindowTesting::CloseDevToolsWindowSync(window);
+  devtools_windows_.clear();
 }
diff --git a/chrome/browser/devtools/devtools_window_testing.h b/chrome/browser/devtools/devtools_window_testing.h
index 0196b94..19fd9ee55 100644
--- a/chrome/browser/devtools/devtools_window_testing.h
+++ b/chrome/browser/devtools/devtools_window_testing.h
@@ -65,16 +65,21 @@
   DevToolsWindowCreationObserver();
   ~DevToolsWindowCreationObserver();
 
-  DevToolsWindow* devtools_window() { return devtools_window_; }
+  using DevToolsWindows = std::vector<DevToolsWindow*>;
+  const DevToolsWindows& devtools_windows() { return devtools_windows_; }
+  DevToolsWindow* devtools_window();
+
   void Wait();
   void WaitForLoad();
+  void CloseAllSync();
 
  private:
   friend class DevToolsWindow;
 
   void DevToolsWindowCreated(DevToolsWindow* devtools_window);
 
-  DevToolsWindow* devtools_window_;
+  base::Callback<void(DevToolsWindow*)> creation_callback_;
+  DevToolsWindows devtools_windows_;
   scoped_refptr<content::MessageLoopRunner> runner_;
 
   DISALLOW_COPY_AND_ASSIGN(DevToolsWindowCreationObserver);
diff --git a/chrome/browser/dom_distiller/tab_utils_android.cc b/chrome/browser/dom_distiller/tab_utils_android.cc
index 2691bf9..8133eb0 100644
--- a/chrome/browser/dom_distiller/tab_utils_android.cc
+++ b/chrome/browser/dom_distiller/tab_utils_android.cc
@@ -17,7 +17,6 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_constants.h"
 #include "jni/DomDistillerTabUtils_jni.h"
-#include "net/base/net_util.h"
 #include "url/gurl.h"
 
 namespace android {
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc
index dcdd570..e8213aed 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate.cc
@@ -751,8 +751,7 @@
 
 bool ChromeDownloadManagerDelegate::IsOpenInBrowserPreferreredForFile(
     const base::FilePath& path) {
-#if defined(OS_WIN) || defined(OS_LINUX) || \
-    (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MACOSX)
   if (path.MatchesExtension(FILE_PATH_LITERAL(".pdf"))) {
     return !download_prefs_->ShouldOpenPdfInSystemReader();
   }
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index d871837..8a098024 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -2662,7 +2662,7 @@
 
 // On mobile, the multiple downloads UI is an infobar. On desktop, it's a
 // bubble. Test each as appropriate.
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_ANDROID)
 IN_PROC_BROWSER_TEST_F(DownloadTest, TestMultipleDownloadsInfobar) {
   // Ensure that infobars are being used instead of bubbles.
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
diff --git a/chrome/browser/download/download_commands.cc b/chrome/browser/download/download_commands.cc
index 06a8023b..285ee4f 100644
--- a/chrome/browser/download/download_commands.cc
+++ b/chrome/browser/download/download_commands.cc
@@ -210,8 +210,7 @@
       return download_item_->GetOpenWhenComplete() ||
              download_crx_util::IsExtensionDownload(*download_item_);
     case ALWAYS_OPEN_TYPE:
-#if defined(OS_WIN) || defined(OS_LINUX) || \
-    (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MACOSX)
       if (CanOpenPdfInSystemViewer()) {
         DownloadPrefs* prefs = DownloadPrefs::FromBrowserContext(
             download_item_->GetBrowserContext());
@@ -254,8 +253,7 @@
       bool is_checked = IsCommandChecked(ALWAYS_OPEN_TYPE);
       DownloadPrefs* prefs = DownloadPrefs::FromBrowserContext(
           download_item_->GetBrowserContext());
-#if defined(OS_WIN) || defined(OS_LINUX) || \
-    (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MACOSX)
       if (CanOpenPdfInSystemViewer()) {
         prefs->SetShouldOpenPdfInSystemReader(!is_checked);
         DownloadItemModel(download_item_)
diff --git a/chrome/browser/download/download_extensions.cc b/chrome/browser/download/download_extensions.cc
index dea28b0..bc7e8eb 100644
--- a/chrome/browser/download/download_extensions.cc
+++ b/chrome/browser/download/download_extensions.cc
@@ -12,7 +12,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "net/base/mime_util.h"
-#include "net/base/net_util.h"
 
 namespace download_util {
 
diff --git a/chrome/browser/download/download_prefs.cc b/chrome/browser/download/download_prefs.cc
index c27970ca..01669d4 100644
--- a/chrome/browser/download/download_prefs.cc
+++ b/chrome/browser/download/download_prefs.cc
@@ -135,8 +135,7 @@
                  GetDefaultDownloadDirectoryForProfile()));
 #endif  // defined(OS_CHROMEOS)
 
-#if defined(OS_WIN) || defined(OS_LINUX) || \
-    (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MACOSX)
   should_open_pdf_in_system_reader_ =
       prefs->GetBoolean(prefs::kOpenPdfDownloadInSystemReader);
 #endif
@@ -212,8 +211,7 @@
                                  default_download_path);
   registry->RegisterFilePathPref(prefs::kSaveFileDefaultDirectory,
                                  default_download_path);
-#if defined(OS_WIN) || defined(OS_LINUX) || \
-    (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MACOSX)
   registry->RegisterBooleanPref(prefs::kOpenPdfDownloadInSystemReader, false);
 #endif
 }
@@ -290,8 +288,7 @@
 }
 
 bool DownloadPrefs::IsAutoOpenUsed() const {
-#if defined(OS_WIN) || defined(OS_LINUX) || \
-      (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MACOSX)
   if (ShouldOpenPdfInSystemReader())
     return true;
 #endif
@@ -305,8 +302,7 @@
     return false;
   DCHECK(extension[0] == base::FilePath::kExtensionSeparator);
   extension.erase(0, 1);
-#if defined(OS_WIN) || defined(OS_LINUX) || \
-    (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MACOSX)
   if (extension == FILE_PATH_LITERAL("pdf") && ShouldOpenPdfInSystemReader())
     return true;
 #endif
@@ -339,8 +335,7 @@
   SaveAutoOpenState();
 }
 
-#if defined(OS_WIN) || defined(OS_LINUX) || \
-    (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MACOSX)
 void DownloadPrefs::SetShouldOpenPdfInSystemReader(bool should_open) {
   if (should_open_pdf_in_system_reader_ == should_open)
     return;
@@ -361,8 +356,7 @@
 #endif
 
 void DownloadPrefs::ResetAutoOpen() {
-#if defined(OS_WIN) || defined(OS_LINUX) || \
-    (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MACOSX)
   SetShouldOpenPdfInSystemReader(false);
 #endif
   auto_open_.clear();
diff --git a/chrome/browser/download/download_prefs.h b/chrome/browser/download/download_prefs.h
index 29608ba9..01bd1c9 100644
--- a/chrome/browser/download/download_prefs.h
+++ b/chrome/browser/download/download_prefs.h
@@ -79,8 +79,7 @@
   // Disables auto-open based on file extension.
   void DisableAutoOpenBasedOnExtension(const base::FilePath& file_name);
 
-#if defined(OS_WIN) || defined(OS_LINUX) || \
-    (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MACOSX)
   // Store the user preference to disk. If |should_open| is true, also disable
   // the built-in PDF plugin. If |should_open| is false, enable the PDF plugin.
   void SetShouldOpenPdfInSystemReader(bool should_open);
@@ -111,8 +110,7 @@
                    AutoOpenCompareFunctor> AutoOpenSet;
   AutoOpenSet auto_open_;
 
-#if defined(OS_WIN) || defined(OS_LINUX) || \
-    (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MACOSX)
   bool should_open_pdf_in_system_reader_;
 #endif
 
diff --git a/chrome/browser/download/drag_download_item_views.cc b/chrome/browser/download/drag_download_item_views.cc
index 43c25a50..ed618310 100644
--- a/chrome/browser/download/drag_download_item_views.cc
+++ b/chrome/browser/download/drag_download_item_views.cc
@@ -10,7 +10,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "content/public/browser/download_item.h"
 #include "net/base/mime_util.h"
-#include "net/base/net_util.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/base/dragdrop/drag_drop_types.h"
diff --git a/chrome/browser/engagement/site_engagement_metrics.cc b/chrome/browser/engagement/site_engagement_metrics.cc
index 1159253..3dd3a10e 100644
--- a/chrome/browser/engagement/site_engagement_metrics.cc
+++ b/chrome/browser/engagement/site_engagement_metrics.cc
@@ -33,6 +33,12 @@
 const char SiteEngagementMetrics::kEngagementScoreHistogram[] =
     "SiteEngagementService.EngagementScore";
 
+const char SiteEngagementMetrics::kEngagementScoreHistogramHTTP[] =
+    "SiteEngagementService.EngagementScore.HTTP";
+
+const char SiteEngagementMetrics::kEngagementScoreHistogramHTTPS[] =
+    "SiteEngagementService.EngagementScore.HTTPS";
+
 const char SiteEngagementMetrics::kOriginsWithMaxEngagementHistogram[] =
     "SiteEngagementService.OriginsWithMaxEngagement";
 
@@ -85,6 +91,11 @@
   for (const auto& value : score_map) {
     UMA_HISTOGRAM_COUNTS_100(kEngagementScoreHistogram, value.second);
     score_buckets.lower_bound(value.second)->second++;
+
+    if (value.first.SchemeIs(url::kHttpsScheme))
+      UMA_HISTOGRAM_COUNTS_100(kEngagementScoreHistogramHTTPS, value.second);
+    else if (value.first.SchemeIs(url::kHttpScheme))
+      UMA_HISTOGRAM_COUNTS_100(kEngagementScoreHistogramHTTP, value.second);
   }
 
   for (const auto& b : score_buckets) {
diff --git a/chrome/browser/engagement/site_engagement_metrics.h b/chrome/browser/engagement/site_engagement_metrics.h
index c424824..0d249e7 100644
--- a/chrome/browser/engagement/site_engagement_metrics.h
+++ b/chrome/browser/engagement/site_engagement_metrics.h
@@ -54,6 +54,8 @@
   static const char kMeanEngagementHistogram[];
   static const char kMedianEngagementHistogram[];
   static const char kEngagementScoreHistogram[];
+  static const char kEngagementScoreHistogramHTTP[];
+  static const char kEngagementScoreHistogramHTTPS[];
   static const char kOriginsWithMaxEngagementHistogram[];
   static const char kOriginsWithMaxDailyEngagementHistogram[];
   static const char kPercentOriginsWithMaxEngagementHistogram[];
diff --git a/chrome/browser/engagement/site_engagement_service.cc b/chrome/browser/engagement/site_engagement_service.cc
index 03a7ff0..e97cade 100644
--- a/chrome/browser/engagement/site_engagement_service.cc
+++ b/chrome/browser/engagement/site_engagement_service.cc
@@ -40,15 +40,17 @@
 // Keys used in the variations params. Order matches
 // SiteEngagementScore::Variation enum.
 const char* kVariationNames[] = {
-  "max_points_per_day",
-  "decay_period_in_days",
-  "decay_points",
-  "navigation_points",
-  "user_input_points",
-  "visible_media_playing_points",
-  "hidden_media_playing_points",
-  "web_app_installed_points",
-  "first_daily_engagement_points",
+    "max_points_per_day",
+    "decay_period_in_days",
+    "decay_points",
+    "navigation_points",
+    "user_input_points",
+    "visible_media_playing_points",
+    "hidden_media_playing_points",
+    "web_app_installed_points",
+    "first_daily_engagement_points",
+    "medium_engagement_boundary",
+    "high_engagement_boundary",
 };
 
 // Length of time between metrics logging.
@@ -127,6 +129,8 @@
     5,     // WEB_APP_INSTALLED_POINTS
     0.5,   // FIRST_DAILY_ENGAGEMENT
     8,     // BOOTSTRAP_POINTS
+    5,     // MEDIUM_ENGAGEMENT_BOUNDARY
+    50,    // HIGH_ENGAGEMENT_BOUNDARY
 };
 
 const char* SiteEngagementScore::kRawScoreKey = "rawScore";
@@ -175,6 +179,14 @@
   return param_values[BOOTSTRAP_POINTS];
 }
 
+double SiteEngagementScore::GetMediumEngagementBoundary() {
+  return param_values[MEDIUM_ENGAGEMENT_BOUNDARY];
+}
+
+double SiteEngagementScore::GetHighEngagementBoundary() {
+  return param_values[HIGH_ENGAGEMENT_BOUNDARY];
+}
+
 void SiteEngagementScore::UpdateFromVariations() {
   double param_vals[MAX_VARIATION];
 
@@ -347,6 +359,8 @@
   param_values[HIDDEN_MEDIA_POINTS] = 0.01;
   param_values[WEB_APP_INSTALLED_POINTS] = 5;
   param_values[BOOTSTRAP_POINTS] = 8;
+  param_values[MEDIUM_ENGAGEMENT_BOUNDARY] = 5;
+  param_values[HIGH_ENGAGEMENT_BOUNDARY] = 50;
 
   // This is set to zero to avoid interference with tests and is set when
   // testing this functionality.
@@ -537,6 +551,48 @@
          SiteEngagementScore::GetBootstrapPoints();
 }
 
+SiteEngagementService::EngagementLevel
+SiteEngagementService::GetEngagementLevel(const GURL& url) const {
+  DCHECK_LT(SiteEngagementScore::GetMediumEngagementBoundary(),
+            SiteEngagementScore::GetHighEngagementBoundary());
+  double score = GetScore(url);
+  if (score == 0)
+    return ENGAGEMENT_LEVEL_NONE;
+
+  if (score < SiteEngagementScore::GetMediumEngagementBoundary())
+    return ENGAGEMENT_LEVEL_LOW;
+
+  if (score < SiteEngagementScore::GetHighEngagementBoundary())
+    return ENGAGEMENT_LEVEL_MEDIUM;
+
+  if (score < SiteEngagementScore::kMaxPoints)
+    return ENGAGEMENT_LEVEL_HIGH;
+
+  return ENGAGEMENT_LEVEL_MAX;
+}
+
+bool SiteEngagementService::IsEngagementAtLeast(
+    const GURL& url,
+    EngagementLevel level) const {
+  DCHECK_LT(SiteEngagementScore::GetMediumEngagementBoundary(),
+            SiteEngagementScore::GetHighEngagementBoundary());
+  double score = GetScore(url);
+  switch (level) {
+    case ENGAGEMENT_LEVEL_NONE:
+      return true;
+    case ENGAGEMENT_LEVEL_LOW:
+      return score > 0;
+    case ENGAGEMENT_LEVEL_MEDIUM:
+      return score >= SiteEngagementScore::GetMediumEngagementBoundary();
+    case ENGAGEMENT_LEVEL_HIGH:
+      return score >= SiteEngagementScore::GetHighEngagementBoundary();
+    case ENGAGEMENT_LEVEL_MAX:
+      return score == SiteEngagementScore::kMaxPoints;
+  }
+  NOTREACHED();
+  return false;
+}
+
 SiteEngagementService::SiteEngagementService(Profile* profile,
                                              scoped_ptr<base::Clock> clock)
     : profile_(profile), clock_(std::move(clock)), weak_factory_(this) {
diff --git a/chrome/browser/engagement/site_engagement_service.h b/chrome/browser/engagement/site_engagement_service.h
index 2c4afa4..50583c6 100644
--- a/chrome/browser/engagement/site_engagement_service.h
+++ b/chrome/browser/engagement/site_engagement_service.h
@@ -64,6 +64,11 @@
     // considered 'useful'.
     BOOTSTRAP_POINTS,
 
+    // The boundaries between low/medium and medium/high engagement as returned
+    // by GetEngagementLevel().
+    MEDIUM_ENGAGEMENT_BOUNDARY,
+    HIGH_ENGAGEMENT_BOUNDARY,
+
     MAX_VARIATION
   };
 
@@ -80,6 +85,8 @@
   static double GetWebAppInstalledPoints();
   static double GetFirstDailyEngagementPoints();
   static double GetBootstrapPoints();
+  static double GetMediumEngagementBoundary();
+  static double GetHighEngagementBoundary();
 
   // Update the default engagement settings via variations.
   static void UpdateFromVariations();
@@ -190,6 +197,14 @@
                               public history::HistoryServiceObserver,
                               public SiteEngagementScoreProvider {
  public:
+  enum EngagementLevel {
+    ENGAGEMENT_LEVEL_NONE,
+    ENGAGEMENT_LEVEL_LOW,
+    ENGAGEMENT_LEVEL_MEDIUM,
+    ENGAGEMENT_LEVEL_HIGH,
+    ENGAGEMENT_LEVEL_MAX,
+  };
+
   // The name of the site engagement variation field trial.
   static const char kEngagementParams[];
 
@@ -209,6 +224,13 @@
   // this is true.
   bool IsBootstrapped();
 
+  // Returns the engagement level of |url|. This is the recommended API for
+  // clients
+  EngagementLevel GetEngagementLevel(const GURL& url) const;
+
+  // Returns whether |url| has at least the given |level| of engagement.
+  bool IsEngagementAtLeast(const GURL& url, EngagementLevel level) const;
+
   // Update the engagement score of the origin matching |url| for navigation.
   void HandleNavigation(const GURL& url, ui::PageTransition transition);
 
@@ -251,6 +273,7 @@
   FRIEND_TEST_ALL_PREFIXES(SiteEngagementServiceTest,
                            CleanupOriginsOnHistoryDeletion);
   FRIEND_TEST_ALL_PREFIXES(SiteEngagementServiceTest, IsBootstrapped);
+  FRIEND_TEST_ALL_PREFIXES(SiteEngagementServiceTest, EngagementLevel);
   FRIEND_TEST_ALL_PREFIXES(SiteEngagementServiceTest, ScoreDecayHistograms);
   FRIEND_TEST_ALL_PREFIXES(AppBannerSettingsHelperTest, SiteEngagementTrigger);
 
diff --git a/chrome/browser/engagement/site_engagement_service_unittest.cc b/chrome/browser/engagement/site_engagement_service_unittest.cc
index 14f0e93..be3fc1e 100644
--- a/chrome/browser/engagement/site_engagement_service_unittest.cc
+++ b/chrome/browser/engagement/site_engagement_service_unittest.cc
@@ -736,6 +736,10 @@
   histograms.ExpectTotalCount(SiteEngagementMetrics::kEngagementScoreHistogram,
                               0);
   histograms.ExpectTotalCount(
+      SiteEngagementMetrics::kEngagementScoreHistogramHTTP, 0);
+  histograms.ExpectTotalCount(
+      SiteEngagementMetrics::kEngagementScoreHistogramHTTPS, 0);
+  histograms.ExpectTotalCount(
       SiteEngagementMetrics::kOriginsWithMaxEngagementHistogram, 0);
   histograms.ExpectTotalCount(
       SiteEngagementMetrics::kOriginsWithMaxDailyEngagementHistogram, 0);
@@ -753,6 +757,10 @@
                                 0, 1);
   histograms.ExpectTotalCount(SiteEngagementMetrics::kEngagementScoreHistogram,
                               0);
+  histograms.ExpectTotalCount(
+      SiteEngagementMetrics::kEngagementScoreHistogramHTTP, 0);
+  histograms.ExpectTotalCount(
+      SiteEngagementMetrics::kEngagementScoreHistogramHTTPS, 0);
   histograms.ExpectUniqueSample(SiteEngagementMetrics::kMeanEngagementHistogram,
                                 0, 1);
   histograms.ExpectUniqueSample(
@@ -796,6 +804,10 @@
   // Recorded per origin.
   histograms.ExpectTotalCount(SiteEngagementMetrics::kEngagementScoreHistogram,
                               1);
+  histograms.ExpectTotalCount(
+      SiteEngagementMetrics::kEngagementScoreHistogramHTTP, 0);
+  histograms.ExpectTotalCount(
+      SiteEngagementMetrics::kEngagementScoreHistogramHTTPS, 1);
   histograms.ExpectUniqueSample(
       SiteEngagementMetrics::kOriginsWithMaxEngagementHistogram, 0, 2);
   histograms.ExpectUniqueSample(
@@ -861,6 +873,10 @@
   // Recorded per origin.
   histograms.ExpectTotalCount(SiteEngagementMetrics::kEngagementScoreHistogram,
                               4);
+  histograms.ExpectTotalCount(
+      SiteEngagementMetrics::kEngagementScoreHistogramHTTP, 2);
+  histograms.ExpectTotalCount(
+      SiteEngagementMetrics::kEngagementScoreHistogramHTTPS, 2);
   histograms.ExpectUniqueSample(
       SiteEngagementMetrics::kOriginsWithMaxEngagementHistogram, 0, 3);
   histograms.ExpectUniqueSample(
@@ -933,6 +949,10 @@
                               4);
   histograms.ExpectTotalCount(SiteEngagementMetrics::kEngagementScoreHistogram,
                               7);
+  histograms.ExpectTotalCount(
+      SiteEngagementMetrics::kEngagementScoreHistogramHTTP, 4);
+  histograms.ExpectTotalCount(
+      SiteEngagementMetrics::kEngagementScoreHistogramHTTPS, 3);
   histograms.ExpectUniqueSample(
       SiteEngagementMetrics::kOriginsWithMaxEngagementHistogram, 0, 4);
   histograms.ExpectBucketCount(
@@ -1157,6 +1177,119 @@
   }
 }
 
+TEST_F(SiteEngagementServiceTest, EngagementLevel) {
+  static_assert(SiteEngagementService::ENGAGEMENT_LEVEL_NONE !=
+                    SiteEngagementService::ENGAGEMENT_LEVEL_LOW,
+                "enum values should not be equal");
+  static_assert(SiteEngagementService::ENGAGEMENT_LEVEL_LOW !=
+                    SiteEngagementService::ENGAGEMENT_LEVEL_MEDIUM,
+                "enum values should not be equal");
+  static_assert(SiteEngagementService::ENGAGEMENT_LEVEL_MEDIUM !=
+                    SiteEngagementService::ENGAGEMENT_LEVEL_HIGH,
+                "enum values should not be equal");
+  static_assert(SiteEngagementService::ENGAGEMENT_LEVEL_HIGH !=
+                    SiteEngagementService::ENGAGEMENT_LEVEL_MAX,
+                "enum values should not be equal");
+
+  base::SimpleTestClock* clock = new base::SimpleTestClock();
+  scoped_ptr<SiteEngagementService> service(
+      new SiteEngagementService(profile(), make_scoped_ptr(clock)));
+
+  base::Time current_day = GetReferenceTime();
+  clock->SetNow(current_day);
+
+  GURL url1("https://www.google.com/");
+  GURL url2("http://www.google.com/");
+
+  EXPECT_EQ(SiteEngagementService::ENGAGEMENT_LEVEL_NONE,
+            service->GetEngagementLevel(url1));
+  EXPECT_EQ(SiteEngagementService::ENGAGEMENT_LEVEL_NONE,
+            service->GetEngagementLevel(url2));
+  EXPECT_TRUE(service->IsEngagementAtLeast(
+      url1, SiteEngagementService::ENGAGEMENT_LEVEL_NONE));
+  EXPECT_FALSE(service->IsEngagementAtLeast(
+      url1, SiteEngagementService::ENGAGEMENT_LEVEL_LOW));
+  EXPECT_FALSE(service->IsEngagementAtLeast(
+      url1, SiteEngagementService::ENGAGEMENT_LEVEL_MEDIUM));
+  EXPECT_FALSE(service->IsEngagementAtLeast(
+      url1, SiteEngagementService::ENGAGEMENT_LEVEL_HIGH));
+  EXPECT_FALSE(service->IsEngagementAtLeast(
+      url1, SiteEngagementService::ENGAGEMENT_LEVEL_MAX));
+
+  // Bring url1 to LOW engagement.
+  service->AddPoints(url1, 1.0);
+  EXPECT_EQ(SiteEngagementService::ENGAGEMENT_LEVEL_LOW,
+            service->GetEngagementLevel(url1));
+  EXPECT_EQ(SiteEngagementService::ENGAGEMENT_LEVEL_NONE,
+            service->GetEngagementLevel(url2));
+  EXPECT_TRUE(service->IsEngagementAtLeast(
+      url1, SiteEngagementService::ENGAGEMENT_LEVEL_NONE));
+  EXPECT_TRUE(service->IsEngagementAtLeast(
+      url1, SiteEngagementService::ENGAGEMENT_LEVEL_LOW));
+  EXPECT_FALSE(service->IsEngagementAtLeast(
+      url1, SiteEngagementService::ENGAGEMENT_LEVEL_MEDIUM));
+  EXPECT_FALSE(service->IsEngagementAtLeast(
+      url1, SiteEngagementService::ENGAGEMENT_LEVEL_HIGH));
+  EXPECT_FALSE(service->IsEngagementAtLeast(
+      url1, SiteEngagementService::ENGAGEMENT_LEVEL_MAX));
+
+  // Bring url2 to MEDIUM engagement.
+  service->AddPoints(url2, 5.0);
+  EXPECT_EQ(SiteEngagementService::ENGAGEMENT_LEVEL_LOW,
+            service->GetEngagementLevel(url1));
+  EXPECT_EQ(SiteEngagementService::ENGAGEMENT_LEVEL_MEDIUM,
+            service->GetEngagementLevel(url2));
+  EXPECT_TRUE(service->IsEngagementAtLeast(
+      url2, SiteEngagementService::ENGAGEMENT_LEVEL_NONE));
+  EXPECT_TRUE(service->IsEngagementAtLeast(
+      url2, SiteEngagementService::ENGAGEMENT_LEVEL_LOW));
+  EXPECT_TRUE(service->IsEngagementAtLeast(
+      url2, SiteEngagementService::ENGAGEMENT_LEVEL_MEDIUM));
+  EXPECT_FALSE(service->IsEngagementAtLeast(
+      url2, SiteEngagementService::ENGAGEMENT_LEVEL_HIGH));
+  EXPECT_FALSE(service->IsEngagementAtLeast(
+      url2, SiteEngagementService::ENGAGEMENT_LEVEL_MAX));
+
+  // Bring url2 to HIGH engagement.
+  for (int i = 0; i < 9; ++i) {
+    current_day += base::TimeDelta::FromDays(1);
+    clock->SetNow(current_day);
+    service->AddPoints(url2, 5.0);
+  }
+  EXPECT_EQ(SiteEngagementService::ENGAGEMENT_LEVEL_HIGH,
+            service->GetEngagementLevel(url2));
+
+  EXPECT_TRUE(service->IsEngagementAtLeast(
+      url2, SiteEngagementService::ENGAGEMENT_LEVEL_NONE));
+  EXPECT_TRUE(service->IsEngagementAtLeast(
+      url2, SiteEngagementService::ENGAGEMENT_LEVEL_LOW));
+  EXPECT_TRUE(service->IsEngagementAtLeast(
+      url2, SiteEngagementService::ENGAGEMENT_LEVEL_MEDIUM));
+  EXPECT_TRUE(service->IsEngagementAtLeast(
+      url2, SiteEngagementService::ENGAGEMENT_LEVEL_HIGH));
+  EXPECT_FALSE(service->IsEngagementAtLeast(
+      url2, SiteEngagementService::ENGAGEMENT_LEVEL_MAX));
+
+  // Bring url2 to MAX engagement.
+  for (int i = 0; i < 10; ++i) {
+    current_day += base::TimeDelta::FromDays(1);
+    clock->SetNow(current_day);
+    service->AddPoints(url2, 5.0);
+  }
+  EXPECT_EQ(SiteEngagementService::ENGAGEMENT_LEVEL_MAX,
+            service->GetEngagementLevel(url2));
+  EXPECT_TRUE(service->IsEngagementAtLeast(
+      url2, SiteEngagementService::ENGAGEMENT_LEVEL_NONE));
+  EXPECT_TRUE(service->IsEngagementAtLeast(
+      url2, SiteEngagementService::ENGAGEMENT_LEVEL_LOW));
+  EXPECT_TRUE(service->IsEngagementAtLeast(
+      url2, SiteEngagementService::ENGAGEMENT_LEVEL_MEDIUM));
+  EXPECT_TRUE(service->IsEngagementAtLeast(
+      url2, SiteEngagementService::ENGAGEMENT_LEVEL_HIGH));
+  EXPECT_TRUE(service->IsEngagementAtLeast(
+      url2, SiteEngagementService::ENGAGEMENT_LEVEL_MAX));
+}
+
 TEST_F(SiteEngagementServiceTest, ScoreDecayHistograms) {
   base::SimpleTestClock* clock = new base::SimpleTestClock();
   scoped_ptr<SiteEngagementService> service(
diff --git a/chrome/browser/errorpage_browsertest.cc b/chrome/browser/errorpage_browsertest.cc
index e85d3eb..5104bef5 100644
--- a/chrome/browser/errorpage_browsertest.cc
+++ b/chrome/browser/errorpage_browsertest.cc
@@ -47,7 +47,6 @@
 #include "content/public/test/test_navigation_observer.h"
 #include "net/base/filename_util.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/http/failing_http_transaction_factory.h"
 #include "net/http/http_cache.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
diff --git a/chrome/browser/extensions/api/cast_streaming/cast_streaming_apitest.cc b/chrome/browser/extensions/api/cast_streaming/cast_streaming_apitest.cc
index 4c18cb8..ce17cbf 100644
--- a/chrome/browser/extensions/api/cast_streaming/cast_streaming_apitest.cc
+++ b/chrome/browser/extensions/api/cast_streaming/cast_streaming_apitest.cc
@@ -30,7 +30,6 @@
 #include "media/cast/test/utility/net_utility.h"
 #include "media/cast/test/utility/standalone_cast_environment.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/rand_callback.h"
 #include "net/udp/udp_server_socket.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/extensions/api/cast_streaming/performance_test.cc b/chrome/browser/extensions/api/cast_streaming/performance_test.cc
index 409f8fb4..41a3c4d3 100644
--- a/chrome/browser/extensions/api/cast_streaming/performance_test.cc
+++ b/chrome/browser/extensions/api/cast_streaming/performance_test.cc
@@ -45,7 +45,6 @@
 #include "media/cast/test/utility/udp_proxy.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/rand_callback.h"
 #include "net/udp/udp_server_socket.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/extensions/api/dial/dial_service_unittest.cc b/chrome/browser/extensions/api/dial/dial_service_unittest.cc
index 654a3c7..9eae360 100644
--- a/chrome/browser/extensions/api/dial/dial_service_unittest.cc
+++ b/chrome/browser/extensions/api/dial/dial_service_unittest.cc
@@ -11,7 +11,6 @@
 #include "chrome/browser/extensions/api/dial/dial_device_data.h"
 #include "chrome/browser/extensions/api/dial/dial_service.h"
 #include "net/base/ip_endpoint.h"
-#include "net/base/net_util.h"
 #include "net/base/network_interfaces.h"
 #include "net/log/test_net_log.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
index 0266ef8..b0055284 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
@@ -48,7 +48,6 @@
 #include "extensions/browser/event_router.h"
 #include "extensions/browser/notification_types.h"
 #include "net/base/data_url.h"
-#include "net/base/net_util.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/url_request/url_request_slow_download_job.h"
 #include "net/url_request/url_request.h"
diff --git a/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api.cc b/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api.cc
index a0024f73..5166107 100644
--- a/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api.cc
+++ b/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_api.cc
@@ -22,7 +22,7 @@
   const user_manager::User* user =
       chromeos::ProfileHelper::Get()->GetUserByProfile(
           Profile::FromBrowserContext(context));
-  return user->is_affiliated();
+  return user->IsAffiliated();
 }
 
 // Returns the directory device id for the permitted extensions or an empty
diff --git a/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc b/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc
index c0f98cd2..5d6a5fd 100644
--- a/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc
+++ b/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc
@@ -200,7 +200,7 @@
   SetPolicy();
 
   EXPECT_EQ(GetParam().affiliated_, user_manager::UserManager::Get()->
-      FindUser(affiliated_account_id_)->is_affiliated());
+      FindUser(affiliated_account_id_)->IsAffiliated());
 
   // Device ID is available only for affiliated user.
   std::string device_id = GetParam().affiliated_ ? kDeviceId : "";
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc
index 04e1f324c..99c6f4070 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc
+++ b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc
@@ -152,7 +152,7 @@
           AccountId::FromUserEmail(email));
 
   if (user) {
-    return user->is_affiliated();
+    return user->IsAffiliated();
   }
 
   return false;
diff --git a/chrome/browser/extensions/api/file_handlers/api_file_handler_util_unittest.cc b/chrome/browser/extensions/api/file_handlers/api_file_handler_util_unittest.cc
index a4a8927..6454656f 100644
--- a/chrome/browser/extensions/api/file_handlers/api_file_handler_util_unittest.cc
+++ b/chrome/browser/extensions/api/file_handlers/api_file_handler_util_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
 
+#include "extensions/browser/entry_info.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace extensions {
@@ -16,30 +17,47 @@
   return handler_info;
 }
 
+FileHandlerInfo CreateHandlerInfoFromIncludeDirectories(
+    bool include_directories) {
+  FileHandlerInfo handler_info;
+  handler_info.include_directories = include_directories;
+  return handler_info;
 }
 
-TEST(FileHandlersAppFileHandlerUtilTest, FileHandlerCanHandleFile) {
+}  // namespace
+
+TEST(FileHandlersAppFileHandlerUtilTest, FileHandlerCanHandleEntry) {
   // File handler for extension "gz" should accept "*.gz", including "*.tar.gz".
-  EXPECT_TRUE(FileHandlerCanHandleFile(
+  EXPECT_TRUE(FileHandlerCanHandleEntry(
       CreateHandlerInfoFromExtension("gz"),
-      "application/octet-stream",
-      base::FilePath::FromUTF8Unsafe("foo.gz")));
-  EXPECT_FALSE(FileHandlerCanHandleFile(
+      EntryInfo(base::FilePath::FromUTF8Unsafe("foo.gz"),
+                "application/octet-stream", false)));
+  EXPECT_FALSE(FileHandlerCanHandleEntry(
       CreateHandlerInfoFromExtension("gz"),
-      "application/octet-stream",
-      base::FilePath::FromUTF8Unsafe("foo.tgz")));
-  EXPECT_TRUE(FileHandlerCanHandleFile(
+      EntryInfo(base::FilePath::FromUTF8Unsafe("foo.tgz"),
+                "application/octet-stream", false)));
+  EXPECT_TRUE(FileHandlerCanHandleEntry(
       CreateHandlerInfoFromExtension("gz"),
-      "application/octet-stream",
-      base::FilePath::FromUTF8Unsafe("foo.tar.gz")));
-  EXPECT_FALSE(FileHandlerCanHandleFile(
+      EntryInfo(base::FilePath::FromUTF8Unsafe("foo.tar.gz"),
+                "application/octet-stream", false)));
+  EXPECT_FALSE(FileHandlerCanHandleEntry(
       CreateHandlerInfoFromExtension("tar.gz"),
-      "application/octet-stream",
-      base::FilePath::FromUTF8Unsafe("foo.gz")));
-  EXPECT_TRUE(FileHandlerCanHandleFile(
+      EntryInfo(base::FilePath::FromUTF8Unsafe("foo.gz"),
+                "application/octet-stream", false)));
+  EXPECT_TRUE(FileHandlerCanHandleEntry(
       CreateHandlerInfoFromExtension("tar.gz"),
-      "application/octet-stream",
-      base::FilePath::FromUTF8Unsafe("foo.tar.gz")));
+      EntryInfo(base::FilePath::FromUTF8Unsafe("foo.tar.gz"),
+                "application/octet-stream", false)));
+  EXPECT_FALSE(FileHandlerCanHandleEntry(
+      CreateHandlerInfoFromExtension("gz"),
+      EntryInfo(base::FilePath::FromUTF8Unsafe("directory"), "", true)));
+
+  EXPECT_FALSE(FileHandlerCanHandleEntry(
+      CreateHandlerInfoFromIncludeDirectories(false),
+      EntryInfo(base::FilePath::FromUTF8Unsafe("directory"), "", true)));
+  EXPECT_TRUE(FileHandlerCanHandleEntry(
+      CreateHandlerInfoFromIncludeDirectories(true),
+      EntryInfo(base::FilePath::FromUTF8Unsafe("directory"), "", true)));
 }
 
 }  // namespace app_file_handler_util
diff --git a/chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc b/chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc
index 9132be8..07ce6f1 100644
--- a/chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc
+++ b/chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc
@@ -10,6 +10,7 @@
 #include "build/build_config.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/child_process_security_policy.h"
+#include "extensions/browser/entry_info.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/granted_file_entry.h"
 #include "extensions/common/permissions/permissions_data.h"
@@ -101,7 +102,7 @@
   WritableFileChecker(
       const std::vector<base::FilePath>& paths,
       Profile* profile,
-      bool is_directory,
+      const std::set<base::FilePath>& directory_paths,
       const base::Closure& on_success,
       const base::Callback<void(const base::FilePath&)>& on_failure);
 
@@ -127,7 +128,7 @@
 
   const std::vector<base::FilePath> paths_;
   Profile* profile_;
-  const bool is_directory_;
+  const std::set<base::FilePath> directory_paths_;
   int outstanding_tasks_;
   base::FilePath error_path_;
   base::Closure on_success_;
@@ -137,12 +138,12 @@
 WritableFileChecker::WritableFileChecker(
     const std::vector<base::FilePath>& paths,
     Profile* profile,
-    bool is_directory,
+    const std::set<base::FilePath>& directory_paths,
     const base::Closure& on_success,
     const base::Callback<void(const base::FilePath&)>& on_failure)
     : paths_(paths),
       profile_(profile),
-      is_directory_(is_directory),
+      directory_paths_(directory_paths),
       outstanding_tasks_(1),
       on_success_(on_success),
       on_failure_(on_failure) {}
@@ -150,9 +151,10 @@
 void WritableFileChecker::Check() {
     outstanding_tasks_ = paths_.size();
     for (const auto& path : paths_) {
+      bool is_directory = directory_paths_.find(path) != directory_paths_.end();
 #if defined(OS_CHROMEOS)
       if (file_manager::util::IsUnderNonNativeLocalPath(profile_, path)) {
-        if (is_directory_) {
+        if (is_directory) {
           file_manager::util::IsNonNativeLocalPathDirectory(
               profile_, path,
               base::Bind(&WritableFileChecker::OnPrepareFileDone, this, path));
@@ -166,8 +168,7 @@
 #endif
       content::BrowserThread::PostTaskAndReplyWithResult(
           content::BrowserThread::FILE, FROM_HERE,
-          base::Bind(&PrepareNativeLocalFileForWritableApp, path,
-                     is_directory_),
+          base::Bind(&PrepareNativeLocalFileForWritableApp, path, is_directory),
           base::Bind(&WritableFileChecker::OnPrepareFileDone, this, path));
     }
 }
@@ -216,26 +217,25 @@
   return NULL;
 }
 
-const FileHandlerInfo* FirstFileHandlerForFile(
-    const Extension& app,
-    const std::string& mime_type,
-    const base::FilePath& path) {
+const FileHandlerInfo* FirstFileHandlerForEntry(const Extension& app,
+                                                const EntryInfo& entry) {
   const FileHandlersInfo* file_handlers = FileHandlers::GetFileHandlers(&app);
   if (!file_handlers)
     return NULL;
 
   for (FileHandlersInfo::const_iterator i = file_handlers->begin();
        i != file_handlers->end(); i++) {
-    if (FileHandlerCanHandleFile(*i, mime_type, path))
+    if (FileHandlerCanHandleEntry(*i, entry))
       return &*i;
   }
   return NULL;
 }
 
-std::vector<const FileHandlerInfo*> FindFileHandlersForFiles(
-    const Extension& app, const PathAndMimeTypeSet& files) {
+std::vector<const FileHandlerInfo*> FindFileHandlersForEntries(
+    const Extension& app,
+    const std::vector<EntryInfo> entries) {
   std::vector<const FileHandlerInfo*> handlers;
-  if (files.empty())
+  if (entries.empty())
     return handlers;
 
   // Look for file handlers which can handle all the MIME types specified.
@@ -246,9 +246,9 @@
   for (FileHandlersInfo::const_iterator data = file_handlers->begin();
        data != file_handlers->end(); ++data) {
     bool handles_all_types = true;
-    for (PathAndMimeTypeSet::const_iterator it = files.begin();
-         it != files.end(); ++it) {
-      if (!FileHandlerCanHandleFile(*data, it->second, it->first)) {
+    for (std::vector<EntryInfo>::const_iterator it = entries.begin();
+         it != entries.end(); ++it) {
+      if (!FileHandlerCanHandleEntry(*data, *it)) {
         handles_all_types = false;
         break;
       }
@@ -259,12 +259,13 @@
   return handlers;
 }
 
-bool FileHandlerCanHandleFile(
-    const FileHandlerInfo& handler,
-    const std::string& mime_type,
-    const base::FilePath& path) {
-  return FileHandlerCanHandleFileWithMimeType(handler, mime_type) ||
-      FileHandlerCanHandleFileWithExtension(handler, path);
+bool FileHandlerCanHandleEntry(const FileHandlerInfo& handler,
+                               const EntryInfo& entry) {
+  if (entry.is_directory)
+    return handler.include_directories;
+
+  return FileHandlerCanHandleFileWithMimeType(handler, entry.mime_type) ||
+         FileHandlerCanHandleFileWithExtension(handler, entry.path);
 }
 
 GrantedFileEntry CreateFileEntry(
@@ -303,11 +304,11 @@
 void PrepareFilesForWritableApp(
     const std::vector<base::FilePath>& paths,
     Profile* profile,
-    bool is_directory,
+    const std::set<base::FilePath>& directory_paths,
     const base::Closure& on_success,
     const base::Callback<void(const base::FilePath&)>& on_failure) {
   scoped_refptr<WritableFileChecker> checker(new WritableFileChecker(
-      paths, profile, is_directory, on_success, on_failure));
+      paths, profile, directory_paths, on_success, on_failure));
   checker->Check();
 }
 
diff --git a/chrome/browser/extensions/api/file_handlers/app_file_handler_util.h b/chrome/browser/extensions/api/file_handlers/app_file_handler_util.h
index 3ca6f6ae..d90b7073 100644
--- a/chrome/browser/extensions/api/file_handlers/app_file_handler_util.h
+++ b/chrome/browser/extensions/api/file_handlers/app_file_handler_util.h
@@ -19,6 +19,7 @@
 namespace extensions {
 
 class ExtensionPrefs;
+struct EntryInfo;
 struct FileHandlerInfo;
 struct GrantedFileEntry;
 
@@ -28,31 +29,23 @@
 extern const char kInvalidParameters[];
 extern const char kSecurityError[];
 
-// A set of pairs of path and its corresponding MIME type.
-typedef std::set<std::pair<base::FilePath, std::string> > PathAndMimeTypeSet;
-
 // Returns the file handler with the specified |handler_id|, or NULL if there
 // is no such handler.
 const FileHandlerInfo* FileHandlerForId(const Extension& app,
                                         const std::string& handler_id);
 
-// Returns the first file handler that can handle the given MIME type or
-// filename, or NULL if is no such handler.
-const FileHandlerInfo* FirstFileHandlerForFile(
-    const Extension& app,
-    const std::string& mime_type,
-    const base::FilePath& path);
+// Returns the first file handler that can handle the given entry,
+// or NULL if is no such handler.
+const FileHandlerInfo* FirstFileHandlerForEntry(const Extension& app,
+                                                const EntryInfo* entry);
 
-// Returns the handlers that can handle all files in |files|. The paths in
-// |files| must be populated, but the MIME types are optional.
-std::vector<const FileHandlerInfo*>
-FindFileHandlersForFiles(const Extension& extension,
-                         const PathAndMimeTypeSet& files);
+// Returns the handlers that can handle all files in |entries|.
+std::vector<const FileHandlerInfo*> FindFileHandlersForEntries(
+    const Extension& extension,
+    const std::vector<EntryInfo> entries);
 
-bool FileHandlerCanHandleFile(
-    const FileHandlerInfo& handler,
-    const std::string& mime_type,
-    const base::FilePath& path);
+bool FileHandlerCanHandleEntry(const FileHandlerInfo& handler,
+                               const EntryInfo& entry);
 
 // Creates a new file entry and allows |renderer_id| to access |path|. This
 // registers a new file system for |path|.
@@ -62,15 +55,15 @@
                                  const base::FilePath& path,
                                  bool is_directory);
 
-// When |is_directory| is true, it verifies that directories exist at each of
-// the |paths| and calls back to |on_success| or otherwise to |on_failure|.
-// When |is_directory| is false, it ensures regular files exists (not links and
-// directories) at the |paths|, creating files if needed, and calls back to
-// |on_success| or to |on_failure| depending on the result.
+// |directory_paths| contain the set of directories out of |paths|.
+// For directories it makes sure they exist at their corresponding |paths|,
+// while for regular files it makes sure they exist (i.e. not links) at |paths|,
+// creating files if needed. If result is successful it calls |on_success|,
+// otherwise calls |on_failure|.
 void PrepareFilesForWritableApp(
     const std::vector<base::FilePath>& paths,
     Profile* profile,
-    bool is_directory,
+    const std::set<base::FilePath>& directory_paths,
     const base::Closure& on_success,
     const base::Callback<void(const base::FilePath&)>& on_failure);
 
diff --git a/chrome/browser/extensions/api/file_handlers/directory_util.cc b/chrome/browser/extensions/api/file_handlers/directory_util.cc
new file mode 100644
index 0000000..1638f2d
--- /dev/null
+++ b/chrome/browser/extensions/api/file_handlers/directory_util.cc
@@ -0,0 +1,84 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/file_handlers/directory_util.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/thread_task_runner_handle.h"
+#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/base/filename_util.h"
+#include "storage/browser/fileapi/file_system_url.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/file_manager/filesystem_api_util.h"
+#endif
+
+namespace extensions {
+namespace app_file_handler_util {
+
+void EntryIsDirectory(Profile* profile,
+                      const base::FilePath& path,
+                      const base::Callback<void(bool)>& callback) {
+#if defined(OS_CHROMEOS)
+  if (file_manager::util::IsUnderNonNativeLocalPath(profile, path)) {
+    file_manager::util::IsNonNativeLocalPathDirectory(profile, path, callback);
+    return;
+  }
+#endif
+
+  base::File::Info file_info;
+  bool is_directory = GetFileInfo(path, &file_info) && file_info.is_directory;
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, is_directory));
+}
+
+IsDirectoryCollector::IsDirectoryCollector(Profile* profile)
+    : profile_(profile), left_(0), weak_ptr_factory_(this) {}
+
+IsDirectoryCollector::~IsDirectoryCollector() {}
+
+void IsDirectoryCollector::CollectForEntriesPaths(
+    const std::vector<base::FilePath>& paths,
+    const CompletionCallback& callback) {
+  DCHECK(!callback.is_null());
+  paths_ = paths;
+  callback_ = callback;
+
+  DCHECK(!result_.get());
+  result_.reset(new std::set<base::FilePath>());
+  left_ = paths.size();
+
+  if (!left_) {
+    // Nothing to process.
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(callback_, base::Passed(&result_)));
+    callback_ = CompletionCallback();
+    return;
+  }
+
+  for (size_t i = 0; i < paths.size(); ++i) {
+    EntryIsDirectory(profile_, paths[i],
+                     base::Bind(&IsDirectoryCollector::OnIsDirectoryCollected,
+                                weak_ptr_factory_.GetWeakPtr(), i));
+  }
+}
+
+void IsDirectoryCollector::OnIsDirectoryCollected(size_t index,
+                                                  bool is_directory) {
+  if (is_directory)
+    result_->insert(paths_[index]);
+  if (!--left_) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(callback_, base::Passed(&result_)));
+    // Release the callback to avoid a circullar reference in case an instance
+    // of this class is a member of a ref counted class, which instance is bound
+    // to this callback.
+    callback_ = CompletionCallback();
+  }
+}
+
+}  // namespace app_file_handler_util
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/file_handlers/directory_util.h b/chrome/browser/extensions/api/file_handlers/directory_util.h
new file mode 100644
index 0000000..9921e6bb
--- /dev/null
+++ b/chrome/browser/extensions/api/file_handlers/directory_util.h
@@ -0,0 +1,65 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_FILE_HANDLERS_DIRECTORY_UTIL_H_
+#define CHROME_BROWSER_EXTENSIONS_API_FILE_HANDLERS_DIRECTORY_UTIL_H_
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+
+class Profile;
+
+namespace base {
+class FilePath;
+}  // namespace base
+
+namespace storage {
+class FileSystemURL;
+}  // namespace storage
+
+namespace extensions {
+namespace app_file_handler_util {
+
+// The callback parameter contains the result and is required for support of
+// non native local path directories that require a callback.
+void EntryIsDirectory(Profile* profile,
+                      const base::FilePath& path,
+                      const base::Callback<void(bool)>& callback);
+
+class IsDirectoryCollector {
+ public:
+  typedef base::Callback<void(scoped_ptr<std::set<base::FilePath>>)>
+      CompletionCallback;
+
+  explicit IsDirectoryCollector(Profile* profile);
+  virtual ~IsDirectoryCollector();
+
+  // For the given paths obtains a set with which of them are directories.
+  // The collector does not support virtual files if OS != CHROMEOS.
+  void CollectForEntriesPaths(const std::vector<base::FilePath>& paths,
+                              const CompletionCallback& callback);
+
+ private:
+  void OnIsDirectoryCollected(size_t index, bool directory);
+
+  Profile* profile_;
+  std::vector<base::FilePath> paths_;
+  scoped_ptr<std::set<base::FilePath>> result_;
+  size_t left_;
+  CompletionCallback callback_;
+  base::WeakPtrFactory<IsDirectoryCollector> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(IsDirectoryCollector);
+};
+
+}  // namespace app_file_handler_util
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_FILE_HANDLERS_DIRECTORY_UTIL_H_
diff --git a/chrome/browser/extensions/api/file_handlers/directory_util_unittest.cc b/chrome/browser/extensions/api/file_handlers/directory_util_unittest.cc
new file mode 100644
index 0000000..3530d19
--- /dev/null
+++ b/chrome/browser/extensions/api/file_handlers/directory_util_unittest.cc
@@ -0,0 +1,99 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/file_handlers/directory_util.h"
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/run_loop.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+namespace app_file_handler_util {
+namespace {
+
+const char kRandomPath[] = "/random/path";
+
+void OnEntryIsDirectoryResult(bool* output, bool is_directory) {
+  *output = is_directory;
+}
+
+void OnCollectForEntriesPath(
+    std::set<base::FilePath>* output,
+    scoped_ptr<std::set<base::FilePath>> path_directory_set) {
+  *output = *path_directory_set;
+}
+
+}  // namespace
+
+class IsDirectoryUtilTest : public testing::Test {
+ protected:
+  IsDirectoryUtilTest() {}
+  ~IsDirectoryUtilTest() override {}
+
+  void SetUp() override {
+    EXPECT_TRUE(
+        base::CreateNewTempDirectory(base::FilePath::StringType(), &dir_path_));
+    EXPECT_TRUE(base::CreateTemporaryFile(&file_path_));
+  }
+
+  content::TestBrowserThreadBundle thread_bundle_;
+  TestingProfile profile_;
+  base::FilePath dir_path_;
+  base::FilePath file_path_;
+};
+
+TEST_F(IsDirectoryUtilTest, EntryIsDirectory) {
+  {
+    bool result = false;
+    EntryIsDirectory(&profile_, dir_path_,
+                     base::Bind(&OnEntryIsDirectoryResult, &result));
+    content::RunAllBlockingPoolTasksUntilIdle();
+    EXPECT_TRUE(result);
+  }
+
+  {
+    bool result = true;
+    EntryIsDirectory(&profile_, base::FilePath::FromUTF8Unsafe(kRandomPath),
+                     base::Bind(&OnEntryIsDirectoryResult, &result));
+    content::RunAllBlockingPoolTasksUntilIdle();
+    EXPECT_FALSE(result);
+  }
+
+  {
+    bool result = true;
+    EntryIsDirectory(&profile_, file_path_,
+                     base::Bind(&OnEntryIsDirectoryResult, &result));
+    content::RunAllBlockingPoolTasksUntilIdle();
+    EXPECT_FALSE(result);
+  }
+}
+
+TEST_F(IsDirectoryUtilTest, CollectForEntriesPaths) {
+  std::vector<base::FilePath> paths;
+  paths.push_back(dir_path_);
+  paths.push_back(file_path_);
+  paths.push_back(base::FilePath::FromUTF8Unsafe(kRandomPath));
+
+  IsDirectoryCollector collector(&profile_);
+  std::set<base::FilePath> result;
+  collector.CollectForEntriesPaths(
+      paths, base::Bind(&OnCollectForEntriesPath, &result));
+  content::RunAllBlockingPoolTasksUntilIdle();
+
+  ASSERT_EQ(1u, result.size());
+  EXPECT_GT(result.count(dir_path_), 0u);
+}
+
+}  // namespace app_file_handler_util
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/file_system/file_system_api.cc b/chrome/browser/extensions/api/file_system/file_system_api.cc
index 7968fdf..2e365c8 100644
--- a/chrome/browser/extensions/api/file_system/file_system_api.cc
+++ b/chrome/browser/extensions/api/file_system/file_system_api.cc
@@ -508,13 +508,17 @@
 void FileSystemEntryFunction::PrepareFilesForWritableApp(
     const std::vector<base::FilePath>& paths) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  // TODO(cmihail): Path directory set should be initialized only with the
+  // paths that are actually directories, but for now we will consider
+  // all paths directories in case is_directory_ is true, otherwise
+  // all paths files, as this was the previous logic.
+  std::set<base::FilePath> path_directory_set_ =
+      is_directory_ ? std::set<base::FilePath>(paths.begin(), paths.end())
+                    : std::set<base::FilePath>{};
   app_file_handler_util::PrepareFilesForWritableApp(
-      paths,
-      GetProfile(),
-      is_directory_,
+      paths, GetProfile(), path_directory_set_,
       base::Bind(&FileSystemEntryFunction::RegisterFileSystemsAndSendResponse,
-                 this,
-                 paths),
+                 this, paths),
       base::Bind(&FileSystemEntryFunction::HandleWritableFileError, this));
 }
 
diff --git a/chrome/browser/extensions/api/messaging/native_message_process_host.cc b/chrome/browser/extensions/api/messaging/native_message_process_host.cc
index 691c270..a26df3e 100644
--- a/chrome/browser/extensions/api/messaging/native_message_process_host.cc
+++ b/chrome/browser/extensions/api/messaging/native_message_process_host.cc
@@ -22,7 +22,6 @@
 #include "net/base/file_stream.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "url/gurl.h"
 
 namespace {
diff --git a/chrome/browser/extensions/api/music_manager_private/device_id_win.cc b/chrome/browser/extensions/api/music_manager_private/device_id_win.cc
index 64caf3b..90814d7 100644
--- a/chrome/browser/extensions/api/music_manager_private/device_id_win.cc
+++ b/chrome/browser/extensions/api/music_manager_private/device_id_win.cc
@@ -25,7 +25,6 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/win/windows_version.h"
 #include "content/public/browser/browser_thread.h"
-#include "net/base/net_util.h"
 
 #if defined(ENABLE_RLZ)
 #include "rlz/lib/machine_id.h"
diff --git a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
index d617211..a3c4a1f1 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
@@ -47,7 +47,6 @@
 #include "extensions/common/features/feature.h"
 #include "net/base/auth.h"
 #include "net/base/elements_upload_data_stream.h"
-#include "net/base/net_util.h"
 #include "net/base/request_priority.h"
 #include "net/base/upload_bytes_element_reader.h"
 #include "net/base/upload_file_element_reader.h"
diff --git a/chrome/browser/extensions/display_info_provider_chromeos.cc b/chrome/browser/extensions/display_info_provider_chromeos.cc
index 782eced..89f3339 100644
--- a/chrome/browser/extensions/display_info_provider_chromeos.cc
+++ b/chrome/browser/extensions/display_info_provider_chromeos.cc
@@ -66,7 +66,8 @@
          static_cast<int64_t>(point.y()) * static_cast<int64_t>(vector.x());
 }
 
-// Created ash::DisplayLayout value for |rectangle| compared to the |reference|
+// Created ash::DisplayPlacement value for |rectangle| compared to the
+// |reference|
 // rectangle.
 // The layout consists of two values:
 //   - position: Whether the rectangle is positioned left, right, over or under
@@ -96,8 +97,9 @@
 //
 // The rectangle shares an egde with the reference's bottom edge, but it's
 // center point is in the left area.
-ash::DisplayPlacement GetPlacementForRectangles(const gfx::Rect& reference,
-                                                const gfx::Rect& rectangle) {
+scoped_ptr<ash::DisplayPlacement> CreatePlacementForRectangles(
+    const gfx::Rect& reference,
+    const gfx::Rect& rectangle) {
   // Translate coordinate system so origin is in the reference's top left point
   // (so the reference's down-diagonal vector starts in the (0, 0)) and scale it
   // up by two (to avoid division when calculating the rectangle's center
@@ -151,7 +153,7 @@
                 position == ash::DisplayPlacement::RIGHT)
                    ? rectangle.y()
                    : rectangle.x();
-  return ash::DisplayPlacement(position, offset);
+  return make_scoped_ptr(new ash::DisplayPlacement(position, offset));
 }
 
 // Updates the display layout for the target display in reference to the primary
@@ -160,12 +162,14 @@
                          int64_t primary_display_id,
                          const gfx::Rect& target_display_bounds,
                          int64_t target_display_id) {
+  scoped_ptr<ash::DisplayPlacement> placement(CreatePlacementForRectangles(
+      primary_display_bounds, target_display_bounds));
+  placement->display_id = target_display_id;
+  placement->parent_display_id = primary_display_id;
+
   scoped_ptr<ash::DisplayLayout> layout(new ash::DisplayLayout);
-  layout->placement =
-      GetPlacementForRectangles(primary_display_bounds, target_display_bounds);
+  layout->placement_list.push_back(std::move(placement));
   layout->primary_id = primary_display_id;
-  layout->placement.display_id = target_display_id;
-  layout->placement.parent_display_id = primary_display_id;
 
   ash::Shell::GetInstance()
       ->display_configuration_controller()
diff --git a/chrome/browser/extensions/extension_tabs_apitest.cc b/chrome/browser/extensions/extension_tabs_apitest.cc
index c7d6c0e2..a2f2b4c44 100644
--- a/chrome/browser/extensions/extension_tabs_apitest.cc
+++ b/chrome/browser/extensions/extension_tabs_apitest.cc
@@ -87,7 +87,8 @@
 }
 
 // Flaky on linux: http://crbug.com/396364
-#if defined(OS_LINUX)
+// Flaky on Mac: https://crbug.com/588827
+#if defined(OS_LINUX) || defined(OS_MACOSX)
 #define MAYBE_TabUpdate DISABLED_TabUpdate
 #else
 #define MAYBE_TabUpdate TabUpdate
diff --git a/chrome/browser/external_protocol/external_protocol_observer.cc b/chrome/browser/external_protocol/external_protocol_observer.cc
index 8f69517..ec66503 100644
--- a/chrome/browser/external_protocol/external_protocol_observer.cc
+++ b/chrome/browser/external_protocol/external_protocol_observer.cc
@@ -17,6 +17,9 @@
 ExternalProtocolObserver::~ExternalProtocolObserver() {
 }
 
-void ExternalProtocolObserver::DidGetUserGesture() {
-  ExternalProtocolHandler::PermitLaunchUrl();
+void ExternalProtocolObserver::DidGetUserInteraction(
+    const blink::WebInputEvent::Type type) {
+  // Ignore scroll events for allowing external protocol launch.
+  if (type != blink::WebInputEvent::MouseWheel)
+    ExternalProtocolHandler::PermitLaunchUrl();
 }
diff --git a/chrome/browser/external_protocol/external_protocol_observer.h b/chrome/browser/external_protocol/external_protocol_observer.h
index 72a3b8f..29c3817 100644
--- a/chrome/browser/external_protocol/external_protocol_observer.h
+++ b/chrome/browser/external_protocol/external_protocol_observer.h
@@ -18,7 +18,7 @@
   ~ExternalProtocolObserver() override;
 
   // content::WebContentsObserver overrides.
-  void DidGetUserGesture() override;
+  void DidGetUserInteraction(const blink::WebInputEvent::Type type) override;
 
  private:
   explicit ExternalProtocolObserver(content::WebContents* web_contents);
diff --git a/chrome/browser/favicon/chrome_fallback_icon_client.cc b/chrome/browser/favicon/chrome_fallback_icon_client.cc
index 5bff09eb..33c9e49 100644
--- a/chrome/browser/favicon/chrome_fallback_icon_client.cc
+++ b/chrome/browser/favicon/chrome_fallback_icon_client.cc
@@ -11,8 +11,6 @@
 ChromeFallbackIconClient::ChromeFallbackIconClient() {
 #if defined(OS_CHROMEOS)
   font_list_.push_back("Noto Sans");
-#elif defined(OS_IOS)
-  font_list_.push_back("Helvetica Neue");
 #else
   font_list_.push_back(l10n_util::GetStringUTF8(IDS_SANS_SERIF_FONT_FAMILY));
 #endif
diff --git a/chrome/browser/file_select_helper.cc b/chrome/browser/file_select_helper.cc
index 8ae013a..9043ad8 100644
--- a/chrome/browser/file_select_helper.cc
+++ b/chrome/browser/file_select_helper.cc
@@ -156,14 +156,14 @@
   std::vector<ui::SelectedFileInfo> files;
   files.push_back(file);
 
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
   content::BrowserThread::PostTask(
       content::BrowserThread::FILE_USER_BLOCKING,
       FROM_HERE,
       base::Bind(&FileSelectHelper::ProcessSelectedFilesMac, this, files));
 #else
   NotifyRenderViewHostAndEnd(files);
-#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
+#endif  // defined(OS_MACOSX)
 }
 
 void FileSelectHelper::MultiFilesSelected(
@@ -181,14 +181,14 @@
   if (!files.empty() && IsValidProfile(profile_))
     profile_->set_last_selected_directory(files[0].file_path.DirName());
 
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
   content::BrowserThread::PostTask(
       content::BrowserThread::FILE_USER_BLOCKING,
       FROM_HERE,
       base::Bind(&FileSelectHelper::ProcessSelectedFilesMac, this, files));
 #else
   NotifyRenderViewHostAndEnd(files);
-#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
+#endif  // defined(OS_MACOSX)
 }
 
 void FileSelectHelper::FileSelectionCanceled(void* params) {
diff --git a/chrome/browser/file_select_helper.h b/chrome/browser/file_select_helper.h
index 7f5e81de..1644d55 100644
--- a/chrome/browser/file_select_helper.h
+++ b/chrome/browser/file_select_helper.h
@@ -156,7 +156,7 @@
   // callback is received from the enumeration code.
   void EnumerateDirectoryEnd();
 
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
   // Must be called on the FILE_USER_BLOCKING thread. Each selected file that is
   // a package will be zipped, and the zip will be passed to the render view
   // host in place of the package.
@@ -172,7 +172,7 @@
   // temporary destination, if the zip was successful. Otherwise returns an
   // empty path.
   static base::FilePath ZipPackage(const base::FilePath& path);
-#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
+#endif  // defined(OS_MACOSX)
 
   // Utility method that passes |files| to the render view host, and ends the
   // file chooser.
diff --git a/chrome/browser/file_select_helper_unittest.cc b/chrome/browser/file_select_helper_unittest.cc
index 90e8c3d..fe6385b 100644
--- a/chrome/browser/file_select_helper_unittest.cc
+++ b/chrome/browser/file_select_helper_unittest.cc
@@ -47,7 +47,7 @@
   EXPECT_FALSE(FileSelectHelper::IsAcceptTypeValid("abc/def "));
 }
 
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
 TEST_F(FileSelectHelperTest, ZipPackage) {
   // Zip the package.
   const char app_name[] = "CalculatorFake.app";
@@ -80,7 +80,7 @@
     EXPECT_TRUE(base::ContentsEqual(orig_file, final_file));
   }
 }
-#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
+#endif  // defined(OS_MACOSX)
 
 TEST_F(FileSelectHelperTest, GetSanitizedFileName) {
   // The empty path should be preserved.
diff --git a/chrome/browser/geolocation/geolocation_browsertest.cc b/chrome/browser/geolocation/geolocation_browsertest.cc
index e6437ce..8be381a 100644
--- a/chrome/browser/geolocation/geolocation_browsertest.cc
+++ b/chrome/browser/geolocation/geolocation_browsertest.cc
@@ -34,7 +34,6 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/geoposition.h"
 #include "content/public/test/browser_test_utils.h"
-#include "net/base/net_util.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 
 namespace {
diff --git a/chrome/browser/history/chrome_history_backend_client.cc b/chrome/browser/history/chrome_history_backend_client.cc
index bbfcd1b8..7159c12 100644
--- a/chrome/browser/history/chrome_history_backend_client.cc
+++ b/chrome/browser/history/chrome_history_backend_client.cc
@@ -23,7 +23,7 @@
 const base::FilePath::CharType kAndroidCacheFilename[] =
     FILE_PATH_LITERAL("AndroidCache");
 }
-#endif  // defined(OS_IOS)
+#endif
 
 ChromeHistoryBackendClient::ChromeHistoryBackendClient(
     bookmarks::BookmarkModel* bookmark_model)
diff --git a/chrome/browser/interstitials/chrome_controller_client.cc b/chrome/browser/interstitials/chrome_controller_client.cc
index 0160fc1..1c7e74b 100644
--- a/chrome/browser/interstitials/chrome_controller_client.cc
+++ b/chrome/browser/interstitials/chrome_controller_client.cc
@@ -55,11 +55,6 @@
   chrome::ShowSettingsSubPageForProfile(ProfileManager::GetActiveUserProfile(),
                                         sub_page);
 
-#elif defined(OS_IOS)
-  // TODO(blundell): Remove this once iOS has its own version of this class.
-  // iOS does not have a way to launch the date and time settings.
-  NOTREACHED();
-
 #elif defined(OS_LINUX)
   struct ClockCommand {
     const char* pathname;
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index 557bb17d..b8dda317 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -61,7 +61,6 @@
 #include "content/public/common/user_agent.h"
 #include "net/base/external_estimate_provider.h"
 #include "net/base/host_mapping_rules.h"
-#include "net/base/net_util.h"
 #include "net/base/network_quality_estimator.h"
 #include "net/base/sdch_manager.h"
 #include "net/cert/cert_verifier.h"
@@ -115,7 +114,7 @@
 #include "chrome/browser/extensions/event_router_forwarder.h"
 #endif
 
-#if defined(USE_NSS_CERTS) || defined(OS_IOS)
+#if defined(USE_NSS_CERTS)
 #include "net/cert_net/nss_ocsp.h"
 #endif
 
@@ -184,7 +183,7 @@
 const char kNpnTrialEnabledGroupNamePrefix[] = "Enable";
 const char kNpnTrialDisabledGroupNamePrefix[] = "Disable";
 
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
 void ObserveKeychainEvents() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   net::CertDatabase::GetInstance()->SetMessageLoopForKeychainEvents();
@@ -218,7 +217,7 @@
 class SystemURLRequestContext : public net::URLRequestContext {
  public:
   SystemURLRequestContext() {
-#if defined(USE_NSS_CERTS) || defined(OS_IOS)
+#if defined(USE_NSS_CERTS)
     net::SetURLRequestContextForNSSHttpIO(this);
 #endif
   }
@@ -226,7 +225,7 @@
  private:
   ~SystemURLRequestContext() override {
     AssertNoURLRequests();
-#if defined(USE_NSS_CERTS) || defined(OS_IOS)
+#if defined(USE_NSS_CERTS)
     net::SetURLRequestContextForNSSHttpIO(NULL);
 #endif
   }
@@ -561,7 +560,7 @@
   TRACE_EVENT0("startup", "IOThread::InitAsync");
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-#if defined(USE_NSS_CERTS) || defined(OS_IOS)
+#if defined(USE_NSS_CERTS)
   net::SetMessageLoopForNSSHttpIO();
 #endif
 
@@ -834,7 +833,7 @@
         new net::URLRequestBackoffManager());
   }
 
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
   // Start observing Keychain events. This needs to be done on the UI thread,
   // as Keychain services requires a CFRunLoop.
   BrowserThread::PostTask(BrowserThread::UI,
@@ -861,7 +860,7 @@
 void IOThread::CleanUp() {
   base::debug::LeakTracker<SafeBrowsingURLRequestContext>::CheckForLeaks();
 
-#if defined(USE_NSS_CERTS) || defined(OS_IOS)
+#if defined(USE_NSS_CERTS)
   net::ShutdownNSSHttpIO();
 #endif
 
diff --git a/chrome/browser/io_thread_unittest.cc b/chrome/browser/io_thread_unittest.cc
index 8f69890..5383823c 100644
--- a/chrome/browser/io_thread_unittest.cc
+++ b/chrome/browser/io_thread_unittest.cc
@@ -762,7 +762,7 @@
   }
 
   ~IOThreadTestWithIOThreadObject() override {
-#if defined(USE_NSS_CERTS) || defined(OS_IOS)
+#if defined(USE_NSS_CERTS)
     // Reset OCSPIOLoop thread checks, so that the test runner can run
     // futher tests in the same process.
     RunOnIOThreadBlocking(base::Bind(&net::ResetNSSHttpIOForTesting));
diff --git a/chrome/browser/media/android/remote/remote_media_player_bridge.cc b/chrome/browser/media/android/remote/remote_media_player_bridge.cc
index b09b150..bcb4dab 100644
--- a/chrome/browser/media/android/remote/remote_media_player_bridge.cc
+++ b/chrome/browser/media/android/remote/remote_media_player_bridge.cc
@@ -25,6 +25,7 @@
 using base::android::ScopedJavaLocalRef;
 using base::android::AttachCurrentThread;
 using content::BrowserThread;
+using media::MediaPlayerAndroid;
 
 namespace {
 /*
@@ -38,17 +39,20 @@
 namespace remote_media {
 
 RemoteMediaPlayerBridge::RemoteMediaPlayerBridge(
-    MediaPlayerAndroid* local_player, const std::string& user_agent,
-    bool hide_url_log, RemoteMediaPlayerManager* manager)
-    : MediaPlayerAndroid(local_player->player_id(), manager,
+    int player_id,
+    const std::string& user_agent,
+    bool hide_url_log,
+    RemoteMediaPlayerManager* manager)
+    : MediaPlayerAndroid(player_id,
+                         manager,
                          base::Bind(&DoNothing),
-                         local_player->frame_url()),
-      local_player_(local_player),
+                         manager->GetLocalPlayer(player_id)->frame_url()),
       width_(0),
       height_(0),
       hide_url_log_(hide_url_log),
-      url_(local_player->GetUrl()),
-      first_party_for_cookies_(local_player->GetFirstPartyForCookies()),
+      url_(manager->GetLocalPlayer(player_id)->GetUrl()),
+      first_party_for_cookies_(
+          manager->GetLocalPlayer(player_id)->GetFirstPartyForCookies()),
       user_agent_(user_agent),
       weak_factory_(this) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -60,10 +64,10 @@
     j_url_string = ConvertUTF8ToJavaString(env, url_.spec());
   }
   ScopedJavaLocalRef<jstring> j_frame_url_string;
-  if (local_player->frame_url().is_valid()) {
+  GURL frameUrl = GetLocalPlayer()->frame_url();
+  if (frameUrl.is_valid()) {
     // Create a Java String for the URL.
-    j_frame_url_string = ConvertUTF8ToJavaString(
-        env, local_player->frame_url().spec());
+    j_frame_url_string = ConvertUTF8ToJavaString(env, frameUrl.spec());
   }
   java_bridge_.Reset(Java_RemoteMediaPlayerBridge_create(
       env, reinterpret_cast<intptr_t>(this), j_url_string.obj(),
@@ -89,11 +93,17 @@
 }
 
 int RemoteMediaPlayerBridge::GetVideoWidth() {
-  return local_player_->GetVideoWidth();
+  MediaPlayerAndroid* local_player = GetLocalPlayer();
+  if (!local_player)
+    return 0;
+  return local_player->GetVideoWidth();
 }
 
 int RemoteMediaPlayerBridge::GetVideoHeight() {
-  return local_player_->GetVideoHeight();
+  MediaPlayerAndroid* local_player = GetLocalPlayer();
+  if (!local_player)
+    return 0;
+  return local_player->GetVideoHeight();
 }
 
 void RemoteMediaPlayerBridge::OnVideoSizeChanged(int width, int height) {
@@ -135,14 +145,20 @@
 
 void RemoteMediaPlayerBridge::PauseLocal(JNIEnv* env,
                                          const JavaParamRef<jobject>& obj) {
-  local_player_->Pause(true);
+  MediaPlayerAndroid* local_player = GetLocalPlayer();
+  if (!local_player)
+    return;
+  local_player->Pause(true);
   static_cast<RemoteMediaPlayerManager*>(manager())->OnPaused(player_id());
 }
 
 jint RemoteMediaPlayerBridge::GetLocalPosition(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj) {
-  base::TimeDelta time = local_player_->GetCurrentTime();
+  MediaPlayerAndroid* local_player = GetLocalPlayer();
+  if (!local_player)
+    return 0;
+  base::TimeDelta time = local_player->GetCurrentTime();
   return static_cast<jint>(time.InMilliseconds());
 }
 
@@ -191,7 +207,10 @@
   // Since the remote player doesn't use it, we forward it to the local player
   // for the time when user disconnects and resumes local playback
   // (see crbug.com/420690).
-  local_player_->SetVideoSurface(std::move(surface));
+  MediaPlayerAndroid* local_player = GetLocalPlayer();
+  if (!local_player)
+    return;
+  local_player->SetVideoSurface(std::move(surface));
 }
 
 void RemoteMediaPlayerBridge::OnPlaying(JNIEnv* env,
@@ -236,12 +255,14 @@
 
 void RemoteMediaPlayerBridge::RequestRemotePlayback() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  MediaPlayerAndroid* local_player = GetLocalPlayer();
+  if (!local_player)
+    return;
   JNIEnv* env = AttachCurrentThread();
   CHECK(env);
 
   Java_RemoteMediaPlayerBridge_requestRemotePlayback(
-      env, java_bridge_.obj(),
-      local_player_->GetCurrentTime().InMilliseconds());
+      env, java_bridge_.obj(), local_player->GetCurrentTime().InMilliseconds());
 }
 
 void RemoteMediaPlayerBridge::RequestRemotePlaybackControl() {
@@ -362,7 +383,10 @@
   // TODO (aberent) This is for YouTube. Remove it when the YouTube receiver is
   // fixed.
   if (duration_ms == 0) {
-    return local_player_->GetDuration();
+    MediaPlayerAndroid* local_player = GetLocalPlayer();
+    if (!local_player)
+      return media::kInfiniteDuration();
+    return local_player->GetDuration();
   }
   return duration_ms < 0 ? media::kInfiniteDuration()
                          : base::TimeDelta::FromMilliseconds(duration_ms);
@@ -446,4 +470,9 @@
       env, java_bridge_.obj(), ConvertUTF8ToJavaString(env, cookies).obj());
 }
 
+MediaPlayerAndroid* RemoteMediaPlayerBridge::GetLocalPlayer() {
+  return static_cast<RemoteMediaPlayerManager*>(manager())->GetLocalPlayer(
+      player_id());
+}
+
 }  // namespace remote_media
diff --git a/chrome/browser/media/android/remote/remote_media_player_bridge.h b/chrome/browser/media/android/remote/remote_media_player_bridge.h
index 10eb46bc..1eb86e9 100644
--- a/chrome/browser/media/android/remote/remote_media_player_bridge.h
+++ b/chrome/browser/media/android/remote/remote_media_player_bridge.h
@@ -24,11 +24,10 @@
 
 class RemoteMediaPlayerBridge : public media::MediaPlayerAndroid {
  public:
-  RemoteMediaPlayerBridge(
-      MediaPlayerAndroid* local_player,
-      const std::string& user_agent,
-      bool hide_url_log,
-      RemoteMediaPlayerManager* manager);
+  RemoteMediaPlayerBridge(int player_id,
+                          const std::string& user_agent,
+                          bool hide_url_log,
+                          RemoteMediaPlayerManager* manager);
   ~RemoteMediaPlayerBridge() override;
 
   static bool RegisterRemoteMediaPlayerBridge(JNIEnv* env);
@@ -118,7 +117,8 @@
   // are retrieved.
   void OnCookiesRetrieved(const std::string& cookies);
 
-  MediaPlayerAndroid* local_player_;
+  media::MediaPlayerAndroid* GetLocalPlayer();
+
   int width_;
   int height_;
   base::RepeatingTimer time_update_timer_;
diff --git a/chrome/browser/media/android/remote/remote_media_player_manager.cc b/chrome/browser/media/android/remote/remote_media_player_manager.cc
index b101898..3559b83 100644
--- a/chrome/browser/media/android/remote/remote_media_player_manager.cc
+++ b/chrome/browser/media/android/remote/remote_media_player_manager.cc
@@ -41,9 +41,9 @@
     const MediaPlayerHostMsg_Initialize_Params& media_params) {
   BrowserMediaPlayerManager::OnInitialize(media_params);
 
-  MediaPlayerAndroid* player = GetPlayer(media_params.player_id);
-  if (player) {
-    RemoteMediaPlayerBridge* remote_player = CreateRemoteMediaPlayer(player);
+  if (GetPlayer(media_params.player_id)) {
+    RemoteMediaPlayerBridge* remote_player =
+        CreateRemoteMediaPlayer(media_params.player_id);
     remote_player->OnPlayerCreated();
   }
 }
@@ -134,12 +134,9 @@
 }
 
 RemoteMediaPlayerBridge* RemoteMediaPlayerManager::CreateRemoteMediaPlayer(
-     MediaPlayerAndroid* local_player) {
-  RemoteMediaPlayerBridge* player = new RemoteMediaPlayerBridge(
-      local_player,
-      GetUserAgent(),
-      false,
-      this);
+    int player_id) {
+  RemoteMediaPlayerBridge* player =
+      new RemoteMediaPlayerBridge(player_id, GetUserAgent(), false, this);
   alternative_players_.push_back(player);
   player->Initialize();
   return player;
@@ -185,8 +182,8 @@
   Send(new MediaPlayerMsg_DidMediaPlayerPause(RoutingID(), player_id));
   Send(new MediaPlayerMsg_DisconnectedFromRemoteDevice(RoutingID(), player_id));
 
-  SwapCurrentPlayer(player_id);
   GetLocalPlayer(player_id)->SeekTo(remote_player->GetCurrentTime());
+  SwapCurrentPlayer(player_id);
   remote_player->Release();
   players_playing_remotely_.erase(player_id);
 }
diff --git a/chrome/browser/media/android/remote/remote_media_player_manager.h b/chrome/browser/media/android/remote/remote_media_player_manager.h
index a2462df..07a2bcf 100644
--- a/chrome/browser/media/android/remote/remote_media_player_manager.h
+++ b/chrome/browser/media/android/remote/remote_media_player_manager.h
@@ -50,6 +50,10 @@
   void SwitchToRemotePlayer(int player_id, const std::string& casting_message);
   void SwitchToLocalPlayer(int player_id);
 
+  // Get the local player for a given player id, whether or not it is currently
+  // playing locally. Will return nullptr if the local player no longer exists.
+  media::MediaPlayerAndroid* GetLocalPlayer(int player_id);
+
  protected:
   void OnSetPoster(int player_id, const GURL& url) override;
 
@@ -57,8 +61,7 @@
 
  private:
   // Returns a MediaPlayerAndroid implementation for playing the media remotely.
-  RemoteMediaPlayerBridge* CreateRemoteMediaPlayer(
-      media::MediaPlayerAndroid* local_player);
+  RemoteMediaPlayerBridge* CreateRemoteMediaPlayer(int player_id);
 
   // Replaces the remote player with the local player this class is holding.
   // Does nothing if there is no remote player.
@@ -98,10 +101,6 @@
   // playing remotely.
   RemoteMediaPlayerBridge* GetRemotePlayer(int player_id);
 
-  // Get the local player for a given player id, whether or not it is currently
-  // playing locally.
-  media::MediaPlayerAndroid* GetLocalPlayer(int player_id);
-
   void SwapCurrentPlayer(int player_id);
 
   void FetchPosterBitmap(int player_id);
diff --git a/chrome/browser/media/cast_transport_host_filter.cc b/chrome/browser/media/cast_transport_host_filter.cc
index ee31f41..acdcd05 100644
--- a/chrome/browser/media/cast_transport_host_filter.cc
+++ b/chrome/browser/media/cast_transport_host_filter.cc
@@ -16,8 +16,47 @@
 // How often to send raw events.
 const int kSendRawEventsIntervalSecs = 1;
 
+class TransportClient : public media::cast::CastTransportSender::Client {
+ public:
+  TransportClient(int32_t channel_id,
+                  cast::CastTransportHostFilter* cast_transport_host_filter)
+      : channel_id_(channel_id),
+        cast_transport_host_filter_(cast_transport_host_filter) {}
+
+  void OnStatusChanged(media::cast::CastTransportStatus status) final;
+  void OnLoggingEventsReceived(
+      scoped_ptr<std::vector<media::cast::FrameEvent>> frame_events,
+      scoped_ptr<std::vector<media::cast::PacketEvent>> packet_events) final;
+  void ProcessRtpPacket(scoped_ptr<media::cast::Packet> packet) final;
+
+ private:
+  const int32_t channel_id_;
+  cast::CastTransportHostFilter* const cast_transport_host_filter_;
+
+  DISALLOW_COPY_AND_ASSIGN(TransportClient);
+};
+
+void TransportClient::OnStatusChanged(media::cast::CastTransportStatus status) {
+  cast_transport_host_filter_->Send(
+      new CastMsg_NotifyStatusChange(channel_id_, status));
 }
 
+void TransportClient::OnLoggingEventsReceived(
+    scoped_ptr<std::vector<media::cast::FrameEvent>> frame_events,
+    scoped_ptr<std::vector<media::cast::PacketEvent>> packet_events) {
+  if (frame_events->empty() && packet_events->empty())
+    return;
+  cast_transport_host_filter_->Send(
+      new CastMsg_RawEvents(channel_id_, *packet_events, *frame_events));
+}
+
+void TransportClient::ProcessRtpPacket(scoped_ptr<media::cast::Packet> packet) {
+  cast_transport_host_filter_->Send(
+      new CastMsg_ReceivedPacket(channel_id_, *packet));
+}
+
+}  // namespace
+
 namespace cast {
 
 CastTransportHostFilter::CastTransportHostFilter()
@@ -26,6 +65,12 @@
 
 CastTransportHostFilter::~CastTransportHostFilter() {}
 
+void CastTransportHostFilter::OnStatusChanged(
+    int32_t channel_id,
+    media::cast::CastTransportStatus status) {
+  Send(new CastMsg_NotifyStatusChange(channel_id, status));
+}
+
 bool CastTransportHostFilter::OnMessageReceived(const IPC::Message& message) {
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(CastTransportHostFilter, message)
@@ -49,27 +94,6 @@
   return handled;
 }
 
-void CastTransportHostFilter::ReceivedPacket(
-    int32_t channel_id,
-    scoped_ptr<media::cast::Packet> packet) {
-  Send(new CastMsg_ReceivedPacket(channel_id, *packet));
-}
-
-void CastTransportHostFilter::NotifyStatusChange(
-    int32_t channel_id,
-    media::cast::CastTransportStatus status) {
-  Send(new CastMsg_NotifyStatusChange(channel_id, status));
-}
-
-void CastTransportHostFilter::SendRawEvents(
-    int32_t channel_id,
-    scoped_ptr<std::vector<media::cast::FrameEvent>> frame_events,
-    scoped_ptr<std::vector<media::cast::PacketEvent>> packet_events) {
-  if (frame_events->empty() && packet_events->empty())
-    return;
-  Send(new CastMsg_RawEvents(channel_id, *packet_events, *frame_events));
-}
-
 void CastTransportHostFilter::SendRtt(int32_t channel_id,
                                       uint32_t ssrc,
                                       base::TimeDelta rtt) {
@@ -100,24 +124,19 @@
     id_map_.Remove(channel_id);
   }
 
+  scoped_ptr<media::cast::UdpTransport> udp_transport(
+      new media::cast::UdpTransport(
+          g_browser_process->net_log(), base::ThreadTaskRunnerHandle::Get(),
+          local_end_point, remote_end_point,
+          base::Bind(&CastTransportHostFilter::OnStatusChanged,
+                     weak_factory_.GetWeakPtr(), channel_id)));
+  udp_transport->SetUdpOptions(options);
   scoped_ptr<media::cast::CastTransportSender> sender =
       media::cast::CastTransportSender::Create(
-          g_browser_process->net_log(),
-          &clock_,
-          local_end_point,
-          remote_end_point,
-          make_scoped_ptr(options.DeepCopy()),
-          base::Bind(&CastTransportHostFilter::NotifyStatusChange,
-                     weak_factory_.GetWeakPtr(),
-                     channel_id),
-          base::Bind(&CastTransportHostFilter::SendRawEvents,
-                     weak_factory_.GetWeakPtr(),
-                     channel_id),
-          base::TimeDelta::FromSeconds(kSendRawEventsIntervalSecs),
-          base::Bind(&CastTransportHostFilter::ReceivedPacket,
-                     weak_factory_.GetWeakPtr(),
-                     channel_id),
-          base::ThreadTaskRunnerHandle::Get());
+          &clock_, base::TimeDelta::FromSeconds(kSendRawEventsIntervalSecs),
+          make_scoped_ptr(new TransportClient(channel_id, this)),
+          std::move(udp_transport), base::ThreadTaskRunnerHandle::Get());
+  sender->SetOptions(options);
   id_map_.AddWithID(sender.release(), channel_id);
 }
 
@@ -264,5 +283,4 @@
   }
 }
 
-
 }  // namespace cast
diff --git a/chrome/browser/media/cast_transport_host_filter.h b/chrome/browser/media/cast_transport_host_filter.h
index 127e7d1..2331e971 100644
--- a/chrome/browser/media/cast_transport_host_filter.h
+++ b/chrome/browser/media/cast_transport_host_filter.h
@@ -16,6 +16,7 @@
 #include "media/cast/cast_sender.h"
 #include "media/cast/logging/logging_defines.h"
 #include "media/cast/net/cast_transport_sender.h"
+#include "media/cast/net/udp_transport.h"
 
 namespace content {
 class PowerSaveBlocker;
@@ -30,18 +31,13 @@
  private:
   ~CastTransportHostFilter() override;
 
-  void NotifyStatusChange(int32_t channel_id,
-                          media::cast::CastTransportStatus result);
-  void SendRawEvents(
-      int32_t channel_id,
-      scoped_ptr<std::vector<media::cast::FrameEvent>> frame_events,
-      scoped_ptr<std::vector<media::cast::PacketEvent>> packet_events);
+  // Status callback to create UdpTransport.
+  void OnStatusChanged(int32_t channel_id,
+                       media::cast::CastTransportStatus status);
   void SendRtt(int32_t channel_id, uint32_t ssrc, base::TimeDelta rtt);
   void SendCastMessage(int32_t channel_id,
                        uint32_t ssrc,
                        const media::cast::RtcpCastMessage& cast_message);
-  void ReceivedPacket(int32_t channel_id,
-                      scoped_ptr<media::cast::Packet> packet);
 
   // BrowserMessageFilter implementation.
   bool OnMessageReceived(const IPC::Message& message) override;
diff --git a/chrome/browser/media/combined_desktop_media_list_unittest.cc b/chrome/browser/media/combined_desktop_media_list_unittest.cc
index 80e46129..e5da4506 100644
--- a/chrome/browser/media/combined_desktop_media_list_unittest.cc
+++ b/chrome/browser/media/combined_desktop_media_list_unittest.cc
@@ -51,7 +51,7 @@
 class FakeDesktopMediaListBaseImpl : public DesktopMediaListBase {
  public:
   explicit FakeDesktopMediaListBaseImpl(DesktopMediaID::Type type)
-      : DesktopMediaListBase(base::TimeDelta::FromMilliseconds(1)),
+      : DesktopMediaListBase(base::TimeDelta()),
         media_type_(type) {
     SetThumbnailSize(gfx::Size(kThumbnailSize, kThumbnailSize));
 
@@ -78,7 +78,6 @@
     fake_thumbnails_.erase(fake_thumbnails_.begin() + index);
   }
 
- private:
   void Refresh() override {
     UpdateSourcesList(fake_sources_);
 
@@ -92,8 +91,6 @@
       }
     }
     refreshed_thumbnail_map_ = current_thumbnail_map_;
-
-    ScheduleNextRefresh();
   }
 
   std::vector<DesktopMediaListBase::SourceDescription> fake_sources_;
@@ -226,6 +223,7 @@
   EXPECT_CALL(observer_, OnSourceThumbnailChanged(combined_list_.get(), index))
       .WillOnce(QuitMessageLoop(&message_loop_));
 
+  list1_->Refresh();
   message_loop_.Run();
 
   list2_->AddFakeSource(index, base::UTF8ToUTF16("Test media"), index);
@@ -238,6 +236,7 @@
                                                   2 * kDefaultSourceCount + 1))
       .WillOnce(QuitMessageLoop(&message_loop_));
 
+  list2_->Refresh();
   message_loop_.Run();
 
   // Verify last source for list1_ and first source for list2_.
@@ -260,6 +259,7 @@
           CheckListSize(combined_list_.get(), 2 * kDefaultSourceCount - 1),
           QuitMessageLoop(&message_loop_)));
 
+  list1_->Refresh();
   message_loop_.Run();
 
   list2_->RemoveFakeSource(index);
@@ -270,6 +270,7 @@
           CheckListSize(combined_list_.get(), 2 * kDefaultSourceCount - 2),
           QuitMessageLoop(&message_loop_)));
 
+  list2_->Refresh();
   message_loop_.Run();
 
   // Verify last source for list1_ and first source for list2_.
@@ -299,6 +300,7 @@
                             kDefaultSourceCount - 2))
       .WillOnce(QuitMessageLoop(&message_loop_));
 
+  list1_->Refresh();
   message_loop_.Run();
 
   // Swap sources.
@@ -316,6 +318,7 @@
                             2 * kDefaultSourceCount - 2))
       .WillOnce(QuitMessageLoop(&message_loop_));
 
+  list2_->Refresh();
   message_loop_.Run();
 }
 
@@ -332,6 +335,7 @@
                                              kDefaultSourceCount - 1))
       .WillOnce(QuitMessageLoop(&message_loop_));
 
+  list1_->Refresh();
   message_loop_.Run();
 
   // Change title.
@@ -344,6 +348,7 @@
                                              2 * kDefaultSourceCount - 1))
       .WillOnce(QuitMessageLoop(&message_loop_));
 
+  list2_->Refresh();
   message_loop_.Run();
 
   EXPECT_EQ(combined_list_->GetSource(kDefaultSourceCount - 1).name,
@@ -364,6 +369,7 @@
                                                   kDefaultSourceCount - 1))
       .WillOnce(QuitMessageLoop(&message_loop_));
 
+  list1_->Refresh();
   message_loop_.Run();
 
   // Change thumbnail.
@@ -375,5 +381,6 @@
                                                   2 * kDefaultSourceCount - 1))
       .WillOnce(QuitMessageLoop(&message_loop_));
 
+  list2_->Refresh();
   message_loop_.Run();
 }
diff --git a/chrome/browser/media/media_capture_devices_dispatcher.cc b/chrome/browser/media/media_capture_devices_dispatcher.cc
index 28419eb..b4db4b19 100644
--- a/chrome/browser/media/media_capture_devices_dispatcher.cc
+++ b/chrome/browser/media/media_capture_devices_dispatcher.cc
@@ -32,7 +32,6 @@
 #include "content/public/common/media_stream_request.h"
 #include "extensions/common/constants.h"
 #include "media/base/media_switches.h"
-#include "net/base/net_util.h"
 
 #if defined(OS_CHROMEOS)
 #include "ash/shell.h"
diff --git a/chrome/browser/media/webrtc_logging_handler_host.cc b/chrome/browser/media/webrtc_logging_handler_host.cc
index 2174c53..53b7f5a 100644
--- a/chrome/browser/media/webrtc_logging_handler_host.cc
+++ b/chrome/browser/media/webrtc_logging_handler_host.cc
@@ -36,7 +36,6 @@
 #include "gpu/config/gpu_info.h"
 #include "net/base/address_family.h"
 #include "net/base/ip_address_number.h"
-#include "net/base/net_util.h"
 #include "net/url_request/url_request_context_getter.h"
 
 #if defined(OS_LINUX)
diff --git a/chrome/browser/media_galleries/media_folder_finder.cc b/chrome/browser/media_galleries/media_folder_finder.cc
index fcbf065..9193614 100644
--- a/chrome/browser/media_galleries/media_folder_finder.cc
+++ b/chrome/browser/media_galleries/media_folder_finder.cc
@@ -51,7 +51,7 @@
   base::DIR_PROGRAM_FILESX86,
   base::DIR_WINDOWS,
 #endif
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
   chrome::DIR_USER_APPLICATIONS,
   chrome::DIR_USER_LIBRARY,
 #endif
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.cc b/chrome/browser/metrics/chrome_metrics_service_client.cc
index 2fbb86f..d7004ca 100644
--- a/chrome/browser/metrics/chrome_metrics_service_client.cc
+++ b/chrome/browser/metrics/chrome_metrics_service_client.cc
@@ -95,7 +95,7 @@
 const int kMaxHistogramGatheringWaitDuration = 60000;  // 60 seconds.
 
 // Standard interval between log uploads, in seconds.
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_ANDROID)
 const int kStandardUploadIntervalSeconds = 5 * 60;  // Five minutes.
 const int kStandardUploadIntervalCellularSeconds = 15 * 60;  // Fifteen minutes.
 #else
@@ -304,7 +304,7 @@
 }
 
 base::TimeDelta ChromeMetricsServiceClient::GetStandardUploadInterval() {
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_ANDROID)
   if (IsCellularLogicEnabled())
     return base::TimeDelta::FromSeconds(kStandardUploadIntervalCellularSeconds);
 #endif
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.h b/chrome/browser/metrics/chrome_metrics_service_client.h
index 9282aba..34723b4 100644
--- a/chrome/browser/metrics/chrome_metrics_service_client.h
+++ b/chrome/browser/metrics/chrome_metrics_service_client.h
@@ -28,7 +28,7 @@
 class PrefRegistrySimple;
 class PrefService;
 
-#if !defined(OS_CHROMEOS) && !defined(OS_IOS)
+#if !defined(OS_CHROMEOS)
 class SigninStatusMetricsProvider;
 #endif
 
diff --git a/chrome/browser/metrics/variations/chrome_variations_service_client.cc b/chrome/browser/metrics/variations/chrome_variations_service_client.cc
index b99ece9..7260801 100644
--- a/chrome/browser/metrics/variations/chrome_variations_service_client.cc
+++ b/chrome/browser/metrics/variations/chrome_variations_service_client.cc
@@ -11,7 +11,7 @@
 #include "components/version_info/version_info.h"
 #include "content/public/browser/browser_thread.h"
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_CHROMEOS)
+#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
 #include "chrome/browser/upgrade_detector_impl.h"
 #endif
 
@@ -24,12 +24,12 @@
 // Gets the version number to use for variations seed simulation. Must be called
 // on a thread where IO is allowed.
 base::Version GetVersionForSimulation() {
-#if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_CHROMEOS)
+#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
   const base::Version installed_version =
       UpgradeDetectorImpl::GetCurrentlyInstalledVersion();
   if (installed_version.IsValid())
     return installed_version;
-#endif  // !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_CHROMEOS)
+#endif  // !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
 
   // TODO(asvitkine): Get the version that will be used on restart instead of
   // the current version on Android, iOS and ChromeOS.
diff --git a/chrome/browser/net/async_dns_field_trial.cc b/chrome/browser/net/async_dns_field_trial.cc
index 3013ef9..e37d3b03 100644
--- a/chrome/browser/net/async_dns_field_trial.cc
+++ b/chrome/browser/net/async_dns_field_trial.cc
@@ -61,12 +61,6 @@
 }  // namespace
 
 bool ConfigureAsyncDnsFieldTrial() {
-#if defined(OS_IOS)
-  // There is no DnsConfigService on those platforms so disable the field trial.
-  HistogramPrefDefaultSource(PLATFORM, false);
-  return false;
-#endif
-
 #if defined(OS_CHROMEOS) || defined(OS_MACOSX)
   const bool kDefault = true;
 #else
diff --git a/chrome/browser/net/chrome_network_delegate.cc b/chrome/browser/net/chrome_network_delegate.cc
index 9d87e85..fa9ba6d3 100644
--- a/chrome/browser/net/chrome_network_delegate.cc
+++ b/chrome/browser/net/chrome_network_delegate.cc
@@ -485,9 +485,7 @@
 void ChromeNetworkDelegate::OnBeforeRedirect(net::URLRequest* request,
                                              const GURL& new_location) {
 // Recording data use of request on redirects.
-#if !defined(OS_IOS)
   data_use_measurement_.ReportDataUseUMA(request);
-#endif
   if (domain_reliability_monitor_)
     domain_reliability_monitor_->OnBeforeRedirect(request);
   extensions_delegate_->OnBeforeRedirect(request, new_location);
@@ -517,11 +515,9 @@
 
 void ChromeNetworkDelegate::OnCompleted(net::URLRequest* request,
                                         bool started) {
-#if !defined(OS_IOS)
   // TODO(amohammadkhan): Verify that there is no double recording in data use
   // of redirected requests.
   data_use_measurement_.ReportDataUseUMA(request);
-#endif
   RecordNetworkErrorHistograms(request);
   if (started) {
     // Only call in for requests that were started, to obey the precondition
diff --git a/chrome/browser/net/chrome_network_delegate.h b/chrome/browser/net/chrome_network_delegate.h
index ea2a007d..033c0ac0 100644
--- a/chrome/browser/net/chrome_network_delegate.h
+++ b/chrome/browser/net/chrome_network_delegate.h
@@ -16,11 +16,8 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "net/base/network_delegate_impl.h"
-
-#if !defined(OS_IOS)
 #include "components/data_use_measurement/content/data_use_measurement.h"
-#endif
+#include "net/base/network_delegate_impl.h"
 
 class ChromeExtensionsNetworkDelegate;
 class PrefService;
@@ -219,10 +216,8 @@
   // When true, allow access to all file:// URLs.
   static bool g_allow_file_access_;
 
-// Component to measure data use.
-#if !defined(OS_IOS)
+  // Component to measure data use.
   data_use_measurement::DataUseMeasurement data_use_measurement_;
-#endif
 
   bool experimental_web_platform_features_enabled_;
 
diff --git a/chrome/browser/net/chrome_network_delegate_unittest.cc b/chrome/browser/net/chrome_network_delegate_unittest.cc
index 5b1ffaf..868e53d 100644
--- a/chrome/browser/net/chrome_network_delegate_unittest.cc
+++ b/chrome/browser/net/chrome_network_delegate_unittest.cc
@@ -27,6 +27,7 @@
 #include "components/data_usage/core/data_use_aggregator.h"
 #include "components/data_usage/core/data_use_amortizer.h"
 #include "components/data_usage/core/data_use_annotator.h"
+#include "components/data_use_measurement/core/data_use_user_data.h"
 #include "components/prefs/pref_member.h"
 #include "components/syncable_prefs/testing_pref_service_syncable.h"
 #include "content/public/browser/resource_request_info.h"
@@ -44,10 +45,6 @@
 #include "chrome/browser/extensions/event_router_forwarder.h"
 #endif
 
-#if !defined(OS_IOS)
-#include "components/data_use_measurement/core/data_use_user_data.h"
-#endif
-
 namespace {
 
 // This function requests a URL, and makes it return a known response. If
@@ -200,7 +197,6 @@
 // DataUse.TrafficSize.System.Dimensions and DataUse.MessageSize.ServiceName
 // histograms. AppState and ConnectionType dimensions are always Foreground and
 // NotCellular respectively.
-#if !defined(OS_IOS)
 TEST_F(ChromeNetworkDelegateTest, DataUseMeasurementServiceTest) {
   Initialize();
   base::HistogramTester histogram_tester;
@@ -285,8 +281,6 @@
   histogram_tester.ExpectTotalCount("DataUse.MessageSize.Suggestions", 0);
 }
 
-#endif
-
 TEST_F(ChromeNetworkDelegateTest, DisableSameSiteCookiesIffFlagDisabled) {
   Initialize();
   EXPECT_FALSE(network_delegate()->AreExperimentalCookieFeaturesEnabled());
diff --git a/chrome/browser/net/dns_probe_runner.cc b/chrome/browser/net/dns_probe_runner.cc
index e9e9a7b..fcd0d26 100644
--- a/chrome/browser/net/dns_probe_runner.cc
+++ b/chrome/browser/net/dns_probe_runner.cc
@@ -11,7 +11,6 @@
 #include "net/base/address_list.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/network_change_notifier.h"
 #include "net/dns/dns_client.h"
 #include "net/dns/dns_protocol.h"
diff --git a/chrome/browser/net/dns_probe_service.cc b/chrome/browser/net/dns_probe_service.cc
index fb6c12da..fcec9981 100644
--- a/chrome/browser/net/dns_probe_service.cc
+++ b/chrome/browser/net/dns_probe_service.cc
@@ -10,7 +10,6 @@
 #include "base/metrics/histogram.h"
 #include "base/strings/string_number_conversions.h"
 #include "net/base/ip_endpoint.h"
-#include "net/base/net_util.h"
 #include "net/dns/dns_client.h"
 #include "net/dns/dns_config_service.h"
 #include "net/dns/dns_protocol.h"
diff --git a/chrome/browser/net/proxy_service_factory.cc b/chrome/browser/net/proxy_service_factory.cc
index 6192bac..58bebf00 100644
--- a/chrome/browser/net/proxy_service_factory.cc
+++ b/chrome/browser/net/proxy_service_factory.cc
@@ -22,6 +22,7 @@
 #include "net/log/net_log.h"
 #include "net/proxy/dhcp_proxy_script_fetcher_factory.h"
 #include "net/proxy/proxy_config_service.h"
+#include "net/proxy/proxy_resolver_v8.h"
 #include "net/proxy/proxy_script_fetcher_impl.h"
 #include "net/proxy/proxy_service.h"
 #include "net/proxy/proxy_service_v8.h"
@@ -32,11 +33,7 @@
 #include "chromeos/network/dhcp_proxy_script_fetcher_chromeos.h"
 #endif  // defined(OS_CHROMEOS)
 
-#if !defined(OS_IOS)
-#include "net/proxy/proxy_resolver_v8.h"
-#endif
-
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
+#if !defined(OS_ANDROID)
 #include "chrome/browser/net/utility_process_mojo_proxy_resolver_factory.h"
 #include "net/proxy/proxy_service_mojo.h"
 #endif
@@ -125,9 +122,6 @@
     const base::CommandLine& command_line,
     bool quick_check_enabled) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-#if defined(OS_IOS)
-  bool use_v8 = false;
-#else
   bool use_v8 = !command_line.HasSwitch(switches::kWinHttpProxyResolver);
   // TODO(eroman): Figure out why this doesn't work in single-process mode.
   // Should be possible now that a private isolate is used.
@@ -136,7 +130,6 @@
     LOG(ERROR) << "Cannot use V8 Proxy resolver in single process mode.";
     use_v8 = false;  // Fallback to non-v8 implementation.
   }
-#endif  // defined(OS_IOS)
 
   size_t num_pac_threads = 0u;  // Use default number of threads.
 
@@ -156,9 +149,6 @@
 
   scoped_ptr<net::ProxyService> proxy_service;
   if (use_v8) {
-#if defined(OS_IOS)
-    NOTREACHED();
-#else
     scoped_ptr<net::DhcpProxyScriptFetcher> dhcp_proxy_script_fetcher;
 #if defined(OS_CHROMEOS)
     dhcp_proxy_script_fetcher.reset(
@@ -194,7 +184,6 @@
           std::move(dhcp_proxy_script_fetcher), context->host_resolver(),
           net_log, network_delegate);
     }
-#endif  // defined(OS_IOS)
   } else {
     proxy_service = net::ProxyService::CreateUsingSystemProxyResolver(
         std::move(proxy_config_service), num_pac_threads, net_log);
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc
index b0085f9..eee93188 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc
@@ -189,7 +189,7 @@
     scoped_ptr<data_reduction_proxy::DataStore> store,
     const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
     const scoped_refptr<base::SequencedTaskRunner>& db_task_runner) {
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_ANDROID)
   // On mobile we write Data Reduction Proxy prefs directly to the pref service.
   // On desktop we store Data Reduction Proxy prefs in memory, writing to disk
   // every 60 minutes and on termination. Shutdown hooks must be added for
@@ -224,8 +224,6 @@
 data_reduction_proxy::Client DataReductionProxyChromeSettings::GetClient() {
 #if defined(OS_ANDROID)
   return data_reduction_proxy::Client::CHROME_ANDROID;
-#elif defined(OS_IOS)
-  return data_reduction_proxy::Client::CHROME_IOS;
 #elif defined(OS_MACOSX)
   return data_reduction_proxy::Client::CHROME_MAC;
 #elif defined(OS_CHROMEOS)
diff --git a/chrome/browser/notifications/notification_browsertest.cc b/chrome/browser/notifications/notification_browsertest.cc
index a120e06b..4e19c54 100644
--- a/chrome/browser/notifications/notification_browsertest.cc
+++ b/chrome/browser/notifications/notification_browsertest.cc
@@ -41,7 +41,6 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
-#include "net/base/net_util.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/window_open_disposition.h"
diff --git a/chrome/browser/ntp_snippets/ntp_snippets_service_factory.cc b/chrome/browser/ntp_snippets/ntp_snippets_service_factory.cc
index 5730e2f..0cf2dba 100644
--- a/chrome/browser/ntp_snippets/ntp_snippets_service_factory.cc
+++ b/chrome/browser/ntp_snippets/ntp_snippets_service_factory.cc
@@ -8,9 +8,18 @@
 #include "base/memory/singleton.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/ntp_snippets/ntp_snippets_fetcher.h"
 #include "components/ntp_snippets/ntp_snippets_service.h"
+#include "components/signin/core/browser/profile_oauth2_token_service.h"
+#include "components/signin/core/browser/signin_manager.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/url_request/url_request_context_getter.h"
+
+using content::BrowserThread;
 
 // static
 NTPSnippetsServiceFactory* NTPSnippetsServiceFactory::GetInstance() {
@@ -34,6 +43,23 @@
 
 KeyedService* NTPSnippetsServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
+  Profile* profile = Profile::FromBrowserContext(context);
+  SigninManagerBase* signin_manager =
+      SigninManagerFactory::GetForProfile(profile);
+  OAuth2TokenService* token_service =
+      ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
+  scoped_refptr<net::URLRequestContextGetter> request_context =
+      context->GetRequestContext();
+
+  scoped_refptr<base::SequencedTaskRunner> task_runner =
+      BrowserThread::GetBlockingPool()
+          ->GetSequencedTaskRunnerWithShutdownBehavior(
+              base::SequencedWorkerPool::GetSequenceToken(),
+              base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
+
   return new ntp_snippets::NTPSnippetsService(
-      g_browser_process->GetApplicationLocale());
+      task_runner, g_browser_process->GetApplicationLocale(),
+      make_scoped_ptr(new ntp_snippets::NTPSnippetsFetcher(
+          task_runner, signin_manager, token_service, request_context,
+          profile->GetPath())));
 }
diff --git a/chrome/browser/password_manager/account_chooser_dialog_android.cc b/chrome/browser/password_manager/account_chooser_dialog_android.cc
index a025de8..309253f 100644
--- a/chrome/browser/password_manager/account_chooser_dialog_android.cc
+++ b/chrome/browser/password_manager/account_chooser_dialog_android.cc
@@ -123,7 +123,7 @@
 void AccountChooserDialogAndroid::ShowDialog() {
   JNIEnv* env = AttachCurrentThread();
   bool is_smartlock_branding_enabled =
-      password_bubble_experiment::IsSmartLockBrandingEnabled(
+      password_bubble_experiment::IsSmartLockUser(
           ProfileSyncServiceFactory::GetForProfile(
               Profile::FromBrowserContext(web_contents_->GetBrowserContext())));
   base::string16 title;
@@ -186,7 +186,7 @@
     JNIEnv* env,
     const JavaParamRef<jobject>& obj) {
   web_contents_->OpenURL(content::OpenURLParams(
-      GURL(password_manager::kPasswordManagerAccountDashboardURL),
+      GURL(password_manager::kPasswordManagerHelpCenterSmartLock),
       content::Referrer(), NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_LINK,
       false /* is_renderer_initiated */));
 }
diff --git a/chrome/browser/password_manager/auto_signin_first_run_dialog_android.cc b/chrome/browser/password_manager/auto_signin_first_run_dialog_android.cc
index 2b395ba9..36edf01 100644
--- a/chrome/browser/password_manager/auto_signin_first_run_dialog_android.cc
+++ b/chrome/browser/password_manager/auto_signin_first_run_dialog_android.cc
@@ -39,7 +39,7 @@
       Profile::FromBrowserContext(web_contents_->GetBrowserContext());
 
   bool is_smartlock_branding_enabled =
-      password_bubble_experiment::IsSmartLockBrandingEnabled(
+      password_bubble_experiment::IsSmartLockUser(
           ProfileSyncServiceFactory::GetForProfile(profile));
   base::string16 explanation;
   gfx::Range explanation_link_range = gfx::Range();
@@ -86,7 +86,7 @@
 
 void AutoSigninFirstRunDialogAndroid::OnLinkClicked(JNIEnv* env, jobject obj) {
   web_contents_->OpenURL(content::OpenURLParams(
-      GURL(password_manager::kPasswordManagerAccountDashboardURL),
+      GURL(password_manager::kPasswordManagerHelpCenterSmartLock),
       content::Referrer(), NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_LINK,
       false /* is_renderer_initiated */));
 }
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index f72ac4f9..3aa46f5 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -67,6 +67,7 @@
 #include "chrome/browser/password_manager/account_chooser_dialog_android.h"
 #include "chrome/browser/password_manager/auto_signin_first_run_dialog_android.h"
 #include "chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.h"
+#include "chrome/browser/password_manager/update_password_infobar_delegate.h"
 #include "chrome/browser/ui/android/snackbars/auto_signin_prompt_controller.h"
 #endif
 
@@ -241,6 +242,13 @@
 #if defined(OS_MACOSX) || BUILDFLAG(ANDROID_JAVA_UI)
     if (form_to_save->IsBlacklisted())
       return false;
+#if BUILDFLAG(ANDROID_JAVA_UI)
+    if (update_password && IsUpdatePasswordUIEnabled()) {
+      UpdatePasswordInfoBarDelegate::Create(web_contents(),
+                                            std::move(form_to_save));
+      return true;
+    }
+#endif
     std::string uma_histogram_suffix(
         password_manager::metrics_util::GroupIdToString(
             password_manager::metrics_util::MonitoredDomainGroupId(
@@ -503,17 +511,21 @@
     content::RenderFrameHost* render_frame_host,
     const gfx::RectF& bounds,
     int max_length,
+    const base::string16& generation_element,
+    bool is_manually_triggered,
     const autofill::PasswordForm& form) {
   // TODO(gcasto): Validate data in PasswordForm.
 
+  auto* driver = driver_factory_->GetDriverForFrame(render_frame_host);
+  password_manager_.SetGenerationElementAndReasonForForm(
+      driver, form, generation_element, is_manually_triggered);
   gfx::RectF element_bounds_in_screen_space = GetBoundsInScreenSpace(bounds);
 
   popup_controller_ =
       autofill::PasswordGenerationPopupControllerImpl::GetOrCreate(
           popup_controller_, element_bounds_in_screen_space, form, max_length,
-          &password_manager_,
-          driver_factory_->GetDriverForFrame(render_frame_host), observer_,
-          web_contents(), web_contents()->GetNativeView());
+          &password_manager_, driver, observer_, web_contents(),
+          web_contents()->GetNativeView());
   popup_controller_->Show(true /* display_password */);
 }
 
@@ -579,8 +591,12 @@
 }
 
 bool ChromePasswordManagerClient::IsUpdatePasswordUIEnabled() const {
-  // Currently Password update UI is implemented only for Bubble UI.
+#if BUILDFLAG(ANDROID_JAVA_UI)
+  return base::FeatureList::IsEnabled(
+      password_manager::features::kEnablePasswordChangeSupport);
+#else
   return IsTheHotNewBubbleUIEnabled();
+#endif
 }
 
 bool ChromePasswordManagerClient::EnabledForSyncSignin() {
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.h b/chrome/browser/password_manager/chrome_password_manager_client.h
index d64a2d7..97b2d405 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.h
+++ b/chrome/browser/password_manager/chrome_password_manager_client.h
@@ -127,10 +127,15 @@
 
   // Causes the password generation UI to be shown for the specified form.
   // The popup will be anchored at |element_bounds|. The generated password
-  // will be no longer than |max_length|.
+  // will be no longer than |max_length|. |generation_element| should contain a
+  // name of a password field at which generation popup is attached.
+  // |is_manually_triggered| informs whether it is automatically or manually
+  // triggered generation.
   void ShowPasswordGenerationPopup(content::RenderFrameHost* render_frame_host,
                                    const gfx::RectF& bounds,
                                    int max_length,
+                                   const base::string16& generation_element,
+                                   bool is_manually_triggered,
                                    const autofill::PasswordForm& form);
 
   // Causes the password editing UI to be shown anchored at |element_bounds|.
diff --git a/chrome/browser/password_manager/password_manager_infobar_delegate.cc b/chrome/browser/password_manager/password_manager_infobar_delegate.cc
index c7f608d6..8c4dda9 100644
--- a/chrome/browser/password_manager/password_manager_infobar_delegate.cc
+++ b/chrome/browser/password_manager/password_manager_infobar_delegate.cc
@@ -39,7 +39,7 @@
 }
 
 GURL PasswordManagerInfoBarDelegate::GetLinkURL() const {
-  return GURL(password_manager::kPasswordManagerAccountDashboardURL);
+  return GURL(password_manager::kPasswordManagerHelpCenterSmartLock);
 }
 
 bool PasswordManagerInfoBarDelegate::LinkClicked(
diff --git a/chrome/browser/password_manager/save_password_infobar_delegate.cc b/chrome/browser/password_manager/save_password_infobar_delegate.cc
index 435c0c42..92c4282 100644
--- a/chrome/browser/password_manager/save_password_infobar_delegate.cc
+++ b/chrome/browser/password_manager/save_password_infobar_delegate.cc
@@ -96,7 +96,7 @@
   PasswordTittleType type =
       form_to_save_->pending_credentials().federation_url.is_empty()
       ? PasswordTittleType::SAVE_PASSWORD
-      : PasswordTittleType::UPDATE_PASSWORD;
+      : PasswordTittleType::SAVE_ACCOUNT;
   GetSavePasswordDialogTitleTextAndLinkRange(
       web_contents->GetVisibleURL(), form_to_save_->observed_form().origin,
       is_smartlock_branding_enabled, type,
diff --git a/chrome/browser/password_manager/update_password_infobar_delegate.cc b/chrome/browser/password_manager/update_password_infobar_delegate.cc
new file mode 100644
index 0000000..7044a3ba
--- /dev/null
+++ b/chrome/browser/password_manager/update_password_infobar_delegate.cc
@@ -0,0 +1,100 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/password_manager/update_password_infobar_delegate.h"
+
+#include "base/numerics/safe_conversions.h"
+#include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/password_manager/chrome_password_manager_client.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sync/profile_sync_service_factory.h"
+#include "chrome/browser/ui/android/infobars/update_password_infobar.h"
+#include "chrome/browser/ui/passwords/manage_passwords_view_utils.h"
+#include "chrome/grit/chromium_strings.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/browser_sync/browser/profile_sync_service.h"
+#include "components/infobars/core/infobar.h"
+#include "components/password_manager/core/browser/password_bubble_experiment.h"
+#include "content/public/browser/web_contents.h"
+#include "ui/base/l10n/l10n_util.h"
+
+// static
+void UpdatePasswordInfoBarDelegate::Create(
+    content::WebContents* web_contents,
+    scoped_ptr<password_manager::PasswordFormManager> form_to_save) {
+  const bool is_smartlock_branding_enabled =
+      password_bubble_experiment::IsSmartLockBrandingEnabled(
+          ProfileSyncServiceFactory::GetForProfile(
+              Profile::FromBrowserContext(web_contents->GetBrowserContext())));
+  InfoBarService::FromWebContents(web_contents)
+      ->AddInfoBar(make_scoped_ptr(new UpdatePasswordInfoBar(
+          make_scoped_ptr(new UpdatePasswordInfoBarDelegate(
+              web_contents, std::move(form_to_save),
+              is_smartlock_branding_enabled)))));
+}
+
+UpdatePasswordInfoBarDelegate::~UpdatePasswordInfoBarDelegate() {}
+
+base::string16 UpdatePasswordInfoBarDelegate::GetBranding() const {
+  return l10n_util::GetStringUTF16(
+      is_smartlock_branding_enabled_
+          ? IDS_PASSWORD_MANAGER_SMART_LOCK_FOR_PASSWORDS
+          : IDS_PASSWORD_MANAGER_TITLE_BRAND);
+}
+
+bool UpdatePasswordInfoBarDelegate::ShowMultipleAccounts() const {
+  const password_manager::PasswordFormManager* form_manager =
+      passwords_state_.form_manager();
+  bool is_password_overriden =
+      form_manager && form_manager->password_overridden();
+  return GetCurrentForms().size() > 1 && !is_password_overriden;
+}
+
+const std::vector<const autofill::PasswordForm*>&
+UpdatePasswordInfoBarDelegate::GetCurrentForms() const {
+  return passwords_state_.GetCurrentForms();
+}
+
+UpdatePasswordInfoBarDelegate::UpdatePasswordInfoBarDelegate(
+    content::WebContents* web_contents,
+    scoped_ptr<password_manager::PasswordFormManager> form_to_update,
+    bool is_smartlock_branding_enabled)
+    : is_smartlock_branding_enabled_(is_smartlock_branding_enabled) {
+  // TODO(melandory): Add histograms, crbug.com/577129
+  passwords_state_.set_client(
+      ChromePasswordManagerClient::FromWebContents(web_contents));
+  passwords_state_.OnUpdatePassword(std::move(form_to_update));
+}
+
+infobars::InfoBarDelegate::InfoBarIdentifier
+UpdatePasswordInfoBarDelegate::GetIdentifier() const {
+  return UPDATE_PASSWORD_INFOBAR_DELEGATE;
+}
+
+base::string16 UpdatePasswordInfoBarDelegate::GetButtonLabel(
+    InfoBarButton button) const {
+  return l10n_util::GetStringUTF16((button == BUTTON_OK)
+                                       ? IDS_PASSWORD_MANAGER_UPDATE_BUTTON
+                                       : IDS_PASSWORD_MANAGER_CANCEL_BUTTON);
+}
+
+bool UpdatePasswordInfoBarDelegate::Accept() {
+  UpdatePasswordInfoBar* update_password_infobar =
+      static_cast<UpdatePasswordInfoBar*>(infobar());
+  password_manager::PasswordFormManager* form_manager =
+      passwords_state_.form_manager();
+  if (ShowMultipleAccounts()) {
+    int form_index = update_password_infobar->GetIdOfSelectedUsername();
+    DCHECK_GE(form_index, 0);
+    DCHECK_LT(static_cast<size_t>(form_index), GetCurrentForms().size());
+    form_manager->Update(*GetCurrentForms()[form_index]);
+  } else {
+    form_manager->Update(form_manager->pending_credentials());
+  }
+  return true;
+}
+
+bool UpdatePasswordInfoBarDelegate::Cancel() {
+  return true;
+}
diff --git a/chrome/browser/password_manager/update_password_infobar_delegate.h b/chrome/browser/password_manager/update_password_infobar_delegate.h
new file mode 100644
index 0000000..ee41a28
--- /dev/null
+++ b/chrome/browser/password_manager/update_password_infobar_delegate.h
@@ -0,0 +1,72 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PASSWORD_MANAGER_UPDATE_PASSWORD_INFOBAR_DELEGATE_H_
+#define CHROME_BROWSER_PASSWORD_MANAGER_UPDATE_PASSWORD_INFOBAR_DELEGATE_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/password_manager/password_manager_infobar_delegate.h"
+#include "chrome/browser/ui/passwords/manage_passwords_state.h"
+#include "components/password_manager/core/browser/password_form_manager.h"
+
+namespace content {
+class WebContents;
+}
+
+// An infobar delegate which asks the user if the password should be updated for
+// a set of saved credentials for a site.  If several such sets are present, the
+// user can choose which one to update.  PasswordManager displays this infobar
+// when the user signs into the site with a new password for a known username
+// or fills in a password change form.
+class UpdatePasswordInfoBarDelegate : public PasswordManagerInfoBarDelegate {
+ public:
+  static void Create(
+      content::WebContents* web_contents,
+      scoped_ptr<password_manager::PasswordFormManager> form_to_update);
+
+  ~UpdatePasswordInfoBarDelegate() override;
+
+  base::string16 GetBranding() const;
+  bool is_smartlock_branding_enabled() const {
+    return is_smartlock_branding_enabled_;
+  }
+
+  // Returns whether the user has multiple saved credentials, of which the
+  // infobar affects just one. In this case the infobar should clarify which
+  // credential is being affected.
+  bool ShowMultipleAccounts() const;
+
+  const std::vector<const autofill::PasswordForm*>& GetCurrentForms() const;
+
+  // Returns the username of the saved credentials in the case when there is
+  // only one credential pair stored.
+  base::string16 get_username_for_single_account() {
+    return passwords_state_.form_manager()
+        ->pending_credentials()
+        .username_value;
+  }
+
+ private:
+  UpdatePasswordInfoBarDelegate(
+      content::WebContents* web_contents,
+      scoped_ptr<password_manager::PasswordFormManager> form_to_update,
+      bool is_smartlock_branding_enabled);
+
+  // ConfirmInfoBarDelegate:
+  infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
+  base::string16 GetButtonLabel(InfoBarButton button) const override;
+  bool Accept() override;
+  bool Cancel() override;
+
+  ManagePasswordsState passwords_state_;
+  base::string16 branding_;
+  bool is_smartlock_branding_enabled_;
+
+  DISALLOW_COPY_AND_ASSIGN(UpdatePasswordInfoBarDelegate);
+};
+
+#endif  // CHROME_BROWSER_PASSWORD_MANAGER_UPDATE_PASSWORD_INFOBAR_DELEGATE_H_
diff --git a/chrome/browser/permissions/permission_context_base_unittest.cc b/chrome/browser/permissions/permission_context_base_unittest.cc
index bd69fe8..8c052ba 100644
--- a/chrome/browser/permissions/permission_context_base_unittest.cc
+++ b/chrome/browser/permissions/permission_context_base_unittest.cc
@@ -368,7 +368,7 @@
 }
 #endif
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 // Simulates granting and revoking of permissions using permission bubbles.
 // This test shouldn't run on mobile because mobile platforms use infobars.
 TEST_F(PermissionContextBaseTests, TestGrantAndRevokeWithBubbles) {
diff --git a/chrome/browser/plugins/plugin_observer.cc b/chrome/browser/plugins/plugin_observer.cc
index 59fae76..e3846d1 100644
--- a/chrome/browser/plugins/plugin_observer.cc
+++ b/chrome/browser/plugins/plugin_observer.cc
@@ -176,7 +176,7 @@
 }
 
 gfx::VectorIconId ReloadPluginInfoBarDelegate::GetVectorIconId() const {
-#if !defined(OS_MACOSX) && !defined(OS_IOS) && !defined(OS_ANDROID)
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
   return gfx::VectorIconId::EXTENSION_CRASHED;
 #else
   return gfx::VectorIconId::VECTOR_ICON_NONE;
@@ -391,7 +391,7 @@
       InfoBarService::FromWebContents(web_contents()),
       infobars::InfoBarDelegate::PLUGIN_OBSERVER,
       IDR_INFOBAR_PLUGIN_CRASHED,
-#if !defined(OS_MACOSX) && !defined(OS_IOS) && !defined(OS_ANDROID)
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
       gfx::VectorIconId::EXTENSION_CRASHED,
 #else
       gfx::VectorIconId::VECTOR_ICON_NONE,
diff --git a/chrome/browser/policy/cloud/cloud_policy_invalidator_unittest.cc b/chrome/browser/policy/cloud/cloud_policy_invalidator_unittest.cc
index 7b31225..3428d995 100644
--- a/chrome/browser/policy/cloud/cloud_policy_invalidator_unittest.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_invalidator_unittest.cc
@@ -1095,11 +1095,6 @@
     CloudPolicyInvalidatorUserTypedTestInstance,
     CloudPolicyInvalidatorUserTypedTest,
     testing::Values(em::DeviceRegisterRequest::ANDROID_BROWSER));
-#elif defined(OS_IOS)
-INSTANTIATE_TEST_CASE_P(
-    CloudPolicyInvalidatorUserTypedTestInstance,
-    CloudPolicyInvalidatorUserTypedTest,
-    testing::Values(em::DeviceRegisterRequest::IOS_BROWSER));
 #else
 INSTANTIATE_TEST_CASE_P(
     CloudPolicyInvalidatorUserTypedTestInstance,
diff --git a/chrome/browser/policy/cloud/user_cloud_policy_invalidator.cc b/chrome/browser/policy/cloud/user_cloud_policy_invalidator.cc
index 95784b642..237e7a7 100644
--- a/chrome/browser/policy/cloud/user_cloud_policy_invalidator.cc
+++ b/chrome/browser/policy/cloud/user_cloud_policy_invalidator.cc
@@ -47,8 +47,6 @@
   return enterprise_management::DeviceRegisterRequest::USER;
 #elif defined(OS_ANDROID)
   return enterprise_management::DeviceRegisterRequest::ANDROID_BROWSER;
-#elif defined(OS_IOS)
-  return enterprise_management::DeviceRegisterRequest::IOS_BROWSER;
 #else
   return enterprise_management::DeviceRegisterRequest::BROWSER;
 #endif
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_base.cc b/chrome/browser/policy/cloud/user_policy_signin_service_base.cc
index 72ca972..29a300e 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_base.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_base.cc
@@ -153,11 +153,7 @@
     const std::string& username) {
   DCHECK(!username.empty());
   // We should not be called with a client already initialized.
-#if !defined(OS_IOS)
-  // On iOS we check if an account has policy while the profile is signed in
-  // to another account.
   DCHECK(!policy_manager() || !policy_manager()->core()->client());
-#endif
 
   // If the user should not get policy, just bail out.
   if (!policy_manager() || !ShouldLoadPolicyForUser(username)) {
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_factory.cc b/chrome/browser/policy/cloud/user_policy_signin_service_factory.cc
index 0dfe155..9a1592d 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_factory.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_factory.cc
@@ -18,7 +18,7 @@
 #include "components/prefs/pref_service.h"
 #include "net/url_request/url_request_context_getter.h"
 
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_ANDROID)
 #include "chrome/browser/policy/cloud/user_policy_signin_service_mobile.h"
 #else
 #include "chrome/browser/policy/cloud/user_policy_signin_service.h"
@@ -83,22 +83,14 @@
 
 bool
 UserPolicySigninServiceFactory::ServiceIsCreatedWithBrowserContext() const {
-#if defined(OS_IOS)
-  // This service isn't required at Profile creation time on iOS.
-  // Creating it at that time also leads to a crash, because the SigninManager
-  // trigger a token fetch too early (this isn't a problem on other platforms,
-  // because the refresh token isn't available that early).
-  return false;
-#else
   // Create this object when the profile is created so it can track any
   // user signin activity.
   return true;
-#endif
 }
 
 void UserPolicySigninServiceFactory::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* user_prefs) {
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_ANDROID)
   user_prefs->RegisterInt64Pref(prefs::kLastPolicyCheckTime, 0);
 #endif
 }
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_mobile.cc b/chrome/browser/policy/cloud/user_policy_signin_service_mobile.cc
index a7ac389b..3b777a5 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_mobile.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_mobile.cc
@@ -30,14 +30,11 @@
 
 namespace {
 
-#if defined(OS_IOS)
-const em::DeviceRegisterRequest::Type kCloudPolicyRegistrationType =
-    em::DeviceRegisterRequest::IOS_BROWSER;
-#elif defined(OS_ANDROID)
+#if defined(OS_ANDROID)
 const em::DeviceRegisterRequest::Type kCloudPolicyRegistrationType =
     em::DeviceRegisterRequest::ANDROID_BROWSER;
 #else
-#error "This file can be built only on OS_IOS or OS_ANDROID."
+#error "This file can be built only on OS_ANDROID."
 #endif
 
 }  // namespace
@@ -59,11 +56,6 @@
       oauth2_token_service_(token_service),
       profile_prefs_(profile->GetPrefs()),
       weak_factory_(this) {
-#if defined(OS_IOS)
-  // iOS doesn't create this service with the Profile; instead it's created
-  // a little bit later. See UserPolicySigninServiceFactory.
-  InitializeOnProfileReady(profile);
-#endif
 }
 
 UserPolicySigninService::~UserPolicySigninService() {}
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 129ad70..c8bfa33 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -13,8 +13,13 @@
 #include "base/memory/scoped_vector.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "chrome/browser/net/disk_cache_dir_policy_handler.h"
+#include "chrome/browser/policy/file_selection_dialogs_policy_handler.h"
+#include "chrome/browser/policy/javascript_policy_handler.h"
 #include "chrome/browser/policy/managed_bookmarks_policy_handler.h"
+#include "chrome/browser/policy/network_prediction_policy_handler.h"
 #include "chrome/browser/profiles/incognito_mode_policy_handler.h"
+#include "chrome/browser/sessions/restore_on_startup_policy_handler.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
@@ -36,6 +41,7 @@
 #include "components/search_engines/default_search_policy_handler.h"
 #include "components/signin/core/common/signin_pref_names.h"
 #include "components/ssl_config/ssl_config_prefs.h"
+#include "components/sync_driver/sync_policy_handler.h"
 #include "components/translate/core/common/translate_pref_names.h"
 #include "components/variations/pref_names.h"
 #include "policy/policy_constants.h"
@@ -44,15 +50,6 @@
 #include "chrome/browser/search/contextual_search_policy_handler_android.h"
 #endif
 
-#if !defined(OS_IOS)
-#include "chrome/browser/net/disk_cache_dir_policy_handler.h"
-#include "chrome/browser/policy/file_selection_dialogs_policy_handler.h"
-#include "chrome/browser/policy/javascript_policy_handler.h"
-#include "chrome/browser/policy/network_prediction_policy_handler.h"
-#include "chrome/browser/sessions/restore_on_startup_policy_handler.h"
-#include "components/sync_driver/sync_policy_handler.h"
-#endif
-
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/platform_keys/key_permissions_policy_handler.h"
 #include "chrome/browser/chromeos/policy/configuration_policy_handler_chromeos.h"
@@ -64,7 +61,7 @@
 #include "ui/chromeos/accessibility_types.h"
 #endif
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 #include "chrome/browser/download/download_dir_policy_handler.h"
 #endif
 
@@ -391,7 +388,7 @@
     ssl_config::prefs::kRC4Enabled,
     base::Value::TYPE_BOOLEAN },
 
-#if !defined(OS_MACOSX) && !defined(OS_IOS)
+#if !defined(OS_MACOSX)
   { key::kFullscreenAllowed,
     prefs::kFullscreenAllowed,
     base::Value::TYPE_BOOLEAN },
@@ -400,7 +397,7 @@
     extensions::pref_names::kAppFullscreenAllowed,
     base::Value::TYPE_BOOLEAN },
 #endif  // defined(ENABLE_EXTENSIONS)
-#endif  // !defined(OS_MACOSX) && !defined(OS_IOS)
+#endif  // !defined(OS_MACOSX)
 
 #if defined(OS_CHROMEOS)
   { key::kChromeOsLockOnIdleSuspend,
@@ -530,7 +527,7 @@
     base::Value::TYPE_STRING },
 #endif  // BUILDFLAG(ANDROID_JAVA_UI)
 
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
   { key::kNativeMessagingUserLevelHosts,
     extensions::pref_names::kNativeMessagingUserLevelHosts,
     base::Value::TYPE_BOOLEAN },
@@ -540,7 +537,7 @@
   { key::kBrowserAddPersonEnabled,
     prefs::kBrowserAddPersonEnabled,
     base::Value::TYPE_BOOLEAN },
-#endif  // !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif  // !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
 
 #if defined(OS_WIN)
   { key::kWelcomePageOnOSUpgradeEnabled,
@@ -594,13 +591,11 @@
 }
 #endif
 
-#if !defined(OS_IOS)
 void GetDeprecatedFeaturesMap(
     ScopedVector<StringMappingListPolicyHandler::MappingEntry>* result) {
   // Maps feature tags as specified in policy to the corresponding switch to
   // re-enable them.
 }
-#endif  // !defined(OS_IOS)
 
 }  // namespace
 
@@ -641,7 +636,6 @@
       make_scoped_ptr(new ContextualSearchPolicyHandlerAndroid()));
 #endif
 
-#if !defined(OS_IOS)
   handlers->AddHandler(
       make_scoped_ptr(new FileSelectionDialogsPolicyHandler()));
   handlers->AddHandler(make_scoped_ptr(new JavascriptPolicyHandler()));
@@ -653,7 +647,6 @@
       key::kEnableDeprecatedWebPlatformFeatures,
       prefs::kEnableDeprecatedWebPlatformFeatures,
       base::Bind(GetDeprecatedFeaturesMap))));
-#endif  // !defined(OS_IOS)
 
 #if defined(ENABLE_EXTENSIONS)
   handlers->AddHandler(
@@ -677,7 +670,7 @@
       new extensions::ExtensionSettingsPolicyHandler(chrome_schema)));
 #endif
 
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
   handlers->AddHandler(make_scoped_ptr(new DiskCacheDirPolicyHandler()));
 
   handlers->AddHandler(
@@ -688,9 +681,9 @@
       make_scoped_ptr(new extensions::NativeMessagingHostListPolicyHandler(
           key::kNativeMessagingBlacklist,
           extensions::pref_names::kNativeMessagingBlacklist, true)));
-#endif  // !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif  // !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   handlers->AddHandler(make_scoped_ptr(new DownloadDirPolicyHandler));
 
   handlers->AddHandler(make_scoped_ptr(new SimpleSchemaValidatingPolicyHandler(
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 6817c64..df2ca80 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -163,7 +163,6 @@
 #include "extensions/common/extension_set.h"
 #include "extensions/common/manifest_handlers/shared_module_info.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/url_util.h"
 #include "net/http/http_stream_factory.h"
 #include "net/ssl/ssl_config.h"
@@ -2730,12 +2729,12 @@
 IN_PROC_BROWSER_TEST_F(PolicyTest, SSLVersionFallbackMin) {
   PrefService* prefs = g_browser_process->local_state();
 
-  const std::string new_value("tls1.2");
+  const std::string new_value("tls1.1");
   const std::string default_value(
       prefs->GetString(ssl_config::prefs::kSSLVersionFallbackMin));
 
   EXPECT_NE(default_value, new_value);
-  EXPECT_NE(net::SSL_PROTOCOL_VERSION_TLS1_2,
+  EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1_2,
             GetSSLVersionFallbackMin(browser()->profile()));
 
   PolicyMap policies;
@@ -2747,7 +2746,7 @@
                NULL);
   UpdateProviderPolicy(policies);
 
-  EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1_2,
+  EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1_1,
             GetSSLVersionFallbackMin(browser()->profile()));
 }
 
diff --git a/chrome/browser/policy/policy_helpers.cc b/chrome/browser/policy/policy_helpers.cc
index da43eec..ed3be58 100644
--- a/chrome/browser/policy/policy_helpers.cc
+++ b/chrome/browser/policy/policy_helpers.cc
@@ -13,7 +13,7 @@
 #include "chromeos/chromeos_switches.h"
 #endif
 
-#if !defined(OS_CHROMEOS) && !defined(OS_IOS)
+#if !defined(OS_CHROMEOS)
 #include "google_apis/gaia/gaia_urls.h"
 #endif
 
@@ -41,8 +41,6 @@
   *reason = net::ERR_BLOCKED_ENROLLMENT_CHECK_PENDING;
   *block = true;
   return true;
-#elif defined(OS_IOS)
-  return false;
 #else
   static const char kServiceLoginAuth[] = "/ServiceLoginAuth";
 
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index f258ac3..aa33bff9 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -149,7 +149,7 @@
 #include "chrome/browser/upgrade_detector.h"
 #endif
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 #include "chrome/browser/signin/signin_promo.h"
 #include "chrome/browser/ui/webui/foreign_session_handler.h"
 #endif
@@ -487,7 +487,7 @@
 #endif
 
 #if defined(ENABLE_SUPERVISED_USERS)
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   SupervisedUserSharedSettingsService::RegisterProfilePrefs(registry);
   SupervisedUserSyncService::RegisterProfilePrefs(registry);
 #endif
@@ -556,7 +556,7 @@
   ash::RegisterChromeLauncherUserPrefs(registry);
 #endif
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   browser_sync::ForeignSessionHandler::RegisterProfilePrefs(registry);
 #endif
 
diff --git a/chrome/browser/prefs/chrome_pref_service_factory.cc b/chrome/browser/prefs/chrome_pref_service_factory.cc
index 15539f88..2472dee 100644
--- a/chrome/browser/prefs/chrome_pref_service_factory.cc
+++ b/chrome/browser/prefs/chrome_pref_service_factory.cc
@@ -193,12 +193,8 @@
     PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
     PrefHashFilter::VALUE_IMPERSONAL
   },
-  {
-    17, sync_driver::prefs::kSyncRemainingRollbackTries,
-    PrefHashFilter::ENFORCE_ON_LOAD,
-    PrefHashFilter::TRACKING_STRATEGY_ATOMIC,
-    PrefHashFilter::VALUE_IMPERSONAL
-  },
+  // kSyncRemainingRollbackTries is deprecated and will be removed a few
+  // releases after M50.
   {
     18, prefs::kSafeBrowsingIncidentsSent,
     PrefHashFilter::ENFORCE_ON_LOAD,
diff --git a/chrome/browser/prefs/pref_service_syncable_util.cc b/chrome/browser/prefs/pref_service_syncable_util.cc
index 49cadee..68bf0e0 100644
--- a/chrome/browser/prefs/pref_service_syncable_util.cc
+++ b/chrome/browser/prefs/pref_service_syncable_util.cc
@@ -12,7 +12,7 @@
 #include "chrome/common/pref_names.h"
 #include "components/syncable_prefs/pref_service_syncable.h"
 
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_ANDROID)
 #include "components/proxy_config/proxy_config_pref_names.h"
 #endif
 
@@ -36,7 +36,7 @@
   std::vector<const char*> overlay_pref_names;
   overlay_pref_names.push_back(prefs::kBrowserWindowPlacement);
   overlay_pref_names.push_back(prefs::kSaveFileDefaultDirectory);
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_ANDROID)
   overlay_pref_names.push_back(proxy_config::prefs::kProxy);
 #endif
   return pref_service->CreateIncognitoPrefService(
diff --git a/chrome/browser/prefs/profile_pref_store_manager.cc b/chrome/browser/prefs/profile_pref_store_manager.cc
index cfd5f9c..d694d5f 100644
--- a/chrome/browser/prefs/profile_pref_store_manager.cc
+++ b/chrome/browser/prefs/profile_pref_store_manager.cc
@@ -39,7 +39,7 @@
 // Preference tracking and protection is not required on platforms where other
 // apps do not have access to chrome's persistent storage.
 const bool ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking =
-#if defined(OS_ANDROID) || defined(OS_CHROMEOS) || defined(OS_IOS)
+#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
     false;
 #else
     true;
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc
index 4c6dfc6..556da43 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.cc
+++ b/chrome/browser/profiles/off_the_record_profile_impl.cc
@@ -63,10 +63,10 @@
 #include "chrome/browser/media/protected_media_identifier_permission_context_factory.h"
 #endif  // defined(OS_ANDROID)
 
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_ANDROID)
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/proxy_config/proxy_prefs.h"
-#endif  // defined(OS_ANDROID) || defined(OS_IOS)
+#endif  // defined(OS_ANDROID)
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/preferences.h"
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.h b/chrome/browser/profiles/off_the_record_profile_impl.h
index 8cd1fe5..fe6f2be 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.h
+++ b/chrome/browser/profiles/off_the_record_profile_impl.h
@@ -116,9 +116,9 @@
   // Allows a profile to track changes in zoom levels in its parent profile.
   void TrackZoomLevelsFromParent();
 
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_ANDROID)
   void UseSystemProxy();
-#endif  // defined(OS_ANDROID) || defined(OS_IOS)
+#endif  // defined(OS_ANDROID)
 
   PrefProxyConfigTracker* CreateProxyConfigTracker();
   // Callback function for tracking parent's zoom level changes.
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index 1376450..4e70a7e 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -142,7 +142,7 @@
   registry->RegisterBooleanPref(prefs::kDataSaverEnabled, false);
   data_reduction_proxy::RegisterSyncableProfilePrefs(registry);
 
-#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS) && !defined(OS_IOS)
+#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
   // Preferences related to the avatar bubble and user manager tutorials.
   registry->RegisterIntegerPref(prefs::kProfileAvatarTutorialShown, 0);
 #endif
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 01912fb..70bf353 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -644,7 +644,7 @@
 
   PushMessagingServiceImpl::InitializeForProfile(this);
 
-#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS) && !defined(OS_IOS)
+#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
   signin_ui_util::InitializePrefsForProfile(this);
 #endif
 }
diff --git a/chrome/browser/profiles/profile_info_cache.cc b/chrome/browser/profiles/profile_info_cache.cc
index 34ad387..48478436 100644
--- a/chrome/browser/profiles/profile_info_cache.cc
+++ b/chrome/browser/profiles/profile_info_cache.cc
@@ -368,7 +368,7 @@
       return *image;
   }
 
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
   // Use the high resolution version of the avatar if it exists. Mobile and
   // ChromeOS don't need the high resolution version so no need to fetch it.
   const gfx::Image* image = GetHighResAvatarOfProfileAtIndex(index);
@@ -951,7 +951,7 @@
     size_t icon_index) const {
   base::string16 name;
   for (int name_index = 1; ; ++name_index) {
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
     name = l10n_util::GetStringFUTF16Int(IDS_NEW_NUMBERED_PROFILE_NAME,
                                          name_index);
 #else
@@ -1044,7 +1044,7 @@
     size_t icon_index,
     const base::FilePath& profile_path) {
   // Downloading is only supported on desktop.
-#if defined(OS_ANDROID) || defined(OS_IOS) || defined(OS_CHROMEOS)
+#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
   return;
 #endif
   DCHECK(!disable_avatar_download_for_testing_);
@@ -1152,7 +1152,7 @@
     bool allow_generic_icon,
     bool must_be_unique,
     size_t* out_icon_index) const {
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
   // Always allow the generic icon when displaying the new avatar menu.
   allow_generic_icon = true;
 #endif
@@ -1207,7 +1207,7 @@
     size_t icon_index,
     const base::FilePath& profile_path) {
   // Downloading is only supported on desktop.
-#if defined(OS_ANDROID) || defined(OS_IOS) || defined(OS_CHROMEOS)
+#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
   return;
 #endif
   // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/461175
@@ -1326,7 +1326,7 @@
 
 void ProfileInfoCache::MigrateLegacyProfileNamesAndDownloadAvatars() {
   // Only do this on desktop platforms.
-#if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_CHROMEOS)
+#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
   // Migrate any legacy profile names ("First user", "Default Profile") to
   // new style default names ("Person 1"). The problem here is that every
   // time you rename a profile, the ProfileInfoCache sorts itself, so
diff --git a/chrome/browser/profiles/profile_info_cache_unittest.cc b/chrome/browser/profiles/profile_info_cache_unittest.cc
index 3da169c6..246f63e 100644
--- a/chrome/browser/profiles/profile_info_cache_unittest.cc
+++ b/chrome/browser/profiles/profile_info_cache_unittest.cc
@@ -554,7 +554,7 @@
 }
 
 // High res avatar downloading is only supported on desktop.
-#if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_CHROMEOS)
+#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
 TEST_F(ProfileInfoCacheTest, DownloadHighResAvatarTest) {
   // The TestingProfileManager's ProfileInfoCache doesn't download avatars.
   ProfileInfoCache profile_info_cache(g_browser_process->local_state(),
@@ -690,7 +690,7 @@
 }
 #endif
 
-#if defined(OS_CHROMEOS) || defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
 TEST_F(ProfileInfoCacheTest,
        DontMigrateLegacyProfileNamesWithoutNewAvatarMenu) {
   EXPECT_EQ(0U, GetCache()->GetNumberOfProfiles());
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index 6c7611f6..9e86ca9a 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -455,7 +455,7 @@
 
       // Use the device-wide system key slot only if the user is affiliated on
       // the device.
-      params->use_system_key_slot = user->is_affiliated();
+      params->use_system_key_slot = user->IsAffiliated();
     }
   }
 
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index 55b1d61..11d852b 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -43,6 +43,7 @@
 #include "chrome/browser/profiles/profile_metrics.h"
 #include "chrome/browser/profiles/profile_statistics.h"
 #include "chrome/browser/profiles/profiles_state.h"
+#include "chrome/browser/sessions/session_service_factory.h"
 #include "chrome/browser/signin/account_fetcher_service_factory.h"
 #include "chrome/browser/signin/account_reconcilor_factory.h"
 #include "chrome/browser/signin/account_tracker_service_factory.h"
@@ -105,11 +106,6 @@
 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
 #endif
 
-#if !defined(OS_IOS)
-#include "chrome/browser/sessions/session_service_factory.h"
-#include "chrome/browser/ui/browser_list.h"
-#endif  // !defined (OS_IOS)
-
 #if defined(OS_WIN)
 #include "chrome/installer/util/browser_distribution.h"
 #endif
@@ -199,7 +195,7 @@
     UMA_HISTOGRAM_COUNTS_10000("Profile.AppCount", enabled_app_count);
 }
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 void QueueProfileDirectoryForDeletion(const base::FilePath& path) {
   ProfilesToDelete().push_back(path);
 }
@@ -258,7 +254,7 @@
 ProfileManager::ProfileManager(const base::FilePath& user_data_dir)
     : user_data_dir_(user_data_dir),
       logged_in_(false),
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
       browser_list_observer_(this),
 #endif
       closing_all_browsers_(false) {
@@ -472,7 +468,7 @@
   }
 }
 
-bool ProfileManager::IsValidProfile(void* profile) {
+bool ProfileManager::IsValidProfile(const void* profile) {
   for (ProfilesInfoMap::iterator iter = profiles_info_.begin();
        iter != profiles_info_.end(); ++iter) {
     if (iter->second->created) {
@@ -671,7 +667,7 @@
   return profile_shortcut_manager_.get();
 }
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 void ProfileManager::ScheduleProfileForDeletion(
     const base::FilePath& profile_dir,
     const CreateCallback& callback) {
@@ -708,7 +704,7 @@
     std::string new_avatar_url;
     base::string16 new_profile_name;
 
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
     int avatar_index = profiles::GetPlaceholderAvatarIndex();
     new_avatar_url = profiles::GetDefaultAvatarIconUrl(avatar_index);
     new_profile_name = cache.ChooseNameForNewProfile(avatar_index);
@@ -753,7 +749,7 @@
 
   FinishDeletingProfile(profile_dir, last_non_supervised_profile_path);
 }
-#endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif  // !defined(OS_ANDROID)
 
 void ProfileManager::AutoloadProfiles() {
   // If running in the background is disabled for the browser, do not autoload
@@ -841,7 +837,7 @@
     } else if (profile->GetPath() ==
                profiles::GetDefaultProfileDir(cache.GetUserDataDir())) {
       avatar_index = profiles::GetPlaceholderAvatarIndex();
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
       profile_name =
           base::UTF16ToUTF8(cache.ChooseNameForNewProfile(avatar_index));
 #else
@@ -1119,7 +1115,7 @@
   ChildAccountServiceFactory::GetForProfile(profile)->Init();
   SupervisedUserServiceFactory::GetForProfile(profile)->Init();
 #endif
-#if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_CHROMEOS)
+#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
   // If the lock enabled algorithm changed, update this profile's lock status.
   // This depends on services which shouldn't be initialized until
   // DoFinalInitForServices.
@@ -1265,7 +1261,7 @@
   return profile;
 }
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 void ProfileManager::FinishDeletingProfile(
     const base::FilePath& profile_dir,
     const base::FilePath& new_active_profile_dir) {
@@ -1336,7 +1332,7 @@
   cache.DeleteProfileFromCache(profile_dir);
   ProfileMetrics::UpdateReportedProfilesStatistics(this);
 }
-#endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif  // !defined(OS_ANDROID)
 
 ProfileManager::ProfileInfo* ProfileManager::RegisterProfile(
     Profile* profile,
@@ -1437,7 +1433,7 @@
   ProfileDestroyer::DestroyProfileWhenAppropriate(profile.release());
 }
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 void ProfileManager::UpdateLastUser(Profile* last_active) {
   PrefService* local_state = g_browser_process->local_state();
   DCHECK(local_state);
@@ -1550,7 +1546,7 @@
   if (!original_callback.is_null())
     original_callback.Run(loaded_profile, status);
 }
-#endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif  // !defined(OS_ANDROID)
 
 ProfileManagerWithoutInit::ProfileManagerWithoutInit(
     const base::FilePath& user_data_dir) : ProfileManager(user_data_dir) {
diff --git a/chrome/browser/profiles/profile_manager.h b/chrome/browser/profiles/profile_manager.h
index b8ce056..b4db4fb 100644
--- a/chrome/browser/profiles/profile_manager.h
+++ b/chrome/browser/profiles/profile_manager.h
@@ -98,7 +98,7 @@
 
   // Returns true if the profile pointer is known to point to an existing
   // profile.
-  bool IsValidProfile(void* profile);
+  bool IsValidProfile(const void* profile);
 
   // Returns the directory where the first created profile is stored,
   // relative to the user data directory currently in use.
@@ -174,7 +174,7 @@
   // profile specfic desktop shortcuts.
   ProfileShortcutManager* profile_shortcut_manager();
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   // Schedules the profile at the given path to be deleted on shutdown. If we're
   // deleting the last profile, a new one will be created in its place, and in
   // that case the callback will be called when profile creation is complete.
@@ -275,7 +275,7 @@
   // creation and adds it to the set managed by this ProfileManager.
   Profile* CreateAndInitializeProfile(const base::FilePath& profile_dir);
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   // Schedules the profile at the given path to be deleted on shutdown,
   // and marks the new profile as active.
   void FinishDeletingProfile(const base::FilePath& profile_dir,
@@ -309,7 +309,7 @@
                     Profile* profile,
                     Profile::CreateStatus status);
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   // Updates the last active user of the current session.
   // On Chrome OS updating this user will have no effect since when browser is
   // restored after crash there's another preference that is taken into account.
@@ -342,7 +342,7 @@
       const CreateCallback& original_callback,
       Profile* loaded_profile,
       Profile::CreateStatus status);
-#endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif  // !defined(OS_ANDROID)
 
   // Object to cache various information about profiles. Contains information
   // about every profile which has been created for this instance of Chrome,
@@ -361,9 +361,9 @@
   // default.
   bool logged_in_;
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   BrowserListObserver browser_list_observer_;
-#endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif  // !defined(OS_ANDROID)
 
   // Maps profile path to ProfileInfo (if profile has been created). Use
   // RegisterProfile() to add into this map. This map owns all loaded profile
diff --git a/chrome/browser/profiles/profile_metrics.cc b/chrome/browser/profiles/profile_metrics.cc
index 2cf2535..6d4bcea 100644
--- a/chrome/browser/profiles/profile_metrics.cc
+++ b/chrome/browser/profiles/profile_metrics.cc
@@ -28,7 +28,7 @@
 
 const int kMaximumDaysOfDisuse = 4 * 7;  // Should be integral number of weeks.
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 size_t number_of_profile_switches_ = 0;
 #endif
 
@@ -42,7 +42,7 @@
   PROFILE_UNOPENED
 };
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 ProfileOpenState GetProfileOpenState(
     ProfileManager* manager,
     const base::FilePath& path) {
@@ -100,7 +100,7 @@
 bool HasProfileAtIndexBeenActiveSince(const ProfileInfoCache& info_cache,
                                       int index,
                                       const base::Time& active_limit) {
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   // TODO(mlerman): iOS and Android should set an ActiveTime in the
   // ProfileInfoCache. (see ProfileManager::OnBrowserSetLastActive)
   if (info_cache.GetProfileActiveTimeAtIndex(index) < active_limit)
@@ -193,7 +193,7 @@
 #endif
 }
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 void ProfileMetrics::LogNumberOfProfileSwitches() {
   UMA_HISTOGRAM_COUNTS_100("Profile.NumberOfSwitches",
                            number_of_profile_switches_);
@@ -346,7 +346,7 @@
                             NUM_PROFILE_OPEN_METRICS);
 }
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 void ProfileMetrics::LogProfileSwitch(
     ProfileOpen metric,
     ProfileManager* manager,
diff --git a/chrome/browser/profiles/profile_metrics.h b/chrome/browser/profiles/profile_metrics.h
index 9657bd98..6f14946 100644
--- a/chrome/browser/profiles/profile_metrics.h
+++ b/chrome/browser/profiles/profile_metrics.h
@@ -203,7 +203,7 @@
   static bool CountProfileInformation(ProfileManager* manager,
                                       profile_metrics::Counts* counts);
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   static void LogNumberOfProfileSwitches();
 #endif
 
@@ -217,7 +217,7 @@
   static void LogProfileAvatarSelection(size_t icon_index);
   static void LogProfileDeleteUser(ProfileDelete metric);
   static void LogProfileOpenMethod(ProfileOpen metric);
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   static void LogProfileSwitch(ProfileOpen metric,
                                ProfileManager* manager,
                                const base::FilePath& profile_path);
diff --git a/chrome/browser/profiles/profile_window_browsertest.cc b/chrome/browser/profiles/profile_window_browsertest.cc
index 7d5a034..f6b826d 100644
--- a/chrome/browser/profiles/profile_window_browsertest.cc
+++ b/chrome/browser/profiles/profile_window_browsertest.cc
@@ -35,7 +35,7 @@
 #include "net/test/embedded_test_server/embedded_test_server.h"
 
 // This test verifies the Desktop implementation of Guest only.
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
 
 namespace {
 
@@ -212,4 +212,4 @@
   EXPECT_EQ(-1, model_guest_profile.GetIndexOfCommandId(IDC_BOOKMARKS_MENU));
 }
 
-#endif  // !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif  // !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/background/keymaps/next_keymap.json b/chrome/browser/resources/chromeos/chromevox/chromevox/background/keymaps/next_keymap.json
index d75314fd..f64e8f4 100644
--- a/chrome/browser/resources/chromeos/chromevox/chromevox/background/keymaps/next_keymap.json
+++ b/chrome/browser/resources/chromeos/chromevox/chromevox/background/keymaps/next_keymap.json
@@ -457,6 +457,41 @@
           "keyCode": [65, 69]
         }
       }
+    },
+    {
+      "command": "speakTimeAndDate",
+      "sequence": {
+        "cvoxModifier": true,
+        "keys": {
+          "keyCode": [65, 68]}
+      }
+    },
+    {
+      "command": "readCurrentTitle",
+      "sequence": {
+        "cvoxModifier": true,
+        "keys": {
+          "keyCode": [65, 87]
+        }
+      }
+    },
+    {
+      "command": "readCurrentURL",
+      "sequence": {
+        "cvoxModifier": true,
+        "keys": {
+          "keyCode": [65, 85]
+        }
+      }
+    },
+    {
+      "command": "reportIssue",
+      "sequence": {
+        "cvoxModifier": true,
+        "keys": {
+          "keyCode": [65, 73]
+        }
+      }
     }
   ]
 }
diff --git a/chrome/browser/resources/chromeos/chromevox/common/chrome_extension_externs.js b/chrome/browser/resources/chromeos/chromevox/common/chrome_extension_externs.js
index 26cb50e..440f0d5a 100644
--- a/chrome/browser/resources/chromeos/chromevox/common/chrome_extension_externs.js
+++ b/chrome/browser/resources/chromeos/chromevox/common/chrome_extension_externs.js
@@ -557,3 +557,6 @@
  * @type {(number|undefined)}
  */
 chrome.automation.focusOffset;
+
+/** @type {function() : !Object} */
+chrome.app.getDetails;
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
index f671a2a4..4a3d70f 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
@@ -139,6 +139,14 @@
     chrome.accessibilityPrivate.setKeyboardListener = function() {};
 };
 
+/**
+ * @const {string}
+ */
+Background.ISSUE_URL = 'https://code.google.com/p/chromium/issues/entry?' +
+    'labels=Type-Bug,Pri-2,cvox2,OS-Chrome&' +
+    'components=UI>accessibility&' +
+    'description=';
+
 Background.prototype = {
   __proto__: ChromeVoxState.prototype,
 
@@ -265,8 +273,11 @@
     if (!newRange)
       return;
 
+    // Exclude saving ranges inside of the Panel and any parenting webviews.
     var panelUrl = chrome.extension.getURL('cvox2/background/panel.html');
-    if (newRange.start.node.root.docUrl.indexOf(panelUrl) != 0)
+    var testNode = newRange.start.node;
+    if (newRange.start.node.root.docUrl.indexOf(panelUrl) != 0 &&
+        newRange.start.node.role != RoleType.webView)
       this.savedRange_ = new cursors.Range(newRange.start, newRange.end);
 
     this.currentRange_ = newRange;
@@ -601,6 +612,45 @@
             global.backgroundTts.cyclePunctuationEcho()),
                        cvox.QueueMode.FLUSH);
         return false;
+      case 'speakTimeAndDate':
+        var output = new Output();
+        var dateTime = new Date();
+        output.withString(
+            dateTime.toLocaleTimeString() +
+                ', ' + dateTime.toLocaleDateString()).go();
+        return false;
+      case 'readCurrentTitle':
+        var target = this.currentRange_.start.node;
+        var output = new Output();
+
+        if (target.root.role == RoleType.rootWebArea) {
+          // Web.
+          target = target.root;
+          output.withString(target.name || target.docUrl);
+        } else {
+          // Views.
+          while (target.role != RoleType.window)
+            target = target.parent;
+          if (target)
+            output.withString(target.name || '');
+        }
+        output.go();
+        return false;
+      case 'readCurrentURL':
+        var output = new Output();
+        var target = this.currentRange_.start.node.root;
+        output.withString(target.docUrl || '').go();
+        return false;
+      case 'reportIssue':
+        var url = Background.ISSUE_URL;
+        var description = {};
+        description['Mode'] = this.mode_;
+        description['Version'] = chrome.app.getDetails().version;
+        description['Reproduction Steps'] = '%0a1.%0a2.%0a3.';
+        for (var key in description)
+          url += key + ':%20' + description[key] + '%0a';
+        chrome.tabs.create({url: url});
+        return false;
       default:
         return true;
     }
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/desktop_automation_handler.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/desktop_automation_handler.js
index a278b9a..fae9129 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/desktop_automation_handler.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/desktop_automation_handler.js
@@ -170,16 +170,21 @@
         ChromeVoxState.instance.mode === ChromeVoxMode.CLASSIC)
       return;
 
-    // If initial focus was already placed on this page (e.g. if a user starts
-    // tabbing before load complete), then don't move ChromeVox's position on
-    // the page.
-    if (ChromeVoxState.instance.currentRange &&
-        ChromeVoxState.instance.currentRange.start.node.root == evt.target)
-      return;
+    chrome.automation.getFocus((function(focus) {
+      if (!focus)
+        return;
 
-    ChromeVoxState.instance.setCurrentRange(cursors.Range.fromNode(evt.target));
-    new Output().withRichSpeechAndBraille(
-        ChromeVoxState.instance.currentRange, null, evt.type).go();
+      // If initial focus was already placed on this page (e.g. if a user starts
+      // tabbing before load complete), then don't move ChromeVox's position on
+      // the page.
+      if (ChromeVoxState.instance.currentRange &&
+          ChromeVoxState.instance.currentRange.start.node.root == focus.root)
+        return;
+
+      ChromeVoxState.instance.setCurrentRange(cursors.Range.fromNode(focus));
+      new Output().withRichSpeechAndBraille(
+          ChromeVoxState.instance.currentRange, null, evt.type).go();
+    }).bind(this));
   },
 
   /** @override */
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
index f3bfa17..fc1dd9f 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
@@ -310,6 +310,10 @@
   toolbar: {
     msgId: 'role_toolbar'
   },
+  toggleButton: {
+    msgId: 'role_checkbox',
+    inherits: 'checkBox'
+  },
   tree: {
     msgId: 'role_tree'
   },
@@ -755,6 +759,17 @@
   },
 
   /**
+   * Output a string literal.
+   * @param {string} value
+   * @return {!Output}
+   */
+  withString: function(value) {
+    this.append_(this.speechBuffer_, value);
+    this.append_(this.brailleBuffer_, value);
+    return this;
+  },
+
+  /**
    * Apply a format string directly to the output buffer. This lets you
    * output a message directly to the buffer using the format syntax.
    * @param {string} formatStr
@@ -1322,8 +1337,13 @@
   node_: function(node, prevNode, type, buff) {
     // Navigate is the default event.
     var eventBlock = Output.RULES[type] || Output.RULES['navigate'];
-    var roleBlock = eventBlock[node.role] || eventBlock['default'];
-    var speakFormat = roleBlock.speak || eventBlock['default'].speak;
+    var roleBlock = eventBlock[node.role] || {};
+    var parentRole = (Output.ROLE_INFO_[node.role] || {}).inherits;
+    var parentRoleBlock = eventBlock[parentRole || ''] || {};
+    var speakFormat = roleBlock.speak ||
+        parentRoleBlock.speak ||
+        eventBlock['default'].speak;
+
     this.format_(node, speakFormat, buff);
   },
 
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output_test.extjs
index bc4e8b0..2e722586 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output_test.extjs
@@ -615,3 +615,17 @@
       }
   });
 });
+TEST_F('OutputE2ETest', 'ToggleButton', function() {
+  this.runWithLoadedTree(function() {/*!
+      <div role="button" aria-pressed="true">Subscribe</div>*/},
+    function(root) {
+      var el = root.firstChild;
+      var o = new Output().withSpeech(cursors.Range.fromNode(el));
+      assertEqualsJSON({string_: '|Subscribe|Check box|not checked', spans_: [
+        {value: {earconId: 'CHECK_OFF'}, start: 0, end: 0},
+        {value: 'name', start: 1, end:10},
+        {value: 'role', start: 11, end: 20},
+        {value: 'state', start: 21, end: 32}
+      ]}, o.speechOutputForTest);
+  });
+});
diff --git a/chrome/browser/resources/chromeos/login/custom_elements_login.html b/chrome/browser/resources/chromeos/login/custom_elements_login.html
index 7949e486..135b0944 100644
--- a/chrome/browser/resources/chromeos/login/custom_elements_login.html
+++ b/chrome/browser/resources/chromeos/login/custom_elements_login.html
@@ -8,5 +8,6 @@
 <include src="saml_confirm_password.html">
 <include src="throbber_notice.html">
 <include src="navigation_bar.html">
+<include src="unrecoverable_cryptohome_error_card.html">
 
 <script src="chrome://oobe/custom_elements.js"></script>
diff --git a/chrome/browser/resources/chromeos/login/custom_elements_login.js b/chrome/browser/resources/chromeos/login/custom_elements_login.js
index f201492..92c51d2e 100644
--- a/chrome/browser/resources/chromeos/login/custom_elements_login.js
+++ b/chrome/browser/resources/chromeos/login/custom_elements_login.js
@@ -12,3 +12,4 @@
 <include src="saml_confirm_password.js">
 <include src="throbber_notice.js">
 <include src="navigation_bar.js">
+<include src="unrecoverable_cryptohome_error_card.js">
diff --git a/chrome/browser/resources/chromeos/login/login.js b/chrome/browser/resources/chromeos/login/login.js
index 2ecdc86..52019ae 100644
--- a/chrome/browser/resources/chromeos/login/login.js
+++ b/chrome/browser/resources/chromeos/login/login.js
@@ -36,6 +36,7 @@
       login.ConfirmPasswordScreen.register();
       login.FatalErrorScreen.register();
       login.DeviceDisabledScreen.register();
+      login.UnrecoverableCryptohomeErrorScreen.register();
 
       cr.ui.Bubble.decorate($('bubble'));
       login.HeaderBar.decorate($('login-header-bar'));
diff --git a/chrome/browser/resources/chromeos/login/login_common.js b/chrome/browser/resources/chromeos/login/login_common.js
index 5f2d007..cd48d35 100644
--- a/chrome/browser/resources/chromeos/login/login_common.js
+++ b/chrome/browser/resources/chromeos/login/login_common.js
@@ -32,6 +32,7 @@
 <include src="screen_confirm_password.js">
 <include src="screen_fatal_error.js">
 <include src="screen_device_disabled.js">
+<include src="screen_unrecoverable_cryptohome_error.js">
 <include src="../../../../../ui/login/login_ui_tools.js">
 <include src="../../../../../ui/login/account_picker/user_pod_row.js">
 <include src="../../../../../ui/login/resource_loader.js">
diff --git a/chrome/browser/resources/chromeos/login/login_resources.html b/chrome/browser/resources/chromeos/login/login_resources.html
index b9b9c84..0e22ac48 100644
--- a/chrome/browser/resources/chromeos/login/login_resources.html
+++ b/chrome/browser/resources/chromeos/login/login_resources.html
@@ -39,6 +39,7 @@
 <link rel="stylesheet" href="screen_confirm_password.css">
 <link rel="stylesheet" href="screen_fatal_error.css">
 <link rel="stylesheet" href="screen_device_disabled.css">
+<link rel="stylesheet" href="screen_unrecoverable_cryptohome_error.css">
 <link rel="stylesheet" href="../../../../../ui/login/account_picker/user_pod_row.css">
 <link rel="stylesheet" href="../../options/chromeos/bluetooth.css">
 <script src="chrome://resources/js/cr.js"></script>
diff --git a/chrome/browser/resources/chromeos/login/login_screens.html b/chrome/browser/resources/chromeos/login/login_screens.html
index 676c8f8..be7208a 100644
--- a/chrome/browser/resources/chromeos/login/login_screens.html
+++ b/chrome/browser/resources/chromeos/login/login_screens.html
@@ -14,3 +14,4 @@
 <include src="screen_confirm_password.html">
 <include src="screen_fatal_error.html">
 <include src="screen_device_disabled.html">
+<include src="screen_unrecoverable_cryptohome_error.html">
diff --git a/chrome/browser/resources/chromeos/login/screen_unrecoverable_cryptohome_error.css b/chrome/browser/resources/chromeos/login/screen_unrecoverable_cryptohome_error.css
new file mode 100644
index 0000000..bafb98a
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/screen_unrecoverable_cryptohome_error.css
@@ -0,0 +1,9 @@
+/* Copyright (c) 2016 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.
+ */
+
+#unrecoverable-cryptohome-error {
+  height: 528px; /* Should be the same as #gaia-signin. */
+  width: 448px; /* Should be the same as #gaia-signin. */
+}
diff --git a/chrome/browser/resources/chromeos/login/screen_unrecoverable_cryptohome_error.html b/chrome/browser/resources/chromeos/login/screen_unrecoverable_cryptohome_error.html
new file mode 100644
index 0000000..11a6f35
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/screen_unrecoverable_cryptohome_error.html
@@ -0,0 +1,9 @@
+<link rel="import" href="chrome://oobe/custom_elements.html">
+
+<div id="unrecoverable-cryptohome-error" class="step faded no-logo" hidden>
+  <unrecoverable-cryptohome-error-card id="unrecoverable-cryptohome-error-card">
+  </unrecoverable-cryptohome-error-card>
+  <div id="unrecoverable-cryptohome-error-busy" class="step-loading" hidden>
+    <throbber-notice i18n-values="text:gaiaLoading"></throbber-notice>
+  </div>
+</div>
diff --git a/chrome/browser/resources/chromeos/login/screen_unrecoverable_cryptohome_error.js b/chrome/browser/resources/chromeos/login/screen_unrecoverable_cryptohome_error.js
new file mode 100644
index 0000000..d19e80af
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/screen_unrecoverable_cryptohome_error.js
@@ -0,0 +1,49 @@
+// Copyright 2016 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.
+
+login.createScreen('UnrecoverableCryptohomeErrorScreen',
+                   'unrecoverable-cryptohome-error', function() {
+  return {
+    EXTERNAL_API: [
+      'show'
+    ],
+
+    /** @override */
+    decorate: function() {
+      this.card_ = $('unrecoverable-cryptohome-error-card');
+      this.throbber_ = $('unrecoverable-cryptohome-error-busy');
+
+      this.card_.addEventListener('recreate', function() {
+        this.setLoading_(true);
+        chrome.send('resyncUserData');
+      }.bind(this));
+
+      this.card_.addEventListener('sendFeedbackAndRecreate', function() {
+        this.setLoading_(true);
+        chrome.send('sendFeedbackAndResyncUserData');
+      }.bind(this));
+    },
+
+    /**
+     * Sets whether to show the loading throbber.
+     * @param {boolean} loading
+     */
+    setLoading_: function(loading) {
+      this.card_.hidden = loading;
+      this.throbber_.hidden = !loading;
+    },
+
+    /**
+     * Show password changed screen.
+     * @param {string} email User email to display in header.
+     */
+    show: function(email) {
+      this.card_.email = email;
+      this.setLoading_(false);
+
+      Oobe.getInstance().headerHidden = true;
+      Oobe.showScreen({id: SCREEN_UNRECOVERABLE_CRYPTOHOME_ERROR});
+    }
+  };
+});
diff --git a/chrome/browser/resources/chromeos/login/unrecoverable_cryptohome_error_card.css b/chrome/browser/resources/chromeos/login/unrecoverable_cryptohome_error_card.css
new file mode 100644
index 0000000..3de413a9
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/unrecoverable_cryptohome_error_card.css
@@ -0,0 +1,12 @@
+/* Copyright 2016 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.
+ */
+
+iron-icon[icon='warning'] {
+  -webkit-margin-end: 15px;
+  -webkit-margin-start: 0;
+  color: var(--google-yellow-500);
+  margin-bottom: 0;
+  margin-top: 0;
+}
diff --git a/chrome/browser/resources/chromeos/login/unrecoverable_cryptohome_error_card.html b/chrome/browser/resources/chromeos/login/unrecoverable_cryptohome_error_card.html
new file mode 100644
index 0000000..ab6a3c9
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/unrecoverable_cryptohome_error_card.html
@@ -0,0 +1,47 @@
+<!-- Copyright 2016 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. -->
+
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+
+<!--
+  Unrecoverable cryptohome error card that shows to use when an unrecoverable
+  cryptohome error happens. It asks user to help us debugging the issue by
+  sending us a feedback and allows user to re-create the cryptohome so that
+  the device could still be used.
+
+  Attributes:
+    'email' - displayed email in header
+
+  Events:
+    'sendFeedbackAndRecreate' - fired when user clicks on send feedkback button.
+    'recreate' - fired when user clicks on re-create cryptohome button.
+-->
+<dom-module name="unrecoverable-cryptohome-error-card">
+  <link rel="stylesheet" href="unrecoverable_cryptohome_error_card.css">
+
+  <template>
+    <gaia-card class="fit">
+      <gaia-header class="header" email="[[email]]">
+      </gaia-header>
+      <div class="footer">
+        <div class="gaia-body-text horizontal layout">
+          <iron-icon icon="warning"></iron-icon>
+          <p i18n-values=".innerHTML:unrecoverableCryptohomeErrorMessage"
+              class="flex">
+          </p>
+        </div>
+        <div class="horizontal layout justified center">
+          <gaia-button on-tap="onRecreateClicked_"
+              i18n-content="unrecoverableCryptohomeErrorContinue">
+          </gaia-button>
+          <gaia-button on-tap="onSendFeedbackAndRecreateClicked_"
+              i18n-content="unrecoverableCryptohomeErrorSendFeedback">
+          </gaia-button>
+        </div>
+      </div>
+    </gaia-card>
+  </template>
+</dom-module>
diff --git a/chrome/browser/resources/chromeos/login/unrecoverable_cryptohome_error_card.js b/chrome/browser/resources/chromeos/login/unrecoverable_cryptohome_error_card.js
new file mode 100644
index 0000000..9a4b9f85
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/unrecoverable_cryptohome_error_card.js
@@ -0,0 +1,19 @@
+// Copyright 2016 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.
+
+Polymer({
+  is: 'unrecoverable-cryptohome-error-card',
+
+  properties: {
+    email: String
+  },
+
+  onRecreateClicked_: function() {
+    this.fire('recreate');
+  },
+
+  onSendFeedbackAndRecreateClicked_: function() {
+    this.fire('sendFeedbackAndRecreate');
+  }
+});
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.js b/chrome/browser/resources/local_ntp/most_visited_single.js
index 98ebea5..d6a1d5c 100644
--- a/chrome/browser/resources/local_ntp/most_visited_single.js
+++ b/chrome/browser/resources/local_ntp/most_visited_single.js
@@ -379,7 +379,7 @@
         ev.button == 1,  // MIDDLE BUTTON
         ev.altKey, ev.ctrlKey, ev.metaKey, ev.shiftKey);
 
-      window.chrome.embeddedSearch.newTabPage.navigateContentWindow(this.href,
+      window.chrome.embeddedSearch.newTabPage.navigateContentWindow(data.rid,
                                                                     disp);
     });
   }
diff --git a/chrome/browser/resources/local_ntp/most_visited_util.js b/chrome/browser/resources/local_ntp/most_visited_util.js
index 9c00c58ae..d0338ab1 100644
--- a/chrome/browser/resources/local_ntp/most_visited_util.js
+++ b/chrome/browser/resources/local_ntp/most_visited_util.js
@@ -165,9 +165,10 @@
                                             provider || '');
     }
 
-    if (!isServerSuggestion) {
+    if ('rid' in params) {
       e.preventDefault();
-      ntpApiHandle.navigateContentWindow(href, getDispositionFromEvent(e));
+      ntpApiHandle.navigateContentWindow(params.rid,
+                                         getDispositionFromEvent(e));
     }
     // Else follow <a> normally, so transition type would be LINK.
   };
diff --git a/chrome/browser/resources/md_history/history_item.html b/chrome/browser/resources/md_history/history_item.html
index 6d685818..a011e449 100644
--- a/chrome/browser/resources/md_history/history_item.html
+++ b/chrome/browser/resources/md_history/history_item.html
@@ -7,9 +7,11 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/shadow.html">
 <link rel="import" href="chrome://resources/html/util.html">
+<link rel="import" href="chrome://history/shared_style.html">
 
 <dom-module id="history-item">
   <template>
+    <style include="shared-style"></style>
     <style>
       :host {
         @apply(--layout-center);
@@ -19,11 +21,11 @@
 
       #main-container {
         background: #fff;
-        border-color: rgba(0, 0, 0, 0.14);
+        border-color: var(--card-border-color);
         border-style: solid;
         border-width: 0 1px;
-        max-width: 960px;
-        min-width: 500px;
+        max-width: var(--card-max-width);
+        min-width: var(--card-min-width);
         width: 100%;
       }
 
@@ -41,16 +43,7 @@
       }
 
       :host([is-card-start]) #date-accessed {
-        @apply(--layout-center);
-        @apply(--layout-horizontal);
-        -webkit-padding-start: 20px;
-        background: #fafafa;
-        border-bottom: 1px solid rgba(0, 0, 0, 0.14);
-        border-radius: 2px 2px 0 0;
-        color: #333;
-        font-size: 14px;
-        font-weight: 500;
-        height: 48px;
+        display: flex;
       }
 
       #item-container {
@@ -67,7 +60,7 @@
         padding-bottom: 8px;
       }
 
-      #titleAndDomain {
+      #title-and-domain {
         @apply(--layout-center);
         @apply(--layout-flex);
         @apply(--layout-horizontal);
@@ -85,40 +78,17 @@
         width: 16px;
       }
 
-      #time {
+      #time-accessed {
         color: #646464;
         min-width: 96px;
       }
 
-      #title {
-        color: #333;
-        overflow: hidden;
-        text-decoration: none;
-        text-overflow: ellipsis;
-        white-space: nowrap;
-      }
-
-      #title:hover {
-        text-decoration: underline;
-      }
-
       #domain {
         -webkit-margin-start: 16px;
         color: #969696;
         flex-shrink: 0;
       }
 
-      iron-icon {
-        --iron-icon-height: 16px;
-        --iron-icon-width: 16px;
-      }
-
-      #website-icon {
-        -webkit-margin-end: 16px;
-        height: 16px;
-        min-width: 16px;
-      }
-
       #menu-button {
         -webkit-margin-end: 12px;
         -webkit-margin-start: 2px;
@@ -128,7 +98,9 @@
         width: 36px;
       }
 
-      #bookmark {
+      #bookmark-star {
+        --iron-icon-height: 16px;
+        --iron-icon-width: 16px;
         -webkit-margin-end: 10px;
         -webkit-margin-start: 20px;
         color: rgb(68, 136, 255);
@@ -143,18 +115,20 @@
       }
     </style>
     <div id="main-container">
-      <div id="date-accessed">[[historyDate]]</div>
+      <div id="date-accessed" class="card-title">[[historyDate]]</div>
       <div id="item-container">
         <paper-checkbox id="checkbox" on-tap="onCheckboxSelected_"
             checked="{{selected}}" disabled="[[selectionNotAllowed_()]]">
         </paper-checkbox>
-        <span id="time">{{timeAccessed}}</span>
-        <div id="website-icon"></div>
-        <div id="titleAndDomain">
-          <a href$="{{websiteUrl}}" id="title">{{websiteTitle}}</a>
+        <span id="time-accessed">{{timeAccessed}}</span>
+        <div class="website-icon" id="icon"></div>
+        <div id="title-and-domain">
+          <a href$="{{websiteUrl}}" id="title" class="website-title">
+            {{websiteTitle}}
+          </a>
           <span id="domain">{{websiteDomain}}</span>
         </div>
-        <iron-icon icon="star" id="bookmark"></iron-icon>
+        <iron-icon icon="star" id="bookmark-star"></iron-icon>
         <paper-icon-button icon="more-vert" id="menu-button"
             on-tap="onMenuButtonTap_">
         </paper-icon-button>
diff --git a/chrome/browser/resources/md_history/history_item.js b/chrome/browser/resources/md_history/history_item.js
index 375da18be..b6af296 100644
--- a/chrome/browser/resources/md_history/history_item.js
+++ b/chrome/browser/resources/md_history/history_item.js
@@ -94,7 +94,7 @@
    * @private
    */
   showIcon_: function() {
-    this.$['website-icon'].style.backgroundImage =
+    this.$.icon.style.backgroundImage =
         getFaviconImageSet(this.websiteUrl);
   },
 
diff --git a/chrome/browser/resources/md_history/history_toolbar.html b/chrome/browser/resources/md_history/history_toolbar.html
index 6de760d..b32fc84 100644
--- a/chrome/browser/resources/md_history/history_toolbar.html
+++ b/chrome/browser/resources/md_history/history_toolbar.html
@@ -3,10 +3,11 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_search_field/cr_search_field.html">
+<link rel="import" href="chrome://history/shared_style.html">
 
 <dom-module id="history-toolbar">
   <template>
-
+    <style include="shared-style"></style>
     <style>
       :host {
         background: rgb(63, 85, 102);
@@ -38,7 +39,7 @@
 
       #items {
         margin: 0 auto;
-        max-width: 960px;
+        max-width: var(--card-max-width);
       }
 
       #number-selected {
@@ -53,8 +54,7 @@
       }
 
       #centered-buttons {
-        flex: 1 1 960px;
-        max-width: 960px;
+        flex: 0 1 var(--card-max-width);
       }
 
       paper-button {
diff --git a/chrome/browser/resources/md_history/shared_style.html b/chrome/browser/resources/md_history/shared_style.html
new file mode 100644
index 0000000..c55e2bb
--- /dev/null
+++ b/chrome/browser/resources/md_history/shared_style.html
@@ -0,0 +1,42 @@
+<dom-module id="shared-style">
+  <template>
+    <style>
+      :root {
+        --card-border-color: rgba(0, 0, 0, 0.14);
+        --card-max-width: 960px;
+        --card-min-width: 500px;
+      }
+
+      .card-title {
+        @apply(--layout-center);
+        @apply(--layout-horizontal);
+        -webkit-padding-start: 20px;
+        background: #fafafa;
+        border-bottom: 1px solid var(--card-border-color);
+        border-radius: 2px 2px 0 0;
+        color: #333;
+        font-size: 14px;
+        font-weight: 500;
+        height: 48px;
+      }
+
+      .website-icon {
+        -webkit-margin-end: 16px;
+        height: 16px;
+        min-width: 16px;
+      }
+
+      .website-title {
+        color: #333;
+        overflow: hidden;
+        text-decoration: none;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+      }
+
+      .website-title:hover {
+        text-decoration: underline;
+      }
+    </style>
+  </template>
+</dom-module>
diff --git a/chrome/browser/resources/options/chromeos/display_layout.js b/chrome/browser/resources/options/chromeos/display_layout.js
index f7506d66..bcef558 100644
--- a/chrome/browser/resources/options/chromeos/display_layout.js
+++ b/chrome/browser/resources/options/chromeos/display_layout.js
@@ -212,26 +212,33 @@
     },
 
     /**
-     * Snap |newPosition| to the edge specified by |layoutType| and call
-     * setDivPosition.
+     * Return the position closest to |newPosition| along the edge of
+     * |parentDiv| specified by |layoutType|.
      * @param {options.DisplayPosition} newPosition
      * @param {?HTMLElement} parentDiv
      * @param {!options.DisplayLayoutType} layoutType
+     * @return {!options.DisplayPosition}
      */
-    snapAndSetDivPosition(newPosition, parentDiv, layoutType) {
-      var snapX = (layoutType == options.DisplayLayoutType.LEFT ||
-                   layoutType == options.DisplayLayoutType.RIGHT) ?
-          0 /* infinite */ :
-          undefined /* default */;
-      var snapY = (layoutType == options.DisplayLayoutType.TOP ||
-                   layoutType == options.DisplayLayoutType.BOTTOM) ?
-          0 /* infinite */ :
-          undefined /* default */;
+    getSnapPosition: function(newPosition, parentDiv, layoutType) {
+      var x;
+      if (layoutType == options.DisplayLayoutType.LEFT) {
+        x = parentDiv.offsetLeft - this.div.offsetWidth;
+      } else if (layoutType == options.DisplayLayoutType.RIGHT) {
+        x = parentDiv.offsetLeft + parentDiv.offsetWidth;
+      } else {
+        x = this.snapToX(newPosition.x, parentDiv);
+      }
 
-      newPosition.x = this.snapToX(newPosition.x, parentDiv, snapX);
-      newPosition.y = this.snapToY(newPosition.y, parentDiv, snapY);
+      var y;
+      if (layoutType == options.DisplayLayoutType.TOP) {
+        y = parentDiv.offsetTop - this.div.offsetHeight;
+      } else if (layoutType == options.DisplayLayoutType.BOTTOM) {
+        y = parentDiv.offsetTop + parentDiv.offsetHeight;
+      } else {
+        y = this.snapToY(newPosition.y, parentDiv);
+      }
 
-      this.setDivPosition(newPosition, parentDiv, layoutType);
+      return {x: x, y: y};
     },
 
     /**
@@ -241,7 +248,7 @@
      * @param {?HTMLElement} parentDiv
      * @param {!options.DisplayLayoutType} layoutType
      */
-    setDivPosition(newPosition, parentDiv, layoutType) {
+    setDivPosition: function(newPosition, parentDiv, layoutType) {
       var div = this.div;
       switch (layoutType) {
         case options.DisplayLayoutType.RIGHT:
@@ -264,6 +271,27 @@
     },
 
     /**
+     * Return the position of the corner of the div closest to |pos|.
+     * @param {?HTMLElement} parentDiv
+     * @param {options.DisplayPosition} pos
+     * @return {!options.DisplayPosition}
+     * @private
+     */
+    getCornerPos: function(parentDiv, pos) {
+      var x;
+      if (pos.x > parentDiv.offsetLeft + parentDiv.offsetWidth / 2)
+        x = parentDiv.offsetLeft + parentDiv.offsetWidth;
+      else
+        x = parentDiv.offsetLeft - this.div.offsetWidth;
+      var y;
+      if (pos.y > parentDiv.offsetTop + parentDiv.offsetHeight / 2)
+        y = parentDiv.offsetTop + parentDiv.offsetHeight;
+      else
+        y = parentDiv.offsetTop - this.div.offsetHeight;
+      return {x: x, y: y};
+    },
+
+    /**
      * Ensures that there is a minimum overlap when displays meet at a corner.
      * @param {?HTMLElement} parentDiv
      * @param {options.DisplayLayoutType} layoutType
@@ -307,11 +335,10 @@
       var y = position.y + div.offsetHeight / 2;
 
       // Determine the distance from the new position to both of the near edges.
-      var div = parentDiv;
-      var left = div.offsetLeft;
-      var top = div.offsetTop;
-      var width = div.offsetWidth;
-      var height = div.offsetHeight;
+      var left = parentDiv.offsetLeft;
+      var top = parentDiv.offsetTop;
+      var width = parentDiv.offsetWidth;
+      var height = parentDiv.offsetHeight;
 
       // Signed deltas to the center of the div.
       var dx = x - (left + width / 2);
@@ -360,6 +387,61 @@
       return snapToEdge_(
           y, this.div.offsetHeight, parentDiv.offsetTop, parentDiv.offsetHeight,
           opt_snapDistance);
+    },
+
+    /**
+     * Intersects this.div with |otherDiv|. If there is a collision, modifies
+     * |deltaPos| to limit movement to a single axis and avoid the collision
+     * and returns true.
+     * @param {?HTMLElement} otherDiv
+     * @param {!options.DisplayPosition} deltaPos
+     * @return {boolean} Whether there was a collision.
+     */
+    collideWithDivAndModifyDelta: function(otherDiv, deltaPos) {
+      var div = this.div;
+      var newX = div.offsetLeft + deltaPos.x;
+      var newY = div.offsetTop + deltaPos.y;
+
+      if ((newX + div.offsetWidth <= otherDiv.offsetLeft) ||
+          (newX >= otherDiv.offsetLeft + otherDiv.offsetWidth) ||
+          (newY + div.offsetHeight <= otherDiv.offsetTop) ||
+          (newY >= otherDiv.offsetTop + otherDiv.offsetHeight)) {
+        return false;
+      }
+
+      if (Math.abs(deltaPos.x) > Math.abs(deltaPos.y)) {
+        if (deltaPos.x > 0) {
+          var x = otherDiv.offsetLeft - div.offsetWidth;
+          if (x > div.offsetLeft)
+            deltaPos.x = x - div.offsetLeft;
+          else
+            deltaPos.x = 0;
+        } else {
+          var x = otherDiv.offsetLeft + otherDiv.offsetWidth;
+          if (x < div.offsetLeft)
+            deltaPos.x = x - div.offsetLeft;
+          else
+            deltaPos.x = 0;
+        }
+        deltaPos.y = 0;
+      } else {
+        deltaPos.x = 0;
+        if (deltaPos.y > 0) {
+          var y = otherDiv.offsetTop - div.offsetHeight;
+          if (y > div.offsetTop)
+            deltaPos.y = y - div.offsetTop;
+          else
+            deltaPos.y = 0;
+        } else if (deltaPos.y < 0) {
+          var y = otherDiv.offsetTop + otherDiv.offsetTop;
+          if (y < div.offsetTop)
+            deltaPos.y = y - div.offsetTop;
+          else
+            deltaPos.y = 0;
+        }
+      }
+
+      return true;
     }
   };
 
diff --git a/chrome/browser/resources/options/chromeos/display_layout_manager_multi.js b/chrome/browser/resources/options/chromeos/display_layout_manager_multi.js
index b5cc4ab..59bab4e9 100644
--- a/chrome/browser/resources/options/chromeos/display_layout_manager_multi.js
+++ b/chrome/browser/resources/options/chromeos/display_layout_manager_multi.js
@@ -57,25 +57,41 @@
     /** @override */
     updatePosition: function(id, newPosition) {
       this.dragId_ = id;
-      // Find the closest parent.
       var layout = this.displayLayoutMap_[id];
-      this.dragParentId_ = this.findClosest_(layout, newPosition);
-      var parent = this.displayLayoutMap_[this.dragParentId_];
+
+      // Find the closest parent.
+      var parentId = this.findClosest_(layout, newPosition);
+      var parent = this.displayLayoutMap_[parentId];
 
       // Find the closest edge.
-      this.dragLayoutType_ =
-          layout.getLayoutTypeForPosition(parent.div, newPosition);
+      var layoutType = layout.getLayoutTypeForPosition(parent.div, newPosition);
+
+      // Calculate the new position and delta.
+      var oldPos = {x: layout.div.offsetLeft, y: layout.div.offsetTop};
+      var newPos = layout.getSnapPosition(newPosition, parent.div, layoutType);
+      var deltaPos = {x: newPos.x - oldPos.x, y: newPos.y - oldPos.y};
+
+      // Check for collisions.
+      this.collideAndModifyDelta_(layout, deltaPos);
+      if (deltaPos.x == 0 && deltaPos.y == 0)
+        return;
 
       // Update the div (but not the actual layout type or offset yet),
-      layout.snapAndSetDivPosition(
-          newPosition, parent.div, this.dragLayoutType_);
+      newPos = {x: oldPos.x + deltaPos.x, y: oldPos.y + deltaPos.y};
+      layout.setDivPosition(newPos, parent.div, layoutType);
 
-      this.highlightEdge_(this.dragParentId_, this.dragLayoutType_);
+      // If the edge changed, update and highlight it.
+      if (layoutType != this.dragLayoutType_ ||
+          parentId != this.dragParentId_) {
+        this.dragLayoutType_ = layoutType;
+        this.dragParentId_ = parentId;
+        this.highlightEdge_(this.dragParentId_, this.dragLayoutType_);
+      }
     },
 
     /** @override */
     finalizePosition: function(id) {
-      if (id != this.dragId_) {
+      if (id != this.dragId_ || !this.dragParentId_) {
         this.dragId_ = '';
         return false;
       }
@@ -197,11 +213,21 @@
       var parent = this.displayLayoutMap_[newParentId];
 
       // Find the closest edge.
-      orphan.layoutType = orphan.getLayoutTypeForPosition(parent.div, pos);
+      var layoutType = orphan.getLayoutTypeForPosition(parent.div, pos);
+
+      // Snap from the nearest corner to the desired locaiton and get the delta.
+      var cornerPos = orphan.getCornerPos(parent.div, pos);
+      pos = orphan.getSnapPosition(pos, parent.div, layoutType);
+      var deltaPos = {x: pos.x - cornerPos.x, y: pos.y - cornerPos.y};
+
+      // Check for collisions.
+      this.collideAndModifyDelta_(orphan, deltaPos);
+      pos = {x: cornerPos.x + deltaPos.x, y: cornerPos.y + deltaPos.y};
 
       // Update the div and adjust the corners.
-      orphan.snapAndSetDivPosition(pos, parent.div, orphan.layoutType);
-      orphan.adjustCorners(parent.div, orphan.layoutType);
+      orphan.layoutType = layoutType;
+      orphan.setDivPosition(pos, parent.div, layoutType);
+      orphan.adjustCorners(parent.div, layoutType);
 
       // Calculate the bounds from the new div position.
       orphan.calculateOffset(this.visualScale_, parent);
@@ -280,6 +306,35 @@
     },
 
     /**
+     * Intersects |layout| with each other layout and reduces |deltaPos| to
+     * avoid any collisions (or sets it to [0,0] if the div can not be moved
+     * in the direction of |deltaPos|).
+     * @param {!options.DisplayLayout} layout
+     * @param {!options.DisplayPosition} deltaPos
+     */
+    collideAndModifyDelta_: function(layout, deltaPos) {
+      var keys = Object.keys(
+          /** @type {!Object<!options.DisplayLayout>}*/ (
+              this.displayLayoutMap_));
+      var others = new Set(keys);
+      others.delete(layout.id);
+      var checkCollisions = true;
+      while (checkCollisions) {
+        checkCollisions = false;
+        for (var tid of others) {
+          var tlayout = this.displayLayoutMap_[tid];
+          if (layout.collideWithDivAndModifyDelta(tlayout.div, deltaPos)) {
+            if (deltaPos.x == 0 && deltaPos.y == 0)
+              return;
+            others.delete(tid);
+            checkCollisions = true;
+            break;
+          }
+        }
+      }
+    },
+
+    /**
      * Highlights the edge of the div associated with |parentId| based on
      * |layoutType| and removes any other highlights. If |layoutType| is
      * undefined, removes all highlights.
diff --git a/chrome/browser/resources/print_preview/settings/page_settings.js b/chrome/browser/resources/print_preview/settings/page_settings.js
index f86c02d..78aeeb8 100644
--- a/chrome/browser/resources/print_preview/settings/page_settings.js
+++ b/chrome/browser/resources/print_preview/settings/page_settings.js
@@ -112,7 +112,7 @@
       this.tracker.add(
           this.customInput_, 'keydown', this.onCustomInputKeyDown_.bind(this));
       this.tracker.add(
-          this.customInput_, 'keyup', this.onCustomInputKeyUp_.bind(this));
+          this.customInput_, 'input', this.onCustomInputChange_.bind(this));
       this.tracker.add(
           this.pageRangeTicketItem_,
           print_preview.ticket_items.TicketItem.EventType.CHANGE,
@@ -210,24 +210,6 @@
     },
 
     /**
-     * Called when a key is pressed on the custom input.
-     * @param {Event} event Contains the key that was pressed.
-     * @private
-     */
-    onCustomInputKeyUp_: function(event) {
-      if (this.customInputTimeout_) {
-        clearTimeout(this.customInputTimeout_);
-        this.customInputTimeout_ = null;
-      }
-      if (event.keyCode != 13 /*enter*/) {
-        this.customRadio_.checked = true;
-        this.customInputTimeout_ = setTimeout(
-            this.onCustomInputTimeout_.bind(this),
-            PageSettings.CUSTOM_INPUT_DELAY_);
-      }
-    },
-
-    /**
      * Called after a delay following a key press in the custom input.
      * @private
      */
@@ -239,6 +221,20 @@
     },
 
     /**
+     * Called for events that change the text - undo, redo, paste and
+     * keystrokes outside of enter, copy, etc. (Re)starts the
+     * re-evaluation timer.
+     * @private
+     */
+    onCustomInputChange_: function() {
+      if (this.customInputTimeout_)
+        clearTimeout(this.customInputTimeout_);
+      this.customInputTimeout_ = setTimeout(
+          this.onCustomInputTimeout_.bind(this),
+          PageSettings.CUSTOM_INPUT_DELAY_);
+    },
+
+    /**
      * Called when the print ticket changes. Updates the state of the component.
      * @private
      */
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
index f308a00..71b302f 100644
--- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
@@ -5,7 +5,6 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="chrome://md-settings/settings_page/settings_animated_pages.html">
diff --git a/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.html b/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.html
index bdaa740..5482243 100644
--- a/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.html
+++ b/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.html
@@ -1,8 +1,5 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-menu/paper-menu.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-dropdown-menu/paper-dropdown-menu.html">
 <link rel="import" href="chrome://md-settings/controls/settings_checkbox.html">
 <link rel="import" href="chrome://md-settings/controls/settings_dropdown_menu.html">
 <link rel="import" href="chrome://md-settings/settings_shared_css.html">
diff --git a/chrome/browser/resources/settings/controls/settings_checkbox.html b/chrome/browser/resources/settings/controls/settings_checkbox.html
index 03d2c9a..6ddb8b6 100644
--- a/chrome/browser/resources/settings/controls/settings_checkbox.html
+++ b/chrome/browser/resources/settings/controls/settings_checkbox.html
@@ -8,7 +8,7 @@
 <dom-module id="settings-checkbox">
   <link rel="import" type="css" href="chrome://resources/cr_elements/shared.css">
   <template>
-    <style is="custom-style">
+    <style is="custom-style" include="settings-shared">
       :host {
         display: block;
         margin-bottom: 10px;
@@ -22,6 +22,10 @@
         --paper-checkbox-unchecked-color: #969696;
         -webkit-margin-start: 2px;
       }
+
+      .secondary {
+        @apply(--settings-secondary);
+      }
     </style>
     <cr-events id="events"></cr-events>
     <settings-pref-tracker pref="[[pref]]"></settings-pref-tracker>
diff --git a/chrome/browser/resources/settings/default_browser_page/default_browser_page.html b/chrome/browser/resources/settings/default_browser_page/default_browser_page.html
index 5cf158c..6bea5d8 100644
--- a/chrome/browser/resources/settings/default_browser_page/default_browser_page.html
+++ b/chrome/browser/resources/settings/default_browser_page/default_browser_page.html
@@ -9,16 +9,20 @@
   <template>
     <style include="settings-shared"></style>
     <div class="settings-card">
-      <div class="settings-box first">[[message_]]</div>
-      <div class="settings-box">
+      <div class="settings-box first">
         <template is="dom-if" if="[[showButton_]]">
-          <paper-button on-tap="onSetDefaultBrowserTap_"
-              >[[i18n('defaultBrowserMakeDefault')]]</paper-button>
+          <div on-tap="onSetDefaultBrowserTap_">
+            <div>[[i18n('defaultBrowser')]]</div>
+            <div class="secondary">[[i18n('defaultBrowserMakeDefault')]]</div>
+          </div>
           <template is="dom-if" if="[[showError_]]">
             <iron-icon icon="error" class="error-icon"
                 title="[[i18n('unableToSetDefaultBrowser')]]"></iron-icon>
           </template>
         </template>
+        <template is="dom-if" if="[[!showButton_]]">
+          <div class="secondary">[[message_]]</div>
+        </template>
       </div>
     </div>
   </template>
diff --git a/chrome/browser/resources/settings/default_browser_page/default_browser_page.js b/chrome/browser/resources/settings/default_browser_page/default_browser_page.js
index 67f7678f35..d5bc63698 100644
--- a/chrome/browser/resources/settings/default_browser_page/default_browser_page.js
+++ b/chrome/browser/resources/settings/default_browser_page/default_browser_page.js
@@ -97,12 +97,9 @@
     }
 
     this.showButton_ = !isDefault && canBeDefault;
-    if (canBeDefault) {
-      this.message_ = loadTimeData.getString(isDefault ?
-          'defaultBrowserDefault' :
-          'defaultBrowserNotDefault');
-    } else {
-      this.message_ = loadTimeData.getString('defaultBrowserUnknown');
+    if (!this.showButton) {
+      this.message_ = loadTimeData.getString(
+          canBeDefault ? 'defaultBrowserDefault' : 'defaultBrowserUnknown');
     }
   },
 
diff --git a/chrome/browser/resources/settings/languages_page/manage_languages_page.html b/chrome/browser/resources/settings/languages_page/manage_languages_page.html
index 44d2474f..ff7d7f21 100644
--- a/chrome/browser/resources/settings/languages_page/manage_languages_page.html
+++ b/chrome/browser/resources/settings/languages_page/manage_languages_page.html
@@ -14,35 +14,37 @@
   <template>
     <style include="settings-shared"></style>
     <settings-languages languages="{{languages}}"></settings-languages>
-    <div class="settings-box block content">
-      <h2 i18n-content="enabledLanguages"></h2>
-      <div class="list-frame vertical-list">
-        <template is="dom-repeat" items="{{languages.enabledLanguages}}">
-          <div class="list-item">
-            <div class="language-name start"
-                title="[[item.language.nativeDisplayName]]">
-              [[item.language.displayName]]
-            </div>
-            <paper-icon-button icon="clear" on-tap="onRemoveLanguageTap_"
-                hidden$="[[!canRemoveLanguage_(item.language.code, prefs.intl.app_locale.value)]]">
-            </paper-icon-button>
-          </div>
-        </template>
-      </div>
-      <h2 i18n-content="allLanguages"></h2>
-      <div class="list-frame vertical-list">
-        <iron-list items="{{availableLanguages_}}" as="item">
-          <template>
-            <div class="list-item" on-tap="onAddLanguageTap_">
-              <div class="language-name">
-                <span>[[item.displayName]]</span> -
-                <span>[[item.nativeDisplayName]]</span>
+    <div class="settings-box first content">
+      <div class="start">
+        <h2 i18n-content="enabledLanguages"></h2>
+        <div class="list-frame vertical-list">
+          <template is="dom-repeat" items="{{languages.enabledLanguages}}">
+            <div class="list-item">
+              <div class="language-name start"
+                  title="[[item.language.nativeDisplayName]]">
+                [[item.language.displayName]]
               </div>
-              <iron-icon icon="done" hidden$="[[!item.enabled]]">
-              </iron-icon>
+              <paper-icon-button icon="clear" on-tap="onRemoveLanguageTap_"
+                  hidden$="[[!canRemoveLanguage_(item.language.code, prefs.intl.app_locale.value)]]">
+              </paper-icon-button>
             </div>
           </template>
-        </iron-list>
+        </div>
+        <h2 i18n-content="allLanguages"></h2>
+        <div class="list-frame vertical-list">
+          <iron-list items="{{availableLanguages_}}" as="item">
+            <template>
+              <div class="list-item" on-tap="onAddLanguageTap_">
+                <div class="language-name">
+                  <span>[[item.displayName]]</span> -
+                  <span>[[item.nativeDisplayName]]</span>
+                </div>
+                <iron-icon icon="done" hidden$="[[!item.enabled]]">
+                </iron-icon>
+              </div>
+            </template>
+          </iron-list>
+        </div>
       </div>
     </div>
   </template>
diff --git a/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html b/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html
index 47d2419a..8b1b380 100644
--- a/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html
+++ b/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html
@@ -1,7 +1,6 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-dialog/paper-dialog.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-icon-item.html">
 <link rel="import" href="chrome://md-settings/settings_shared_css.html">
 
 <dom-module id="settings-startup-urls-page">
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.html b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.html
index 852f4b1..34ecc8c 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.html
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.html
@@ -3,8 +3,6 @@
 <link rel="import" href="chrome://resources/html/assert.html">
 <link rel="import" href="chrome://resources/html/cr.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item-body.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html">
 <link rel="import" href="chrome://md-settings/passwords_and_forms_page/passwords_section.html">
 <link rel="import" href="chrome://md-settings/settings_shared_css.html">
diff --git a/chrome/browser/resources/settings/people_page/people_page.html b/chrome/browser/resources/settings/people_page/people_page.html
index 547b8a6..848958d 100644
--- a/chrome/browser/resources/settings/people_page/people_page.html
+++ b/chrome/browser/resources/settings/people_page/people_page.html
@@ -43,7 +43,7 @@
           </div>
 <if expr="not chromeos">
           <template is="dom-if" if="[[!syncStatus.signedIn]]">
-            <paper-button class="primary-button" on-tap="onSigninTap_" raised
+            <paper-button class="secondary-button" on-tap="onSigninTap_"
                 disabled="[[syncStatus.setupInProgress]]">
                 [[i18n('syncSignin')]]
             </paper-button>
@@ -74,7 +74,7 @@
         <template is="dom-if"
             if="[[isAdvancedSyncSettingsVisible_(syncStatus)]]">
           <div class="settings-box">
-            <paper-button on-tap="onSyncTap_" raised>
+            <paper-button on-tap="onSyncTap_" class="primary-button">
               [[i18n('syncPageTitle')]]
             </paper-button>
           </div>
@@ -89,7 +89,7 @@
 </if>
 
         <div class="settings-box">
-          <paper-button class="link-button" i18n-content="manageOtherPeople"
+          <paper-button class="primary-button" i18n-content="manageOtherPeople"
               on-tap="onManageOtherPeople_">
           </paper-button>
         </div>
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.css b/chrome/browser/resources/settings/privacy_page/privacy_page.css
index cebdb9a..24b0ceb 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.css
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.css
@@ -2,10 +2,6 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
 
-paper-item {
-  --paper-item-min-height: 24px;
-}
-
 .privacy-buttons {
   margin-top: 25px;
 }
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html
index 41dcf32..2894d39 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -2,8 +2,6 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item-body.html">
 <link rel="import" href="chrome://md-settings/certificate_manager_page/certificate_manager_page.html">
 <link rel="import" href="chrome://md-settings/clear_browsing_data_page/clear_browsing_data_page.html">
 <link rel="import" href="chrome://md-settings/controls/settings_checkbox.html">
@@ -75,7 +73,7 @@
           <div class="start">
             <div i18n-content="manageCertificates"></div>
             <div class="secondary">
-              <!-- TODO(dschuyler) replace this placeholder text -->
+              <!-- TODO(dschuyler): replace this placeholder text -->
               Contrary to popular belief, Lorem Ipsum is not simply random text.
             </div>
           </div>
@@ -84,13 +82,13 @@
           <div class="start">
             <div i18n-content="siteSettings"></div>
             <div class="secondary">
-              <!-- TODO(dschuyler) replace this placeholder text -->
+              <!-- TODO(dschuyler): replace this placeholder text -->
               Contrary to popular belief, Lorem Ipsum is not simply random text.
             </div>
           </div>
         </div>
         <div class="settings-box">
-          <paper-button on-tap="onClearBrowsingDataTap_"
+          <paper-button on-tap="onClearBrowsingDataTap_" class="primary-button"
               i18n-content="clearBrowsingData">
           </paper-button>
         </div>
diff --git a/chrome/browser/resources/settings/search_engines_page/search_engine_entry.css b/chrome/browser/resources/settings/search_engines_page/search_engine_entry.css
index 0a643fe..96995f3 100644
--- a/chrome/browser/resources/settings/search_engines_page/search_engine_entry.css
+++ b/chrome/browser/resources/settings/search_engines_page/search_engine_entry.css
@@ -2,37 +2,34 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
 
+:host([is-default]) {
+  font-weight: 500;
+}
+
 .name-column,
 .keyword-column {
   flex: 3;
 }
 
-.name-column {
-  display: flex;
-}
-
 .url-column {
-  flex: 3.5;
+  flex: 4;
   overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
 }
 
 .icon-container {
-  flex: 1;
-  margin: auto;
-  text-align: center;
+  -webkit-margin-end: 8px;
 }
 
 .name {
-  flex: 3;
   margin: auto;
 }
 
 #container {
   border-top: 1px solid lightgray;
   display: flex;
-  padding: 10px 0;
+  padding: 2px 0;
 }
 
 .dropdown-content {
@@ -43,3 +40,9 @@
 paper-item:hover {
   background-color: #f0f0f0;
 }
+
+paper-icon-button {
+  -webkit-padding-end: 0;
+  padding-bottom: var(--search-engines-list-item-vertical-space);
+  padding-top: var(--search-engines-list-item-vertical-space);
+}
diff --git a/chrome/browser/resources/settings/search_engines_page/search_engine_entry.html b/chrome/browser/resources/settings/search_engines_page/search_engine_entry.html
index 509da503..de03849 100644
--- a/chrome/browser/resources/settings/search_engines_page/search_engine_entry.html
+++ b/chrome/browser/resources/settings/search_engines_page/search_engine_entry.html
@@ -1,9 +1,11 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-dropdown/iron-dropdown.html">
+<link rel="import" href="chrome://md-settings/search_engines_page/search_engine_dialog.html">
 <link rel="import" href="chrome://md-settings/search_engines_page/search_engines_browser_proxy.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-dropdown/iron-dropdown.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item.html">
-<link rel="import" href="chrome://md-settings/search_engines_page/search_engine_dialog.html">
 <link rel="import" href="chrome://md-settings/settings_shared_css.html">
 
 <dom-module id="settings-search-engine-entry">
@@ -17,13 +19,17 @@
     <div id="container" class="list-item">
       <div class="name-column">
         <span class="icon-container">
-          <iron-icon src="[[engine.iconURL]]"></iron-icon>
+          <template is="dom-if" if="[[engine.iconURL]]">
+            <iron-icon src="[[engine.iconURL]]"></iron-icon>
+          </template>
+          <template is="dom-if" if="[[!engine.iconURL]]">
+            <iron-icon icon="icons:find-in-page"></iron-icon>
+          </template>
         </span>
-        <div class="name">[[engine.displayName]]</div>
+        <span class="name">[[engine.displayName]]</span>
       </div>
       <div class="keyword-column">[[engine.keyword]]</div>
       <div class="url-column">[[engine.url]]</div>
-      <div class="icon-container">
         <paper-icon-button icon="more-vert" toggles active="{{editMenuOpened}}">
         </paper-icon-button>
         <iron-dropdown opened="{{editMenuOpened}}" horizontal-align="right"
@@ -39,7 +45,6 @@
                 hidden="[[engine.default]]" id="delete"></paper-item>
           <div>
         </iron-dropdown>
-      </div>
     </div>
   </template>
   <script src="search_engine_entry.js"></script>
diff --git a/chrome/browser/resources/settings/search_engines_page/search_engine_entry.js b/chrome/browser/resources/settings/search_engines_page/search_engine_entry.js
index 9e840ab8..e504676 100644
--- a/chrome/browser/resources/settings/search_engines_page/search_engine_entry.js
+++ b/chrome/browser/resources/settings/search_engines_page/search_engine_entry.js
@@ -18,15 +18,31 @@
 
     /** @private {boolean} */
     showEditSearchEngineDialog_: Boolean,
+
+    /** @type {boolean} */
+    isDefault: {
+      reflectToAttribute: true,
+      type: Boolean,
+      computed: 'computeIsDefault_(engine)'
+    },
   },
 
   /** @private {!settings.SearchEnginesBrowserProxy} */
   browserProxy_: null,
 
+  /** @override */
   created: function() {
     this.browserProxy_ = settings.SearchEnginesBrowserProxyImpl.getInstance();
   },
 
+  /**
+   * @return {boolean}
+   * @private
+   */
+  computeIsDefault_: function() {
+    return this.engine.default;
+  },
+
   /** @private */
   onDeleteTap_: function() {
     this.browserProxy_.removeSearchEngine(this.engine.modelIndex);
diff --git a/chrome/browser/resources/settings/search_engines_page/search_engines_list.css b/chrome/browser/resources/settings/search_engines_page/search_engines_list.css
index 7be65e6..07160f58 100644
--- a/chrome/browser/resources/settings/search_engines_page/search_engines_list.css
+++ b/chrome/browser/resources/settings/search_engines_page/search_engines_list.css
@@ -2,6 +2,10 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
 
+:host {
+  --search-engines-list-item-vertical-space: 8px;
+}
+
 .headers {
   display: flex;
   padding: 10px 0;
@@ -15,3 +19,11 @@
 .headers .url {
   flex: 4.5;
 }
+
+div {
+  margin: 0 40px;
+}
+
+::content [is='action-link'] {
+  margin: var(--search-engines-list-item-vertical-space) 0;
+}
diff --git a/chrome/browser/resources/settings/search_engines_page/search_engines_list.html b/chrome/browser/resources/settings/search_engines_page/search_engines_list.html
index ef46116..22deb0a3 100644
--- a/chrome/browser/resources/settings/search_engines_page/search_engines_list.html
+++ b/chrome/browser/resources/settings/search_engines_page/search_engines_list.html
@@ -1,21 +1,16 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
 <link rel="import" href="chrome://md-settings/search_engines_page/search_engine_entry.html">
 
 <dom-module id="settings-search-engines-list">
   <link rel="import" type="css" href="search_engines_list.css">
   <template>
-      <div class="headers">
-        <div class="name" i18n-content="searchEnginesSearchEngine"></div>
-        <div class="keyword" i18n-content="searchEnginesKeyword"></div>
-        <div class="url" i18n-content="searchEnginesQueryURL"></div>
-      </div>
-      <div>
-        <template is="dom-repeat" items="[[engines]]">
-          <settings-search-engine-entry engine="[[item]]">
-          </settings-search-engine-entry>
-        </template>
-      </div>
+    <div>
+      <content></content>
+      <template is="dom-repeat" items="[[engines]]">
+        <settings-search-engine-entry engine="[[item]]">
+        </settings-search-engine-entry>
+      </template>
+    </div>
   </template>
   <script src="search_engines_list.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/settings/search_engines_page/search_engines_page.html b/chrome/browser/resources/settings/search_engines_page/search_engines_page.html
index 6a0d45c2..ede1419 100644
--- a/chrome/browser/resources/settings/search_engines_page/search_engines_page.html
+++ b/chrome/browser/resources/settings/search_engines_page/search_engines_page.html
@@ -3,47 +3,38 @@
 <link rel="import" href="chrome://resources/html/cr.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
 <link rel="import" href="chrome://md-settings/search_engines_page/search_engines_browser_proxy.html">
 <link rel="import" href="chrome://md-settings/search_engines_page/search_engine_dialog.html">
 <link rel="import" href="chrome://md-settings/search_engines_page/search_engines_list.html">
 <link rel="import" href="chrome://md-settings/settings_shared_css.html">
+<link rel="import" href="chrome://md-settings/web_ui_listener_behavior.html">
+<link rel="import" href="chrome://resources/html/action_link.html">
 
 <dom-module id="settings-search-engines-page">
   <template>
     <style include="settings-shared">
-      .other-label-container {
-        display: flex;
-      }
-
-      .other-label-container span {
-        flex: 1;
+      .label {
+        margin: 20px;
       }
     </style>
-    <div class="settings-box block">
+    <div>
+      <div class="label" i18n-content="searchEnginesDefault"></div>
       <settings-search-engines-list engines="[[defaultEngines]]">
       </settings-search-engines-list>
     </div>
-    <div class="settings-box">
-      <paper-button class="link-button"
-          i18n-content="searchEnginesAddSearchEngine"
-          on-tap="onAddSearchEngineTap_" id="addSearchEngine"></paper-button>
-    </div>
     <template is="dom-if" if="[[showAddSearchEngineDialog_]]" restamp>
       <settings-search-engine-dialog></settings-search-engine-dialog>
     </template>
-    <div class="settings-box block">
-      <div class="other-label-container">
-        <span i18n-content="searchEnginesOther"></span>
-        <cr-expand-button expanded="{{otherSearchEnginesExpanded_}}">
-        </cr-expand-button>
-      </div>
-
-      <iron-collapse id="collapse" opened=[[otherSearchEnginesExpanded_]]>
-        <settings-search-engines-list engines="[[otherEngines]]">
-        </settings-search-engines-list>
-      </iron-collapse>
+    <div>
+      <div class="label" i18n-content="searchEnginesOther"></div>
+      <!-- TODO(dbeam): why does on-click work with keyboard but on-tap
+           doesn't? -->
+      <settings-search-engines-list engines="[[otherEngines]]">
+        <a is="action-link" i18n-content="searchEnginesAddSearchEngine"
+            on-tap="onAddSearchEngineTap_" id="addSearchEngine"></a>
+      </settings-search-engines-list>
     </div>
   </template>
+  <link rel="import" type="css" href="chrome://resources/css/action_link.css">
   <script src="search_engines_page.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/settings/search_engines_page/search_engines_page.js b/chrome/browser/resources/settings/search_engines_page/search_engines_page.js
index 2f58998..f2d9be6 100644
--- a/chrome/browser/resources/settings/search_engines_page/search_engines_page.js
+++ b/chrome/browser/resources/settings/search_engines_page/search_engines_page.js
@@ -12,6 +12,8 @@
 Polymer({
   is: 'settings-search-engines-page',
 
+  behaviors: [settings.WebUIListenerBehavior],
+
   properties: {
     /** @type {!Array<!SearchEngine>} */
     defaultEngines: {
@@ -27,36 +29,14 @@
 
     /** @private {boolean} */
     showAddSearchEngineDialog_: Boolean,
-
-    /** @private {boolean} */
-    otherSearchEnginesExpanded_: {
-      type: Boolean,
-      value: true,
-    },
   },
 
-  /**
-   * Holds WebUI listeners that need to be removed when this element is
-   * destroyed.
-   * TODO(dpapad): Move listener tracking logic to a Polymer behavior class,
-   * such that it can be re-used.
-   * @private {!Array<!WebUIListener>}
-   */
-  webUIListeners_: [],
-
   /** @override */
   ready: function() {
     settings.SearchEnginesBrowserProxyImpl.getInstance().
         getSearchEnginesList().then(this.enginesChanged_.bind(this));
-    this.webUIListeners_.push(cr.addWebUIListener(
-        'search-engines-changed', this.enginesChanged_.bind(this)));
-  },
-
-  /** @override */
-  detached: function() {
-    this.webUIListeners_.forEach(function(listener) {
-      cr.removeWebUIListener(listener);
-    });
+    this.addWebUIListener(
+        'search-engines-changed', this.enginesChanged_.bind(this));
   },
 
   /**
diff --git a/chrome/browser/resources/settings/search_page/search_page.css b/chrome/browser/resources/settings/search_page/search_page.css
index 24b3126f..49ed33b 100644
--- a/chrome/browser/resources/settings/search_page/search_page.css
+++ b/chrome/browser/resources/settings/search_page/search_page.css
@@ -2,10 +2,6 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
 
-paper-button.search-engines-advanced {
-  margin-top: 10px;
-}
-
-#searchEnginesMenu {
+select {
   min-width: 150px;
 }
diff --git a/chrome/browser/resources/settings/search_page/search_page.html b/chrome/browser/resources/settings/search_page/search_page.html
index 395f80b..e4ea2be 100644
--- a/chrome/browser/resources/settings/search_page/search_page.html
+++ b/chrome/browser/resources/settings/search_page/search_page.html
@@ -1,8 +1,8 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
-<link rel="import" href="chrome://md-settings/controls/settings_checkbox.html">
 <link rel="import" href="chrome://md-settings/search_engines_page/search_engines_page.html">
+<link rel="import" href="chrome://md-settings/search_engines_page/search_engines_browser_proxy.html">
 <link rel="import" href="chrome://md-settings/settings_page/settings_animated_pages.html">
 <link rel="import" href="chrome://md-settings/settings_page/settings_subheader.html">
 <link rel="import" href="chrome://md-settings/settings_shared_css.html">
@@ -16,16 +16,17 @@
       <neon-animatable id="main">
         <div class="settings-box first">
           <p class="start" i18n-content="searchExplanation"></p>
-          <select id="searchEnginesMenu"
-                on-change="defaultEngineGuidChanged_">
-            <template is="dom-repeat" items="[[searchEngines]]">
-              <option value="[[item.guid]]">[[item.name]]</option>
+          <select id="searchEnginesMenu" on-change="onDefaultEngineChanged_">
+            <template is="dom-repeat" items="[[searchEngines_]]">
+              <option selected$="[[item.default]]" value="[[item.modelIndex]]">
+                [[item.name]]
+              </option>
             </template>
           </select>
         </div>
         <div class="settings-box">
-          <paper-button class="link-button"
-              i18n-content="searchEnginesManage" on-tap="onSearchEnginesTap_">
+          <paper-button i18n-content="searchEnginesManage"
+              on-tap="onManageSearchEnginesTap_" class="primary-button">
           </paper-button>
         </div>
       </neon-animatable>
diff --git a/chrome/browser/resources/settings/search_page/search_page.js b/chrome/browser/resources/settings/search_page/search_page.js
index 0f8b3cb..fc5fdaa 100644
--- a/chrome/browser/resources/settings/search_page/search_page.js
+++ b/chrome/browser/resources/settings/search_page/search_page.js
@@ -6,13 +6,6 @@
  * @fileoverview
  * 'settings-search-page' is the settings page containing search settings.
  *
- * Example:
- *
- *    <iron-animated-pages>
- *      <settings-search-page prefs="{{prefs}}"></settings-search-page>
- *      ... other pages ...
- *    </iron-animated-pages>
- *
  * @group Chrome Settings Elements
  * @element settings-search-page
  */
@@ -30,56 +23,38 @@
 
     /**
      * List of default search engines available.
-     * @type {?Array<!SearchEngine>}
+     * @private {!Array<!SearchEngine>}
      */
-    searchEngines: {
+    searchEngines_: {
       type: Array,
-      value: function() { return []; },
+      value: function() { return []; }
     },
+
+    /** @private {!settings.SearchEnginesBrowserProxy} */
+    browserProxy_: Object,
   },
 
   /** @override */
   created: function() {
-    chrome.searchEnginesPrivate.onSearchEnginesChanged.addListener(
-        this.updateSearchEngines_.bind(this));
-    chrome.searchEnginesPrivate.getSearchEngines(
-        this.updateSearchEngines_.bind(this));
+    this.browserProxy_ = settings.SearchEnginesBrowserProxyImpl.getInstance();
   },
 
-  /**
-   * Persists the new default search engine back to Chrome. Called when the
-   * user selects a new default in the search engines dropdown.
-   * @private
-   */
-  defaultEngineGuidChanged_: function() {
-    chrome.searchEnginesPrivate.setSelectedSearchEngine(
-        this.$.searchEnginesMenu.value);
-  },
-
-
-  /**
-   * Updates the list of default search engines based on the given |engines|.
-   * @param {!Array<!SearchEngine>} engines All the search engines.
-   * @private
-   */
-  updateSearchEngines_: function(engines) {
-    var defaultEngines = [];
-
-    engines.forEach(function(engine) {
-      if (engine.type ==
-          chrome.searchEnginesPrivate.SearchEngineType.DEFAULT) {
-        defaultEngines.push(engine);
-        if (engine.isSelected) {
-          this.$.searchEnginesMenu.value = engine.guid;
-        }
-      }
-    }, this);
-
-    this.searchEngines = defaultEngines;
+  /** @override */
+  ready: function() {
+    var updateSearchEngines = function(searchEngines) {
+      this.set('searchEngines_', searchEngines.defaults);
+    }.bind(this);
+    this.browserProxy_.getSearchEnginesList().then(updateSearchEngines);
+    cr.addWebUIListener('search-engines-changed', updateSearchEngines);
   },
 
   /** @private */
-  onSearchEnginesTap_: function() {
+  onManageSearchEnginesTap_: function() {
     this.$.pages.setSubpageChain(['search-engines']);
   },
+
+  /** @private */
+  onDefaultEngineChanged_: function() {
+    this.browserProxy_.setDefaultSearchEngine(this.$.searchEnginesMenu.value);
+  },
 });
diff --git a/chrome/browser/resources/settings/settings.html b/chrome/browser/resources/settings/settings.html
index 5741b2d..0f0520a 100644
--- a/chrome/browser/resources/settings/settings.html
+++ b/chrome/browser/resources/settings/settings.html
@@ -10,6 +10,7 @@
   <link rel="import" href="chrome://md-settings/direction_delegate.html">
   <link rel="import" href="chrome://md-settings/settings_ui/settings_ui.html">
   <link rel="import" href="chrome://md-settings/prefs/prefs.html">
+  <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
 </head>
 <body>
 
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index ed795e8..abcd894c 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -545,6 +545,12 @@
                  type="chrome_html"
                  flattenhtml="true"
                  allowexternalscript="true" />
+      <structure name="IDR_SETTINGS_WEB_UI_LISTENER_BEHAVIOR_HTML"
+                 file="web_ui_listener_behavior.html"
+                 type="chrome_html" />
+      <structure name="IDR_SETTINGS_WEB_UI_LISTENER_BEHAVIOR_JS"
+                 file="web_ui_listener_behavior.js"
+                 type="chrome_html" />
       <structure name="IDR_SETTINGS_SEARCH_PAGE_JS"
                  file="search_page/search_page.js"
                  type="chrome_html" />
diff --git a/chrome/browser/resources/settings/settings_shared_css.html b/chrome/browser/resources/settings/settings_shared_css.html
index b2c7411..16a194a1 100644
--- a/chrome/browser/resources/settings/settings_shared_css.html
+++ b/chrome/browser/resources/settings/settings_shared_css.html
@@ -10,12 +10,21 @@
 <dom-module id="settings-shared">
   <template>
     <style>
+      :root {
+        --settings-secondary: {
+          color: #969696;
+          font-weight: 400;
+        }
+      }
+
       h2 {
+        @apply(--layout-center);
         color: var(--paper-grey-500);
+        display: flex;
         font-size: 100%;
-        font-weight: normal;
-        margin-bottom: 20px;
-        margin-top: 30px;
+        font-weight: 500;
+        margin: 0;
+        min-height: 40px;
       }
 
       iron-icon {
@@ -29,7 +38,6 @@
       paper-button {
         margin: 0;
         min-width: auto;
-        padding: 0;
       }
 
       paper-button[toggles][active] {
@@ -40,13 +48,28 @@
         -webkit-margin-start: 4px;
       }
 
+      [is='action-link'],
+      [is='action-link']:active,
+      [is='action-link']:hover,
+      [is='action-link']:visited,
+      paper-button.primary-button {
+        /* TODO(dbeam): change all other colors in this file into --google or
+         * --paper where applicable. */
+        color: var(--google-blue-700);
+      }
+
+      [is='action-link']:hover {
+        /* TODO(dbeam): check with bettes@ on this one, but I'm pretty sure we
+         * shouldn't be showing much :hover stuff on Polymer pages. */
+        text-decoration: none;
+      }
+
       paper-button.primary-button {
         --paper-button: {
-          color: rgb(66, 133, 244);
-          text-align: start;
-          text-transform: none;
           font-weight: 500;
+          text-align: start;
         };
+        margin: 0 -0.57em;  /* Offsets default paper-button padding. */
       }
 
       paper-button.secondary-button {
@@ -60,8 +83,8 @@
       paper-button.tertiary-button {
         --paper-button: {
           color: rgb(51, 103, 214);
-          text-decoration: none;
           font-weight: 400;
+          text-decoration: none;
         };
       }
 
@@ -89,9 +112,9 @@
 
       .list-frame {
         @apply(--layout-center);
-        display: block;
         -webkit-padding-end: 20px;
         -webkit-padding-start: 48px;
+        display: block;
         padding-bottom: 0;
         padding-top: 0;
       }
@@ -101,7 +124,7 @@
       }
 
       .list-frame .secondary {
-        color: #969696;
+        @apply(--settings-secondary);
       }
 
       .list-item {
@@ -147,15 +170,6 @@
         @apply(--layout-center);
         color: rgb(66, 133, 244);
         font-weight: 500;
-        padding: 0;
-        text-decoration: none;
-        text-transform: none;
-      }
-
-      .link-button {
-        color: rgb(61, 130, 243);
-        padding: 6px 0;
-        text-transform: none;
       }
 
       .settings-card {
@@ -189,8 +203,7 @@
       }
 
       .settings-box .secondary {
-        color: #969696;
-        font-weight: 400;
+        @apply(--settings-secondary);
       }
 
       .settings-box .middle {
diff --git a/chrome/browser/resources/settings/web_ui_listener_behavior.html b/chrome/browser/resources/settings/web_ui_listener_behavior.html
new file mode 100644
index 0000000..d021bebc
--- /dev/null
+++ b/chrome/browser/resources/settings/web_ui_listener_behavior.html
@@ -0,0 +1,2 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<script src="web_ui_listener_behavior.js"></script>
diff --git a/chrome/browser/resources/settings/web_ui_listener_behavior.js b/chrome/browser/resources/settings/web_ui_listener_behavior.js
new file mode 100644
index 0000000..b3c44cd
--- /dev/null
+++ b/chrome/browser/resources/settings/web_ui_listener_behavior.js
@@ -0,0 +1,52 @@
+// Copyright 2016 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.
+
+/**
+ * @fileoverview Behavior to be used by Polymer elements that want to
+ * automatically remove WebUI listeners when detached.
+ *
+ * TODO(dpapad): This file can be useful for any WebUI Polymer code, not just
+ * for settings, consider moving elsewhere.
+ */
+
+cr.define('settings', function() {
+  /** @polymerBehavior */
+  var WebUIListenerBehavior = {
+    properties: {
+      /**
+       * Holds WebUI listeners that need to be removed when this element is
+       * destroyed.
+       * @private {!Array<!WebUIListener>}
+       */
+      webUIListeners_: {
+        type: Array,
+        value: function() { return []; },
+      },
+    },
+
+    /**
+     * Adds a WebUI listener and registers it for automatic removal when this
+     * element is detached.
+     * Note: Do not use this method if you intend to remove this listener
+     * manually (use cr.addWebUIListener directly instead).
+     *
+     * @param {string} eventName The event to listen to.
+     * @param {!Function} callback The callback run when the event is fired.
+     */
+    addWebUIListener: function(eventName, callback) {
+      this.webUIListeners_.push(cr.addWebUIListener(eventName, callback));
+    },
+
+    /** @override */
+    detached: function() {
+      while (this.webUIListeners_.length > 0) {
+        cr.removeWebUIListener(this.webUIListeners_.pop());
+      }
+    },
+  };
+
+  return {
+    WebUIListenerBehavior: WebUIListenerBehavior,
+  };
+});
diff --git a/chrome/browser/safe_browsing/client_side_detection_service.cc b/chrome/browser/safe_browsing/client_side_detection_service.cc
index ed37776..1a8dbe4 100644
--- a/chrome/browser/safe_browsing/client_side_detection_service.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_service.cc
@@ -31,7 +31,6 @@
 #include "google_apis/google_api_keys.h"
 #include "net/base/escape.h"
 #include "net/base/load_flags.h"
-#include "net/base/net_util.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_status_code.h"
 #include "net/url_request/url_fetcher.h"
diff --git a/chrome/browser/safe_browsing/incident_reporting/resource_request_detector.cc b/chrome/browser/safe_browsing/incident_reporting/resource_request_detector.cc
index f9ea84c..6ddac354 100644
--- a/chrome/browser/safe_browsing/incident_reporting/resource_request_detector.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/resource_request_detector.cc
@@ -21,207 +21,6 @@
 
 namespace {
 
-const char* const kScriptHashes[] = {
-    "\xdc\xf1\x0b\xb3\x29\x98\xac\x40\x24\x16\x09\x4b\x50\x3c\xe2\xa7"
-    "\x7f\xde\x5f\xdf\x76\x4a\x29\x54\xbc\x49\xd6\x67\x11\x92\x16\xdf",
-    "\x98\x28\x26\x7a\xa9\xc9\x8b\xab\xd6\x64\xe4\xd6\x89\x70\x67\x97"
-    "\x84\x37\x92\x8b\x1b\xa4\xdf\x4f\x49\xc9\x0a\x12\x15\xff\x6e\x91",
-    "\x92\xb7\x39\xf2\xc2\xc0\xa3\xfe\xb7\x14\x06\xa6\xc5\xa8\xed\x62"
-    "\xed\xa9\x74\xc4\x64\x80\xbd\x95\x01\x48\x92\x16\x2b\xff\xc5\x1b",
-    "\x30\xa5\x65\x41\xaf\x60\x9d\x2a\x84\x38\x98\xf0\x41\xa9\x4f\x97"
-    "\xbd\x39\x20\xad\x94\x3a\x0b\x3e\x43\xa4\xe1\x91\x90\x9f\xdf\x25",
-    "\xc0\x30\x87\x8b\x44\xca\x35\xbf\x9c\x94\x48\xac\xcc\xa5\x0e\xb4"
-    "\x1c\x18\x35\x96\x81\x41\xa0\x66\xc5\x08\x4f\x5e\x84\xa0\x2d\x85",
-    "\x5a\x2b\x9b\x45\x81\x5c\x4b\xa5\xf5\x9b\x54\x78\x21\x73\x79\x87"
-    "\x37\xdb\x88\x97\xd9\x76\xd9\x21\x80\xfc\x54\x83\x77\xdb\x17\x7f",
-    "\xf0\xfb\xe6\x43\xa7\xc7\xc4\xda\x58\xee\x74\xf5\x23\x7e\xe5\x77"
-    "\xbf\x66\x80\xd0\x9b\x69\x65\xa5\x30\x8e\x3b\xf9\x7a\xa2\x14\xb1",
-    "\xe8\xb5\xf9\xcf\x7b\xff\xd7\x13\xb9\xd2\xa7\x74\x04\xd9\xbe\x3f"
-    "\xe2\x9f\xd8\x35\x9a\xf6\xa4\x77\x4f\x0d\xe5\x14\x95\x7d\x8c\x1e",
-    "\x90\x22\xa4\x24\x31\xed\x03\x1b\x51\xe5\x87\x11\x0b\xbb\x6c\xec"
-    "\x57\x25\x6c\x4f\xaa\xcc\x03\x98\x73\x0a\x7c\x1c\xc7\x05\x61\xcc",
-    "\xdb\x73\x50\xd3\x58\x50\x2e\xfc\x00\xca\xef\x9d\x68\xf4\xb5\x77"
-    "\x2b\x00\xf9\x7d\xf8\x89\x96\x6e\x35\x22\x17\x35\x4d\xb2\x89\xb3",
-    "\x13\x17\xfb\x42\xda\x54\xe2\x81\x24\x07\x19\xdf\xff\x40\x46\x3b"
-    "\xb6\xa2\xe9\xbe\xfd\x39\xb0\x8b\xf8\xf5\x6a\x3f\xee\xeb\xfa\x3f",
-    "\x28\x5d\xe5\xc5\xa3\xdc\x4a\x33\x25\xc9\xd6\xe6\xa6\xd9\x1e\xcf"
-    "\xa2\x50\x9e\x46\x0c\x40\x45\x2f\xb3\x33\x56\x3e\x82\x6d\x81\x30",
-    "\x7a\xab\xa4\x2e\xf2\xc8\x2c\xa4\xfc\xf0\xea\xb3\xc0\x70\xcd\x81"
-    "\x03\x7b\x46\x34\x2d\x15\xdd\xc3\x81\x97\x3b\x62\xe4\xf3\xcd\xa2",
-    "\x31\x99\x6d\x19\xe3\xa0\x75\x64\x19\x9b\x99\x12\x64\x40\xc9\x66"
-    "\x3e\xa4\x8d\x2f\xbc\x4d\x7b\xbd\x7c\xa7\x7a\xe2\x3f\xc9\xe0\xbc",
-    "\xa9\x18\x65\x4d\xd3\xf5\xdf\x09\xf6\xe7\xfe\x21\x0f\x11\x35\x9a"
-    "\x53\xbf\xb4\xa8\x5e\x23\xb1\x0c\x3c\x64\x94\xf5\x08\x9b\x29\x15",
-    "\x24\x15\x42\x76\x4d\x29\xae\x4e\x1b\x2b\xd5\x8a\xdb\x85\x77\xea"
-    "\xe6\xc4\x21\x26\x83\x17\x3e\x7f\xe1\xf4\xdc\xe8\xd1\xee\x38\xac",
-    "\xd7\x3a\xd9\x8a\x5d\x77\xa5\x3e\x4f\x0f\x7d\x27\xb7\xa2\xae\x73"
-    "\x53\x13\x7f\xd5\xf0\x0c\x5a\x78\xa5\x08\xe9\x55\x3a\x9d\xa4\x93",
-    "\xed\x87\x1b\x13\xda\xb7\x78\x80\x99\x85\x9f\x24\xbb\x73\x98\x94"
-    "\xda\xcb\xad\x2e\x44\x74\x99\x8e\xc9\x0b\x3a\xb0\xc6\x99\xe8\xee",
-    "\xdf\xb0\xe0\x83\xfd\xd1\x3f\x0b\xad\xd6\x08\x9d\x47\x91\x10\xba"
-    "\x59\xdc\x87\xd3\x68\xf1\x5c\xdc\x64\xf9\xdd\xf0\xe8\xd5\xdd\x02",
-    "\xbb\x44\xfe\x76\xeb\x37\x4f\x4e\xd2\x99\x70\x9e\x20\x7f\x08\x30"
-    "\xec\x7b\xe9\x3a\x59\x81\x82\x3e\x45\x01\x41\x8d\xe5\x32\x74\x68",
-    "\x3e\x4c\xf4\x5d\xd6\xb5\x04\x97\x4d\x1b\xe8\xb8\x20\x99\x20\xc2"
-    "\xa4\xf5\xa4\x02\x1d\x71\x2a\xbf\x14\xdd\xad\x23\x7c\xc3\x7f\x1a",
-    "\x11\x21\x0c\x55\xa8\x5d\x31\xbd\x51\x42\xf6\x8b\x4d\xc7\xae\x14"
-    "\x19\x2b\x8b\x04\xb6\xf7\x32\xf8\xa1\x66\x60\x61\xa4\x5d\x10\xd7",
-    "\xca\x39\xfc\x17\x45\xdc\x31\x2e\x69\x88\x16\xfb\x92\x73\x77\x1c"
-    "\xa8\x12\x36\x71\xe2\x87\x61\x39\x4c\x44\x13\x87\x87\x95\x44\xf7",
-    "\xba\xb3\xfe\xa0\xcb\x1a\xcb\x90\xda\x95\x5b\x4c\x0f\x30\xd9\xfb"
-    "\x11\xfb\x87\xd1\x06\xe8\x42\xdb\x5a\x19\x6b\x4a\xb5\x07\xba\xc8",
-    "\x07\x0b\x32\x19\xd0\x57\xfc\x08\xa0\x7a\x82\x3c\x47\xbc\x39\x73"
-    "\x25\x0d\xef\x6c\x74\x8e\x4c\xe6\xea\x82\x21\x6c\x96\x1e\x26\x18",
-    "\x24\x57\x80\x81\x37\xc4\x94\x2c\xac\x8b\x03\x6a\x6e\xe1\x02\x76"
-    "\x7d\x3e\xee\xc7\x8b\x8f\x5e\xd7\xe1\xf8\x67\xdb\xbf\xaa\xed\x47",
-    "\x76\x05\x00\x04\x85\xb5\xd7\xcf\x4e\x77\xdd\x4e\x91\x7e\xb8\xcb"
-    "\x3e\x2d\x3a\x35\xfd\x96\x30\x5f\xba\xfa\x4d\x2d\xf5\x40\xfa\xbb",
-    "\x3b\xb1\x47\xe0\x2d\xeb\x28\x06\x50\x9e\x25\x6c\x5c\x64\xd8\x5f"
-    "\x10\xda\x2a\x3f\x22\x21\x87\x0c\xdb\xf4\x96\xb6\xa4\x48\xb5\x73",
-    "\x4b\xbb\x06\xa9\x2e\x07\xaf\xa4\x6f\x97\x6d\x57\x5a\x80\x65\x4e"
-    "\x60\x7a\x9b\xdb\xca\x70\x14\x56\x03\x9f\x14\x8c\x3e\x29\x76\xd4",
-    "\x1e\x32\xd1\xd0\x85\x92\x67\xac\x8e\xb5\xad\x40\xe7\x13\xb7\x46"
-    "\xde\x62\x33\x27\x20\xdd\xe6\x61\x4b\x11\xfd\x4a\xa7\x50\xf7\xdb",
-    "\x7e\xa2\xa8\x09\xca\x6d\x45\x3d\x51\xbd\x14\x67\xd3\x77\xa3\xbc"
-    "\x16\x91\x71\x9e\x3f\x44\xc8\xfe\x71\xbc\x6f\x09\x6e\x13\x43\xa1",
-    "\x72\x19\xa5\x70\x5b\x07\x61\x30\x6a\x51\xcd\x40\xc4\x65\x1e\x69"
-    "\x91\x59\x15\x7c\x73\x8b\x80\x1a\x2c\x16\x58\x7d\x5e\x04\x42\x80",
-    "\x7b\x57\x48\xde\x08\x7e\x8e\xba\xe9\x61\xa8\xec\xa9\x14\x70\xeb"
-    "\x6f\x70\x3d\xd7\xb7\x73\x4b\x9e\x1c\x01\x80\x39\x64\x6a\x1e\xee",
-    "\x90\xc5\xe8\xff\xcd\xab\xaa\x6f\x0c\xff\x60\x9e\x78\x26\x7d\xcd"
-    "\x82\xb0\x98\x54\x0c\x06\x67\x5e\x86\xb0\xa2\xb4\x1b\xd1\x72\xea",
-    "\x2e\xf3\x04\xd3\x5d\x4b\x58\xc7\x2f\x8b\xb8\xe9\x77\x01\xa8\x78"
-    "\x1b\x4e\xea\x16\xca\x86\xdb\x76\x04\x8e\xc6\x84\x10\x15\x3c\xe6",
-    "\x9e\x46\x07\x4f\xab\x6a\x08\x09\x27\xa8\xcd\xaa\xe8\xef\x6e\xe7"
-    "\x41\xd1\x40\x39\xf5\xa7\xb9\xe7\x9a\xbd\xc4\x03\xa6\x5b\x06\x7c",
-    "\x9d\x89\x41\xc7\xd5\x29\xcf\xde\x9e\xbe\x0a\x59\xaa\x68\xef\x29"
-    "\x66\x76\x79\xc9\x0a\x67\xdc\x59\x2a\x8d\xe4\xf9\x75\x1d\xe9\x3f",
-    "\x4d\x44\x1b\x68\xe8\xd0\xfc\xa3\x89\xec\xf2\x54\xc9\x7b\xbb\x5e"
-    "\x82\x22\x76\x45\x5c\xfd\x78\xf8\x2c\xb4\xd3\x7d\x86\x39\xda\xe3",
-    "\xf7\xa3\xd3\x59\x8e\x62\x81\x4e\x31\xec\x93\xfb\x08\xe9\x1f\x7b"
-    "\x3f\x63\xe1\x64\xde\xb1\x6b\x27\x5c\x41\x89\x9a\x0d\x18\x70\x86",
-    "\x39\x31\x43\x36\x92\xc1\xa9\x94\xee\x68\x71\xd6\x21\x40\x17\xd4"
-    "\xaf\x00\x11\x1d\x29\x1d\x29\x5c\x92\x10\xd2\x6b\xda\x86\x8f\xf1",
-    "\x69\x3d\x88\xf2\x00\xf6\x50\x9a\x30\x68\xf5\xeb\x95\x6c\x33\xa2"
-    "\x5e\xc5\x2c\x06\x08\x97\x36\xf9\xc2\xca\xbc\x4a\x49\xc5\xe4\xc1",
-    "\xd7\x21\xda\xf4\x76\xdb\x69\x70\xa7\xbc\xd0\x20\x67\x0c\x90\x6b"
-    "\x72\xbc\x5a\xc2\x87\x62\xb0\x15\x68\x0b\x48\xbb\xd2\xa0\x3d\x81",
-    "\x21\x34\xb0\x3c\x32\x29\x5b\x73\xf1\xac\xad\x11\x28\x95\xf6\x74"
-    "\xfc\xbd\xf3\xed\x35\xac\xd2\xc9\xe0\x9f\xe4\xd8\x0d\x7c\xc9\x7f",
-    "\x0a\x5a\x1e\x01\xcd\xaa\x2b\xe3\x9a\x59\x9a\xc9\x3e\x47\x9b\xb5"
-    "\x10\xe4\x84\x81\xb6\x1b\x27\xe2\x1d\x0b\x91\x39\xc4\x00\x8b\x7e",
-    "\x3a\x65\x3d\x71\x2d\x3a\xc4\x35\x10\xd7\x01\xb6\xbb\xfb\x49\xda"
-    "\x12\xce\x09\xfd\x48\x45\x76\x64\x12\xff\xd4\x7c\x61\x47\x3c\x0b",
-    // Test data:
-    "\x8b\x2e\x30\xfa\x2e\xe1\xa1\x8e\xb6\x00\xb9\xe3\xc2\xc9\xa4\xad"
-    "\x70\x03\x72\xea\xa8\x68\xdc\x95\x43\x6d\xdf\x40\x26\x58\xde\xe6",
-};
-
-const char* const kDomainHashes[] = {
-    "\x1e\x11\x37\x30\xc2\x8a\xf5\xde\xac\x4c\xf3\x6b\x45\xbf\xc2\x64"
-    "\x86\x73\x44\xad\xb5\x81\xb0\xc8\x54\x58\x6e\x6b\x6f\x92\x50\xc9",
-    "\xac\xc0\x51\x88\x40\xfe\xdd\x9b\x02\x5b\x58\x8a\xe7\x19\x58\xaa"
-    "\x45\xb9\x19\x7e\x8a\xf0\xd0\xa8\x2a\x53\x6e\xc4\x38\x31\xc9\x96",
-    "\x2b\xbe\xdf\x89\x33\x2c\xe4\xc7\xcf\xca\x65\xfb\x91\x1c\x9d\x3a"
-    "\x4e\x51\xbe\x56\xe3\xfa\x2c\x32\x78\x6b\x90\x03\x68\xf4\x3f\xc5",
-    "\x5b\x81\x16\xa0\xce\xa4\x6d\x57\xbd\x38\x7f\xd0\x85\x25\x59\x53"
-    "\xaf\x46\xf8\x24\x44\xde\x6e\x3e\x24\x96\x97\x9a\x7c\x53\xbc\xdf",
-    "\x07\x9e\x8d\xe6\x1e\x5e\xb8\x35\x24\x84\x0f\xd9\x08\x2a\x99\xf3"
-    "\x28\x73\xac\x7b\x67\x01\x33\xa3\x49\xf8\xad\xb7\xef\xc6\xb4\xb8",
-    "\x9e\xb5\x08\x1e\x63\x1a\x76\xb1\x32\x6f\xf1\xf7\xad\x31\xbf\xf8"
-    "\xa1\x65\x4a\x90\x6d\x08\xc5\xb4\xca\xb5\x7a\x83\xc9\xbf\x2f\xcc",
-    "\x8e\xc5\xf8\x8f\x1e\x16\x5a\x6c\x32\x89\x03\xca\x57\xd2\x5b\xda"
-    "\x90\xac\x27\x87\x8d\x31\x0d\x3e\xae\x23\xa9\xfd\x90\x3a\xca\x44",
-    "\xae\xad\x0e\x56\xa8\x15\x77\xfd\x7e\x57\x31\x73\x09\xd0\x64\x17"
-    "\x39\xdb\x81\x5f\x21\x9a\x68\x7c\x93\x31\xd6\x08\x44\x9e\xe0\x8c",
-    "\xe9\x50\x69\xc7\xfe\xd2\x6b\xc6\x07\xd5\x0e\x4d\x66\x0f\xf7\x7e"
-    "\xc8\xdd\xb8\xba\xdd\x77\x24\x50\x22\x4a\xfe\xb0\x17\x6c\x97\x70",
-    "\x2a\xa2\xd3\xaa\x45\x98\xf7\x02\x21\x25\xc0\xe2\x8d\x56\x57\xe5"
-    "\xc5\x50\x63\x86\x1a\x31\xfd\xae\x68\x63\x68\x60\x97\xaf\x70\xb9",
-    "\xb3\xc9\x4e\x79\x0b\x34\xec\x92\xba\x62\x6d\x0a\x1a\xe8\xb8\xed"
-    "\xf6\x32\xb6\x46\xeb\x48\x12\xa2\x7c\x97\x8c\x01\x5f\xab\x00\xf1",
-    "\xb1\x46\x39\xdc\x41\x12\xdf\x27\x41\x20\x0c\x29\x34\xc0\x76\x3f"
-    "\xdc\xfa\x19\x4d\x76\xfe\x7b\xce\x0e\x22\x00\x36\x0d\xc8\xaa\x61",
-    "\xfb\x3a\xc8\xdc\x0e\x89\xa0\x6a\xf5\xe4\x6d\x8b\x47\x05\xdb\x0b"
-    "\x27\xeb\x15\x41\x14\xdc\xbc\xa1\x3a\x63\x10\xc2\xb6\x28\xcd\xc9",
-    "\x98\xa0\x19\x03\x97\x3b\xee\x5b\x7d\x11\xde\xa4\xd2\x07\x58\xa0"
-    "\x5d\x4a\x45\x85\x95\x5d\xd5\x82\x74\x12\x64\xbf\x7a\x3d\x84\x84",
-    "\xc9\x05\x29\x1e\x3f\x37\x68\x4a\xac\x50\x36\x0b\xc8\x31\x4d\x5c"
-    "\xa7\x3b\x3d\x5c\x1b\xeb\xd3\xcc\xbb\x9e\x74\x64\x69\x42\x23\x6c",
-    "\xe9\x68\xe5\x82\xc8\xb6\x78\xc4\xb2\xcc\xfa\xa2\xd2\x6c\x58\x89"
-    "\x59\x41\xee\x98\x25\x64\xd4\x12\x59\x81\x2c\xea\xa6\xd3\x23\xd8",
-    "\x7f\xd8\x3f\x84\x70\xfd\x08\x9b\xe6\x66\x65\x77\x4a\x0e\x20\x25"
-    "\xc9\x9a\xc0\x6c\x12\x82\x00\x08\x4a\x62\xe8\x1c\xa7\xb3\x90\x07",
-    "\xaa\x45\x3b\x66\xab\x46\x95\x21\x92\x5f\x7c\xc3\xab\xa3\x3e\x5e"
-    "\x23\x14\x4a\x50\xfa\x5d\xb8\xf5\x25\x29\x42\x23\x6c\x23\x95\xeb",
-    "\xf9\xcf\x8a\x1c\xc0\x7f\x38\x8d\x20\x5d\xe9\x88\x00\xdf\x6b\xb3"
-    "\xc4\x39\xa4\x4f\x61\x65\x6e\x43\x35\x54\x2c\x15\x50\xc3\xa3\x21",
-    "\xc4\x1b\x1a\x9d\xdd\x18\xd3\xb7\xdd\x2c\x02\x07\xfd\x63\x3b\x53"
-    "\x7b\xe0\x1d\x17\xcf\x15\xc9\x25\xa8\x76\xd1\x41\x9e\x62\x34\x0a",
-    "\xc3\xeb\x5e\x05\x55\x1e\x63\xe9\x6e\xa7\x98\x92\xd7\x3b\x45\xe1"
-    "\x5f\xbc\xc4\xf0\x2f\xb1\x9f\xbf\x4b\x1f\xe5\xdd\xde\x76\x2a\x77",
-    "\xfc\xd4\xa8\x97\x50\x0d\xba\x15\xac\x3c\x2b\x6e\x2b\x79\x93\xcd"
-    "\x18\x1a\xb1\xad\x32\x04\x27\x01\x39\xf7\x6d\x7a\x39\xb5\x92\x35",
-    "\x97\x94\xec\x59\x45\xd8\xfe\xa3\x73\x1f\x03\xe6\xb2\xfc\x2e\xe8"
-    "\xf7\x95\xe3\xaf\x8f\x97\x01\x6f\xef\x6b\x7b\xee\x41\x5e\x27\x7e",
-    "\x75\xc1\x70\x94\x68\xf6\xcc\x07\xb7\xbe\x0b\x84\x0c\x64\xa8\x47"
-    "\x4e\xea\x7f\x75\x3b\xcb\x28\x39\xab\xe5\x14\x8a\xb4\x5a\x38\xb2",
-    "\x94\x48\xfd\x84\x30\xba\x7d\x81\x04\xdc\xbb\x16\xa1\x06\xa9\xe4"
-    "\xb1\xa7\xff\xc5\x13\x22\xed\x4e\x05\xfe\xf9\xb8\x69\xfe\x23\xd4",
-    "\x16\xe6\x9c\xdf\xa2\x18\x13\x60\xe4\x2b\xb3\x07\x29\xa8\xd8\x1b"
-    "\xc5\xa8\xd1\x85\x42\x67\x57\x81\x55\x34\x97\x1d\x8c\xe9\xee\xb7",
-    "\x28\x3f\x74\x64\xb2\x15\xfc\x1b\x75\xcd\x69\x88\x04\x1b\x27\x62"
-    "\xd0\xc2\xdc\xbe\x31\xbe\xb5\x30\xa3\x6e\x01\xdd\x0f\x4e\x31\x2b",
-    "\x75\xc2\x30\x5b\xa3\x9b\xff\x0d\xdc\x75\xdf\x20\x8e\xa1\xe6\x5c"
-    "\x17\xab\xf0\x58\x06\xf3\xda\x9f\xa5\xaa\x98\xfe\x1a\x7e\x74\x2b",
-    "\x3c\xc1\x60\xc5\xd0\x56\x0d\x08\xd5\x19\xbf\x08\x51\x18\x9b\xc8"
-    "\xdd\x8d\x58\x5f\x1d\x75\x88\x14\x73\x8c\xda\x66\x12\x94\x8a\xeb",
-    "\x54\xba\x7d\x21\x4e\x4e\xc2\xf3\x37\x37\x86\xcd\xbe\x7b\x89\x42"
-    "\xa9\x7b\x3b\xec\x69\x49\x6c\x1c\x58\xb8\x4d\xe8\x06\x1c\x88\x37",
-    "\x62\xef\x4d\x5f\xa4\x64\x80\xd6\x97\xd2\xd0\xbd\x31\x30\x03\x5f"
-    "\x22\x37\x8d\x48\xdd\x8a\xb2\xf0\xe3\x57\x35\x98\x37\x70\x32\x25",
-    "\x23\x93\xc0\xa1\xd4\x27\xbd\x64\x65\x86\xe1\xa4\x86\x99\x99\x47"
-    "\x89\xf9\x69\xe2\xba\xce\x7c\x42\xc7\x5d\xbc\xe9\x14\x73\x1c\x8d",
-    "\x10\xe5\x75\x6d\x09\x43\xb3\xca\x0d\x1b\x78\xd1\xc2\x1a\xe5\xc0"
-    "\xd8\x29\x57\x86\x87\xe3\x43\x95\x87\xf6\x92\x83\x5e\x08\x4f\x7a",
-    "\x1c\xf9\xec\x01\x62\xbe\x78\x9b\x0e\x42\x3b\x7e\x70\x47\x27\x46"
-    "\x34\x52\x6e\x45\x1b\x60\x6e\xaf\xcb\x74\x8e\xdd\xbd\xe3\x4f\x5a",
-    "\x62\x02\x40\x4d\x50\xd8\x2a\xd0\x67\xdc\xb5\xc7\xfc\x13\xe9\x66"
-    "\x6a\x14\x33\x7e\xef\xf7\x20\x83\x4c\xf6\x32\xf4\x7a\x75\x32\xa1",
-    "\x35\x89\xab\x5d\xeb\xd5\x4c\x3a\x0f\x34\xeb\x35\x39\x9d\x51\xda"
-    "\x7c\x98\x40\xb7\xd4\xca\x5b\x5e\x3f\x82\x22\xbb\xd6\x56\x42\x78",
-    "\x30\x91\xf8\x24\xa3\xb6\x66\xb0\xc5\xe6\xe0\xfc\xa8\xfc\x2c\x9f"
-    "\x53\x09\x3f\xe5\x4f\x19\xab\xae\x09\xbc\x40\xa9\xd1\x37\x8e\x84",
-    "\xfa\x5a\x2f\xf0\xb0\x3e\x81\xbb\x7b\x4b\xc0\xf0\x67\xf1\xbe\x9d"
-    "\x86\x87\x51\xe6\x72\x34\x70\x02\xc2\xec\xb5\x66\xe7\xd1\x4d\x55",
-    "\x10\x24\x54\x8f\xe4\x06\x49\x6b\x0f\xcf\x95\x5c\xf9\xa6\xdc\xa9"
-    "\xc0\x7d\xda\xda\x78\x21\x57\x40\xdb\xb3\x54\x5f\x3b\x53\x48\xee",
-    "\xf7\xf2\x47\x19\x6e\x7d\x14\x08\x4b\xf3\x6f\x5c\x40\x19\x11\x54"
-    "\x68\xa5\x0d\xde\x6e\xba\x5e\x1b\x34\x04\x72\x41\x55\x31\xb1\x18",
-    "\xb6\xfa\x48\xa8\xd7\x20\xde\x56\x8c\x90\x81\xac\xaf\xd8\xf2\xe6"
-    "\xab\x56\xbb\x64\x1e\xbc\x93\x56\x3f\xce\xac\xd9\xa7\x4d\xa8\x40",
-    "\xfb\x8b\x14\x2e\xa8\x6a\x77\xaf\x7c\x13\x8a\x38\x6b\xd9\xf1\xc8"
-    "\x87\x63\x8d\x00\xe4\xac\xf2\x11\x4a\x1f\x39\x57\x1f\xa6\xca\xdf",
-    "\xba\xad\xe8\xdb\x70\x80\x8d\xbd\x3c\xc7\x6b\xd6\x02\x6a\x41\x40"
-    "\x62\x45\x7b\x18\x65\x94\xf3\x56\xc5\x24\x1e\xcb\x81\x8d\x45\x09",
-    "\x8f\xd5\xf8\xd3\x29\x82\x94\x51\xa8\xe6\x3a\x9d\x3a\xc7\x51\xe1"
-    "\xd3\x54\x32\xcb\x2c\x20\x98\x5a\x70\x04\x18\xfd\x49\x75\x85\x6e",
-    "\x90\x73\x6e\x8e\xe9\x75\xdf\xc6\x7e\xe7\x00\xe4\x4d\xc7\x0f\x04"
-    "\xe6\x58\x78\xa3\xbc\x98\x22\xb9\x38\xe0\xf0\x67\xe2\xa9\x8e\x1f",
-    "\x99\x3b\x39\x8e\x69\x7f\x28\xfd\x09\x8d\xc9\xed\xf9\x57\x0e\x41"
-    "\x1b\x41\x48\x40\x37\xf4\x77\xd3\x07\xbd\x82\xc6\xda\x16\xa8\xec",
-    "\x6d\x57\xf2\xd8\xf9\x6a\x82\x76\x1d\xb6\x8a\xe8\xb6\x3a\xcc\xd4"
-    "\x30\x59\xdd\xa6\x18\x64\xac\xd9\x83\x80\x7c\x75\x7a\xdf\x20\xfe",
-    "\x33\x5a\x23\xb0\xde\xd3\x7f\xc2\x96\xb7\x2e\xd4\x8a\xdc\x65\x0e"
-    "\xe6\x95\x6b\x41\xf0\xfe\xa0\xdf\xdf\x28\x73\xce\x6e\x1d\x79\x2d",
-    "\x13\xe3\xbc\x23\xb3\xf2\x10\x76\x10\xe8\x83\x8b\x83\xf0\x5e\x8d"
-    "\x4a\x8e\xf3\x98\x4d\x05\x03\x53\x69\xe0\xc0\x21\x9f\x69\x3f\x77",
-    "\xba\x88\x57\x60\x31\x4c\xd9\x6b\x21\x3e\xa3\x88\xe7\x45\x6c\x41"
-    "\x91\x66\xf2\x08\xd0\x89\xe6\x39\x68\x6c\xb8\x7a\xd7\x7d\x9f\x76",
-    "\xcd\xd5\x93\x5a\xe2\xdb\xf3\x63\xeb\xfd\xd0\x88\x49\x7d\xf6\x29"
-    "\xbf\x1f\xee\x3a\xda\xa1\x95\x38\x4d\xc3\x91\x21\xce\x01\xd1\x8d",
-};
-
 Profile* GetProfileForRenderProcessId(int render_process_id) {
   // How to get a profile from a RenderProcess id:
   // 1) Get the RenderProcessHost
@@ -251,12 +50,82 @@
 
 namespace safe_browsing {
 
+namespace {
+
+// Implementation of SafeBrowsingDatabaseManager::Client that is used to lookup
+// a resource blacklist. Can be constructed on any thread.
+class ResourceRequestDetectorClient
+    : public SafeBrowsingDatabaseManager::Client,
+      public base::RefCountedThreadSafe<ResourceRequestDetectorClient> {
+ public:
+  using ResourceRequestIncidentMessage =
+      ClientIncidentReport::IncidentData::ResourceRequestIncident;
+
+  typedef base::Callback<void(scoped_ptr<ResourceRequestIncidentMessage>)>
+      OnResultCallback;
+
+  ResourceRequestDetectorClient(
+      const GURL& resource_url,
+      const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager,
+      const OnResultCallback& callback)
+      : database_manager_(database_manager)
+      , callback_(callback) {
+    content::BrowserThread::PostTask(
+        content::BrowserThread::IO, FROM_HERE,
+        base::Bind(&ResourceRequestDetectorClient::StartCheck, this,
+                   resource_url));
+  }
+
+ private:
+  friend class base::RefCountedThreadSafe<ResourceRequestDetectorClient>;
+  ~ResourceRequestDetectorClient() override {}
+
+  void StartCheck(const GURL& resource_url) {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+    if (!database_manager_)
+      return;
+
+    AddRef();
+    // If database_manager_->CheckResourceUrl returns false, the resource might
+    // be blacklisted and the response will come in OnCheckResourceUrlResult
+    // callback, where AddRef() is balanced by Release().
+    // If the check returns true, the resource is not blacklisted and the
+    // client object may be destroyed immediately.
+    if (database_manager_->CheckResourceUrl(resource_url, this)) {
+      Release();
+    }
+  }
+
+  void OnCheckResourceUrlResult(const GURL& url,
+                                SBThreatType threat_type,
+                                const std::string& threat_hash) override {
+    if (threat_type == SB_THREAT_TYPE_BLACKLISTED_RESOURCE) {
+      scoped_ptr<ResourceRequestIncidentMessage> incident_data(
+          new ResourceRequestIncidentMessage());
+      incident_data->set_type(ResourceRequestIncidentMessage::TYPE_PATTERN);
+      incident_data->set_digest(threat_hash);
+      content::BrowserThread::PostTask(
+          content::BrowserThread::UI, FROM_HERE,
+          base::Bind(callback_, base::Passed(&incident_data)));
+    }
+    Release();  // Balanced in StartCheck.
+  }
+
+  scoped_refptr<SafeBrowsingDatabaseManager> database_manager_;
+  OnResultCallback callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(ResourceRequestDetectorClient);
+};
+
+}  // namespace
+
 ResourceRequestDetector::ResourceRequestDetector(
+    scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
     scoped_ptr<IncidentReceiver> incident_receiver)
     : incident_receiver_(std::move(incident_receiver)),
+      database_manager_(database_manager),
       allow_null_profile_for_testing_(false),
       weak_ptr_factory_(this) {
-  InitializeHashSets();
 }
 
 ResourceRequestDetector::~ResourceRequestDetector() {
@@ -268,85 +137,18 @@
   if (!request->url().SchemeIsHTTPOrHTTPS())
     return;
 
-  DetectDomainRequests(request);
-  DetectScriptRequests(request);
-}
-
-void ResourceRequestDetector::DetectDomainRequests(
-    const net::URLRequest* request) {
   const content::ResourceRequestInfo* request_info =
       content::ResourceRequestInfo::ForRequest(request);
-
-  // Only detect non top-level requests.
-  if (request_info->GetResourceType() == content::RESOURCE_TYPE_MAIN_FRAME)
-    return;
-
-  std::string domain_digest(crypto::kSHA256Length, '\0');
-  crypto::SHA256HashString(request->url().host(), &domain_digest[0],
-                           crypto::kSHA256Length);
-
-  if (domain_set_.count(domain_digest)) {
-    DVLOG(1) << "Domain detector match found.";
-
-    scoped_ptr<ClientIncidentReport_IncidentData_ResourceRequestIncident>
-        incident_data(
-            new ClientIncidentReport_IncidentData_ResourceRequestIncident());
-    incident_data->set_type(
-        ClientIncidentReport_IncidentData_ResourceRequestIncident::TYPE_DOMAIN);
-    incident_data->set_digest(domain_digest);
-
-    // This next bit of work needs a profile, so has to happen on the UI
-    // thread.
-    int render_process_id = 0;
-    int render_frame_id = 0;
+  if (request_info->GetResourceType() != content::RESOURCE_TYPE_MAIN_FRAME) {
+    int render_process_id;
+    int render_frame_id;
     content::ResourceRequestInfo::GetRenderFrameForRequest(
         request, &render_process_id, &render_frame_id);
-
-    content::BrowserThread::PostTask(
-        content::BrowserThread::UI, FROM_HERE,
+    new ResourceRequestDetectorClient(
+        request->url(), database_manager_,
         base::Bind(&ResourceRequestDetector::ReportIncidentOnUIThread,
-                   weak_ptr_factory_.GetWeakPtr(), render_process_id,
-                   render_frame_id, base::Passed(&incident_data)));
-  }
-}
-
-void ResourceRequestDetector::DetectScriptRequests(
-    const net::URLRequest* request) {
-  const content::ResourceRequestInfo* request_info =
-      content::ResourceRequestInfo::ForRequest(request);
-
-  if (request_info->GetResourceType() != content::RESOURCE_TYPE_SCRIPT)
-    return;
-
-  DVLOG(1) << "Script request: " << request->url().spec();
-
-  std::string url(request->url().host() + request->url().path());
-  std::string script_digest(crypto::kSHA256Length, '\0');
-  crypto::SHA256HashString(url, &script_digest[0],
-                           crypto::kSHA256Length);
-
-  if (script_set_.count(script_digest)) {
-    DVLOG(1) << "Script detector match found.";
-
-    scoped_ptr<ClientIncidentReport_IncidentData_ResourceRequestIncident>
-        incident_data(
-            new ClientIncidentReport_IncidentData_ResourceRequestIncident());
-    incident_data->set_type(
-        ClientIncidentReport_IncidentData_ResourceRequestIncident::TYPE_SCRIPT);
-    incident_data->set_digest(script_digest);
-
-    // This next bit of work needs a profile, so has to happen on the UI
-    // thread.
-    int render_process_id = 0;
-    int render_frame_id = 0;
-    content::ResourceRequestInfo::GetRenderFrameForRequest(
-        request, &render_process_id, &render_frame_id);
-
-    content::BrowserThread::PostTask(
-        content::BrowserThread::UI, FROM_HERE,
-        base::Bind(&ResourceRequestDetector::ReportIncidentOnUIThread,
-                   weak_ptr_factory_.GetWeakPtr(), render_process_id,
-                   render_frame_id, base::Passed(&incident_data)));
+                  weak_ptr_factory_.GetWeakPtr(), render_process_id,
+                  render_frame_id));
   }
 }
 
@@ -355,16 +157,6 @@
   allow_null_profile_for_testing_ = allow_null_profile_for_testing;
 }
 
-void ResourceRequestDetector::InitializeHashSets() {
-  // Store a hashed set of decoded string hashes. Probably slower than a linear
-  // search for this size list, but this is only temporary.
-  for (const char* encoded_hash : kScriptHashes)
-    script_set_.insert(std::string(encoded_hash, crypto::kSHA256Length));
-
-  for (const char* encoded_hash : kDomainHashes)
-    domain_set_.insert(std::string(encoded_hash, crypto::kSHA256Length));
-}
-
 void ResourceRequestDetector::ReportIncidentOnUIThread(
     int render_process_id,
     int render_frame_id,
diff --git a/chrome/browser/safe_browsing/incident_reporting/resource_request_detector.h b/chrome/browser/safe_browsing/incident_reporting/resource_request_detector.h
index 6d3b5348..99de878 100644
--- a/chrome/browser/safe_browsing/incident_reporting/resource_request_detector.h
+++ b/chrome/browser/safe_browsing/incident_reporting/resource_request_detector.h
@@ -10,6 +10,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/safe_browsing/incident_reporting/incident_receiver.h"
+#include "components/safe_browsing_db/database_manager.h"
 
 namespace net {
 class URLRequest;
@@ -17,12 +18,15 @@
 
 namespace safe_browsing {
 
+class SafeBrowsingService;
+
 class ClientIncidentReport_IncidentData_ResourceRequestIncident;
 
 // Observes network requests and reports suspicious activity.
 class ResourceRequestDetector {
  public:
-  explicit ResourceRequestDetector(
+  ResourceRequestDetector(
+      scoped_refptr<SafeBrowsingDatabaseManager> sb_database_manager,
       scoped_ptr<IncidentReceiver> incident_receiver);
   ~ResourceRequestDetector();
 
@@ -35,11 +39,6 @@
   void set_allow_null_profile_for_testing(bool allow_null_profile_for_testing);
 
  private:
-  void InitializeHashSets();
-
-  void DetectDomainRequests(const net::URLRequest* request);
-  void DetectScriptRequests(const net::URLRequest* request);
-
   void ReportIncidentOnUIThread(
       int render_process_id,
       int render_frame_id,
@@ -47,6 +46,7 @@
           incident_data);
 
   scoped_ptr<IncidentReceiver> incident_receiver_;
+  scoped_refptr<SafeBrowsingDatabaseManager> database_manager_;
   base::hash_set<std::string> script_set_;
   base::hash_set<std::string> domain_set_;
   bool allow_null_profile_for_testing_;
diff --git a/chrome/browser/safe_browsing/incident_reporting/resource_request_detector_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/resource_request_detector_unittest.cc
index 6d6c52bf..3a75280 100644
--- a/chrome/browser/safe_browsing/incident_reporting/resource_request_detector_unittest.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/resource_request_detector_unittest.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/safe_browsing/incident_reporting/incident_receiver.h"
 #include "chrome/browser/safe_browsing/incident_reporting/mock_incident_receiver.h"
 #include "chrome/common/safe_browsing/csd.pb.h"
+#include "components/safe_browsing_db/test_database_manager.h"
 #include "content/public/browser/resource_request_info.h"
 #include "content/public/common/resource_type.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -25,42 +26,60 @@
 #include "url/gurl.h"
 
 using ::testing::IsNull;
+using ::testing::Return;
 using ::testing::StrictMock;
 using ::testing::WithArg;
 using ::testing::_;
 
-namespace {
-const char kScriptMatchingTestUrl[] = "http://example.com/foo/bar/baz.js";
-const char kScriptMatchingTestUrlParams[] =
-    "http://example.com/foo/bar/baz.js#abc?foo=bar";
-const char kScriptNonMatchingTestUrl[] =
-    "http://example.com/nonmatching/bar/baz.js";
-
-const char kDomainMatchingTestUrl[] =
-    "http://example892904760932459706783457.com/some/request";
-const char kDomainMatchingTestUrlScript[] =
-    "http://example892904760932459706783457.com/path/to/script.js";
-const char kDomainNonMatchingTestUrl[] =
-    "http://example892904760932459706783458.com/some/request";
-}  // namespace
-
 namespace safe_browsing {
 
+namespace {
+
 class FakeResourceRequestDetector : public ResourceRequestDetector {
  public:
-  explicit FakeResourceRequestDetector(
+  FakeResourceRequestDetector(
+      scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
       scoped_ptr<IncidentReceiver> incident_receiver)
-      : ResourceRequestDetector(std::move(incident_receiver)) {
+      : ResourceRequestDetector(database_manager,
+                                std::move(incident_receiver)) {
     FakeResourceRequestDetector::set_allow_null_profile_for_testing(true);
   }
 };
 
+class MockSafeBrowsingDatabaseManager : public TestSafeBrowsingDatabaseManager {
+ public:
+  MockSafeBrowsingDatabaseManager() {}
+
+  MOCK_METHOD2(CheckResourceUrl, bool(
+      const GURL& url,
+      SafeBrowsingDatabaseManager::Client* client));
+
+ protected:
+  ~MockSafeBrowsingDatabaseManager() override {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingDatabaseManager);
+};
+
+}  // namespace
+
+ACTION_P3(CallClientWithResult, url, threat_type, threat_hash) {
+  arg1->OnCheckResourceUrlResult(url, threat_type, threat_hash);
+  return false;
+}
+
 class ResourceRequestDetectorTest : public testing::Test {
  protected:
+  using ResourceRequestIncidentMessage =
+      ClientIncidentReport::IncidentData::ResourceRequestIncident;
+
   ResourceRequestDetectorTest()
       : mock_incident_receiver_(
             new StrictMock<safe_browsing::MockIncidentReceiver>()),
+        mock_database_manager_(
+            new StrictMock<MockSafeBrowsingDatabaseManager>),
         fake_resource_request_detector_(
+            mock_database_manager_,
             make_scoped_ptr(mock_incident_receiver_)) {}
 
   scoped_ptr<net::URLRequest> GetTestURLRequest(
@@ -84,6 +103,27 @@
     return url_request;
   }
 
+  void ExpectNoDatabaseCheck() {
+    EXPECT_CALL(*mock_database_manager_, CheckResourceUrl(_, _))
+        .Times(0);
+  }
+
+  void ExpectNegativeSyncDatabaseCheck(const std::string& url) {
+    EXPECT_CALL(*mock_database_manager_, CheckResourceUrl(GURL(url), _))
+        .WillOnce(Return(true));
+  }
+
+  void ExpectAsyncDatabaseCheck(const std::string& url,
+                                bool is_blacklisted,
+                                const std::string& digest) {
+    SBThreatType threat_type = is_blacklisted
+        ? SB_THREAT_TYPE_BLACKLISTED_RESOURCE
+        : SB_THREAT_TYPE_SAFE;
+    const GURL gurl(url);
+    EXPECT_CALL(*mock_database_manager_, CheckResourceUrl(gurl, _))
+        .WillOnce(CallClientWithResult(gurl, threat_type, digest));
+  }
+
   void ExpectNoIncident(const std::string& url,
                         content::ResourceType resource_type) {
     scoped_ptr<net::URLRequest> request(GetTestURLRequest(url, resource_type));
@@ -98,8 +138,8 @@
   void ExpectIncidentAdded(
       const std::string& url,
       content::ResourceType resource_type,
-      ClientIncidentReport_IncidentData_ResourceRequestIncident_Type
-          expected_type) {
+      ResourceRequestIncidentMessage::Type expected_type,
+      const std::string& expected_digest) {
     scoped_ptr<net::URLRequest> request(GetTestURLRequest(url, resource_type));
     scoped_ptr<Incident> incident;
     EXPECT_CALL(*mock_incident_receiver_, DoAddIncidentForProfile(IsNull(), _))
@@ -108,16 +148,19 @@
     fake_resource_request_detector_.OnResourceRequest(request.get());
     base::RunLoop().RunUntilIdle();
 
+    ASSERT_TRUE(incident);
     scoped_ptr<ClientIncidentReport_IncidentData> incident_data =
         incident->TakePayload();
-    ASSERT_TRUE(incident_data->has_resource_request());
-    const ClientIncidentReport_IncidentData_ResourceRequestIncident&
-        script_request_incident = incident_data->resource_request();
+    ASSERT_TRUE(incident_data && incident_data->has_resource_request());
+    const ResourceRequestIncidentMessage& script_request_incident =
+        incident_data->resource_request();
     EXPECT_TRUE(script_request_incident.has_digest());
-    EXPECT_TRUE(script_request_incident.type() == expected_type);
+    EXPECT_EQ(expected_digest, script_request_incident.digest());
+    EXPECT_EQ(expected_type, script_request_incident.type());
   }
 
   StrictMock<safe_browsing::MockIncidentReceiver>* mock_incident_receiver_;
+  scoped_refptr<MockSafeBrowsingDatabaseManager> mock_database_manager_;
   FakeResourceRequestDetector fake_resource_request_detector_;
 
  private:
@@ -126,48 +169,58 @@
   net::TestURLRequestContext context_;
 };
 
-// Script request tests
-
-TEST_F(ResourceRequestDetectorTest, NoEventForIgnoredResourceTypes) {
-  ExpectNoIncident(kScriptNonMatchingTestUrl, content::RESOURCE_TYPE_IMAGE);
+TEST_F(ResourceRequestDetectorTest, NoDbCheckForIgnoredResourceTypes) {
+  ExpectNoDatabaseCheck();
+  ExpectNoIncident(
+      "http://www.example.com/index.html", content::RESOURCE_TYPE_MAIN_FRAME);
 }
 
-TEST_F(ResourceRequestDetectorTest, NoEventForNonMatchingScript) {
-  ExpectNoIncident(kScriptNonMatchingTestUrl, content::RESOURCE_TYPE_SCRIPT);
+TEST_F(ResourceRequestDetectorTest, NoDbCheckForUnsupportedSchemes) {
+  ExpectNoDatabaseCheck();
+  ExpectNoIncident(
+      "file:///usr/local/script.js", content::RESOURCE_TYPE_SCRIPT);
+  ExpectNoIncident(
+      "chrome-extension://abcdefghi/script.js", content::RESOURCE_TYPE_SCRIPT);
 }
 
-TEST_F(ResourceRequestDetectorTest, EventForBaseMatchingScript) {
-  ExpectIncidentAdded(
-      kScriptMatchingTestUrl, content::RESOURCE_TYPE_SCRIPT,
-      ClientIncidentReport_IncidentData_ResourceRequestIncident::TYPE_SCRIPT);
+TEST_F(ResourceRequestDetectorTest, NoEventForNegativeSynchronousDbCheck) {
+  const std::string url = "http://www.example.com/script.js";
+  ExpectNegativeSyncDatabaseCheck(url);
+  ExpectNoIncident(url, content::RESOURCE_TYPE_SCRIPT);
 }
 
-TEST_F(ResourceRequestDetectorTest, EventForMatchingScriptWithParams) {
-  ExpectIncidentAdded(
-      kScriptMatchingTestUrlParams, content::RESOURCE_TYPE_SCRIPT,
-      ClientIncidentReport_IncidentData_ResourceRequestIncident::TYPE_SCRIPT);
+TEST_F(ResourceRequestDetectorTest, NoEventForNegativeAsynchronousDbCheck) {
+  const std::string url = "http://www.example.com/script.js";
+  ExpectAsyncDatabaseCheck(url, false, "");
+  ExpectNoIncident(url, content::RESOURCE_TYPE_SCRIPT);
 }
 
-// Domain request tests
+TEST_F(ResourceRequestDetectorTest, EventAddedForSupportedSchemes) {
+  std::string schemes[] = {"http", "https"};
+  const std::string digest = "dummydigest";
+  const std::string domain_path = "www.example.com/script.js";
 
-TEST_F(ResourceRequestDetectorTest, NoEventForNonMatchingDomainSubFrame) {
-  ExpectNoIncident(kDomainNonMatchingTestUrl, content::RESOURCE_TYPE_SUB_FRAME);
+  for (const auto& scheme : schemes) {
+    const std::string url = scheme + "://" + domain_path;
+    ExpectAsyncDatabaseCheck(url, true, digest);
+    ExpectIncidentAdded(
+        url, content::RESOURCE_TYPE_SCRIPT,
+        ResourceRequestIncidentMessage::TYPE_PATTERN, digest);
+  }
 }
 
-TEST_F(ResourceRequestDetectorTest, NoEventForMatchingDomainTopLevel) {
-  ExpectNoIncident(kDomainMatchingTestUrl, content::RESOURCE_TYPE_MAIN_FRAME);
-}
-
-TEST_F(ResourceRequestDetectorTest, EventForMatchingDomainSubFrame) {
-  ExpectIncidentAdded(
-      kDomainMatchingTestUrl, content::RESOURCE_TYPE_SUB_FRAME,
-      ClientIncidentReport_IncidentData_ResourceRequestIncident::TYPE_DOMAIN);
-}
-
-TEST_F(ResourceRequestDetectorTest, EventForMatchingDomainScript) {
-  ExpectIncidentAdded(
-      kDomainMatchingTestUrlScript, content::RESOURCE_TYPE_SCRIPT,
-      ClientIncidentReport_IncidentData_ResourceRequestIncident::TYPE_DOMAIN);
+TEST_F(ResourceRequestDetectorTest, EventAddedForSupportedResourceTypes) {
+  content::ResourceType supported_types[] = {
+    content::RESOURCE_TYPE_IMAGE, content::RESOURCE_TYPE_SCRIPT,
+    content::RESOURCE_TYPE_SUB_FRAME,
+  };
+  const std::string url = "http://www.example.com/";
+  const std::string digest = "dummydigest";
+  for (auto resource_type : supported_types) {
+    ExpectAsyncDatabaseCheck(url, true, digest);
+    ExpectIncidentAdded(url, resource_type,
+                        ResourceRequestIncidentMessage::TYPE_PATTERN, digest);
+  }
 }
 
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/incident_reporting/resource_request_incident.cc b/chrome/browser/safe_browsing/incident_reporting/resource_request_incident.cc
index 03b80fa1..997055d1 100644
--- a/chrome/browser/safe_browsing/incident_reporting/resource_request_incident.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/resource_request_incident.cc
@@ -26,14 +26,9 @@
 }
 
 std::string ResourceRequestIncident::GetKey() const {
-  // Use a static key per resource request type in addition to a fixed digest
-  // below to ensure that only one incident per user (and incident type) is
-  // reported.
-  return payload()->resource_request().type() ==
-                 ClientIncidentReport_IncidentData_ResourceRequestIncident::
-                     TYPE_SCRIPT
-             ? "script_request_incident"
-             : "domain_request_incident";
+  // Use a static key in addition to a fixed digest below to ensure that only
+  // one incident per user is reported.
+  return "resource_request_incident";
 }
 
 uint32_t ResourceRequestIncident::ComputeDigest() const {
diff --git a/chrome/browser/safe_browsing/local_database_manager.cc b/chrome/browser/safe_browsing/local_database_manager.cc
index 0787f804..11a32ca 100644
--- a/chrome/browser/safe_browsing/local_database_manager.cc
+++ b/chrome/browser/safe_browsing/local_database_manager.cc
@@ -37,6 +37,7 @@
 #include "components/safe_browsing_db/v4_get_hash_protocol_manager.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_service.h"
+#include "net/url_request/url_request_context_getter.h"
 #include "url/url_constants.h"
 
 using content::BrowserThread;
@@ -271,16 +272,8 @@
 }
 
 LocalSafeBrowsingDatabaseManager::LocalSafeBrowsingDatabaseManager(
-    const scoped_refptr<SafeBrowsingService>& service) :
-    LocalSafeBrowsingDatabaseManager(service, NULL, V4ProtocolConfig()) {
-}
-
-LocalSafeBrowsingDatabaseManager::LocalSafeBrowsingDatabaseManager(
-    const scoped_refptr<SafeBrowsingService>& service,
-    net::URLRequestContextGetter* request_context_getter,
-    const V4ProtocolConfig& config)
-    : SafeBrowsingDatabaseManager(request_context_getter, config),
-      sb_service_(service),
+    const scoped_refptr<SafeBrowsingService>& service)
+    : sb_service_(service),
       database_(NULL),
       enabled_(false),
       enable_download_protection_(false),
@@ -703,8 +696,12 @@
       base::Bind(&LocalSafeBrowsingDatabaseManager::OnResetDatabase, this));
 }
 
-void LocalSafeBrowsingDatabaseManager::StartOnIOThread() {
+void LocalSafeBrowsingDatabaseManager::StartOnIOThread(
+    net::URLRequestContextGetter* request_context_getter,
+    const V4ProtocolConfig& config) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  SafeBrowsingDatabaseManager::StartOnIOThread(request_context_getter, config);
+
   if (enabled_)
     return;
 
@@ -725,6 +722,7 @@
 
 void LocalSafeBrowsingDatabaseManager::StopOnIOThread(bool shutdown) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  SafeBrowsingDatabaseManager::StopOnIOThread(shutdown);
 
   DoStopOnIOThread();
   if (shutdown) {
diff --git a/chrome/browser/safe_browsing/local_database_manager.h b/chrome/browser/safe_browsing/local_database_manager.h
index 0949d19..4c9427aa 100644
--- a/chrome/browser/safe_browsing/local_database_manager.h
+++ b/chrome/browser/safe_browsing/local_database_manager.h
@@ -101,15 +101,9 @@
     DISALLOW_COPY_AND_ASSIGN(SafeBrowsingCheck);
   };
 
-  // Use this constructor for testing only.
-  explicit LocalSafeBrowsingDatabaseManager(
-      const scoped_refptr<SafeBrowsingService>& service);
-
   // Creates the safe browsing service.  Need to initialize before using.
   LocalSafeBrowsingDatabaseManager(
-      const scoped_refptr<SafeBrowsingService>& service,
-      net::URLRequestContextGetter* request_context_getter,
-      const V4ProtocolConfig& config);
+      const scoped_refptr<SafeBrowsingService>& service);
 
   //
   // SafeBrowsingDatabaseManager overrides
@@ -136,7 +130,9 @@
   bool IsMalwareKillSwitchOn() override;
   bool IsCsdWhitelistKillSwitchOn() override;
   void CancelCheck(Client* client) override;
-  void StartOnIOThread() override;
+  void StartOnIOThread(
+      net::URLRequestContextGetter* request_context_getter,
+      const V4ProtocolConfig& config) override;
   void StopOnIOThread(bool shutdown) override;
   bool download_protection_enabled() const override;
 
@@ -157,11 +153,10 @@
   friend class SafeBrowsingServerTest;
   friend class SafeBrowsingServiceTest;
   friend class SafeBrowsingServiceTestHelper;
-  // TODO(nparker): Rename this test to LocalSafeBrowsingDatabaseManagerTest
-  friend class SafeBrowsingDatabaseManagerTest;
-  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingDatabaseManagerTest,
+  friend class LocalDatabaseManagerTest;
+  FRIEND_TEST_ALL_PREFIXES(LocalDatabaseManagerTest,
                            GetUrlSeverestThreatType);
-  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingDatabaseManagerTest,
+  FRIEND_TEST_ALL_PREFIXES(LocalDatabaseManagerTest,
                            ServiceStopWithPendingChecks);
 
   typedef std::set<SafeBrowsingCheck*> CurrentChecks;
diff --git a/chrome/browser/safe_browsing/local_database_manager_unittest.cc b/chrome/browser/safe_browsing/local_database_manager_unittest.cc
index 96f3236..2ce3c3c 100644
--- a/chrome/browser/safe_browsing/local_database_manager_unittest.cc
+++ b/chrome/browser/safe_browsing/local_database_manager_unittest.cc
@@ -13,8 +13,10 @@
 #include "base/run_loop.h"
 #include "chrome/browser/safe_browsing/local_database_manager.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
+#include "components/safe_browsing_db/v4_get_hash_protocol_manager.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_utils.h"
+#include "net/url_request/url_request_context_getter.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 #include "url/gurl.h"
@@ -23,7 +25,7 @@
 
 namespace safe_browsing {
 
-class SafeBrowsingDatabaseManagerTest : public PlatformTest {
+class LocalDatabaseManagerTest : public PlatformTest {
  public:
   struct HostListPair {
     std::string host;
@@ -45,7 +47,7 @@
   TestBrowserThreadBundle thread_bundle_;
 };
 
-bool SafeBrowsingDatabaseManagerTest::RunSBHashTest(
+bool LocalDatabaseManagerTest::RunSBHashTest(
     const ListType list_type,
     const std::vector<SBThreatType>& expected_threats,
     const std::vector<std::string>& result_lists) {
@@ -64,7 +66,7 @@
   return RunTest(check.get(), fake_results);
 }
 
-bool SafeBrowsingDatabaseManagerTest::RunUrlTest(
+bool LocalDatabaseManagerTest::RunUrlTest(
     const GURL& url, ListType list_type,
     const std::vector<SBThreatType>& expected_threats,
     const std::vector<HostListPair>& host_list_results) {
@@ -81,7 +83,7 @@
   return RunTest(check.get(), full_hash_results);
 }
 
-bool SafeBrowsingDatabaseManagerTest::RunTest(
+bool LocalDatabaseManagerTest::RunTest(
     LocalSafeBrowsingDatabaseManager::SafeBrowsingCheck* check,
     const std::vector<SBFullHashResult>& hash_results) {
   scoped_refptr<SafeBrowsingService> sb_service_(
@@ -95,7 +97,7 @@
   return result;
 }
 
-TEST_F(SafeBrowsingDatabaseManagerTest, CheckCorrespondsListTypeForHash) {
+TEST_F(LocalDatabaseManagerTest, CheckCorrespondsListTypeForHash) {
   std::vector<SBThreatType> malware_threat(1,
                                            SB_THREAT_TYPE_BINARY_MALWARE_URL);
   EXPECT_FALSE(RunSBHashTest(BINURL, malware_threat, {kMalwareList}));
@@ -114,7 +116,7 @@
   EXPECT_TRUE(RunSBHashTest(UNWANTEDURL, unwanted_threat, hash_hits));
 }
 
-TEST_F(SafeBrowsingDatabaseManagerTest, CheckCorrespondsListTypeForUrl) {
+TEST_F(LocalDatabaseManagerTest, CheckCorrespondsListTypeForUrl) {
   const GURL url("http://www.host.com/index.html");
   const std::string host1 = "host.com/";
   const std::string host2 = "www.host.com/";
@@ -141,7 +143,7 @@
   EXPECT_TRUE(RunUrlTest(url, UNWANTEDURL, unwanted_threat, multiple_results));
 }
 
-TEST_F(SafeBrowsingDatabaseManagerTest, GetUrlSeverestThreatType) {
+TEST_F(LocalDatabaseManagerTest, GetUrlSeverestThreatType) {
   std::vector<SBFullHashResult> full_hashes;
 
   const GURL kMalwareUrl("http://www.malware.com/page.html");
@@ -305,7 +307,7 @@
   EXPECT_EQ(kArbitraryValue, index);
 }
 
-TEST_F(SafeBrowsingDatabaseManagerTest, ServiceStopWithPendingChecks) {
+TEST_F(LocalDatabaseManagerTest, ServiceStopWithPendingChecks) {
   scoped_refptr<SafeBrowsingService> sb_service(
       SafeBrowsingService::CreateSafeBrowsingService());
   scoped_refptr<LocalSafeBrowsingDatabaseManager> db_manager(
@@ -313,7 +315,7 @@
   SafeBrowsingDatabaseManager::Client client;
 
   // Start the service and flush tasks to ensure database is made available.
-  db_manager->StartOnIOThread();
+  db_manager->StartOnIOThread(NULL, V4ProtocolConfig());
   content::RunAllBlockingPoolTasksUntilIdle();
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(db_manager->DatabaseAvailable());
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc
index c0d8eaa..2bec85f 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service.cc
@@ -257,7 +257,7 @@
 
   incident_service_.reset(CreateIncidentReportingService());
   resource_request_detector_.reset(new ResourceRequestDetector(
-      incident_service_->GetIncidentReceiver()));
+      database_manager_, incident_service_->GetIncidentReceiver()));
 #endif  // !defined(FULL_SAFE_BROWSING)
 
   // Track the safe browsing preference of existing profiles.
@@ -402,11 +402,10 @@
 }
 
 SafeBrowsingDatabaseManager* SafeBrowsingService::CreateDatabaseManager() {
-  V4ProtocolConfig config = GetV4ProtocolConfig();
 #if defined(SAFE_BROWSING_DB_LOCAL)
-  return new LocalSafeBrowsingDatabaseManager(this, NULL, config);
+  return new LocalSafeBrowsingDatabaseManager(this);
 #elif defined(SAFE_BROWSING_DB_REMOTE)
-  return new RemoteSafeBrowsingDatabaseManager(NULL, config);
+  return new RemoteSafeBrowsingDatabaseManager();
 #else
   return NULL;
 #endif
@@ -474,8 +473,6 @@
   // Mark client string to allow server to differentiate mobile.
 #if defined(OS_ANDROID)
   client_name.append("-a");
-#elif defined(OS_IOS)
-  client_name.append("-i");
 #endif
 
 #endif  // defined(OS_WIN)
@@ -504,10 +501,11 @@
   enabled_ = true;
 
   SafeBrowsingProtocolConfig config = GetProtocolConfig();
+  V4ProtocolConfig v4_config = GetV4ProtocolConfig();
 
 #if defined(SAFE_BROWSING_DB_LOCAL) || defined(SAFE_BROWSING_DB_REMOTE)
   DCHECK(database_manager_.get());
-  database_manager_->StartOnIOThread();
+  database_manager_->StartOnIOThread(url_request_context_getter, v4_config);
 #endif
 
 #if defined(SAFE_BROWSING_DB_LOCAL)
diff --git a/chrome/browser/search/instant_unittest_base.cc b/chrome/browser/search/instant_unittest_base.cc
index b6d87b8b..bd65fb9 100644
--- a/chrome/browser/search/instant_unittest_base.cc
+++ b/chrome/browser/search/instant_unittest_base.cc
@@ -42,7 +42,7 @@
   BrowserWithTestWindowTest::TearDown();
 }
 
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
+#if !defined(OS_ANDROID)
 void InstantUnitTestBase::SetUpWithoutQueryExtraction() {
   SetUpHelper();
 }
diff --git a/chrome/browser/search/instant_unittest_base.h b/chrome/browser/search/instant_unittest_base.h
index a427f36..1a13a107 100644
--- a/chrome/browser/search/instant_unittest_base.h
+++ b/chrome/browser/search/instant_unittest_base.h
@@ -26,7 +26,7 @@
   void SetUp() override;
   void TearDown() override;
 
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
+#if !defined(OS_ANDROID)
   // Query extraction is always enabled on Android and iOS.
   void SetUpWithoutQueryExtraction();
 #endif
diff --git a/chrome/browser/search/local_files_ntp_source.cc b/chrome/browser/search/local_files_ntp_source.cc
index f647a34..4c14167 100644
--- a/chrome/browser/search/local_files_ntp_source.cc
+++ b/chrome/browser/search/local_files_ntp_source.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/search/local_files_ntp_source.h"
 
-#if !defined(GOOGLE_CHROME_BUILD) && !defined(OS_IOS)
+#if !defined(GOOGLE_CHROME_BUILD)
 
 #include "base/bind.h"
 #include "base/files/file_path.h"
@@ -122,4 +122,4 @@
 
 }  // namespace local_ntp
 
-#endif  //  !defined(GOOGLE_CHROME_BUILD) && !defined(OS_IOS)
+#endif  //  !defined(GOOGLE_CHROME_BUILD)
diff --git a/chrome/browser/search/local_files_ntp_source.h b/chrome/browser/search/local_files_ntp_source.h
index adfc934..8872009 100644
--- a/chrome/browser/search/local_files_ntp_source.h
+++ b/chrome/browser/search/local_files_ntp_source.h
@@ -9,7 +9,7 @@
 #include "build/build_config.h"
 #include "content/public/browser/url_data_source.h"
 
-#if !defined(GOOGLE_CHROME_BUILD) && !defined(OS_IOS)
+#if !defined(GOOGLE_CHROME_BUILD)
 
 namespace local_ntp {
 
@@ -29,5 +29,5 @@
 
 }  // namespace local_ntp
 
-#endif  // !defined(GOOGLE_CHROME_BUILD) && !defined(OS_IOS)
+#endif  // !defined(GOOGLE_CHROME_BUILD)
 #endif  // CHROME_BROWSER_SEARCH_LOCAL_FILES_NTP_SOURCE_H_
diff --git a/chrome/browser/search/local_ntp_source.cc b/chrome/browser/search/local_ntp_source.cc
index 7b73134..108e6279 100644
--- a/chrome/browser/search/local_ntp_source.cc
+++ b/chrome/browser/search/local_ntp_source.cc
@@ -212,7 +212,7 @@
     return;
   }
 
-#if !defined(GOOGLE_CHROME_BUILD) && !defined(OS_IOS)
+#if !defined(GOOGLE_CHROME_BUILD)
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   if (command_line->HasSwitch(switches::kLocalNtpReload)) {
     if (stripped_path == "local-ntp.html" || stripped_path == "local-ntp.js" ||
@@ -222,7 +222,7 @@
       return;
     }
   }
-#endif  // !defined(GOOGLE_CHROME_BUILD) && !defined(OS_IOS)
+#endif  // !defined(GOOGLE_CHROME_BUILD)
 
   float scale = 1.0f;
   std::string filename;
diff --git a/chrome/browser/search/most_visited_iframe_source.cc b/chrome/browser/search/most_visited_iframe_source.cc
index 983ffbd..11a2c4c 100644
--- a/chrome/browser/search/most_visited_iframe_source.cc
+++ b/chrome/browser/search/most_visited_iframe_source.cc
@@ -52,7 +52,7 @@
   GURL url(chrome::kChromeSearchMostVisitedUrl + path_and_query);
   std::string path(url.path());
 
-#if !defined(GOOGLE_CHROME_BUILD) && !defined(OS_IOS)
+#if !defined(GOOGLE_CHROME_BUILD)
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   if (command_line->HasSwitch(switches::kLocalNtpReload)) {
     std::string rel_path = "most_visited_" + path.substr(1);
diff --git a/chrome/browser/search/search_unittest.cc b/chrome/browser/search/search_unittest.cc
index e8ac009..06f5090 100644
--- a/chrome/browser/search/search_unittest.cc
+++ b/chrome/browser/search/search_unittest.cc
@@ -655,14 +655,9 @@
 }
 
 TEST_F(SearchTest, GetSearchResultPrefetchBaseURL) {
-#if defined(OS_IOS)
-  EXPECT_FALSE(ShouldPrefetchSearchResults());
-  EXPECT_EQ(GURL(), GetSearchResultPrefetchBaseURL(profile()));
-#else
   EXPECT_TRUE(ShouldPrefetchSearchResults());
   EXPECT_EQ(GURL("https://foo.com/instant?ion=1&foo=foo#foo=foo&strk"),
             GetSearchResultPrefetchBaseURL(profile()));
-#endif
 }
 
 struct ExtractSearchTermsTestCase {
diff --git a/chrome/browser/search_engines/template_url_scraper_browsertest.cc b/chrome/browser/search_engines/template_url_scraper_browsertest.cc
index 223c6e0..9303d73 100644
--- a/chrome/browser/search_engines/template_url_scraper_browsertest.cc
+++ b/chrome/browser/search_engines/template_url_scraper_browsertest.cc
@@ -21,7 +21,6 @@
 #include "components/search_engines/template_url_service.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_navigation_observer.h"
-#include "net/base/net_util.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_response.h"
diff --git a/chrome/browser/search_engines/ui_thread_search_terms_data.cc b/chrome/browser/search_engines/ui_thread_search_terms_data.cc
index 424b0908b..8ec9294 100644
--- a/chrome/browser/search_engines/ui_thread_search_terms_data.cc
+++ b/chrome/browser/search_engines/ui_thread_search_terms_data.cc
@@ -84,10 +84,8 @@
     // value has been cached. This normally would mean that at most one omnibox
     // search might not send the RLZ data but this is not really a problem.
     rlz_lib::AccessPoint access_point = rlz::RLZTracker::ChromeOmnibox();
-#if !defined(OS_IOS)
     if (from_app_list)
       access_point = rlz::RLZTracker::ChromeAppList();
-#endif
     rlz::RLZTracker::GetAccessPointRlz(access_point, &rlz_string);
   }
 #endif
diff --git a/chrome/browser/sessions/better_session_restore_browsertest.cc b/chrome/browser/sessions/better_session_restore_browsertest.cc
index db84cfc..39ccea2 100644
--- a/chrome/browser/sessions/better_session_restore_browsertest.cc
+++ b/chrome/browser/sessions/better_session_restore_browsertest.cc
@@ -45,7 +45,6 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
-#include "net/base/net_util.h"
 #include "net/base/upload_bytes_element_reader.h"
 #include "net/base/upload_data_stream.h"
 #include "net/url_request/url_request.h"
diff --git a/chrome/browser/sessions/tab_restore_browsertest.cc b/chrome/browser/sessions/tab_restore_browsertest.cc
index 8f70db15..790a49d 100644
--- a/chrome/browser/sessions/tab_restore_browsertest.cc
+++ b/chrome/browser/sessions/tab_restore_browsertest.cc
@@ -34,7 +34,6 @@
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
-#include "net/base/net_util.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "url/gurl.h"
 
diff --git a/chrome/browser/signin/account_reconcilor_unittest.cc b/chrome/browser/signin/account_reconcilor_unittest.cc
index b70a6caf..9e06da4 100644
--- a/chrome/browser/signin/account_reconcilor_unittest.cc
+++ b/chrome/browser/signin/account_reconcilor_unittest.cc
@@ -817,12 +817,6 @@
   ASSERT_FALSE(reconcilor->is_reconcile_started_);
 }
 
-#if !defined(OS_IOS)
-// These tests don't run on iOS because that platform uses a different
-// implementation of FakeOAuth2TokenServiceDelegate.  However, iOS also removes
-// accounts when an auth error is detected, so the scenarios being tested here
-// do not apply.
-
 TEST_F(AccountReconcilorTest, NoLoopWithBadPrimary) {
   // Connect profile to a primary account and then add a secondary account.
   const std::string account_id1 =
@@ -908,8 +902,6 @@
   ASSERT_FALSE(reconcilor->error_during_last_reconcile_);
 }
 
-#endif  // OS_IOS
-
 INSTANTIATE_TEST_CASE_P(AccountReconcilorMaybeEnabled,
                         AccountReconcilorTest,
                         testing::Bool());
diff --git a/chrome/browser/signin/chrome_signin_client.cc b/chrome/browser/signin/chrome_signin_client.cc
index 62d2212..a49ebed 100644
--- a/chrome/browser/signin/chrome_signin_client.cc
+++ b/chrome/browser/signin/chrome_signin_client.cc
@@ -13,7 +13,8 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/content_settings/cookie_settings_factory.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
-#include "chrome/browser/profiles/profile_info_cache.h"
+#include "chrome/browser/profiles/profile_attributes_entry.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/profile_metrics.h"
 #include "chrome/browser/profiles/profile_window.h"
@@ -166,18 +167,19 @@
 }
 
 void ChromeSigninClient::OnSignedOut() {
-  ProfileInfoCache& cache =
-      g_browser_process->profile_manager()->GetProfileInfoCache();
-  size_t index = cache.GetIndexOfProfileWithPath(profile_->GetPath());
+  ProfileAttributesEntry* entry;
+  bool has_entry = g_browser_process->profile_manager()->
+      GetProfileAttributesStorage().
+      GetProfileAttributesWithPath(profile_->GetPath(), &entry);
 
   // If sign out occurs because Sync setup was in progress and the Profile got
-  // deleted, then the profile's no longer in the ProfileInfoCache.
-  if (index == std::string::npos)
+  // deleted, then the profile's no longer in the ProfileAttributesStorage.
+  if (!has_entry)
     return;
 
-  cache.SetLocalAuthCredentialsOfProfileAtIndex(index, std::string());
-  cache.SetAuthInfoOfProfileAtIndex(index, std::string(), base::string16());
-  cache.SetProfileSigninRequiredAtIndex(index, false);
+  entry->SetLocalAuthCredentials(std::string());
+  entry->SetAuthInfo(std::string(), base::string16());
+  entry->SetIsSigninRequired(false);
 }
 
 net::URLRequestContextGetter* ChromeSigninClient::GetURLRequestContext() {
@@ -239,11 +241,10 @@
                                     const std::string& username,
                                     const std::string& password) {
   ProfileManager* profile_manager = g_browser_process->profile_manager();
-  ProfileInfoCache& cache = profile_manager->GetProfileInfoCache();
-  size_t index = cache.GetIndexOfProfileWithPath(profile_->GetPath());
-  if (index != std::string::npos) {
-    cache.SetAuthInfoOfProfileAtIndex(index, gaia_id,
-                                      base::UTF8ToUTF16(username));
+  ProfileAttributesEntry* entry;
+  if (profile_manager->GetProfileAttributesStorage().
+          GetProfileAttributesWithPath(profile_->GetPath(), &entry)) {
+    entry->SetAuthInfo(gaia_id, base::UTF8ToUTF16(username));
     ProfileMetrics::UpdateReportedProfilesStatistics(profile_manager);
   }
 }
@@ -251,7 +252,7 @@
 void ChromeSigninClient::PostSignedIn(const std::string& account_id,
                                       const std::string& username,
                                       const std::string& password) {
-#if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_CHROMEOS)
+#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
   // Don't store password hash except when lock is available for the user.
   if (!password.empty() && profiles::IsLockAvailable(profile_))
     LocalAuth::SetLocalAuthCredentials(profile_, password);
@@ -263,14 +264,14 @@
   if (g_browser_process->profile_manager() == nullptr)
     return;
 
-  ProfileInfoCache& cache = g_browser_process->profile_manager()->
-      GetProfileInfoCache();
-  size_t index = cache.GetIndexOfProfileWithPath(profile_->GetPath());
-  if (index == std::string::npos)
-    return;
+  ProfileAttributesEntry* entry;
 
-  cache.SetProfileIsAuthErrorAtIndex(index,
-      signin_error_controller_->HasError());
+  if (!g_browser_process->profile_manager()->GetProfileAttributesStorage().
+          GetProfileAttributesWithPath(profile_->GetPath(), &entry)) {
+    return;
+  }
+
+  entry->SetIsAuthError(signin_error_controller_->HasError());
 }
 
 void ChromeSigninClient::OnGetTokenInfoResponse(
@@ -278,10 +279,12 @@
   if (!token_info->HasKey("error")) {
     std::string handle;
     if (token_info->GetString("token_handle", &handle)) {
-      ProfileInfoCache& info_cache =
-          g_browser_process->profile_manager()->GetProfileInfoCache();
-      size_t index = info_cache.GetIndexOfProfileWithPath(profile_->GetPath());
-      info_cache.SetPasswordChangeDetectionTokenAtIndex(index, handle);
+      ProfileAttributesEntry* entry = nullptr;
+      bool has_entry = g_browser_process->profile_manager()->
+          GetProfileAttributesStorage().
+          GetProfileAttributesWithPath(profile_->GetPath(), &entry);
+      DCHECK(has_entry);
+      entry->SetPasswordChangeDetectionToken(handle);
     }
   }
   oauth_request_.reset();
@@ -355,18 +358,18 @@
 }
 
 void ChromeSigninClient::MaybeFetchSigninTokenHandle() {
-#if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_CHROMEOS)
+#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
   // We get a "handle" that can be used to reference the signin token on the
   // server.  We fetch this if we don't have one so that later we can check
   // it to know if the signin token to which it is attached has been revoked
   // and thus distinguish between a password mismatch due to the password
   // being changed and the user simply mis-typing it.
   if (profiles::IsLockAvailable(profile_)) {
-    ProfileInfoCache& info_cache =
-        g_browser_process->profile_manager()->GetProfileInfoCache();
+    ProfileAttributesStorage& storage =
+        g_browser_process->profile_manager()->GetProfileAttributesStorage();
     ProfileAttributesEntry* entry;
     // If we don't have a token for detecting a password change, create one.
-    if (info_cache.GetProfileAttributesWithPath(profile_->GetPath(), &entry) &&
+    if (storage.GetProfileAttributesWithPath(profile_->GetPath(), &entry) &&
         entry->GetPasswordChangeDetectionToken().empty() && !oauth_request_) {
       std::string account_id = SigninManagerFactory::GetForProfile(profile_)
           ->GetAuthenticatedAccountId();
diff --git a/chrome/browser/signin/chrome_signin_status_metrics_provider_delegate.cc b/chrome/browser/signin/chrome_signin_status_metrics_provider_delegate.cc
index 8d2c113..76ebab7 100644
--- a/chrome/browser/signin/chrome_signin_status_metrics_provider_delegate.cc
+++ b/chrome/browser/signin/chrome_signin_status_metrics_provider_delegate.cc
@@ -10,14 +10,13 @@
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_info_cache.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "components/signin/core/browser/signin_manager.h"
 #include "components/signin/core/browser/signin_status_metrics_provider.h"
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 #include "chrome/browser/ui/browser_finder.h"
 #endif
 
@@ -26,7 +25,7 @@
 
 ChromeSigninStatusMetricsProviderDelegate::
     ~ChromeSigninStatusMetricsProviderDelegate() {
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   BrowserList::RemoveObserver(this);
 #endif
 
@@ -36,7 +35,7 @@
 }
 
 void ChromeSigninStatusMetricsProviderDelegate::Initialize() {
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   // On Android, there is always only one profile in any situation, opening new
   // windows (which is possible with only some Android devices) will not change
   // the opened profiles signin status.
@@ -56,7 +55,7 @@
   AccountsStatus accounts_status;
   accounts_status.num_accounts = profile_list.size();
   for (Profile* profile : profile_list) {
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
     if (chrome::GetBrowserCount(profile) == 0) {
       // The profile is loaded, but there's no opened browser for this profile.
       continue;
@@ -114,7 +113,7 @@
 
 void ChromeSigninStatusMetricsProviderDelegate::UpdateStatusWhenBrowserAdded(
     bool signed_in) {
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   SigninStatusMetricsProviderBase::SigninStatus status =
       owner()->signin_status();
 
diff --git a/chrome/browser/signin/chrome_signin_status_metrics_provider_delegate_unittest.cc b/chrome/browser/signin/chrome_signin_status_metrics_provider_delegate_unittest.cc
index eb9f129e..2f5aecc 100644
--- a/chrome/browser/signin/chrome_signin_status_metrics_provider_delegate_unittest.cc
+++ b/chrome/browser/signin/chrome_signin_status_metrics_provider_delegate_unittest.cc
@@ -11,7 +11,7 @@
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 TEST(ChromeSigninStatusMetricsProviderDelegateTest,
      UpdateStatusWhenBrowserAdded) {
   content::TestBrowserThreadBundle thread_bundle;
diff --git a/chrome/browser/signin/local_auth.cc b/chrome/browser/signin/local_auth.cc
index e4b09bdf7..5ddb1e6 100644
--- a/chrome/browser/signin/local_auth.cc
+++ b/chrome/browser/signin/local_auth.cc
@@ -5,12 +5,15 @@
 #include "chrome/browser/signin/local_auth.h"
 
 #include "base/base64.h"
+#include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/histogram.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_attributes_entry.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/pref_names.h"
 #include "components/os_crypt/os_crypt.h"
@@ -158,14 +161,6 @@
   return OSCrypt::DecryptString(unbase64, decoded);
 }
 
-size_t GetProfileInfoIndexOfProfile(const Profile* profile) {
-  DCHECK(profile);
-
-  ProfileInfoCache& info =
-      g_browser_process->profile_manager()->GetProfileInfoCache();
-  return info.GetIndexOfProfileWithPath(profile->GetPath());
-}
-
 }  // namespace
 
 std::string LocalAuth::TruncateStringByBits(const std::string& str,
@@ -179,9 +174,10 @@
                                std::string());
 }
 
-void LocalAuth::SetLocalAuthCredentialsWithEncoding(size_t info_index,
-                                                    const std::string& password,
-                                                    char encoding_version) {
+void LocalAuth::SetLocalAuthCredentialsWithEncoding(
+    ProfileAttributesEntry* entry,
+    const std::string& password,
+    char encoding_version) {
   const HashEncoding& encoding = encodings[(encoding_version - '0') - 1];
 
   // Salt should be random data, as long as the hash length, and different with
@@ -201,42 +197,36 @@
 
   // Encode it and store it.
   std::string encoded = EncodePasswordHashRecord(record, encoding);
-  ProfileInfoCache& info =
-      g_browser_process->profile_manager()->GetProfileInfoCache();
-  info.SetLocalAuthCredentialsOfProfileAtIndex(info_index, encoded);
+  entry->SetLocalAuthCredentials(encoded);
 }
 
-void LocalAuth::SetLocalAuthCredentials(size_t info_index,
+void LocalAuth::SetLocalAuthCredentials(ProfileAttributesEntry* entry,
                                         const std::string& password) {
-  if (info_index == std::string::npos) {
-    NOTREACHED();
-    return;
-  }
+  DCHECK(entry);
   DCHECK(password.length());
   SetLocalAuthCredentialsWithEncoding(
-      info_index, password, '0' + NUM_HASH_ENCODINGS);
+      entry, password, '0' + NUM_HASH_ENCODINGS);
 }
 
 void LocalAuth::SetLocalAuthCredentials(const Profile* profile,
                                         const std::string& password) {
-  SetLocalAuthCredentials(GetProfileInfoIndexOfProfile(profile), password);
+  DCHECK(g_browser_process->profile_manager()->IsValidProfile(profile));
+  ProfileAttributesEntry* entry = nullptr;
+  bool has_entry = g_browser_process->profile_manager()->
+      GetProfileAttributesStorage().
+      GetProfileAttributesWithPath(profile->GetPath(), &entry);
+  DCHECK(has_entry);
+  SetLocalAuthCredentials(entry, password);
 }
 
-bool LocalAuth::ValidateLocalAuthCredentials(size_t info_index,
+bool LocalAuth::ValidateLocalAuthCredentials(ProfileAttributesEntry* entry,
                                              const std::string& password) {
-  if (info_index == std::string::npos) {
-    NOTREACHED();
-    return false;
-  }
+  DCHECK(entry);
 
   std::string record;
   char encoding;
 
-  ProfileInfoCache& info =
-      g_browser_process->profile_manager()->GetProfileInfoCache();
-
-  std::string encodedhash =
-      info.GetLocalAuthCredentialsOfProfileAtIndex(info_index);
+  std::string encodedhash = entry->GetLocalAuthCredentials();
   if (encodedhash.length() == 0 && password.length() == 0)
     return true;
   if (!DecodePasswordHashRecord(encodedhash, &record, &encoding))
@@ -266,12 +256,20 @@
 
   // Update the stored credentials to the latest encoding if necessary.
   if (passwords_match && (hash_encoding->version - '0') != NUM_HASH_ENCODINGS)
-    SetLocalAuthCredentials(info_index, password);
+    SetLocalAuthCredentials(entry, password);
   return passwords_match;
 }
 
 bool LocalAuth::ValidateLocalAuthCredentials(const Profile* profile,
                                              const std::string& password) {
-  return ValidateLocalAuthCredentials(GetProfileInfoIndexOfProfile(profile),
-                                      password);
+  DCHECK(g_browser_process->profile_manager()->IsValidProfile(profile));
+  ProfileAttributesEntry* entry;
+
+  if (!g_browser_process->profile_manager()->GetProfileAttributesStorage().
+          GetProfileAttributesWithPath(profile->GetPath(), &entry)) {
+    NOTREACHED();
+    return false;
+  }
+
+  return ValidateLocalAuthCredentials(entry, password);
 }
diff --git a/chrome/browser/signin/local_auth.h b/chrome/browser/signin/local_auth.h
index 4d591f4bd..0e999f09 100644
--- a/chrome/browser/signin/local_auth.h
+++ b/chrome/browser/signin/local_auth.h
@@ -17,6 +17,7 @@
 
 class LocalAuthTest;
 class Profile;
+class ProfileAttributesEntry;
 
 namespace user_prefs {
 class PrefRegistrySyncable;
@@ -27,14 +28,13 @@
   static void RegisterLocalAuthPrefs(
       user_prefs::PrefRegistrySyncable* registry);
 
-  static void SetLocalAuthCredentials(size_t profile_info_index,
+  static void SetLocalAuthCredentials(ProfileAttributesEntry* entry,
                                       const std::string& password);
 
-
   static void SetLocalAuthCredentials(const Profile* profile,
                                       const std::string& password);
 
-  static bool ValidateLocalAuthCredentials(size_t profile_info_index,
+  static bool ValidateLocalAuthCredentials(ProfileAttributesEntry* entry,
                                            const std::string& password);
 
   static bool ValidateLocalAuthCredentials(const Profile* profile,
@@ -50,7 +50,7 @@
   static std::string TruncateStringByBits(const std::string& str,
                                           const size_t len_bits);
 
-  static void SetLocalAuthCredentialsWithEncoding(size_t profile_info_index,
+  static void SetLocalAuthCredentialsWithEncoding(ProfileAttributesEntry* entry,
                                                   const std::string& password,
                                                   char encoding_version);
 };
diff --git a/chrome/browser/signin/local_auth_unittest.cc b/chrome/browser/signin/local_auth_unittest.cc
index 9145099..8aa0ddd 100644
--- a/chrome/browser/signin/local_auth_unittest.cc
+++ b/chrome/browser/signin/local_auth_unittest.cc
@@ -8,7 +8,8 @@
 
 #include "base/base64.h"
 #include "build/build_config.h"
-#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/profiles/profile_attributes_entry.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
@@ -28,10 +29,10 @@
       TestingBrowserProcess::GetGlobal());
   ASSERT_TRUE(testing_profile_manager.SetUp());
   Profile* prof = testing_profile_manager.CreateTestingProfile("p1");
-  ProfileInfoCache& cache =
-      testing_profile_manager.profile_manager()->GetProfileInfoCache();
-  EXPECT_EQ(1U, cache.GetNumberOfProfiles());
-  EXPECT_EQ("", cache.GetLocalAuthCredentialsOfProfileAtIndex(0));
+  ProfileAttributesEntry* entry;
+  ASSERT_TRUE(testing_profile_manager.profile_attributes_storage()->
+      GetProfileAttributesWithPath(prof->GetPath(), &entry));
+  EXPECT_EQ("", entry->GetLocalAuthCredentials());
 
 #if defined(OS_MACOSX)
   OSCrypt::UseMockKeychain(true);
@@ -41,7 +42,7 @@
   EXPECT_FALSE(LocalAuth::ValidateLocalAuthCredentials(prof, password));
 
   LocalAuth::SetLocalAuthCredentials(prof, password);
-  std::string passhash = cache.GetLocalAuthCredentialsOfProfileAtIndex(0);
+  std::string passhash = entry->GetLocalAuthCredentials();
 
   // We perform basic validation on the written record to ensure bugs don't slip
   // in that cannot be seen from the API:
@@ -60,7 +61,7 @@
   EXPECT_FALSE(LocalAuth::ValidateLocalAuthCredentials(prof, password + "1"));
 
   LocalAuth::SetLocalAuthCredentials(prof, password);  // makes different salt
-  EXPECT_NE(passhash, cache.GetLocalAuthCredentialsOfProfileAtIndex(0));
+  EXPECT_NE(passhash, entry->GetLocalAuthCredentials());
 }
 
 TEST_F(LocalAuthTest, SetUpgradeAndCheckCredentials) {
@@ -68,28 +69,26 @@
       TestingBrowserProcess::GetGlobal());
   ASSERT_TRUE(testing_profile_manager.SetUp());
   Profile* prof = testing_profile_manager.CreateTestingProfile("p1");
-  ProfileInfoCache& cache =
-      testing_profile_manager.profile_manager()->GetProfileInfoCache();
 
 #if defined(OS_MACOSX)
   OSCrypt::UseMockKeychain(true);
 #endif
 
   std::string password("Some Password");
-  size_t profile_index = cache.GetIndexOfProfileWithPath(prof->GetPath());
-  LocalAuth::SetLocalAuthCredentialsWithEncoding(profile_index, password, '1');
+  ProfileAttributesEntry* entry;
+  ASSERT_TRUE(testing_profile_manager.profile_attributes_storage()->
+      GetProfileAttributesWithPath(prof->GetPath(), &entry));
+  LocalAuth::SetLocalAuthCredentialsWithEncoding(entry, password, '1');
 
   // Ensure we indeed persisted the correct encoding.
-  std::string oldpasshash = cache.GetLocalAuthCredentialsOfProfileAtIndex(
-      profile_index);
+  std::string oldpasshash = entry->GetLocalAuthCredentials();
   EXPECT_EQ('1', oldpasshash[0]);
 
   // Validate, ensure we can validate against the old encoding.
   EXPECT_TRUE(LocalAuth::ValidateLocalAuthCredentials(prof, password));
 
   // Ensure we updated the encoding.
-  std::string newpasshash = cache.GetLocalAuthCredentialsOfProfileAtIndex(
-      profile_index);
+  std::string newpasshash = entry->GetLocalAuthCredentials();
   EXPECT_EQ('2', newpasshash[0]);
   // Encoding '2' writes fewer bytes than encoding '1'.
   EXPECT_LE(newpasshash.length(), oldpasshash.length());
diff --git a/chrome/browser/signin/signin_global_error.cc b/chrome/browser/signin/signin_global_error.cc
index e83c3ad..cac74cfc 100644
--- a/chrome/browser/signin/signin_global_error.cc
+++ b/chrome/browser/signin/signin_global_error.cc
@@ -28,7 +28,7 @@
 #include "net/base/url_util.h"
 #include "ui/base/l10n/l10n_util.h"
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 #include "chrome/browser/signin/signin_promo.h"
 #endif
 
@@ -88,7 +88,7 @@
 #endif
 
   // Global errors don't show up in the wrench menu on mobile.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   LoginUIService* login_ui = LoginUIServiceFactory::GetForProfile(profile_);
   if (login_ui->current_login_ui()) {
     login_ui->current_login_ui()->FocusUI();
diff --git a/chrome/browser/signin/signin_global_error_unittest.cc b/chrome/browser/signin/signin_global_error_unittest.cc
index 2bbf7609..ae4fc48 100644
--- a/chrome/browser/signin/signin_global_error_unittest.cc
+++ b/chrome/browser/signin/signin_global_error_unittest.cc
@@ -6,11 +6,14 @@
 
 #include <stddef.h>
 
+#include <string>
+
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/histogram_tester.h"
-#include "chrome/browser/profiles/profile_info_cache.h"
+#include "chrome/browser/profiles/profile_attributes_entry.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/profile_metrics.h"
 #include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
@@ -58,11 +61,10 @@
 
     SigninManagerFactory::GetForProfile(profile())
         ->SetAuthenticatedAccountInfo(kTestAccountId, kTestUsername);
-    ProfileInfoCache& cache =
-        profile_manager_.profile_manager()->GetProfileInfoCache();
-    cache.SetAuthInfoOfProfileAtIndex(
-        cache.GetIndexOfProfileWithPath(profile()->GetPath()),
-            kTestGaiaId, base::UTF8ToUTF16(kTestUsername));
+    ProfileAttributesEntry* entry;
+    ASSERT_TRUE(profile_manager_.profile_attributes_storage()->
+        GetProfileAttributesWithPath(profile()->GetPath(), &entry));
+    entry->SetAuthInfo(kTestGaiaId, base::UTF8ToUTF16(kTestUsername));
 
     global_error_ = SigninGlobalErrorFactory::GetForProfile(profile());
     error_controller_ = SigninErrorControllerFactory::GetForProfile(profile());
diff --git a/chrome/browser/signin/signin_promo.cc b/chrome/browser/signin/signin_promo.cc
index c9aec13..80315d40 100644
--- a/chrome/browser/signin/signin_promo.cc
+++ b/chrome/browser/signin/signin_promo.cc
@@ -16,7 +16,6 @@
 #include "chrome/browser/first_run/first_run.h"
 #include "chrome/browser/google/google_brand.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_info_cache.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/signin/account_tracker_service_factory.h"
 #include "chrome/browser/signin/signin_error_controller_factory.h"
diff --git a/chrome/browser/ssl/captive_portal_blocking_page.cc b/chrome/browser/ssl/captive_portal_blocking_page.cc
index 753057fa..156abd2cc 100644
--- a/chrome/browser/ssl/captive_portal_blocking_page.cc
+++ b/chrome/browser/ssl/captive_portal_blocking_page.cc
@@ -26,7 +26,6 @@
 #include "components/wifi/wifi_service.h"
 #include "content/public/browser/web_contents.h"
 #include "grit/generated_resources.h"
-#include "net/base/net_util.h"
 #include "net/base/network_change_notifier.h"
 #include "net/base/network_interfaces.h"
 #include "net/ssl/ssl_info.h"
diff --git a/chrome/browser/ssl/cert_report_helper.cc b/chrome/browser/ssl/cert_report_helper.cc
index 87f3c7b..49cc741 100644
--- a/chrome/browser/ssl/cert_report_helper.cc
+++ b/chrome/browser/ssl/cert_report_helper.cc
@@ -117,9 +117,6 @@
 }
 
 bool CertReportHelper::ShouldShowCertificateReporterCheckbox() {
-#if defined(OS_IOS)
-  return false;
-#else
   // Only show the checkbox iff the user is part of the respective Finch group
   // and the window is not incognito and the feature is not disabled by policy.
   const bool in_incognito =
@@ -128,11 +125,9 @@
              kFinchGroupShowPossiblySend &&
          !in_incognito &&
          IsPrefEnabled(prefs::kSafeBrowsingExtendedReportingOptInAllowed);
-#endif
 }
 
 bool CertReportHelper::ShouldReportCertificateError() {
-#if !defined(OS_IOS)
   DCHECK(ShouldShowCertificateReporterCheckbox());
   // Even in case the checkbox was shown, we don't send error reports
   // for all of these users. Check the Finch configuration for a sending
@@ -146,7 +141,6 @@
         return base::RandDouble() <= sendingThreshold;
     }
   }
-#endif
   return false;
 }
 
diff --git a/chrome/browser/ssl/chrome_ssl_host_state_delegate.cc b/chrome/browser/ssl/chrome_ssl_host_state_delegate.cc
index c4e7b44..e3cd5dd 100644
--- a/chrome/browser/ssl/chrome_ssl_host_state_delegate.cc
+++ b/chrome/browser/ssl/chrome_ssl_host_state_delegate.cc
@@ -26,7 +26,7 @@
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "components/variations/variations_associated_data.h"
 #include "net/base/hash_value.h"
-#include "net/base/net_util.h"
+#include "net/base/url_util.h"
 #include "net/cert/x509_certificate.h"
 #include "net/http/http_transaction_factory.h"
 #include "net/url_request/url_request_context.h"
diff --git a/chrome/browser/ssl/ssl_blocking_page.cc b/chrome/browser/ssl/ssl_blocking_page.cc
index 4aa09fa..0775e98a 100644
--- a/chrome/browser/ssl/ssl_blocking_page.cc
+++ b/chrome/browser/ssl/ssl_blocking_page.cc
@@ -35,7 +35,6 @@
 #include "content/public/common/renderer_preferences.h"
 #include "content/public/common/ssl_status.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 
 using base::TimeTicks;
 using content::InterstitialPage;
diff --git a/chrome/browser/supervised_user/supervised_user_service.cc b/chrome/browser/supervised_user/supervised_user_service.cc
index c0f01fb3..30b6115a 100644
--- a/chrome/browser/supervised_user/supervised_user_service.cc
+++ b/chrome/browser/supervised_user/supervised_user_service.cc
@@ -50,7 +50,7 @@
 #include "content/public/browser/user_metrics.h"
 #include "ui/base/l10n/l10n_util.h"
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 #include "chrome/browser/supervised_user/legacy/custodian_profile_downloader_service.h"
 #include "chrome/browser/supervised_user/legacy/custodian_profile_downloader_service_factory.h"
 #include "chrome/browser/supervised_user/legacy/permission_request_creator_sync.h"
@@ -326,7 +326,7 @@
                                     base::UTF8ToUTF16(GetCustodianName()));
 }
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 void SupervisedUserService::InitSync(const std::string& refresh_token) {
   StartSetupSync();
 
@@ -367,7 +367,7 @@
       base::Bind(&SupervisedUserService::OnCustodianProfileDownloaded,
                  weak_ptr_factory_.GetWeakPtr()));
 }
-#endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif  // !defined(OS_ANDROID)
 
 void SupervisedUserService::AddNavigationBlockedCallback(
     const NavigationBlockedCallback& callback) {
@@ -516,7 +516,7 @@
 
   if (!delegate_ || !delegate_->SetActive(active_)) {
     if (active_) {
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
       SupervisedUserPrefMappingServiceFactory::GetForBrowserContext(profile_)
           ->Init();
 
@@ -593,7 +593,7 @@
     UpdateManualHosts();
     UpdateManualURLs();
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
     // TODO(bauerb): Get rid of the platform-specific #ifdef here.
     // http://crbug.com/313377
     BrowserList::AddObserver(this);
@@ -613,7 +613,7 @@
     FOR_EACH_OBSERVER(
         SupervisedUserServiceObserver, observer_list_, OnURLFilterChanged());
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
     if (waiting_for_sync_initialization_)
       ProfileSyncServiceFactory::GetForProfile(profile_)->RemoveObserver(this);
 
@@ -624,7 +624,7 @@
   }
 }
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 void SupervisedUserService::OnCustodianProfileDownloaded(
     const base::string16& full_name) {
   profile_->GetPrefs()->SetString(prefs::kSupervisedUserCustodianName,
@@ -674,8 +674,7 @@
   // Continue in FinishSetupSync() once the Sync backend has been initialized.
   ProfileSyncService* service =
       ProfileSyncServiceFactory::GetForProfile(profile_);
-  if (service->IsBackendInitialized() &&
-      service->backend_mode() == ProfileSyncService::SYNC) {
+  if (service->IsBackendInitialized()) {
     FinishSetupSync();
   } else {
     service->AddObserver(this);
@@ -687,7 +686,6 @@
   ProfileSyncService* service =
       ProfileSyncServiceFactory::GetForProfile(profile_);
   DCHECK(service->IsBackendInitialized());
-  DCHECK(service->backend_mode() == ProfileSyncService::SYNC);
 
   // Sync nothing (except types which are set via GetPreferredDataTypes).
   bool sync_everything = false;
@@ -1019,12 +1017,11 @@
   return result;
 }
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 void SupervisedUserService::OnStateChanged() {
   ProfileSyncService* service =
       ProfileSyncServiceFactory::GetForProfile(profile_);
-  if (waiting_for_sync_initialization_ && service->IsBackendInitialized() &&
-      service->backend_mode() == ProfileSyncService::SYNC) {
+  if (waiting_for_sync_initialization_ && service->IsBackendInitialized()) {
     waiting_for_sync_initialization_ = false;
     service->RemoveObserver(this);
     FinishSetupSync();
@@ -1045,7 +1042,7 @@
 
   is_profile_active_ = profile_became_active;
 }
-#endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif  // !defined(OS_ANDROID)
 
 void SupervisedUserService::OnSiteListUpdated() {
   FOR_EACH_OBSERVER(
diff --git a/chrome/browser/supervised_user/supervised_user_service.h b/chrome/browser/supervised_user/supervised_user_service.h
index d661f70..0c5a907 100644
--- a/chrome/browser/supervised_user/supervised_user_service.h
+++ b/chrome/browser/supervised_user/supervised_user_service.h
@@ -71,7 +71,7 @@
                               public extensions::ManagementPolicy::Provider,
 #endif
                               public SyncTypePreferenceProvider,
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
                               public sync_driver::SyncServiceObserver,
                               public chrome::BrowserListObserver,
 #endif
@@ -150,7 +150,7 @@
   // custodian.
   base::string16 GetExtensionsLockedMessage() const;
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   // Initializes this profile for syncing, using the provided |refresh_token| to
   // mint access tokens for Sync.
   void InitSync(const std::string& refresh_token);
@@ -182,13 +182,13 @@
   // SyncTypePreferenceProvider implementation:
   syncer::ModelTypeSet GetPreferredDataTypes() const override;
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   // sync_driver::SyncServiceObserver implementation:
   void OnStateChanged() override;
 
   // chrome::BrowserListObserver implementation:
   void OnBrowserSetLastActive(Browser* browser) override;
-#endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif  // !defined(OS_ANDROID)
 
   // SupervisedUserURLFilter::Observer implementation:
   void OnSiteListUpdated() override;
@@ -258,7 +258,7 @@
 
   void SetActive(bool active);
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   void OnCustodianProfileDownloaded(const base::string16& full_name);
 
   void OnSupervisedUserRegistered(const AuthErrorCallback& callback,
diff --git a/chrome/browser/supervised_user/supervised_user_service_unittest.cc b/chrome/browser/supervised_user/supervised_user_service_unittest.cc
index a7110d7..9c3d07c 100644
--- a/chrome/browser/supervised_user/supervised_user_service_unittest.cc
+++ b/chrome/browser/supervised_user/supervised_user_service_unittest.cc
@@ -50,7 +50,7 @@
 
 namespace {
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 void OnProfileDownloadedFail(const base::string16& full_name) {
   ASSERT_TRUE(false) << "Profile download should not have succeeded.";
 }
@@ -209,7 +209,7 @@
   EXPECT_FALSE(supervised_user_service_->IncludesSyncSessionsType());
 }
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 // Ensure that the CustodianProfileDownloaderService shuts down cleanly. If no
 // DCHECK is hit when the service is destroyed, this test passed.
 TEST_F(SupervisedUserServiceTest, ShutDownCustodianProfileDownloader) {
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index 661ca35..e6fe2c3 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -12,8 +12,6 @@
 #include "build/build_config.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
-#include "chrome/browser/browsing_data/browsing_data_helper.h"
-#include "chrome/browser/browsing_data/browsing_data_remover_factory.h"
 #include "chrome/browser/dom_distiller/dom_distiller_service_factory.h"
 #include "chrome/browser/favicon/favicon_service_factory.h"
 #include "chrome/browser/history/history_service_factory.h"
@@ -248,12 +246,6 @@
   return autofill::PersonalDataManagerFactory::GetForProfile(profile_);
 }
 
-sync_driver::ClearBrowsingDataCallback
-ChromeSyncClient::GetClearBrowsingDataCallback() {
-  return base::Bind(&ChromeSyncClient::ClearBrowsingData,
-                    base::Unretained(this));
-}
-
 base::Closure ChromeSyncClient::GetPasswordStateChangedCallback() {
   return base::Bind(
       &PasswordStoreFactory::OnPasswordsSyncedStatePotentiallyChanged,
@@ -383,7 +375,7 @@
     case syncer::SUPERVISED_USER_SETTINGS:
       return SupervisedUserSettingsServiceFactory::GetForProfile(profile_)->
           AsWeakPtr();
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
     case syncer::SUPERVISED_USERS:
       return SupervisedUserSyncServiceFactory::GetForProfile(profile_)->
           AsWeakPtr();
@@ -484,28 +476,6 @@
   return component_factory_.get();
 }
 
-void ChromeSyncClient::ClearBrowsingData(base::Time start, base::Time end) {
-  BrowsingDataRemover* remover =
-      BrowsingDataRemoverFactory::GetForBrowserContext(profile_);
-  remover->Remove(BrowsingDataRemover::TimeRange(start, end),
-                  BrowsingDataRemover::REMOVE_ALL, BrowsingDataHelper::ALL);
-
-  password_store_->RemoveLoginsSyncedBetween(start, end);
-}
-
-void ChromeSyncClient::SetBrowsingDataRemoverObserverForTesting(
-    BrowsingDataRemover::Observer* observer) {
-  BrowsingDataRemover* remover =
-      BrowsingDataRemoverFactory::GetForBrowserContext(profile_);
-  if (browsing_data_remover_observer_)
-    remover->RemoveObserver(browsing_data_remover_observer_);
-
-  if (observer)
-    remover->AddObserver(observer);
-
-  browsing_data_remover_observer_ = observer;
-}
-
 void ChromeSyncClient::SetSyncApiComponentFactoryForTesting(
     scoped_ptr<sync_driver::SyncApiComponentFactory> component_factory) {
   component_factory_ = std::move(component_factory);
diff --git a/chrome/browser/sync/chrome_sync_client.h b/chrome/browser/sync/chrome_sync_client.h
index 4e5882187..f94c669 100644
--- a/chrome/browser/sync/chrome_sync_client.h
+++ b/chrome/browser/sync/chrome_sync_client.h
@@ -39,8 +39,6 @@
   bookmarks::BookmarkModel* GetBookmarkModel() override;
   favicon::FaviconService* GetFaviconService() override;
   history::HistoryService* GetHistoryService() override;
-  sync_driver::ClearBrowsingDataCallback GetClearBrowsingDataCallback()
-      override;
   base::Closure GetPasswordStateChangedCallback() override;
   sync_driver::SyncApiComponentFactory::RegisterDataTypesMethod
   GetRegisterPlatformTypesCallback() override;
@@ -79,8 +77,6 @@
                                 syncer::ModelTypeSet disabled_types,
                                 syncer::ModelTypeSet enabled_types);
 
-  void ClearBrowsingData(base::Time start, base::Time end);
-
   Profile* const profile_;
 
   // The sync api component factory in use by this client.
diff --git a/chrome/browser/sync/profile_sync_service_factory_unittest.cc b/chrome/browser/sync/profile_sync_service_factory_unittest.cc
index a7e4264..0c38068f 100644
--- a/chrome/browser/sync/profile_sync_service_factory_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_factory_unittest.cc
@@ -28,7 +28,7 @@
     std::vector<syncer::ModelType> datatypes;
 
     // Desktop types.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
     datatypes.push_back(syncer::APPS);
 #if defined(ENABLE_APP_LIST)
     if (app_list::switches::IsAppListSyncEnabled())
@@ -45,7 +45,7 @@
     datatypes.push_back(syncer::THEMES);
     datatypes.push_back(syncer::SUPERVISED_USERS);
     datatypes.push_back(syncer::SUPERVISED_USER_SHARED_SETTINGS);
-#endif // !OS_ANDROID && !OS_IOS
+#endif // !OS_ANDROID
 
     // Common types.
     datatypes.push_back(syncer::AUTOFILL);
diff --git a/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc b/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc
index 90dcacf2..750b869 100644
--- a/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc
+++ b/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc
@@ -2050,7 +2050,7 @@
   ASSERT_TRUE(observer()->notified_of_update());
 }
 
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_ANDROID)
 // Tests that opening the other devices page triggers a session sync refresh.
 // This page only exists on mobile platforms today; desktop has a
 // search-enhanced NTP without other devices.
@@ -2062,7 +2062,7 @@
   NavigateAndCommitActiveTab(GURL("chrome://newtab/#open_tabs"));
   EXPECT_TRUE(observer()->notified_of_refresh());
 }
-#endif  // defined(OS_ANDROID) || defined(OS_IOS)
+#endif  // defined(OS_ANDROID)
 
 // Tests receipt of duplicate tab IDs in the same window.  This should never
 // happen, but we want to make sure the client won't do anything bad if it does
diff --git a/chrome/browser/sync/test/integration/profile_sync_service_harness.cc b/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
index f285656..7cf94c81 100644
--- a/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
+++ b/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
@@ -56,8 +56,6 @@
       : SingleClientStatusChangeChecker(service) {}
 
   bool IsExitConditionSatisfied() override {
-    if (service()->backend_mode() != ProfileSyncService::SYNC)
-      return false;
     if (service()->IsBackendInitialized())
       return true;
     // Backend initialization is blocked by an auth error.
diff --git a/chrome/browser/sync/test/integration/single_client_backup_rollback_test.cc b/chrome/browser/sync/test/integration/single_client_backup_rollback_test.cc
deleted file mode 100644
index 90f7841..0000000
--- a/chrome/browser/sync/test/integration/single_client_backup_rollback_test.cc
+++ /dev/null
@@ -1,451 +0,0 @@
-// 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 "base/command_line.h"
-#include "base/files/file_util.h"
-#include "base/location.h"
-#include "base/macros.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/test/test_timeouts.h"
-#include "base/thread_task_runner_handle.h"
-#include "chrome/browser/browsing_data/browsing_data_remover.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/sync/chrome_sync_client.h"
-#include "chrome/browser/sync/test/integration/bookmarks_helper.h"
-#include "chrome/browser/sync/test/integration/preferences_helper.h"
-#include "chrome/browser/sync/test/integration/sync_integration_test_util.h"
-#include "chrome/browser/sync/test/integration/sync_test.h"
-#include "components/bookmarks/browser/bookmark_model.h"
-#include "components/browser_sync/browser/profile_sync_service.h"
-#include "components/prefs/pref_service.h"
-#include "components/sync_driver/sync_driver_features.h"
-#include "components/sync_driver/sync_driver_switches.h"
-#include "sync/internal_api/public/util/sync_db_util.h"
-#include "sync/test/fake_server/fake_server_verifier.h"
-#include "sync/util/time.h"
-
-using bookmarks::BookmarkNode;
-using bookmarks_helper::AddFolder;
-using bookmarks_helper::AddURL;
-using bookmarks_helper::GetOtherNode;
-using bookmarks_helper::ModelMatchesVerifier;
-using bookmarks_helper::Move;
-using bookmarks_helper::Remove;
-using sync_integration_test_util::AwaitCommitActivityCompletion;
-
-namespace {
-const char kUrl1[] = "http://www.google.com";
-const char kUrl2[] = "http://map.google.com";
-const char kUrl3[] = "http://plus.google.com";
-}  // anonymous namespace
-
-class SingleClientBackupRollbackTest : public SyncTest {
- public:
-  SingleClientBackupRollbackTest() : SyncTest(SINGLE_CLIENT) {}
-  ~SingleClientBackupRollbackTest() override {}
-
-  void DisableBackup() {
-    base::CommandLine::ForCurrentProcess()->AppendSwitch(
-        switches::kSyncDisableBackup);
-  }
-
-  void DisableRollback() {
-    base::CommandLine::ForCurrentProcess()->AppendSwitch(
-        switches::kSyncDisableRollback);
-  }
-
-  base::Time GetBackupDbLastModified() {
-    base::RunLoop run_loop;
-
-    base::Time backup_time;
-    syncer::CheckSyncDbLastModifiedTime(
-        GetProfile(0)->GetPath().Append(FILE_PATH_LITERAL("Sync Data Backup")),
-        base::ThreadTaskRunnerHandle::Get(),
-        base::Bind(&SingleClientBackupRollbackTest::CheckDbCallback,
-                   base::Unretained(this), &backup_time));
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, run_loop.QuitClosure());
-    run_loop.Run();
-    return backup_time;
-  }
-
- private:
-  void CheckDbCallback(base::Time* time_out, base::Time time_in) {
-    *time_out = syncer::ProtoTimeToTime(syncer::TimeToProtoTime(time_in));
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(SingleClientBackupRollbackTest);
-};
-
-// Waits until the ProfileSyncService's backend is in IDLE mode.
-class SyncBackendStoppedChecker : public sync_driver::SyncServiceObserver {
- public:
-  explicit SyncBackendStoppedChecker(ProfileSyncService* service)
-      : pss_(service),
-        timeout_(TestTimeouts::action_max_timeout()),
-        done_(false) {}
-
-  void OnStateChanged() override {
-    if (ProfileSyncService::IDLE == pss_->backend_mode()) {
-      done_ = true;
-      run_loop_.Quit();
-    }
-  }
-
-  bool Wait() {
-    pss_->AddObserver(this);
-    if (ProfileSyncService::IDLE == pss_->backend_mode())
-      return true;
-    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-        FROM_HERE, run_loop_.QuitClosure(), timeout_);
-    run_loop_.Run();
-    pss_->RemoveObserver(this);
-    return done_;
-  }
-
- private:
-
-  ProfileSyncService* const pss_;
-  const base::TimeDelta timeout_;
-  base::RunLoop run_loop_;
-  bool done_;
-};
-
-// Waits until a rollback finishes.
-class SyncRollbackChecker : public sync_driver::SyncServiceObserver,
-                            public BrowsingDataRemover::Observer {
- public:
-  explicit SyncRollbackChecker(ProfileSyncService* service)
-      : pss_(service),
-        timeout_(TestTimeouts::action_max_timeout()),
-        rollback_started_(false),
-        clear_done_(false) {}
-
-  // sync_driver::SyncServiceObserver implementation.
-  void OnStateChanged() override {
-    if (ProfileSyncService::ROLLBACK == pss_->backend_mode()) {
-      rollback_started_ = true;
-      if (clear_done_)
-        run_loop_.Quit();
-    }
-  }
-
-  // BrowsingDataRemoverObserver::Observer implementation.
-  void OnBrowsingDataRemoverDone() override {
-    // Remove ourselves as an observer.
-    browser_sync::ChromeSyncClient* sync_client =
-        static_cast<browser_sync::ChromeSyncClient*>(pss_->GetSyncClient());
-    sync_client->SetBrowsingDataRemoverObserverForTesting(nullptr);
-
-    clear_done_ = true;
-    if (rollback_started_) {
-      run_loop_.Quit();
-    }
-  }
-
-  bool Wait() {
-    pss_->AddObserver(this);
-
-    browser_sync::ChromeSyncClient* sync_client =
-        static_cast<browser_sync::ChromeSyncClient*>(pss_->GetSyncClient());
-    sync_client->SetBrowsingDataRemoverObserverForTesting(this);
-    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-        FROM_HERE, run_loop_.QuitClosure(), timeout_);
-    run_loop_.Run();
-    pss_->RemoveObserver(this);
-    return rollback_started_ && clear_done_;
-  }
-
-  ProfileSyncService* const pss_;
-  const base::TimeDelta timeout_;
-  base::RunLoop run_loop_;
-  bool rollback_started_;
-  bool clear_done_;
-};
-
-#if BUILDFLAG(ENABLE_PRE_SYNC_BACKUP)
-#define MAYBE_TestBackup TestBackup
-#else
-#define MAYBE_TestBackup DISABLED_TestBackup
-#endif
-IN_PROC_BROWSER_TEST_F(SingleClientBackupRollbackTest,
-                       MAYBE_TestBackup) {
-  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
-
-  // Setup sync, wait for its completion, and make sure changes were synced.
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
-  ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService(0)));
-  ASSERT_TRUE(ModelMatchesVerifier(0));
-
-  // Verify backup DB is created and backup time is set on device info.
-  base::Time backup_time = GetBackupDbLastModified();
-  ASSERT_FALSE(backup_time.is_null());
-  ASSERT_EQ(backup_time, GetSyncService(0)->GetDeviceBackupTimeForTesting());
-}
-
-#if BUILDFLAG(ENABLE_PRE_SYNC_BACKUP)
-#define MAYBE_TestBackupDisabled TestBackupDisabled
-#else
-#define MAYBE_TestBackupDisabled DISABLED_TestBackupDisabled
-#endif
-IN_PROC_BROWSER_TEST_F(SingleClientBackupRollbackTest,
-                       MAYBE_TestBackupDisabled) {
-  DisableBackup();
-
-  // Setup sync, wait for its completion, and make sure changes were synced.
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
-  ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService(0)));
-  ASSERT_TRUE(ModelMatchesVerifier(0));
-
-  // Verify backup DB is not created and backup time is not set on device info.
-  ASSERT_FALSE(base::PathExists(
-      GetProfile(0)->GetPath().Append(FILE_PATH_LITERAL("Sync Data Backup"))));
-  ASSERT_TRUE(GetSyncService(0)->GetDeviceBackupTimeForTesting().is_null());
-}
-
-#if BUILDFLAG(ENABLE_PRE_SYNC_BACKUP)
-#define MAYBE_TestRollback TestRollback
-#else
-#define MAYBE_TestRollback DISABLED_TestRollback
-#endif
-IN_PROC_BROWSER_TEST_F(SingleClientBackupRollbackTest,
-                       MAYBE_TestRollback) {
-  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
-
-  // Starting state:
-  // other_node
-  //    -> top
-  //      -> tier1_a
-  //        -> http://mail.google.com  "tier1_a_url0"
-  //      -> tier1_b
-  //        -> http://www.nhl.com "tier1_b_url0"
-  const BookmarkNode* top = AddFolder(0, GetOtherNode(0), 0, "top");
-  const BookmarkNode* tier1_a = AddFolder(0, top, 0, "tier1_a");
-  const BookmarkNode* tier1_b = AddFolder(0, top, 1, "tier1_b");
-  ASSERT_TRUE(AddURL(0, tier1_a, 0, "tier1_a_url0",
-                     GURL("http://mail.google.com")));
-  ASSERT_TRUE(AddURL(0, tier1_b, 0, "tier1_b_url0",
-                     GURL("http://www.nhl.com")));
-
-  // Setup sync, wait for its completion, and make sure changes were synced.
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
-  ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService(0)));
-  ASSERT_TRUE(ModelMatchesVerifier(0));
-
-  // Made bookmark changes while sync is on.
-  Move(0, tier1_a->GetChild(0), tier1_b, 1);
-  Remove(0, tier1_b, 0);
-  ASSERT_TRUE(AddFolder(0, tier1_b, 1, "tier2_c"));
-  ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService(0)));
-  ASSERT_TRUE(ModelMatchesVerifier(0));
-
-  // Let server to return rollback command on next sync request.
-  ASSERT_TRUE(GetFakeServer()->TriggerError(sync_pb::SyncEnums::USER_ROLLBACK));
-
-  // Make another change to trigger downloading of rollback command.
-  Remove(0, tier1_b, 0);
-
-  // Wait for rollback to finish and sync backend is completely shut down.
-  SyncRollbackChecker rollback_checker(GetSyncService(0));
-  ASSERT_TRUE(rollback_checker.Wait());
-  SyncBackendStoppedChecker shutdown_checker(GetSyncService(0));
-  ASSERT_TRUE(shutdown_checker.Wait());
-
-  // Verify bookmarks are restored.
-  ASSERT_EQ(1, tier1_a->child_count());
-  const BookmarkNode* url1 = tier1_a->GetChild(0);
-  ASSERT_EQ(GURL("http://mail.google.com"), url1->url());
-
-  ASSERT_EQ(1, tier1_b->child_count());
-  const BookmarkNode* url2 = tier1_b->GetChild(0);
-  ASSERT_EQ(GURL("http://www.nhl.com"), url2->url());
-}
-
-#if BUILDFLAG(ENABLE_PRE_SYNC_BACKUP)
-#define MAYBE_TestRollbackDisabled TestRollbackDisabled
-#else
-#define MAYBE_TestRollbackDisabled DISABLED_TestRollbackDisabled
-#endif
-IN_PROC_BROWSER_TEST_F(SingleClientBackupRollbackTest,
-                       MAYBE_TestRollbackDisabled) {
-  DisableRollback();
-
-  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
-
-  // Starting state:
-  // other_node
-  //    -> http://mail.google.com  "url0"
-  //    -> http://www.nhl.com "url1"
-  ASSERT_TRUE(AddURL(0, GetOtherNode(0), 0, "url0",
-                     GURL("http://mail.google.com")));
-  ASSERT_TRUE(AddURL(0, GetOtherNode(0), 1, "url1",
-                     GURL("http://www.nhl.com")));
-
-  // Setup sync, wait for its completion, and make sure changes were synced.
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
-  ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService(0)));
-  ASSERT_TRUE(ModelMatchesVerifier(0));
-
-  // Made bookmark changes while sync is on.
-  Remove(0, GetOtherNode(0), 1);
-  ASSERT_TRUE(AddURL(0, GetOtherNode(0), 1, "url2",
-                     GURL("http://www.yahoo.com")));
-  ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService((0))));
-  ASSERT_TRUE(ModelMatchesVerifier(0));
-
-  // Let server to return rollback command on next sync request.
-  ASSERT_TRUE(GetFakeServer()->TriggerError(sync_pb::SyncEnums::USER_ROLLBACK));
-
-  // Make another change to trigger downloading of rollback command.
-  Remove(0, GetOtherNode(0), 0);
-
-  // Wait for sync backend is completely shut down.
-  SyncBackendStoppedChecker shutdown_checker(GetSyncService(0));
-  ASSERT_TRUE(shutdown_checker.Wait());
-
-  // With rollback disabled, bookmarks in backup DB should not be restored.
-  // Only bookmark added during sync is present.
-  ASSERT_EQ(1, GetOtherNode(0)->child_count());
-  ASSERT_EQ(GURL("http://www.yahoo.com"),
-            GetOtherNode(0)->GetChild(0)->url());
-}
-
-#if BUILDFLAG(ENABLE_PRE_SYNC_BACKUP)
-#define MAYBE_TestSyncDisabled TestSyncDisabled
-#else
-#define MAYBE_TestSyncDisabled DISABLED_TestSyncDisabled
-#endif
-IN_PROC_BROWSER_TEST_F(SingleClientBackupRollbackTest,
-                       MAYBE_TestSyncDisabled) {
-  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
-
-  // Starting state:
-  // other_node
-  //    -> http://mail.google.com  "url0"
-  //    -> http://www.nhl.com "url1"
-  ASSERT_TRUE(AddURL(0, GetOtherNode(0), 0, "url0",
-                     GURL("http://mail.google.com")));
-  ASSERT_TRUE(AddURL(0, GetOtherNode(0), 1, "url1",
-                     GURL("http://www.nhl.com")));
-
-  // Setup sync, wait for its completion, and make sure changes were synced.
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
-  ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService(0)));
-  ASSERT_TRUE(ModelMatchesVerifier(0));
-
-  // Made bookmark changes while sync is on.
-  Remove(0, GetOtherNode(0), 1);
-  ASSERT_TRUE(AddURL(0, GetOtherNode(0), 1, "url2",
-                     GURL("http://www.yahoo.com")));
-  ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService((0))));
-  ASSERT_TRUE(ModelMatchesVerifier(0));
-
-  // Let server to return birthday error on next sync request.
-  ASSERT_TRUE(GetFakeServer()->TriggerError(
-      sync_pb::SyncEnums::NOT_MY_BIRTHDAY));
-
-  // Make another change to trigger downloading of rollback command.
-  Remove(0, GetOtherNode(0), 0);
-
-  // Wait sync backend is completely shut down.
-  SyncBackendStoppedChecker shutdown_checker(GetSyncService(0));
-  ASSERT_TRUE(shutdown_checker.Wait());
-
-  // Shouldn't restore bookmarks with sign-out only.
-  ASSERT_EQ(1, GetOtherNode(0)->child_count());
-  ASSERT_EQ(GURL("http://www.yahoo.com"),
-            GetOtherNode(0)->GetChild(0)->url());
-}
-
-#if BUILDFLAG(ENABLE_PRE_SYNC_BACKUP)
-#define MAYBE_RollbackNoBackup RollbackNoBackup
-#else
-#define MAYBE_RollbackNoBackup DISABLED_RollbackNoBackup
-#endif
-IN_PROC_BROWSER_TEST_F(SingleClientBackupRollbackTest,
-                       MAYBE_RollbackNoBackup) {
-  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
-
-  // Starting state:
-  // other_node
-  //    -> http://mail.google.com  "url0"
-  //    -> http://www.nhl.com "url1"
-  ASSERT_TRUE(AddURL(0, GetOtherNode(0), 0, "url0",
-                     GURL("http://mail.google.com")));
-
-  // Setup sync, wait for its completion, and make sure changes were synced.
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
-  ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService((0))));
-  ASSERT_TRUE(ModelMatchesVerifier(0));
-
-  ASSERT_TRUE(AddURL(0, GetOtherNode(0), 1, "url1",
-                     GURL("http://www.nhl.com")));
-
-  // Delete backup DB.
-  base::DeleteFile(
-      GetProfile(0)->GetPath().Append(FILE_PATH_LITERAL("Sync Data Backup")),
-      true);
-
-  // Let server to return rollback command on next sync request.
-  ASSERT_TRUE(GetFakeServer()->TriggerError(sync_pb::SyncEnums::USER_ROLLBACK));
-
-  // Make another change to trigger downloading of rollback command.
-  Remove(0, GetOtherNode(0), 0);
-
-  // Wait for rollback to finish and sync backend is completely shut down.
-  SyncRollbackChecker rollback_checker(GetSyncService(0));
-  ASSERT_TRUE(rollback_checker.Wait());
-  SyncBackendStoppedChecker checker(GetSyncService(0));
-  ASSERT_TRUE(checker.Wait());
-
-  // Without backup DB, bookmarks remain at the state when sync stops.
-  ASSERT_EQ(1, GetOtherNode(0)->child_count());
-  ASSERT_EQ(GURL("http://www.nhl.com"),
-            GetOtherNode(0)->GetChild(0)->url());
-}
-
-#if BUILDFLAG(ENABLE_PRE_SYNC_BACKUP)
-#define MAYBE_DontChangeBookmarkOrdering DontChangeBookmarkOrdering
-#else
-#define MAYBE_DontChangeBookmarkOrdering DISABLED_DontChangeBookmarkOrdering
-#endif
-IN_PROC_BROWSER_TEST_F(SingleClientBackupRollbackTest,
-                       MAYBE_DontChangeBookmarkOrdering) {
-  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
-
-  const BookmarkNode* sub_folder = AddFolder(0, GetOtherNode(0), 0, "test");
-  ASSERT_TRUE(AddURL(0, sub_folder, 0, "", GURL(kUrl1)));
-  ASSERT_TRUE(AddURL(0, sub_folder, 1, "", GURL(kUrl2)));
-  ASSERT_TRUE(AddURL(0, sub_folder, 2, "", GURL(kUrl3)));
-
-  // Setup sync, wait for its completion, and make sure changes were synced.
-  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
-  ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService(0)));
-  ASSERT_TRUE(ModelMatchesVerifier(0));
-
-  // Made bookmark changes while sync is on.
-  Remove(0, sub_folder, 0);
-  Remove(0, sub_folder, 0);
-  ASSERT_TRUE(AwaitCommitActivityCompletion(GetSyncService(0)));
-  ASSERT_TRUE(ModelMatchesVerifier(0));
-
-  // Let server to return rollback command on next sync request.
-  ASSERT_TRUE(GetFakeServer()->TriggerError(sync_pb::SyncEnums::USER_ROLLBACK));
-
-  // Make another change to trigger downloading of rollback command.
-  Remove(0, sub_folder, 0);
-
-  // Wait for rollback to finish and sync backend is completely shut down.
-  SyncRollbackChecker rollback_checker(GetSyncService(0));
-  ASSERT_TRUE(rollback_checker.Wait());
-  SyncBackendStoppedChecker shutdown_checker(GetSyncService(0));
-  ASSERT_TRUE(shutdown_checker.Wait());
-
-  // Verify bookmarks are unchanged.
-  ASSERT_EQ(3, sub_folder->child_count());
-  ASSERT_EQ(GURL(kUrl1), sub_folder->GetChild(0)->url());
-  ASSERT_EQ(GURL(kUrl2), sub_folder->GetChild(1)->url());
-  ASSERT_EQ(GURL(kUrl3), sub_folder->GetChild(2)->url());
-}
diff --git a/chrome/browser/task_management/providers/task.cc b/chrome/browser/task_management/providers/task.cc
index 46d3ad8..f62b077 100644
--- a/chrome/browser/task_management/providers/task.cc
+++ b/chrome/browser/task_management/providers/task.cc
@@ -9,7 +9,8 @@
 #include "base/process/process.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_info_cache.h"
+#include "chrome/browser/profiles/profile_attributes_entry.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/task_management/task_manager_observer.h"
 #include "content/public/common/result_codes.h"
@@ -44,12 +45,12 @@
 // static
 base::string16 Task::GetProfileNameFromProfile(Profile* profile) {
   DCHECK(profile);
-  ProfileInfoCache& cache =
-      g_browser_process->profile_manager()->GetProfileInfoCache();
-  size_t index =
-      cache.GetIndexOfProfileWithPath(profile->GetOriginalProfile()->GetPath());
-  if (index != std::string::npos)
-    return cache.GetNameOfProfileAtIndex(index);
+  ProfileAttributesEntry* entry;
+  if (g_browser_process->profile_manager()->GetProfileAttributesStorage().
+      GetProfileAttributesWithPath(profile->GetOriginalProfile()->GetPath(),
+                                   &entry)) {
+    return entry->GetName();
+  }
 
   return base::string16();
 }
diff --git a/chrome/browser/task_management/providers/task.h b/chrome/browser/task_management/providers/task.h
index c1f09be..992f8bd 100644
--- a/chrome/browser/task_management/providers/task.h
+++ b/chrome/browser/task_management/providers/task.h
@@ -7,6 +7,8 @@
 
 #include <stdint.h>
 
+#include <string>
+
 #include "base/macros.h"
 #include "base/process/process_handle.h"
 #include "base/strings/string16.h"
@@ -51,7 +53,7 @@
        base::ProcessHandle handle);
   virtual ~Task();
 
-  // Gets the name of the given |profile| from the ProfileInfoCache.
+  // Gets the name of the given |profile| from the ProfileAttributesStorage.
   static base::string16 GetProfileNameFromProfile(Profile* profile);
 
   // Activates this TaskManager's task by bringing its container to the front
diff --git a/chrome/browser/themes/browser_theme_pack.cc b/chrome/browser/themes/browser_theme_pack.cc
index 2d915be2..089f2198 100644
--- a/chrome/browser/themes/browser_theme_pack.cc
+++ b/chrome/browser/themes/browser_theme_pack.cc
@@ -31,6 +31,7 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/geometry/safe_integer_conversions.h"
 #include "ui/gfx/geometry/size_conversions.h"
 #include "ui/gfx/image/canvas_image_source.h"
 #include "ui/gfx/image/image.h"
@@ -48,7 +49,7 @@
 // Version number of the current theme pack. We just throw out and rebuild
 // theme packs that aren't int-equal to this. Increment this number if you
 // change default theme assets.
-const int kThemePackVersion = 38;
+const int kThemePackVersion = 39;
 
 // IDs that are in the DataPack won't clash with the positive integer
 // uint16_t. kHeaderID should always have the maximum value because we want the
@@ -993,14 +994,14 @@
         ((color_list->GetSize() == 3) || (color_list->GetSize() == 4))) {
       SkColor color = SK_ColorWHITE;
       int r, g, b;
-      if (color_list->GetInteger(0, &r) &&
-          color_list->GetInteger(1, &g) &&
-          color_list->GetInteger(2, &b)) {
+      if (color_list->GetInteger(0, &r) && r >= 0 && r <= 255 &&
+          color_list->GetInteger(1, &g) && g >= 0 && g <= 255 &&
+          color_list->GetInteger(2, &b) && b >= 0 && b <= 255) {
         if (color_list->GetSize() == 4) {
           double alpha;
           int alpha_int;
-          if (color_list->GetDouble(3, &alpha)) {
-            color = SkColorSetARGB(static_cast<int>(alpha * 255), r, g, b);
+          if (color_list->GetDouble(3, &alpha) && alpha >= 0 && alpha <= 1) {
+            color = SkColorSetARGB(gfx::ToRoundedInt(alpha * 255), r, g, b);
           } else if (color_list->GetInteger(3, &alpha_int) &&
                      (alpha_int == 0 || alpha_int == 1)) {
             color = SkColorSetARGB(alpha_int ? 255 : 0, r, g, b);
diff --git a/chrome/browser/themes/browser_theme_pack_unittest.cc b/chrome/browser/themes/browser_theme_pack_unittest.cc
index f848010..f5930e1 100644
--- a/chrome/browser/themes/browser_theme_pack_unittest.cc
+++ b/chrome/browser/themes/browser_theme_pack_unittest.cc
@@ -288,11 +288,11 @@
     EXPECT_EQ(80, rep1.sk_bitmap().width());
     EXPECT_EQ(80, rep1.sk_bitmap().height());
     rep1.sk_bitmap().lockPixels();
-    EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep1.sk_bitmap().getColor( 4,  4));
-    EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep1.sk_bitmap().getColor( 8,  8));
-    EXPECT_EQ(SkColorSetRGB(  0, 241, 237), rep1.sk_bitmap().getColor(16, 16));
+    EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep1.sk_bitmap().getColor(4, 4));
+    EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep1.sk_bitmap().getColor(8, 8));
+    EXPECT_EQ(SkColorSetRGB(0, 241, 237), rep1.sk_bitmap().getColor(16, 16));
     EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep1.sk_bitmap().getColor(24, 24));
-    EXPECT_EQ(SkColorSetRGB(  0, 241, 237), rep1.sk_bitmap().getColor(32, 32));
+    EXPECT_EQ(SkColorSetRGB(0, 241, 237), rep1.sk_bitmap().getColor(32, 32));
     rep1.sk_bitmap().unlockPixels();
     // Scale 200%.
     const gfx::ImageSkiaRep& rep2 = image_skia->GetRepresentation(2.0f);
@@ -300,10 +300,10 @@
     EXPECT_EQ(160, rep2.sk_bitmap().width());
     EXPECT_EQ(160, rep2.sk_bitmap().height());
     rep2.sk_bitmap().lockPixels();
-    EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep2.sk_bitmap().getColor( 4,  4));
-    EXPECT_EQ(SkColorSetRGB(223,  42,   0), rep2.sk_bitmap().getColor( 8,  8));
-    EXPECT_EQ(SkColorSetRGB(223,  42,   0), rep2.sk_bitmap().getColor(16, 16));
-    EXPECT_EQ(SkColorSetRGB(223,  42,   0), rep2.sk_bitmap().getColor(24, 24));
+    EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep2.sk_bitmap().getColor(4, 4));
+    EXPECT_EQ(SkColorSetRGB(223, 42, 0), rep2.sk_bitmap().getColor(8, 8));
+    EXPECT_EQ(SkColorSetRGB(223, 42, 0), rep2.sk_bitmap().getColor(16, 16));
+    EXPECT_EQ(SkColorSetRGB(223, 42, 0), rep2.sk_bitmap().getColor(24, 24));
     EXPECT_EQ(SkColorSetRGB(255, 255, 255), rep2.sk_bitmap().getColor(32, 32));
     rep2.sk_bitmap().unlockPixels();
 
@@ -428,13 +428,43 @@
   LoadColorJSON(color_json);
 
   std::map<int, SkColor> colors = GetDefaultColorMap();
-  SkColor ntp_header = SkColorSetRGB(120, 120, 120);
-  SkColor ntp_section = SkColorSetRGB(190, 190, 190);
-  colors[ThemeProperties::COLOR_NTP_HEADER] = ntp_header;
-  colors[ThemeProperties::COLOR_NTP_SECTION] = ntp_section;
+  colors[ThemeProperties::COLOR_NTP_HEADER] = SkColorSetRGB(120, 120, 120);
+  colors[ThemeProperties::COLOR_NTP_SECTION] = SkColorSetRGB(190, 190, 190);
   VerifyColorMap(colors);
 }
 
+TEST_F(BrowserThemePackTest, SupportsAlpha) {
+  // Verify that valid alpha values are parsed correctly.
+  std::string color_json = "{ \"toolbar\": [0, 20, 40, 0], "
+                           "  \"tab_text\": [60, 80, 100, 1], "
+                           "  \"tab_background_text\": [120, 140, 160, 0.0], "
+                           "  \"bookmark_text\": [180, 200, 220, 1.0], "
+                           "  \"ntp_text\": [240, 255, 0, 0.5] }";
+  LoadColorJSON(color_json);
+
+  std::map<int, SkColor> colors = GetDefaultColorMap();
+  colors[ThemeProperties::COLOR_TOOLBAR] = SkColorSetARGB(0, 0, 20, 40);
+  colors[ThemeProperties::COLOR_TAB_TEXT] = SkColorSetARGB(255, 60, 80, 100);
+  colors[ThemeProperties::COLOR_BACKGROUND_TAB_TEXT] =
+      SkColorSetARGB(0, 120, 140, 160);
+  colors[ThemeProperties::COLOR_BOOKMARK_TEXT] =
+      SkColorSetARGB(255, 180, 200, 220);
+  colors[ThemeProperties::COLOR_NTP_TEXT] = SkColorSetARGB(128, 240, 255, 0);
+  VerifyColorMap(colors);
+}
+
+TEST_F(BrowserThemePackTest, OutOfRangeColors) {
+  // Ensure colors with out-of-range values are simply ignored.
+  std::string color_json = "{ \"toolbar\": [0, 20, 40, -1], "
+                           "  \"tab_text\": [60, 80, 100, 2], "
+                           "  \"tab_background_text\": [120, 140, 160, 47.6], "
+                           "  \"bookmark_text\": [256, 0, 0], "
+                           "  \"ntp_text\": [0, -100, 100] }";
+  LoadColorJSON(color_json);
+
+  VerifyColorMap(GetDefaultColorMap());
+}
+
 TEST_F(BrowserThemePackTest, CanReadTints) {
   std::string tint_json = "{ \"buttons\": [ 0.5, 0.5, 0.5 ] }";
   LoadTintJSON(tint_json);
diff --git a/chrome/browser/themes/theme_properties.cc b/chrome/browser/themes/theme_properties.cc
index c264bdedc..70b7b5c 100644
--- a/chrome/browser/themes/theme_properties.cc
+++ b/chrome/browser/themes/theme_properties.cc
@@ -20,7 +20,7 @@
 // ----------------------------------------------------------------------------
 // Defaults for properties which are stored in the browser theme pack. If you
 // change these defaults, you must increment the version number in
-// browser_theme_pack.h
+// browser_theme_pack.cc.
 
 // Default colors.
 #if defined(OS_CHROMEOS)
@@ -109,11 +109,7 @@
 const color_utils::HSL kDefaultTintFrameInactive = {-1, -1, 0.75};
 const color_utils::HSL kDefaultTintFrameIncognito = {-1, 0.2, 0.35};
 const color_utils::HSL kDefaultTintFrameIncognitoInactive = {-1, 0.3, 0.6};
-const color_utils::HSL kDefaultTintBackgroundTab = {-1, -1, 0.4296875};
-// In pre-md, reuse the normal tint for incognito.
-const color_utils::HSL kDefaultTintBackgroundTabIncognito[] = {
-    {-1, -1, 0.4296875},
-    {-1, -1, 0.34375}};
+const color_utils::HSL kDefaultTintBackgroundTab = {-1, -1, 0.75};
 
 // ----------------------------------------------------------------------------
 // Defaults for properties which are not stored in the browser theme pack.
@@ -251,18 +247,18 @@
 
 // static
 color_utils::HSL ThemeProperties::GetDefaultTint(int id, bool otr) {
-  int mode = ui::MaterialDesignController::IsModeMaterial();
   switch (id) {
     case TINT_FRAME:
       return otr ? kDefaultTintFrameIncognito : kDefaultTintFrame;
     case TINT_FRAME_INACTIVE:
       return otr ? kDefaultTintFrameIncognitoInactive
                  : kDefaultTintFrameInactive;
-    case TINT_BUTTONS:
+    case TINT_BUTTONS: {
+      const int mode = ui::MaterialDesignController::IsModeMaterial();
       return otr ? kDefaultTintButtonsIncognito[mode] : kDefaultTintButtons;
+    }
     case TINT_BACKGROUND_TAB:
-      return otr ? kDefaultTintBackgroundTabIncognito[mode]
-                 : kDefaultTintBackgroundTab;
+      return kDefaultTintBackgroundTab;
     case TINT_FRAME_INCOGNITO:
     case TINT_FRAME_INCOGNITO_INACTIVE:
       NOTREACHED() << "These values should be queried via their respective "
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc
index 77c20b8..18f0a4f 100644
--- a/chrome/browser/themes/theme_service.cc
+++ b/chrome/browser/themes/theme_service.cc
@@ -484,10 +484,17 @@
       return SkColorSetA(
           GetColor(ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON, incognito),
           0x33);
-    case ThemeProperties::COLOR_BACKGROUND_TAB:
+    case ThemeProperties::COLOR_BACKGROUND_TAB: {
+      // The tints here serve a different purpose than TINT_BACKGROUND_TAB.
+      // That tint is used to create background tab images for custom themes by
+      // lightening the frame images.  The tints here create solid colors for
+      // background tabs by darkening the foreground tab (toolbar) color.
+      const color_utils::HSL kTint = {-1, -1, 0.4296875};
+      const color_utils::HSL kTintIncognito = {-1, -1, 0.34375};
       return color_utils::HSLShift(
           GetColor(ThemeProperties::COLOR_TOOLBAR, incognito),
-          GetTint(ThemeProperties::TINT_BACKGROUND_TAB, incognito));
+          incognito ? kTintIncognito : kTint);
+    }
     case ThemeProperties::COLOR_DETACHED_BOOKMARK_BAR_BACKGROUND:
       if (UsingDefaultTheme())
         break;
diff --git a/chrome/browser/translate/chrome_translate_client.cc b/chrome/browser/translate/chrome_translate_client.cc
index 76496a4..d43dab0 100644
--- a/chrome/browser/translate/chrome_translate_client.cc
+++ b/chrome/browser/translate/chrome_translate_client.cc
@@ -313,7 +313,7 @@
     translate::TranslateStep step,
     translate::TranslateErrors::Type error_type) {
 // The bubble is implemented only on the desktop platforms.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
 
   // |browser| might be NULL when testing. In this case, Show(...) should be
diff --git a/chrome/browser/translate/translate_manager_render_view_host_unittest.cc b/chrome/browser/translate/translate_manager_render_view_host_unittest.cc
index dc7fca9..c82f233 100644
--- a/chrome/browser/translate/translate_manager_render_view_host_unittest.cc
+++ b/chrome/browser/translate/translate_manager_render_view_host_unittest.cc
@@ -8,6 +8,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/command_line.h"
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/stringprintf.h"
@@ -62,6 +63,57 @@
 #include "components/translate/core/browser/translate_infobar_delegate.h"
 #endif
 
+namespace {
+
+class MockTranslateBubbleFactory : public TranslateBubbleFactory {
+ public:
+  MockTranslateBubbleFactory() {}
+
+  void ShowImplementation(
+      BrowserWindow* window,
+      content::WebContents* web_contents,
+      translate::TranslateStep step,
+      translate::TranslateErrors::Type error_type) override {
+    if (model_) {
+      model_->SetViewState(
+          TranslateBubbleModelImpl::TranslateStepToViewState(step));
+      return;
+    }
+
+    ChromeTranslateClient* chrome_translate_client =
+        ChromeTranslateClient::FromWebContents(web_contents);
+    std::string source_language =
+        chrome_translate_client->GetLanguageState().original_language();
+    std::string target_language =
+        translate::TranslateDownloadManager::GetLanguageCode(
+            g_browser_process->GetApplicationLocale());
+
+    scoped_ptr<translate::TranslateUIDelegate> ui_delegate(
+        new translate::TranslateUIDelegate(
+            chrome_translate_client->GetTranslateManager()->GetWeakPtr(),
+            source_language,
+            target_language));
+    model_.reset(new TranslateBubbleModelImpl(step, std::move(ui_delegate)));
+  }
+
+  bool DismissBubble(bool explicitly_closed) {
+    if (!model_)
+      return false;
+    model_->TranslationDeclined(explicitly_closed);
+    model_.reset();
+    return true;
+  }
+
+  TranslateBubbleModel* model() { return model_.get(); }
+
+ private:
+  scoped_ptr<TranslateBubbleModel> model_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockTranslateBubbleFactory);
+};
+
+}  // namespace
+
 // An observer that keeps track of whether a navigation entry was committed.
 class NavEntryCommittedObserver : public content::NotificationObserver {
  public:
@@ -100,6 +152,48 @@
             base::Bind(&TranslateManagerRenderViewHostTest::OnPreferenceChanged,
                        base::Unretained(this))) {}
 
+#if !defined(USE_AURA)
+  // Ensure that we are testing under the bubble UI.
+  // TODO(groby): Remove once the bubble is enabled by default everywhere.
+  // http://crbug.com/507442
+  void EnableBubbleTest() {
+    if (TranslateService::IsTranslateBubbleEnabled()) {
+      bubble_factory_.reset(new MockTranslateBubbleFactory);
+      TranslateBubbleFactory::SetFactory(bubble_factory_.get());
+    }
+  }
+
+  bool TranslateUiVisible() {
+    if (bubble_factory_) {
+      TranslateBubbleModel* bubble = bubble_factory_->model();
+      return bubble != nullptr;
+    } else {
+      bool result = (GetTranslateInfoBar() != nullptr);
+      EXPECT_EQ(infobar_service()->infobar_count() != 0, result);
+      return result;
+    }
+  }
+
+  bool CloseTranslateUi() {
+    if (bubble_factory_) {
+      return bubble_factory_->DismissBubble(true);
+    } else {
+      return CloseTranslateInfoBar();
+    }
+  }
+
+  void SimulateTranslatePress() {
+    // Simulate the user translating.
+    if (bubble_factory_.get()) {
+      bubble_factory_->model()->Translate();
+    } else {
+      translate::TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
+      ASSERT_TRUE(infobar != nullptr);
+      infobar->Translate();
+    }
+  }
+#endif  // defined(USE_AURA)
+
   // Simulates navigating to a page and getting the page contents and language
   // for that navigation.
   void SimulateNavigation(const GURL& url,
@@ -193,12 +287,16 @@
   // If there is 1 infobar and it is a translate infobar, deny translation and
   // returns true.  Returns false otherwise.
   bool DenyTranslation() {
-    translate::TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
-    if (!infobar)
-      return false;
-    infobar->TranslationDeclined();
-    infobar_service()->RemoveInfoBar(infobar_service()->infobar_at(0));
-    return true;
+    if (bubble_factory_.get()) {
+      return bubble_factory_->DismissBubble(true);
+    } else {
+      translate::TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
+      if (!infobar)
+        return false;
+      infobar->TranslationDeclined();
+      infobar_service()->RemoveInfoBar(infobar_service()->infobar_at(0));
+      return true;
+    }
   }
 #endif  // defined(USE_AURA)
 
@@ -365,47 +463,10 @@
   // WARNING: the pointers point to deleted objects, use only for comparison.
   std::set<infobars::InfoBarDelegate*> removed_infobars_;
 
+  scoped_ptr<MockTranslateBubbleFactory> bubble_factory_;
   DISALLOW_COPY_AND_ASSIGN(TranslateManagerRenderViewHostTest);
 };
 
-class MockTranslateBubbleFactory : public TranslateBubbleFactory {
- public:
-  MockTranslateBubbleFactory() {}
-
-  void ShowImplementation(
-      BrowserWindow* window,
-      content::WebContents* web_contents,
-      translate::TranslateStep step,
-      translate::TranslateErrors::Type error_type) override {
-    if (model_) {
-      model_->SetViewState(
-          TranslateBubbleModelImpl::TranslateStepToViewState(step));
-      return;
-    }
-
-    ChromeTranslateClient* chrome_translate_client =
-        ChromeTranslateClient::FromWebContents(web_contents);
-    std::string source_language =
-        chrome_translate_client->GetLanguageState().original_language();
-    std::string target_language =
-        translate::TranslateDownloadManager::GetLanguageCode(
-            g_browser_process->GetApplicationLocale());
-
-    scoped_ptr<translate::TranslateUIDelegate> ui_delegate(
-        new translate::TranslateUIDelegate(
-            chrome_translate_client->GetTranslateManager()->GetWeakPtr(),
-            source_language,
-            target_language));
-    model_.reset(new TranslateBubbleModelImpl(step, std::move(ui_delegate)));
-  }
-
-  TranslateBubbleModel* model() { return model_.get(); }
-
- private:
-  scoped_ptr<TranslateBubbleModel> model_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockTranslateBubbleFactory);
-};
 
 // A list of languages to fake being returned by the translate server.
 // Use only langauges for which Chrome's copy of ICU has
@@ -705,6 +766,8 @@
 // Tests that we show/don't show an info-bar for the languages.
 TEST_F(TranslateManagerRenderViewHostTest, TestLanguages) {
   // TODO(port): Test corresponding bubble translate UX: http://crbug.com/383235
+  // This actually doesn't make sense to port, because the check for supported
+  // languages moved out of the Infobar into the TranslateManager.
   if (TranslateService::IsTranslateBubbleEnabled())
     return;
 
@@ -744,17 +807,11 @@
 
 // Tests auto-translate on page.
 TEST_F(TranslateManagerRenderViewHostTest, AutoTranslateOnNavigate) {
-  // TODO(port): Test corresponding bubble translate UX: http://crbug.com/383235
-  if (TranslateService::IsTranslateBubbleEnabled())
-    return;
+  EnableBubbleTest();
 
   SimulateNavigation(GURL("http://www.google.fr"), "fr", true);
 
-  // Simulate the user translating.
-  translate::TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
-  ASSERT_TRUE(infobar != NULL);
-  infobar->Translate();
-  // Simulate the translate script being retrieved.
+  SimulateTranslatePress();
   SimulateTranslateScriptURLFetch(true);
   SimulateOnPageTranslated("fr", "en");
 
@@ -778,26 +835,26 @@
 
 // Tests that multiple OnPageContents do not cause multiple infobars.
 TEST_F(TranslateManagerRenderViewHostTest, MultipleOnPageContents) {
-  // TODO(port): Test corresponding bubble translate UX: http://crbug.com/383235
-  if (TranslateService::IsTranslateBubbleEnabled())
-    return;
+  EnableBubbleTest();
 
   SimulateNavigation(GURL("http://www.google.fr"), "fr", true);
 
   // Simulate clicking 'Nope' (don't translate).
+  EXPECT_TRUE(TranslateUiVisible());
   EXPECT_TRUE(DenyTranslation());
-  EXPECT_EQ(0U, infobar_service()->infobar_count());
+  EXPECT_FALSE(TranslateUiVisible());
 
-  // Send a new PageContents, we should not show an infobar.
+  // Send a new PageContents, we should not show the translate UI.
   SimulateOnTranslateLanguageDetermined("fr", true);
-  EXPECT_EQ(0U, infobar_service()->infobar_count());
+  EXPECT_FALSE(TranslateUiVisible());
 
   // Do the same steps but simulate closing the infobar this time.
-  SimulateNavigation(GURL("http://www.youtube.fr"), "fr", true);
-  EXPECT_TRUE(CloseTranslateInfoBar());
-  EXPECT_EQ(0U, infobar_service()->infobar_count());
-  SimulateOnTranslateLanguageDetermined("fr", true);
-  EXPECT_EQ(0U, infobar_service()->infobar_count());
+  SimulateNavigation(GURL("http://www.youtube.de"), "de", true);
+  EXPECT_TRUE(TranslateUiVisible());
+  EXPECT_TRUE(CloseTranslateUi());
+  EXPECT_FALSE(TranslateUiVisible());
+  SimulateOnTranslateLanguageDetermined("de", true);
+  EXPECT_FALSE(TranslateUiVisible());
 }
 
 // Test that reloading the page brings back the infobar if the
diff --git a/chrome/browser/ui/android/infobars/update_password_infobar.cc b/chrome/browser/ui/android/infobars/update_password_infobar.cc
new file mode 100644
index 0000000..08dbd0c
--- /dev/null
+++ b/chrome/browser/ui/android/infobars/update_password_infobar.cc
@@ -0,0 +1,68 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/android/infobars/update_password_infobar.h"
+
+#include <vector>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
+#include "chrome/browser/password_manager/update_password_infobar_delegate.h"
+#include "components/password_manager/core/common/credential_manager_types.h"
+#include "jni/UpdatePasswordInfoBar_jni.h"
+
+UpdatePasswordInfoBar::UpdatePasswordInfoBar(
+    scoped_ptr<UpdatePasswordInfoBarDelegate> delegate)
+    : ConfirmInfoBar(std::move(delegate)) {}
+
+UpdatePasswordInfoBar::~UpdatePasswordInfoBar() {}
+
+bool UpdatePasswordInfoBar::Register(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+int UpdatePasswordInfoBar::GetIdOfSelectedUsername() const {
+  return Java_UpdatePasswordInfoBar_getSelectedUsername(
+      base::android::AttachCurrentThread(), java_infobar_.obj());
+}
+
+base::android::ScopedJavaLocalRef<jobject>
+UpdatePasswordInfoBar::CreateRenderInfoBar(JNIEnv* env) {
+  using base::android::ConvertUTF16ToJavaString;
+  using base::android::ScopedJavaLocalRef;
+  UpdatePasswordInfoBarDelegate* update_password_delegate =
+      static_cast<UpdatePasswordInfoBarDelegate*>(delegate());
+  ScopedJavaLocalRef<jstring> ok_button_text = ConvertUTF16ToJavaString(
+      env, GetTextFor(ConfirmInfoBarDelegate::BUTTON_OK));
+  ScopedJavaLocalRef<jstring> cancel_button_text = ConvertUTF16ToJavaString(
+      env, GetTextFor(ConfirmInfoBarDelegate::BUTTON_CANCEL));
+  ScopedJavaLocalRef<jstring> branding_text =
+      ConvertUTF16ToJavaString(env, update_password_delegate->GetBranding());
+
+  std::vector<base::string16> usernames;
+  if (update_password_delegate->ShowMultipleAccounts()) {
+    for (auto password_form : update_password_delegate->GetCurrentForms())
+      usernames.push_back(password_form->username_value);
+  } else {
+    usernames.push_back(
+        update_password_delegate->get_username_for_single_account());
+  }
+
+  base::android::ScopedJavaLocalRef<jobject> infobar;
+  infobar.Reset(Java_UpdatePasswordInfoBar_show(
+      env, reinterpret_cast<intptr_t>(this), GetEnumeratedIconId(),
+      base::android::ToJavaArrayOfStrings(env, usernames).obj(),
+      ok_button_text.obj(), cancel_button_text.obj(), branding_text.obj(),
+      update_password_delegate->ShowMultipleAccounts(),
+      update_password_delegate->is_smartlock_branding_enabled()));
+
+  java_infobar_.Reset(env, infobar.obj());
+  return infobar;
+}
+
+void UpdatePasswordInfoBar::OnLinkClicked(JNIEnv* env,
+                                          const JavaParamRef<jobject>& obj) {
+  GetDelegate()->LinkClicked(NEW_FOREGROUND_TAB);
+}
diff --git a/chrome/browser/ui/android/infobars/update_password_infobar.h b/chrome/browser/ui/android/infobars/update_password_infobar.h
new file mode 100644
index 0000000..f43fddd2
--- /dev/null
+++ b/chrome/browser/ui/android/infobars/update_password_infobar.h
@@ -0,0 +1,37 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_ANDROID_INFOBARS_UPDATE_PASSWORD_INFOBAR_H_
+#define CHROME_BROWSER_UI_ANDROID_INFOBARS_UPDATE_PASSWORD_INFOBAR_H_
+
+#include "base/android/scoped_java_ref.h"
+#include "base/macros.h"
+#include "chrome/browser/ui/android/infobars/confirm_infobar.h"
+
+class UpdatePasswordInfoBarDelegate;
+
+// The infobar to be used with UpdatePasswordInfoBarDelegate.
+class UpdatePasswordInfoBar : public ConfirmInfoBar {
+ public:
+  explicit UpdatePasswordInfoBar(
+      scoped_ptr<UpdatePasswordInfoBarDelegate> delegate);
+  ~UpdatePasswordInfoBar() override;
+
+  static bool Register(JNIEnv* env);
+
+  int GetIdOfSelectedUsername() const;
+
+ private:
+  // ConfirmInfoBar:
+  base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar(
+      JNIEnv* env) override;
+  void OnLinkClicked(JNIEnv* env,
+                     const base::android::JavaParamRef<jobject>& obj) override;
+
+  base::android::ScopedJavaGlobalRef<jobject> java_infobar_;
+
+  DISALLOW_COPY_AND_ASSIGN(UpdatePasswordInfoBar);
+};
+
+#endif  // CHROME_BROWSER_UI_ANDROID_INFOBARS_UPDATE_PASSWORD_INFOBAR_H_
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
index b76d703..3a0c7f4 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -1571,7 +1571,8 @@
     const std::string& user_id) const {
   Profile* other_profile = multi_user_util::GetProfileFromAccountId(
       AccountId::FromUserEmail(user_id));
-  DCHECK_NE(other_profile, profile_);
+  if (other_profile == profile_)
+    return false;
 
   // Note: The Auto hide state from preferences is not the same as the actual
   // visibility of the shelf. Depending on all the various states (full screen,
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
index bf12d330..f6c33d23 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
@@ -144,6 +144,24 @@
   ash::MultiProfileUMA::RecordTeleportWindowType(window_type);
 }
 
+bool HasSystemModalTransientChildWindow(aura::Window* window) {
+  if (window == nullptr)
+    return false;
+
+  aura::Window* system_modal_container = window->GetRootWindow()->GetChildById(
+      ash::kShellWindowId_SystemModalContainer);
+  if (window->parent() == system_modal_container)
+    return true;
+
+  aura::Window::Windows::const_iterator it =
+      wm::GetTransientChildren(window).begin();
+  for (; it != wm::GetTransientChildren(window).end(); ++it) {
+    if (HasSystemModalTransientChildWindow(*it))
+      return true;
+  }
+  return false;
+}
+
 }  // namespace
 
 namespace chrome {
@@ -603,11 +621,7 @@
   // Note that in some cases (e.g. unit test) windows might not have a root
   // window.
   if (!visible && window->GetRootWindow()) {
-    // Get the system modal container for the window's root window.
-    aura::Window* system_modal_container =
-        window->GetRootWindow()->GetChildById(
-            ash::kShellWindowId_SystemModalContainer);
-    if (window->parent() == system_modal_container) {
+    if (HasSystemModalTransientChildWindow(window)) {
       // The window is system modal and we need to find the parent which owns
       // it so that we can switch to the desktop accordingly.
       AccountId account_id = GetUserPresentingWindow(window);
diff --git a/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc b/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc
index 627c8e1..30818ad 100644
--- a/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc
+++ b/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc
@@ -111,6 +111,7 @@
       animation_step_(ANIMATION_STEP_HIDE_OLD_USER),
       screen_cover_(GetScreenCover(NULL)),
       windows_by_account_id_() {
+  ash::Shell::GetInstance()->DismissAppList();
   BuildUserToWindowsListMap();
   AdvanceUserTransitionAnimation();
 
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index a21d2c90..3b8ec54 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -55,7 +55,7 @@
 #include "components/ui/zoom/zoom_controller.h"
 #endif
 
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_ANDROID)
 #include "components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h"
 #include "components/autofill/core/browser/autofill_save_card_infobar_mobile.h"
 #include "components/infobars/core/infobar.h"
@@ -190,7 +190,7 @@
 void ChromeAutofillClient::ConfirmSaveCreditCardLocally(
     const CreditCard& card,
     const base::Closure& callback) {
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_ANDROID)
   InfoBarService::FromWebContents(web_contents())->AddInfoBar(
       CreateSaveCardInfoBarMobile(
           make_scoped_ptr(new AutofillSaveCardInfoBarDelegateMobile(
@@ -216,7 +216,7 @@
     const CreditCard& card,
     scoped_ptr<base::DictionaryValue> legal_message,
     const base::Closure& callback) {
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_ANDROID)
   InfoBarService::FromWebContents(web_contents())->AddInfoBar(
       CreateSaveCardInfoBarMobile(
           make_scoped_ptr(new AutofillSaveCardInfoBarDelegateMobile(
diff --git a/chrome/browser/ui/bluetooth/bluetooth_chooser_bubble_delegate.cc b/chrome/browser/ui/bluetooth/bluetooth_chooser_bubble_delegate.cc
index 7db53f2..10ad62b 100644
--- a/chrome/browser/ui/bluetooth/bluetooth_chooser_bubble_delegate.cc
+++ b/chrome/browser/ui/bluetooth/bluetooth_chooser_bubble_delegate.cc
@@ -6,7 +6,9 @@
 
 #include "base/stl_util.h"
 #include "chrome/browser/ui/bluetooth/bluetooth_chooser_desktop.h"
+#include "chrome/common/url_constants.h"
 #include "components/bubble/bubble_controller.h"
+#include "url/gurl.h"
 
 BluetoothChooserBubbleDelegate::BluetoothChooserBubbleDelegate(
     content::RenderFrameHost* owner)
@@ -56,6 +58,10 @@
   }
 }
 
+GURL BluetoothChooserBubbleDelegate::GetHelpCenterUrl() const {
+  return GURL(chrome::kChooserBluetoothOverviewURL);
+}
+
 void BluetoothChooserBubbleDelegate::AddDevice(
     const std::string& device_id,
     const base::string16& device_name) {
diff --git a/chrome/browser/ui/bluetooth/bluetooth_chooser_bubble_delegate.h b/chrome/browser/ui/bluetooth/bluetooth_chooser_bubble_delegate.h
index fcebd63..b0af713 100644
--- a/chrome/browser/ui/bluetooth/bluetooth_chooser_bubble_delegate.h
+++ b/chrome/browser/ui/bluetooth/bluetooth_chooser_bubble_delegate.h
@@ -29,6 +29,7 @@
   void Select(size_t index) override;
   void Cancel() override;
   void Close() override;
+  GURL GetHelpCenterUrl() const override;
 
   // Shows a new device in the chooser.
   void AddDevice(const std::string& device_id,
diff --git a/chrome/browser/ui/bookmarks/bookmark_utils_desktop.cc b/chrome/browser/ui/bookmarks/bookmark_utils_desktop.cc
index 3802abd..f777396 100644
--- a/chrome/browser/ui/bookmarks/bookmark_utils_desktop.cc
+++ b/chrome/browser/ui/bookmarks/bookmark_utils_desktop.cc
@@ -125,7 +125,7 @@
   DISALLOW_COPY_AND_ASSIGN(OpenURLIterator);
 };
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 bool ShouldOpenAll(gfx::NativeWindow parent,
                    const std::vector<const BookmarkNode*>& nodes) {
   int child_count = 0;
@@ -158,7 +158,7 @@
   return result;
 }
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 // Returns in |urls|, the url and title pairs for each open tab in browser.
 void GetURLsForOpenTabs(Browser* browser,
                         std::vector<std::pair<GURL, base::string16> >* urls) {
@@ -173,7 +173,7 @@
 
 }  // namespace
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 void OpenAll(gfx::NativeWindow parent,
              content::PageNavigator* navigator,
              const std::vector<const BookmarkNode*>& nodes,
@@ -267,6 +267,6 @@
   }
   return false;
 }
-#endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif  // !defined(OS_ANDROID)
 
 }  // namespace chrome
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index 9f081162..da10776 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -2715,12 +2715,12 @@
 }
 
 IN_PROC_BROWSER_TEST_F(BrowserTest, GetSizeForNewRenderView) {
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
   // TODO(erikchen): This behavior has regressed on OSX 10.7 and 10.8 and should
   // be fixed. http://crbug.com/503185
   if (base::mac::IsOSMountainLion() || base::mac::IsOSLion())
     return;
-#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
+#endif  // defined(OS_MACOSX)
   // The instant extended NTP has javascript that does not work with
   // ui_test_utils::NavigateToURL.  The NTP rvh reloads when the browser tries
   // to navigate away from the page, which causes the WebContents to end up in
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index d718bdab..ff551e1 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -439,7 +439,7 @@
   content::RecordAction(UserMetricsAction("Home"));
 
   std::string extra_headers;
-#if defined(ENABLE_RLZ) && !defined(OS_IOS)
+#if defined(ENABLE_RLZ)
   // If the home page is a Google home page, add the RLZ header to the request.
   PrefService* pref_service = browser->profile()->GetPrefs();
   if (pref_service) {
@@ -449,7 +449,7 @@
           rlz::RLZTracker::ChromeHomePage());
     }
   }
-#endif  // defined(ENABLE_RLZ) && !defined(OS_IOS)
+#endif  // defined(ENABLE_RLZ)
 
   GURL url = browser->profile()->GetHomePage();
 
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h
index 467a1ca0..90564a8 100644
--- a/chrome/browser/ui/browser_window.h
+++ b/chrome/browser/ui/browser_window.h
@@ -15,6 +15,7 @@
 #include "chrome/browser/ui/exclusive_access/exclusive_access_bubble_type.h"
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/sync/one_click_signin_sync_starter.h"
+#include "chrome/common/features.h"
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "components/security_state/security_state_model.h"
 #include "components/signin/core/browser/signin_header_helper.h"
@@ -257,7 +258,7 @@
       translate::TranslateErrors::Type error_type,
       bool is_user_gesture) = 0;
 
-#if defined(ENABLE_ONE_CLICK_SIGNIN)
+#if BUILDFLAG(ENABLE_ONE_CLICK_SIGNIN)
   enum OneClickSigninBubbleType {
     ONE_CLICK_SIGNIN_BUBBLE_TYPE_BUBBLE,
     ONE_CLICK_SIGNIN_BUBBLE_TYPE_MODAL_DIALOG,
diff --git a/chrome/browser/ui/chrome_bubble_manager_unittest.cc b/chrome/browser/ui/chrome_bubble_manager_unittest.cc
index a2744b7..4e51a95c 100644
--- a/chrome/browser/ui/chrome_bubble_manager_unittest.cc
+++ b/chrome/browser/ui/chrome_bubble_manager_unittest.cc
@@ -63,7 +63,7 @@
   scoped_ptr<MockBubbleDelegate> delegate(new MockBubbleDelegate);
   EXPECT_CALL(*delegate, ShouldClose(BUBBLE_CLOSE_NAVIGATED))
       .WillOnce(testing::Return(true));
-  EXPECT_CALL(*delegate, DidClose());
+  EXPECT_CALL(*delegate, DidClose(BUBBLE_CLOSE_NAVIGATED));
   EXPECT_CALL(*delegate, Destroyed());
 
   BubbleReference bubble_ref = manager_->ShowBubble(std::move(delegate));
@@ -93,7 +93,7 @@
       .WillRepeatedly(testing::Return(subframe0));
   EXPECT_CALL(*delegate, ShouldClose(BUBBLE_CLOSE_FRAME_DESTROYED))
       .WillOnce(testing::Return(true));
-  EXPECT_CALL(*delegate, DidClose());
+  EXPECT_CALL(*delegate, DidClose(BUBBLE_CLOSE_FRAME_DESTROYED));
   EXPECT_CALL(*delegate, Destroyed());
 
   BubbleReference bubble_ref = manager_->ShowBubble(std::move(delegate));
diff --git a/chrome/browser/ui/chrome_pages.cc b/chrome/browser/ui/chrome_pages.cc
index 4434c4d..bbb12678 100644
--- a/chrome/browser/ui/chrome_pages.cc
+++ b/chrome/browser/ui/chrome_pages.cc
@@ -45,7 +45,7 @@
 #include "extensions/browser/extension_registry.h"
 #endif
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "components/signin/core/browser/signin_manager.h"
 #endif
@@ -353,7 +353,7 @@
   ShowSettingsSubPage(browser, kSearchEnginesSubPage);
 }
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 void ShowBrowserSignin(Browser* browser,
                        signin_metrics::AccessPoint access_point) {
   Profile* original_profile = browser->profile()->GetOriginalProfile();
diff --git a/chrome/browser/ui/chrome_pages.h b/chrome/browser/ui/chrome_pages.h
index e08f4cb..a147de2 100644
--- a/chrome/browser/ui/chrome_pages.h
+++ b/chrome/browser/ui/chrome_pages.h
@@ -14,7 +14,7 @@
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "url/gurl.h"
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 #include "chrome/browser/signin/signin_promo.h"
 #endif
 
@@ -93,7 +93,7 @@
 void ShowAboutChrome(Browser* browser);
 void ShowSearchEngineSettings(Browser* browser);
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 // Initiates signin in a new browser tab.
 void ShowBrowserSignin(Browser* browser,
                        signin_metrics::AccessPoint access_point);
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.h b/chrome/browser/ui/cocoa/browser_window_cocoa.h
index 17eadf0..a6629e22 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.h
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.h
@@ -12,6 +12,7 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/search/search_model_observer.h"
 #include "chrome/browser/ui/tabs/tab_utils.h"
+#include "chrome/common/features.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/security_state/security_state_model.h"
 #include "ui/base/ui_base_types.h"
@@ -112,7 +113,7 @@
                            translate::TranslateStep step,
                            translate::TranslateErrors::Type error_type,
                            bool is_user_gesture) override;
-#if defined(ENABLE_ONE_CLICK_SIGNIN)
+#if BUILDFLAG(ENABLE_ONE_CLICK_SIGNIN)
   void ShowOneClickSigninBubble(
       OneClickSigninBubbleType type,
       const base::string16& email,
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
index c425643..de9dce3 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.mm
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
@@ -53,6 +53,7 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/bookmarks/common/bookmark_pref_names.h"
@@ -71,7 +72,7 @@
 #include "ui/events/keycodes/keyboard_codes.h"
 #include "ui/gfx/geometry/rect.h"
 
-#if defined(ENABLE_ONE_CLICK_SIGNIN)
+#if BUILDFLAG(ENABLE_ONE_CLICK_SIGNIN)
 #import "chrome/browser/ui/cocoa/one_click_signin_bubble_controller.h"
 #import "chrome/browser/ui/cocoa/one_click_signin_dialog_controller.h"
 #endif
@@ -641,7 +642,7 @@
                                        errorType:error_type];
 }
 
-#if defined(ENABLE_ONE_CLICK_SIGNIN)
+#if BUILDFLAG(ENABLE_ONE_CLICK_SIGNIN)
 void BrowserWindowCocoa::ShowOneClickSigninBubble(
     OneClickSigninBubbleType type,
     const base::string16& email,
@@ -734,8 +735,17 @@
 
 void BrowserWindowCocoa::HandleKeyboardEvent(
     const NativeWebKeyboardEvent& event) {
-  if ([BrowserWindowUtils shouldHandleKeyboardEvent:event])
-    [BrowserWindowUtils handleKeyboardEvent:event.os_event inWindow:window()];
+  if ([BrowserWindowUtils shouldHandleKeyboardEvent:event]) {
+    if (![BrowserWindowUtils handleKeyboardEvent:event.os_event
+                                        inWindow:window()]) {
+
+      // TODO(spqchan): This is a temporary fix for exit extension fullscreen.
+      // A priority system for exiting extension fullscreen when there is a
+      // conflict is being experimented. See Issue 536047.
+      if (event.windowsKeyCode == ui::VKEY_ESCAPE)
+        [controller_ exitExtensionFullscreenIfPossible];
+    }
+  }
 }
 
 void BrowserWindowCocoa::CutCopyPaste(int command_id) {
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.h b/chrome/browser/ui/cocoa/browser_window_controller.h
index f6943fd..13bf692 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.h
+++ b/chrome/browser/ui/cocoa/browser_window_controller.h
@@ -14,9 +14,11 @@
 
 #include "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
+#include "chrome/browser/extensions/browser_extension_window_controller.h"
 #include "chrome/browser/translate/chrome_translate_client.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.h"
 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.h"
+#import "chrome/browser/ui/cocoa/exclusive_access_bubble_window_controller.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_window_controller.h"
 #import "chrome/browser/ui/cocoa/themed_window.h"
@@ -524,6 +526,10 @@
 // window must be in immersive or AppKit Fullscreen.
 - (void)updateFullscreenWithToolbar:(BOOL)withToolbar;
 
+// Exits extension fullscreen if we're currently in the mode. Returns YES
+// if we exited fullscreen.
+- (BOOL)exitExtensionFullscreenIfPossible;
+
 // Updates the contents of the fullscreen exit bubble with |url| and
 // |bubbleType|.
 - (void)updateFullscreenExitBubble;
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm
index e6616ac..8bbb544bc 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -101,6 +101,7 @@
 #include "ui/base/l10n/l10n_util_mac.h"
 #import "ui/gfx/mac/coordinate_conversion.h"
 #include "ui/gfx/mac/scoped_cocoa_disable_screen_updates.h"
+#include "ui/gfx/screen.h"
 
 using bookmarks::BookmarkModel;
 using bookmarks::BookmarkNode;
@@ -1980,6 +1981,16 @@
   [self showFullscreenExitBubbleIfNecessary];
 }
 
+- (BOOL)exitExtensionFullscreenIfPossible {
+  if (browser_->exclusive_access_manager()
+          ->fullscreen_controller()
+          ->IsExtensionFullscreenOrPending()) {
+    browser_->extension_window_controller()->SetFullscreenMode(NO, GURL());
+    return YES;
+  }
+  return NO;
+}
+
 - (void)setFullscreenToolbarHidden:(BOOL)shouldHide {
   if (shouldHideFullscreenToolbar_ == shouldHide)
     return;
@@ -2017,11 +2028,18 @@
 
 - (void)enterWebContentFullscreen {
   // HTML5 Fullscreen should only use AppKit fullscreen in 10.10+.
+  // However, if the user is using multiple monitors and turned off
+  // "Separate Space in Each Display", use Immersive Fullscreen so
+  // that the other monitors won't blank out.
+  gfx::Screen* screen = gfx::Screen::GetScreen();
+  BOOL hasMultipleMonitors = screen && screen->GetNumDisplays() > 1;
   if (chrome::mac::SupportsSystemFullscreen() &&
-      base::mac::IsOSYosemiteOrLater())
+      base::mac::IsOSYosemiteOrLater() &&
+      !(hasMultipleMonitors && ![NSScreen screensHaveSeparateSpaces])) {
     [self enterAppKitFullscreen];
-  else
+  } else {
     [self enterImmersiveFullscreen];
+  }
 
   if (!exclusiveAccessController_->url().is_empty())
     [self updateFullscreenExitBubble];
diff --git a/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.mm b/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.mm
index 6bd960b..e737e90 100644
--- a/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.mm
+++ b/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.mm
@@ -21,7 +21,6 @@
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/web_contents.h"
 #include "grit/theme_resources.h"
-#include "net/base/net_util.h"
 #include "ui/base/cocoa/appkit_utils.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/image/image.h"
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
index 3280b81..c3d9761 100644
--- a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
+++ b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
@@ -64,7 +64,6 @@
 #include "extensions/common/extension.h"
 #include "grit/components_scaled_resources.h"
 #include "grit/theme_resources.h"
-#include "net/base/net_util.h"
 #include "skia/ext/skia_utils_mac.h"
 #import "ui/base/cocoa/cocoa_base_utils.h"
 #include "ui/base/l10n/l10n_util_mac.h"
diff --git a/chrome/browser/ui/cocoa/passwords/autosignin_prompt_view_controller.mm b/chrome/browser/ui/cocoa/passwords/autosignin_prompt_view_controller.mm
index f0c110b7..1e27b02 100644
--- a/chrome/browser/ui/cocoa/passwords/autosignin_prompt_view_controller.mm
+++ b/chrome/browser/ui/cocoa/passwords/autosignin_prompt_view_controller.mm
@@ -79,10 +79,7 @@
 
   // Layout.
   // Compute the bubble width using the title and the buttons.
-  const CGFloat contentWidth = 2 * kFramePadding + std::max(
-      NSWidth([titleView frame]),
-      NSWidth([_okButton frame]) + kRelatedControlHorizontalPadding +
-      NSWidth([_turnOffButton frame]));
+  const CGFloat contentWidth = kDesiredBubbleWidth;
   CGFloat curX = contentWidth - kFramePadding;
   CGFloat curY = kFramePadding;
   [_okButton setFrameOrigin:NSMakePoint(curX - NSWidth([_okButton frame]),
diff --git a/chrome/browser/ui/cocoa/screen_capture_notification_ui_cocoa.mm b/chrome/browser/ui/cocoa/screen_capture_notification_ui_cocoa.mm
index 63bef00..00407ae 100644
--- a/chrome/browser/ui/cocoa/screen_capture_notification_ui_cocoa.mm
+++ b/chrome/browser/ui/cocoa/screen_capture_notification_ui_cocoa.mm
@@ -22,6 +22,7 @@
 #include "ui/gfx/font_list.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/image/image_skia_util_mac.h"
+#include "ui/gfx/mac/nswindow_frame_controls.h"
 #include "ui/gfx/text_elider.h"
 #include "ui/native_theme/native_theme.h"
 #include "ui/native_theme/native_theme_mac.h"
@@ -88,6 +89,7 @@
   [window setLevel:NSStatusWindowLevel];
   [window setMovableByWindowBackground:YES];
   [window setDelegate:self];
+  gfx::SetNSWindowVisibleOnAllWorkspaces(window, true);
 
   self = [super initWithWindow:window];
   if (self) {
diff --git a/chrome/browser/ui/extensions/hosted_app_browser_controller.cc b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
index 26cb0b5..dcff7bcf 100644
--- a/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
+++ b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
@@ -19,7 +19,6 @@
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/extension.h"
-#include "net/base/net_util.h"
 #include "url/gurl.h"
 
 namespace extensions {
diff --git a/chrome/browser/ui/layout_constants.cc b/chrome/browser/ui/layout_constants.cc
index b228e09..c226c65 100644
--- a/chrome/browser/ui/layout_constants.cc
+++ b/chrome/browser/ui/layout_constants.cc
@@ -14,7 +14,7 @@
   const int kIconLabelViewTrailingPadding[] = {2, 8, 8};
   const int kLocationBarBorderThickness[] = {2, 1, 1};
   const int kLocationBarBubbleHorizontalPadding[] = {1, 4, 4};
-  const int kLocationBarBubbleVerticalPadding[] = {1, 4, 4};
+  const int kLocationBarBubbleVerticalPadding[] = {1, 3, 3};
   const int kLocationBarHeight[] = {27, 28, 32};
   const int kLocationBarHorizontalPadding[] = {3, 6, 6};
   const int kLocationBarVerticalPadding[] = {0, 1, 1};
diff --git a/chrome/browser/ui/login/login_prompt.cc b/chrome/browser/ui/login/login_prompt.cc
index dd84b4d..abfc10d 100644
--- a/chrome/browser/ui/login/login_prompt.cc
+++ b/chrome/browser/ui/login/login_prompt.cc
@@ -36,7 +36,6 @@
 #include "content/public/common/origin_util.h"
 #include "net/base/auth.h"
 #include "net/base/load_flags.h"
-#include "net/base/net_util.h"
 #include "net/http/http_auth_scheme.h"
 #include "net/http/http_transaction_factory.h"
 #include "net/url_request/url_request.h"
diff --git a/chrome/browser/ui/panels/panel_browsertest.cc b/chrome/browser/ui/panels/panel_browsertest.cc
index 82256eb..632e4b1 100644
--- a/chrome/browser/ui/panels/panel_browsertest.cc
+++ b/chrome/browser/ui/panels/panel_browsertest.cc
@@ -42,7 +42,6 @@
 #include "content/public/test/browser_test_utils.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/constants.h"
-#include "net/base/net_util.h"
 #include "net/test/url_request/url_request_mock_http_job.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/hit_test.h"
diff --git a/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc b/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc
index 9322681d..2fa046a 100644
--- a/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc
@@ -296,19 +296,8 @@
 
 void ManagePasswordsBubbleModel::OnBrandLinkClicked() {
   dismissal_reason_ = metrics_util::CLICKED_BRAND_NAME;
-  switch (GetSmartLockBrandingState(GetProfile())) {
-    case password_bubble_experiment::SmartLockBranding::FULL:
-      PasswordsModelDelegateFromWebContents(web_contents())
-          ->NavigateToExternalPasswordManager();
-      break;
-    case password_bubble_experiment::SmartLockBranding::SAVE_BUBBLE_ONLY:
-      PasswordsModelDelegateFromWebContents(web_contents())
-          ->NavigateToSmartLockHelpPage();
-      break;
-    case password_bubble_experiment::SmartLockBranding::NONE:
-      NOTREACHED();
-      break;
-  }
+  PasswordsModelDelegateFromWebContents(web_contents())
+      ->NavigateToSmartLockHelpPage();
 }
 
 void ManagePasswordsBubbleModel::OnAutoSignInToastTimeout() {
diff --git a/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc b/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc
index 7d14a34..3d026ee 100644
--- a/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc
@@ -364,6 +364,13 @@
       password_manager::prefs::kWasSavePrompFirstRunExperienceShown));
 }
 
+TEST_F(ManagePasswordsBubbleModelTest, OnBrandLinkClicked) {
+  PretendPasswordWaiting();
+
+  EXPECT_CALL(*controller(), NavigateToSmartLockHelpPage());
+  model()->OnBrandLinkClicked();
+}
+
 namespace {
 
 enum class SmartLockStatus { ENABLE, DISABLE };
@@ -485,56 +492,3 @@
 INSTANTIATE_TEST_CASE_P(Default,
                         ManagePasswordsBubbleModelManageLinkTest,
                         ::testing::ValuesIn(kManageLinkTestCases));
-
-enum class BrandLinkTarget { SMART_LOCK_HOME, SMART_LOCK_HELP };
-
-struct BrandLinkTestCase {
-  const char* experiment_group;
-  SmartLockStatus smartlock_status;
-  BrandLinkTarget expected_target;
-};
-
-class ManagePasswordsBubbleModelBrandLinkTest
-    : public ManagePasswordsBubbleModelTest,
-      public ::testing::WithParamInterface<BrandLinkTestCase> {};
-
-TEST_P(ManagePasswordsBubbleModelBrandLinkTest, OnBrandLinkClicked) {
-  BrandLinkTestCase test_case = GetParam();
-  TestSyncService* sync_service = static_cast<TestSyncService*>(
-      ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-          profile(), &TestingSyncFactoryFunction));
-  sync_service->set_smartlock_enabled(test_case.smartlock_status ==
-                                      SmartLockStatus::ENABLE);
-  if (test_case.experiment_group) {
-    base::FieldTrialList::CreateFieldTrial(kBrandingExperimentName,
-                                           test_case.experiment_group);
-  }
-
-  PretendManagingPasswords();
-
-  switch (test_case.expected_target) {
-    case BrandLinkTarget::SMART_LOCK_HOME:
-      EXPECT_CALL(*controller(), NavigateToExternalPasswordManager());
-      break;
-    case BrandLinkTarget::SMART_LOCK_HELP:
-      EXPECT_CALL(*controller(), NavigateToSmartLockHelpPage());
-      break;
-  }
-
-  model()->OnBrandLinkClicked();
-}
-
-namespace {
-
-const BrandLinkTestCase kBrandLinkTestCases[] = {
-    {kSmartLockBrandingGroupName, SmartLockStatus::ENABLE,
-     BrandLinkTarget::SMART_LOCK_HOME},
-    {kSmartLockBrandingSavePromptOnlyGroupName, SmartLockStatus::ENABLE,
-     BrandLinkTarget::SMART_LOCK_HELP},
-};
-
-}  // namespace
-
-INSTANTIATE_TEST_CASE_P(Default,
-                        ManagePasswordsBubbleModelBrandLinkTest,
-                        ::testing::ValuesIn(kBrandLinkTestCases));
diff --git a/chrome/browser/ui/passwords/manage_passwords_view_utils.cc b/chrome/browser/ui/passwords/manage_passwords_view_utils.cc
index 911707f9..4ff7e5a2 100644
--- a/chrome/browser/ui/passwords/manage_passwords_view_utils.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_view_utils.cc
@@ -18,7 +18,6 @@
 #include "components/password_manager/core/browser/affiliation_utils.h"
 #include "components/url_formatter/elide_url.h"
 #include "grit/components_strings.h"
-#include "net/base/net_util.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/geometry/rect.h"
diff --git a/chrome/browser/ui/passwords/password_dialog_controller_impl.cc b/chrome/browser/ui/passwords/password_dialog_controller_impl.cc
index eb70766..3abfd42d 100644
--- a/chrome/browser/ui/passwords/password_dialog_controller_impl.cc
+++ b/chrome/browser/ui/passwords/password_dialog_controller_impl.cc
@@ -22,7 +22,7 @@
 bool IsSmartLockBrandingEnabled(Profile* profile) {
   const ProfileSyncService* sync_service =
       ProfileSyncServiceFactory::GetForProfile(profile);
-  return password_bubble_experiment::IsSmartLockBrandingEnabled(sync_service);
+  return password_bubble_experiment::IsSmartLockUser(sync_service);
 }
 
 }  // namespace
@@ -100,7 +100,7 @@
 }
 
 void PasswordDialogControllerImpl::OnSmartLockLinkClicked() {
-  delegate_->NavigateToExternalPasswordManager();
+  delegate_->NavigateToSmartLockHelpPage();
 }
 
 void PasswordDialogControllerImpl::OnChooseCredentials(
diff --git a/chrome/browser/ui/passwords/password_dialog_controller_impl_unittest.cc b/chrome/browser/ui/passwords/password_dialog_controller_impl_unittest.cc
index b917ea8f..1eb8e23 100644
--- a/chrome/browser/ui/passwords/password_dialog_controller_impl_unittest.cc
+++ b/chrome/browser/ui/passwords/password_dialog_controller_impl_unittest.cc
@@ -173,4 +173,9 @@
       password_manager::prefs::kCredentialsEnableAutosignin));
 }
 
+TEST_F(PasswordDialogControllerTest, OnBrandLinkClicked) {
+  EXPECT_CALL(ui_controller_mock(), NavigateToSmartLockHelpPage());
+  controller().OnSmartLockLinkClicked();
+}
+
 }  // namespace
diff --git a/chrome/browser/ui/profile_error_dialog.cc b/chrome/browser/ui/profile_error_dialog.cc
index 064d98fc..166b63e4 100644
--- a/chrome/browser/ui/profile_error_dialog.cc
+++ b/chrome/browser/ui/profile_error_dialog.cc
@@ -14,7 +14,7 @@
 #include "ui/base/l10n/l10n_util.h"
 
 void ShowProfileErrorDialog(ProfileErrorType type, int message_id) {
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_ANDROID)
   NOTIMPLEMENTED();
 #else
   UMA_HISTOGRAM_ENUMERATION("Profile.ProfileError", type, PROFILE_ERROR_END);
diff --git a/chrome/browser/ui/search/instant_search_prerenderer_unittest.cc b/chrome/browser/ui/search/instant_search_prerenderer_unittest.cc
index 4d857ac..f0432bf3 100644
--- a/chrome/browser/ui/search/instant_search_prerenderer_unittest.cc
+++ b/chrome/browser/ui/search/instant_search_prerenderer_unittest.cc
@@ -478,7 +478,7 @@
                                            ASCIIToUTF16("joy")));
 }
 
-#if !defined(OS_IOS) && !defined(OS_ANDROID)
+#if !defined(OS_ANDROID)
 class TestUsePrerenderPage : public InstantSearchPrerendererTest {
  protected:
   void SetUp() override {
diff --git a/chrome/browser/ui/startup/default_browser_prompt.cc b/chrome/browser/ui/startup/default_browser_prompt.cc
index 832f36dd..4249abe 100644
--- a/chrome/browser/ui/startup/default_browser_prompt.cc
+++ b/chrome/browser/ui/startup/default_browser_prompt.cc
@@ -139,7 +139,7 @@
 }
 
 gfx::VectorIconId DefaultBrowserInfoBarDelegate::GetVectorIconId() const {
-#if defined(OS_MACOSX) || defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_MACOSX) || defined(OS_ANDROID)
   return gfx::VectorIconId::VECTOR_ICON_NONE;
 #else
   return gfx::VectorIconId::CHROME_PRODUCT;
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index 0a2886d..f61c7a8 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -761,12 +761,12 @@
     params.disposition = first_tab ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
     params.tabstrip_add_types = add_types;
 
-#if defined(ENABLE_RLZ) && !defined(OS_IOS)
+#if defined(ENABLE_RLZ)
     if (process_startup && google_util::IsGoogleHomePageUrl(tabs[i].url)) {
       params.extra_headers = rlz::RLZTracker::GetAccessPointHttpHeader(
           rlz::RLZTracker::ChromeHomePage());
     }
-#endif  // defined(ENABLE_RLZ) && !defined(OS_IOS)
+#endif  // defined(ENABLE_RLZ)
 
     chrome::Navigate(&params);
 
diff --git a/chrome/browser/ui/sync/profile_signin_confirmation_helper.cc b/chrome/browser/ui/sync/profile_signin_confirmation_helper.cc
index 5b728a8..33adf23 100644
--- a/chrome/browser/ui/sync/profile_signin_confirmation_helper.cc
+++ b/chrome/browser/ui/sync/profile_signin_confirmation_helper.cc
@@ -52,19 +52,10 @@
 }
 
 bool HasBeenShutdown(Profile* profile) {
-#if defined(OS_IOS)
-  // This check is not useful on iOS: the browser can be shut down without
-  // explicit user action (for example, in response to memory pressure), and
-  // this should be invisible to the user. The desktop assumption that the
-  // profile going through a restart indicates something about user intention
-  // does not hold. We rely on the other profile dirtiness checks.
-  return false;
-#else
   bool has_been_shutdown = !profile->IsNewProfile();
   if (has_been_shutdown)
     DVLOG(1) << "ProfileSigninConfirmationHelper: profile is not new";
   return has_been_shutdown;
-#endif
 }
 
 bool HasSyncedExtensions(Profile* profile) {
diff --git a/chrome/browser/ui/toolbar/app_menu_model.cc b/chrome/browser/ui/toolbar/app_menu_model.cc
index 58c253e..62db93dd 100644
--- a/chrome/browser/ui/toolbar/app_menu_model.cc
+++ b/chrome/browser/ui/toolbar/app_menu_model.cc
@@ -868,8 +868,10 @@
       SetIcon(GetIndexOfCommandId(error->MenuItemCommandID()),
               error->MenuItemIcon());
       menu_items_added = true;
-      content::RecordAction(
-          base::UserMetricsAction("Signin_Impression_FromMenu"));
+      if (IDC_SHOW_SIGNIN_ERROR == error->MenuItemCommandID()) {
+        content::RecordAction(
+            base::UserMetricsAction("Signin_Impression_FromMenu"));
+      }
     }
   }
   return menu_items_added;
diff --git a/chrome/browser/ui/views/bar_control_button.cc b/chrome/browser/ui/views/bar_control_button.cc
index af8ffe4..0d356ae 100644
--- a/chrome/browser/ui/views/bar_control_button.cc
+++ b/chrome/browser/ui/views/bar_control_button.cc
@@ -23,14 +23,6 @@
       ink_drop_delegate_(new views::ButtonInkDropDelegate(this, this)) {
   set_ink_drop_delegate(ink_drop_delegate_.get());
   set_has_ink_drop_action_on_click(true);
-
-  const int kInkDropLargeSize = 32;
-  const int kInkDropLargeCornerRadius = 4;
-  const int kInkDropSmallSize = 24;
-  const int kInkDropSmallCornerRadius = 2;
-  ink_drop_delegate()->SetInkDropSize(
-      kInkDropLargeSize, kInkDropLargeCornerRadius, kInkDropSmallSize,
-      kInkDropSmallCornerRadius);
 }
 
 BarControlButton::~BarControlButton() {}
diff --git a/chrome/browser/ui/views/dropdown_bar_host.cc b/chrome/browser/ui/views/dropdown_bar_host.cc
index 89d976a..9d5ca25 100644
--- a/chrome/browser/ui/views/dropdown_bar_host.cc
+++ b/chrome/browser/ui/views/dropdown_bar_host.cc
@@ -42,7 +42,7 @@
   delegate_ = delegate;
 
   // The |clip_view| exists to paint to a layer so that it can clip descendent
-  // Views which also paint to a Layer.
+  // Views which also paint to a Layer. See http://crbug.com/589497
   scoped_ptr<views::View> clip_view(new views::View());
   clip_view->SetPaintToLayer(true);
   clip_view->SetFillsBoundsOpaquely(false);
diff --git a/chrome/browser/ui/views/extensions/extension_install_dialog_view_browsertest.cc b/chrome/browser/ui/views/extensions/extension_install_dialog_view_browsertest.cc
index 98869b8..211d395 100644
--- a/chrome/browser/ui/views/extensions/extension_install_dialog_view_browsertest.cc
+++ b/chrome/browser/ui/views/extensions/extension_install_dialog_view_browsertest.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/extensions/extension_install_prompt.h"
 #include "chrome/browser/extensions/extension_install_prompt_test_helper.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/webui/extensions/extension_settings_handler.h"
 #include "chrome/common/extensions/extension_test_util.h"
@@ -26,6 +27,7 @@
 #include "ui/views/controls/scroll_view.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
+#include "ui/views/window/dialog_client_view.h"
 
 using extensions::PermissionIDSet;
 using extensions::PermissionMessage;
@@ -152,6 +154,20 @@
             ExtensionInstallPrompt::INSTALL_PROMPT) {}
   ~ExtensionInstallDialogViewTest() override {}
 
+  views::DialogDelegateView* CreateAndShowPrompt(
+      ExtensionInstallPromptTestHelper* helper) {
+    scoped_ptr<ExtensionInstallDialogView> dialog(
+        new ExtensionInstallDialogView(profile(), web_contents(),
+                                       helper->GetCallback(), CreatePrompt()));
+    views::DialogDelegateView* delegate_view = dialog.get();
+
+    views::Widget* modal_dialog = views::DialogDelegate::CreateDialogWidget(
+        dialog.release(), nullptr, browser()->window()->GetNativeWindow());
+    modal_dialog->Show();
+
+    return delegate_view;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(ExtensionInstallDialogViewTest);
 };
@@ -160,46 +176,25 @@
 // cancel the install.
 IN_PROC_BROWSER_TEST_F(ExtensionInstallDialogViewTest, NotifyDelegate) {
   {
+    // User presses install.
     ExtensionInstallPromptTestHelper helper;
-    scoped_ptr<ExtensionInstallDialogView> dialog(
-        new ExtensionInstallDialogView(profile(), web_contents(),
-                                       helper.GetCallback(),
-                                       CreatePrompt()));
-    views::DialogDelegateView* delegate_view = dialog.get();
-
-    delegate_view->Accept();
-    delegate_view->OnClosed();
-    dialog.reset();
-
+    views::DialogDelegateView* delegate_view = CreateAndShowPrompt(&helper);
+    delegate_view->GetDialogClientView()->AcceptWindow();
     EXPECT_EQ(ExtensionInstallPrompt::Result::ACCEPTED, helper.result());
   }
-
   {
-    // The user cancels the install.
+    // User presses cancel.
     ExtensionInstallPromptTestHelper helper;
-    scoped_ptr<ExtensionInstallDialogView> dialog(
-        new ExtensionInstallDialogView(profile(), web_contents(),
-                                       helper.GetCallback(),
-                                       CreatePrompt()));
-    views::DialogDelegateView* delegate_view = dialog.get();
-
-    delegate_view->Cancel();
-    delegate_view->OnClosed();
-    dialog.reset();
-
+    views::DialogDelegateView* delegate_view = CreateAndShowPrompt(&helper);
+    delegate_view->GetDialogClientView()->CancelWindow();
     EXPECT_EQ(ExtensionInstallPrompt::Result::USER_CANCELED, helper.result());
   }
-
   {
-    // Corner case: Dialog is closed without the user explicitly choosing to
-    // proceed or cancel.
+    // Dialog is closed without the user explicitly choosing to proceed or
+    // cancel.
     ExtensionInstallPromptTestHelper helper;
-    scoped_ptr<ExtensionInstallDialogView> dialog(
-        new ExtensionInstallDialogView(profile(), web_contents(),
-                                       helper.GetCallback(),
-                                       CreatePrompt()));
-    dialog.reset();
-
+    views::DialogDelegateView* delegate_view = CreateAndShowPrompt(&helper);
+    delegate_view->GetWidget()->Close();
     // TODO(devlin): Should this be ABORTED?
     EXPECT_EQ(ExtensionInstallPrompt::Result::USER_CANCELED, helper.result());
   }
diff --git a/chrome/browser/ui/views/first_run_dialog.cc b/chrome/browser/ui/views/first_run_dialog.cc
index 32050fe..89b12df 100644
--- a/chrome/browser/ui/views/first_run_dialog.cc
+++ b/chrome/browser/ui/views/first_run_dialog.cc
@@ -111,11 +111,6 @@
   return link;
 }
 
-void FirstRunDialog::OnClosed() {
-  first_run::SetShouldShowWelcomePage();
-  Done();
-}
-
 bool FirstRunDialog::Accept() {
   GetWidget()->Hide();
 
@@ -137,6 +132,11 @@
   return ui::DIALOG_BUTTON_OK;
 }
 
+void FirstRunDialog::WindowClosing() {
+  first_run::SetShouldShowWelcomePage();
+  Done();
+}
+
 void FirstRunDialog::LinkClicked(views::Link* source, int event_flags) {
   platform_util::OpenExternal(profile_, GURL(chrome::kLearnMoreReportingURL));
 }
diff --git a/chrome/browser/ui/views/first_run_dialog.h b/chrome/browser/ui/views/first_run_dialog.h
index 91fe12e..f9e0276f 100644
--- a/chrome/browser/ui/views/first_run_dialog.h
+++ b/chrome/browser/ui/views/first_run_dialog.h
@@ -33,10 +33,12 @@
 
   // views::DialogDelegate:
   views::View* CreateExtraView() override;
-  void OnClosed() override;
   bool Accept() override;
   int GetDialogButtons() const override;
 
+  // views::WidgetDelegate:
+  void WindowClosing() override;
+
   // views::LinkListener:
   void LinkClicked(views::Link* source, int event_flags) override;
 
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 8f1096b..2edae31 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -101,6 +101,7 @@
 #include "chrome/browser/ui/window_sizer/window_sizer.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/command.h"
+#include "chrome/common/features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/chromium_strings.h"
@@ -172,7 +173,7 @@
 #include "ui/views/win/scoped_fullscreen_visibility.h"
 #endif
 
-#if defined(ENABLE_ONE_CLICK_SIGNIN)
+#if BUILDFLAG(ENABLE_ONE_CLICK_SIGNIN)
 #include "chrome/browser/ui/sync/one_click_signin_bubble_delegate.h"
 #include "chrome/browser/ui/sync/one_click_signin_bubble_links_delegate.h"
 #include "chrome/browser/ui/views/sync/one_click_signin_bubble_view.h"
@@ -1337,7 +1338,7 @@
   GetToolbarView()->OnBubbleCreatedForAnchor(anchor_view, bubble_widget);
 }
 
-#if defined(ENABLE_ONE_CLICK_SIGNIN)
+#if BUILDFLAG(ENABLE_ONE_CLICK_SIGNIN)
 void BrowserView::ShowOneClickSigninBubble(
     OneClickSigninBubbleType type,
     const base::string16& email,
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index ccc436a..1660dd7 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -31,6 +31,7 @@
 #include "chrome/browser/ui/views/frame/immersive_mode_controller.h"
 #include "chrome/browser/ui/views/frame/web_contents_close_handler.h"
 #include "chrome/browser/ui/views/load_complete_listener.h"
+#include "chrome/common/features.h"
 #include "components/omnibox/browser/omnibox_popup_model_observer.h"
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/base/models/simple_menu_model.h"
@@ -333,7 +334,7 @@
                            translate::TranslateStep step,
                            translate::TranslateErrors::Type error_type,
                            bool is_user_gesture) override;
-#if defined(ENABLE_ONE_CLICK_SIGNIN)
+#if BUILDFLAG(ENABLE_ONE_CLICK_SIGNIN)
   void ShowOneClickSigninBubble(
       OneClickSigninBubbleType type,
       const base::string16& email,
diff --git a/chrome/browser/ui/views/ime/ime_window_frame_view.cc b/chrome/browser/ui/views/ime/ime_window_frame_view.cc
index a1990ce5..bd3ec0f 100644
--- a/chrome/browser/ui/views/ime/ime_window_frame_view.cc
+++ b/chrome/browser/ui/views/ime/ime_window_frame_view.cc
@@ -203,6 +203,64 @@
   PaintFrameBackground(canvas);
 }
 
+bool ImeWindowFrameView::OnMousePressed(const ui::MouseEvent& event) {
+  if (event.IsOnlyLeftMouseButton()) {
+    gfx::Point mouse_location = event.location();
+    views::View::ConvertPointToScreen(this, &mouse_location);
+    return ime_window_view_->OnTitlebarPointerPressed(
+        mouse_location, ImeWindowView::PointerType::MOUSE);
+  }
+  return false;
+}
+
+bool ImeWindowFrameView::OnMouseDragged(const ui::MouseEvent& event) {
+  gfx::Point mouse_location = event.location();
+  views::View::ConvertPointToScreen(this, &mouse_location);
+  return ime_window_view_->OnTitlebarPointerDragged(
+      mouse_location, ImeWindowView::PointerType::MOUSE);
+}
+
+void ImeWindowFrameView::OnMouseReleased(const ui::MouseEvent& event) {
+  ime_window_view_->OnTitlebarPointerReleased(
+      ImeWindowView::PointerType::MOUSE);
+}
+
+void ImeWindowFrameView::OnMouseCaptureLost() {
+  ime_window_view_->OnTitlebarPointerCaptureLost();
+}
+
+void ImeWindowFrameView::OnGestureEvent(ui::GestureEvent* event) {
+  bool handled = false;
+  switch (event->type()) {
+    case ui::ET_GESTURE_TAP_DOWN: {
+      gfx::Point loc(event->location());
+      views::View::ConvertPointToScreen(this, &loc);
+      handled = ime_window_view_->OnTitlebarPointerPressed(
+          loc, ImeWindowView::PointerType::TOUCH);
+      break;
+    }
+
+    case ui::ET_GESTURE_SCROLL_UPDATE: {
+      gfx::Point loc(event->location());
+      views::View::ConvertPointToScreen(this, &loc);
+      handled = ime_window_view_->OnTitlebarPointerDragged(
+          loc, ImeWindowView::PointerType::TOUCH);
+      break;
+    }
+
+    case ui::ET_GESTURE_END:
+      ime_window_view_->OnTitlebarPointerReleased(
+          ImeWindowView::PointerType::TOUCH);
+      handled = true;
+      break;
+
+    default:
+      break;
+  }
+  if (handled)
+    event->SetHandled();
+}
+
 void ImeWindowFrameView::ButtonPressed(views::Button* sender,
                                        const ui::Event& event) {
   if (sender == close_button_)
diff --git a/chrome/browser/ui/views/ime/ime_window_frame_view.h b/chrome/browser/ui/views/ime/ime_window_frame_view.h
index 93727d8f..484142b2 100644
--- a/chrome/browser/ui/views/ime/ime_window_frame_view.h
+++ b/chrome/browser/ui/views/ime/ime_window_frame_view.h
@@ -53,6 +53,11 @@
   gfx::Size GetMaximumSize() const override;
   void Layout() override;
   void OnPaint(gfx::Canvas* canvas) override;
+  bool OnMousePressed(const ui::MouseEvent& event) override;
+  bool OnMouseDragged(const ui::MouseEvent& event) override;
+  void OnMouseReleased(const ui::MouseEvent& event) override;
+  void OnMouseCaptureLost() override;
+  void OnGestureEvent(ui::GestureEvent* event) override;
 
   // views::ButtonListener:
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
diff --git a/chrome/browser/ui/views/ime/ime_window_view.cc b/chrome/browser/ui/views/ime/ime_window_view.cc
index 521fff46..f1608cb 100644
--- a/chrome/browser/ui/views/ime/ime_window_view.cc
+++ b/chrome/browser/ui/views/ime/ime_window_view.cc
@@ -29,6 +29,8 @@
                              const gfx::Rect& bounds,
                              content::WebContents* contents)
     : ime_window_(ime_window),
+      dragging_pointer_type_(PointerType::MOUSE),
+      dragging_state_(DragState::NO_DRAG),
       window_(nullptr),
       web_view_(nullptr) {
   window_ = new views::Widget;
@@ -88,6 +90,56 @@
   return GetWidget()->GetWindowBoundsInScreen();
 }
 
+bool ImeWindowView::OnTitlebarPointerPressed(
+    const gfx::Point& pointer_location, PointerType pointer_type) {
+  if (dragging_state_ != DragState::NO_DRAG &&
+      dragging_pointer_type_ != pointer_type) {
+    return false;
+  }
+
+  dragging_state_ = DragState::POSSIBLE_DRAG;
+  pointer_location_on_press_ = pointer_location;
+  dragging_pointer_type_ = pointer_type;
+  return true;
+}
+
+bool ImeWindowView::OnTitlebarPointerDragged(
+    const gfx::Point& pointer_location, PointerType pointer_type) {
+  if (dragging_state_ == DragState::NO_DRAG)
+    return false;
+  if (dragging_pointer_type_ != pointer_type)
+    return false;
+
+  if (dragging_state_ == DragState::POSSIBLE_DRAG &&
+      ExceededDragThreshold(pointer_location - pointer_location_on_press_)) {
+    gfx::Rect bounds = GetWidget()->GetWindowBoundsInScreen();
+    bounds_on_drag_start_ = bounds;
+    dragging_state_ = DragState::ACTIVE_DRAG;
+  }
+  if (dragging_state_ == DragState::ACTIVE_DRAG) {
+    gfx::Point target_position = pointer_location -
+        (pointer_location_on_press_ - bounds_on_drag_start_.origin());
+    gfx::Rect bounds = GetWidget()->GetWindowBoundsInScreen();
+    bounds.set_origin(target_position);
+    GetWidget()->SetBounds(bounds);
+  }
+  return true;
+}
+
+void ImeWindowView::OnTitlebarPointerReleased(PointerType pointer_type) {
+  if (dragging_pointer_type_ == pointer_type &&
+      dragging_state_ == DragState::ACTIVE_DRAG) {
+    EndDragging();
+  }
+}
+
+void ImeWindowView::OnTitlebarPointerCaptureLost() {
+  if (dragging_state_ == DragState::ACTIVE_DRAG) {
+    GetWidget()->SetBounds(bounds_on_drag_start_);
+    EndDragging();
+  }
+}
+
 views::View* ImeWindowView::GetContentsView() {
   return this;
 }
@@ -139,4 +191,8 @@
       window_->non_client_view()->frame_view());
 }
 
+void ImeWindowView::EndDragging() {
+  dragging_state_ = DragState::NO_DRAG;
+}
+
 }  // namespace ui
diff --git a/chrome/browser/ui/views/ime/ime_window_view.h b/chrome/browser/ui/views/ime/ime_window_view.h
index 8974a3e..a0e332a 100644
--- a/chrome/browser/ui/views/ime/ime_window_view.h
+++ b/chrome/browser/ui/views/ime/ime_window_view.h
@@ -40,11 +40,21 @@
 class ImeWindowView : public ImeNativeWindow,
                       public views::WidgetDelegateView {
  public:
+  enum class PointerType { MOUSE, TOUCH };
+
   ImeWindowView(ImeWindow* ime_window,
                 const gfx::Rect& bounds,
                 content::WebContents* contents);
   ~ImeWindowView() override;
 
+  // Methods to deal with mouse/touch dragging on the non client view.
+  bool OnTitlebarPointerPressed(const gfx::Point& pointer_location,
+                                PointerType pointer_type);
+  bool OnTitlebarPointerDragged(const gfx::Point& pointer_location,
+                                PointerType pointer_type);
+  void OnTitlebarPointerReleased(PointerType pointer_type);
+  void OnTitlebarPointerCaptureLost();
+
   // ui::ImeNativeWindow:
   void Show() override;
   void Hide() override;
@@ -73,8 +83,17 @@
   views::WebView* web_view() const { return web_view_; }
 
  private:
+  enum class DragState { NO_DRAG, POSSIBLE_DRAG, ACTIVE_DRAG };
+  void EndDragging();
+
   ImeWindow* ime_window_;
 
+  // Member variables for dragging.
+  PointerType dragging_pointer_type_;
+  gfx::Point pointer_location_on_press_;
+  DragState dragging_state_;
+  gfx::Rect bounds_on_drag_start_;
+
   // The native window.
   views::Widget* window_;
 
diff --git a/chrome/browser/ui/views/location_bar/bubble_icon_view.cc b/chrome/browser/ui/views/location_bar/bubble_icon_view.cc
index e10f3332..fd0d0f4 100644
--- a/chrome/browser/ui/views/location_bar/bubble_icon_view.cc
+++ b/chrome/browser/ui/views/location_bar/bubble_icon_view.cc
@@ -13,6 +13,7 @@
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/native_theme/native_theme.h"
 #include "ui/views/animation/button_ink_drop_delegate.h"
+#include "ui/views/animation/ink_drop_hover.h"
 #include "ui/views/bubble/bubble_delegate.h"
 
 BubbleIconView::BubbleIconView(CommandUpdater* command_updater, int command_id)
@@ -26,15 +27,6 @@
   image_->set_interactive(false);
   image_->EnableCanvasFlippingForRTLUI(true);
   image_->SetAccessibilityFocusable(true);
-
-  // TODO(varkha): Provide standard ink drop dimensions in LayoutConstants.
-  const int kInkDropLargeSize = 32;
-  const int kInkDropLargeCornerRadius = 5;
-  const int kInkDropSmallSize = 24;
-  const int kInkDropSmallCornerRadius = 2;
-  ink_drop_delegate_->SetInkDropSize(
-      kInkDropLargeSize, kInkDropLargeCornerRadius, kInkDropSmallSize,
-      kInkDropSmallCornerRadius);
 }
 
 BubbleIconView::~BubbleIconView() {
@@ -75,7 +67,6 @@
 void BubbleIconView::Layout() {
   View::Layout();
   image_->SetBoundsRect(GetLocalBounds());
-  ink_drop_delegate_->OnLayout();
 }
 
 bool BubbleIconView::OnMousePressed(const ui::MouseEvent& event) {
@@ -123,6 +114,23 @@
     UpdateIcon();
 }
 
+void BubbleIconView::AddInkDropLayer(ui::Layer* ink_drop_layer) {
+  image_->SetPaintToLayer(true);
+  image_->SetFillsBoundsOpaquely(false);
+  views::InkDropHostView::AddInkDropLayer(ink_drop_layer);
+}
+
+void BubbleIconView::RemoveInkDropLayer(ui::Layer* ink_drop_layer) {
+  views::InkDropHostView::RemoveInkDropLayer(ink_drop_layer);
+  image_->SetFillsBoundsOpaquely(true);
+  image_->SetPaintToLayer(false);
+}
+
+scoped_ptr<views::InkDropHover> BubbleIconView::CreateInkDropHover() const {
+  // BubbleIconView views don't show hover effect.
+  return nullptr;
+}
+
 void BubbleIconView::OnNativeThemeChanged(const ui::NativeTheme* theme) {
   UpdateIcon();
 }
@@ -135,23 +143,6 @@
   }
 }
 
-void BubbleIconView::AddInkDropLayer(ui::Layer* ink_drop_layer) {
-  image_->SetPaintToLayer(true);
-  image_->SetFillsBoundsOpaquely(false);
-  SetPaintToLayer(true);
-  SetFillsBoundsOpaquely(false);
-  layer()->Add(ink_drop_layer);
-  layer()->StackAtBottom(ink_drop_layer);
-}
-
-void BubbleIconView::RemoveInkDropLayer(ui::Layer* ink_drop_layer) {
-  layer()->Remove(ink_drop_layer);
-  SetFillsBoundsOpaquely(true);
-  SetPaintToLayer(false);
-  image_->SetFillsBoundsOpaquely(true);
-  image_->SetPaintToLayer(false);
-}
-
 void BubbleIconView::OnWidgetDestroying(views::Widget* widget) {
   widget->RemoveObserver(this);
 }
@@ -181,16 +172,6 @@
   views::BubbleDelegateView* bubble = GetBubble();
   if (bubble)
     bubble->OnAnchorBoundsChanged();
-  ink_drop_delegate_->OnLayout();
-}
-
-gfx::Point BubbleIconView::CalculateInkDropCenter() const {
-  return GetLocalBounds().CenterPoint();
-}
-
-bool BubbleIconView::ShouldShowInkDropHover() const {
-  // BubbleIconView views don't show hover effect.
-  return false;
 }
 
 void BubbleIconView::UpdateIcon() {
diff --git a/chrome/browser/ui/views/location_bar/bubble_icon_view.h b/chrome/browser/ui/views/location_bar/bubble_icon_view.h
index db1ef23..0115321 100644
--- a/chrome/browser/ui/views/location_bar/bubble_icon_view.h
+++ b/chrome/browser/ui/views/location_bar/bubble_icon_view.h
@@ -9,7 +9,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/vector_icons_public.h"
-#include "ui/views/animation/ink_drop_host.h"
+#include "ui/views/animation/ink_drop_host_view.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/widget/widget_observer.h"
 
@@ -25,8 +25,7 @@
 }
 
 // Represents an icon on the omnibox that shows a bubble when clicked.
-class BubbleIconView : public views::View,
-                       public views::InkDropHost,
+class BubbleIconView : public views::InkDropHostView,
                        public views::WidgetObserver {
  protected:
   enum ExecuteSource {
@@ -65,15 +64,14 @@
   bool OnKeyPressed(const ui::KeyEvent& event) override;
   void ViewHierarchyChanged(
       const ViewHierarchyChangedDetails& details) override;
+  void AddInkDropLayer(ui::Layer* ink_drop_layer) override;
+  void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override;
+  scoped_ptr<views::InkDropHover> CreateInkDropHover() const override;
   void OnNativeThemeChanged(const ui::NativeTheme* theme) override;
 
   // ui::EventHandler:
   void OnGestureEvent(ui::GestureEvent* event) override;
 
-  // views::InkDropHost:
-  void AddInkDropLayer(ui::Layer* ink_drop_layer) override;
-  void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override;
-
   // views::WidgetObserver:
   void OnWidgetDestroying(views::Widget* widget) override;
   void OnWidgetVisibilityChanged(views::Widget* widget,
@@ -98,10 +96,6 @@
   // views::View:
   void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
 
-  // views::InkDropHost:
-  gfx::Point CalculateInkDropCenter() const override;
-  bool ShouldShowInkDropHover() const override;
-
   // Updates the icon after some state has changed.
   void UpdateIcon();
 
diff --git a/chrome/browser/ui/views/location_bar/content_setting_image_view.cc b/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
index 4b7f12a9..fb5165c 100644
--- a/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
+++ b/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
@@ -17,11 +17,11 @@
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/views/animation/button_ink_drop_delegate.h"
+#include "ui/views/animation/ink_drop_hover.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/widget/widget.h"
 
-
 namespace {
 // Time spent with animation fully open.
 const int kStayOpenTimeMS = 3200;
@@ -56,7 +56,6 @@
     SetBackgroundImageGrid(kBackgroundImages);
   }
 
-  // TODO(varkha): Provide standard ink drop dimensions in LayoutConstants.
   image()->SetHorizontalAlignment(views::ImageView::LEADING);
   image()->set_interactive(true);
   image()->EnableCanvasFlippingForRTLUI(true);
@@ -66,14 +65,6 @@
 
   slide_animator_.SetSlideDuration(kAnimationDurationMS);
   slide_animator_.SetTweenType(gfx::Tween::LINEAR);
-
-  const int kInkDropLargeSize = 32;
-  const int kInkDropLargeCornerRadius = 5;
-  const int kInkDropSmallSize = 24;
-  const int kInkDropSmallCornerRadius = 2;
-  ink_drop_delegate_->SetInkDropSize(
-      kInkDropLargeSize, kInkDropLargeCornerRadius, kInkDropSmallSize,
-      kInkDropSmallCornerRadius);
 }
 
 ContentSettingImageView::~ContentSettingImageView() {
@@ -166,16 +157,10 @@
   return "ContentSettingsImageView";
 }
 
-void ContentSettingImageView::Layout() {
-  IconLabelBubbleView::Layout();
-  ink_drop_delegate_->OnLayout();
-}
-
 void ContentSettingImageView::OnBoundsChanged(
     const gfx::Rect& previous_bounds) {
   if (bubble_view_)
     bubble_view_->OnAnchorBoundsChanged();
-  ink_drop_delegate_->OnLayout();
 }
 
 bool ContentSettingImageView::OnMousePressed(const ui::MouseEvent& event) {
@@ -226,6 +211,24 @@
     event->SetHandled();
 }
 
+void ContentSettingImageView::AddInkDropLayer(ui::Layer* ink_drop_layer) {
+  image()->SetPaintToLayer(true);
+  image()->SetFillsBoundsOpaquely(false);
+  IconLabelBubbleView::AddInkDropLayer(ink_drop_layer);
+}
+
+void ContentSettingImageView::RemoveInkDropLayer(ui::Layer* ink_drop_layer) {
+  IconLabelBubbleView::RemoveInkDropLayer(ink_drop_layer);
+  image()->SetFillsBoundsOpaquely(true);
+  image()->SetPaintToLayer(false);
+}
+
+scoped_ptr<views::InkDropHover> ContentSettingImageView::CreateInkDropHover()
+    const {
+  // Location bar views don't show hover effect.
+  return nullptr;
+}
+
 void ContentSettingImageView::OnNativeThemeChanged(
     const ui::NativeTheme* native_theme) {
   if (ui::MaterialDesignController::IsModeMaterial())
@@ -234,32 +237,6 @@
   IconLabelBubbleView::OnNativeThemeChanged(native_theme);
 }
 
-void ContentSettingImageView::AddInkDropLayer(ui::Layer* ink_drop_layer) {
-  image()->SetPaintToLayer(true);
-  image()->SetFillsBoundsOpaquely(false);
-  SetPaintToLayer(true);
-  SetFillsBoundsOpaquely(false);
-  layer()->Add(ink_drop_layer);
-  layer()->StackAtBottom(ink_drop_layer);
-}
-
-void ContentSettingImageView::RemoveInkDropLayer(ui::Layer* ink_drop_layer) {
-  layer()->Remove(ink_drop_layer);
-  SetFillsBoundsOpaquely(true);
-  SetPaintToLayer(false);
-  image()->SetFillsBoundsOpaquely(true);
-  image()->SetPaintToLayer(false);
-}
-
-gfx::Point ContentSettingImageView::CalculateInkDropCenter() const {
-  return GetLocalBounds().CenterPoint();
-}
-
-bool ContentSettingImageView::ShouldShowInkDropHover() const {
-  // location bar views don't show hover effect.
-  return false;
-}
-
 void ContentSettingImageView::OnWidgetDestroying(views::Widget* widget) {
   DCHECK(bubble_view_);
   DCHECK_EQ(bubble_view_->GetWidget(), widget);
diff --git a/chrome/browser/ui/views/location_bar/content_setting_image_view.h b/chrome/browser/ui/views/location_bar/content_setting_image_view.h
index 5c4280e..31213eff 100644
--- a/chrome/browser/ui/views/location_bar/content_setting_image_view.h
+++ b/chrome/browser/ui/views/location_bar/content_setting_image_view.h
@@ -12,7 +12,6 @@
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "ui/gfx/animation/animation_delegate.h"
 #include "ui/gfx/animation/slide_animation.h"
-#include "ui/views/animation/ink_drop_host.h"
 #include "ui/views/painter.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/widget_observer.h"
@@ -40,7 +39,6 @@
 // blocking, geolocation).
 class ContentSettingImageView : public IconLabelBubbleView,
                                 public gfx::AnimationDelegate,
-                                public views::InkDropHost,
                                 public views::WidgetObserver {
  public:
   // ContentSettingImageView takes ownership of its |image_model|.
@@ -75,19 +73,15 @@
 
   // views::View:
   const char* GetClassName() const override;
-  void Layout() override;
   void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
   bool OnMousePressed(const ui::MouseEvent& event) override;
   void OnMouseReleased(const ui::MouseEvent& event) override;
   bool OnKeyPressed(const ui::KeyEvent& event) override;
   void OnGestureEvent(ui::GestureEvent* event) override;
-  void OnNativeThemeChanged(const ui::NativeTheme* native_theme) override;
-
-  // views::InkDropHost:
   void AddInkDropLayer(ui::Layer* ink_drop_layer) override;
   void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override;
-  gfx::Point CalculateInkDropCenter() const override;
-  bool ShouldShowInkDropHover() const override;
+  scoped_ptr<views::InkDropHover> CreateInkDropHover() const override;
+  void OnNativeThemeChanged(const ui::NativeTheme* native_theme) override;
 
   // views::WidgetObserver:
   void OnWidgetDestroying(views::Widget* widget) override;
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
index a8dc1224..54d1334f 100644
--- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
+++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
@@ -12,6 +12,7 @@
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/native_theme/native_theme.h"
+#include "ui/views/border.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/painter.h"
 
@@ -53,6 +54,14 @@
   if (elide_in_middle)
     label_->SetElideBehavior(gfx::ELIDE_MIDDLE);
   AddChildView(label_);
+
+  // Bubbles are given the full internal height of the location bar so that all
+  // child views in the location bar have the same height. The visible height of
+  // the bubble should be smaller, so use an empty border to shrink down the
+  // content bounds so the background gets painted correctly.
+  const int padding = GetLayoutConstant(LOCATION_BAR_BUBBLE_VERTICAL_PADDING);
+  SetBorder(
+      views::Border::CreateEmptyBorder(gfx::Insets(padding, 0, padding, 0)));
 }
 
 IconLabelBubbleView::~IconLabelBubbleView() {
@@ -199,8 +208,10 @@
 void IconLabelBubbleView::OnPaint(gfx::Canvas* canvas) {
   if (!ShouldShowBackground())
     return;
-  if (background_painter_)
-    background_painter_->Paint(canvas, size());
+  if (background_painter_) {
+    views::Painter::PaintPainterAt(canvas, background_painter_.get(),
+                                   GetContentsBounds());
+  }
   if (background())
     background()->Paint(canvas, this);
 }
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
index 2d6558c8..c5a9b30c 100644
--- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
+++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
@@ -11,7 +11,7 @@
 #include "base/strings/string16.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/size.h"
-#include "ui/views/controls/image_view.h"
+#include "ui/views/animation/ink_drop_host_view.h"
 #include "ui/views/controls/label.h"
 
 namespace gfx {
@@ -21,6 +21,7 @@
 }
 
 namespace views {
+class ImageView;
 class Label;
 class Painter;
 }
@@ -28,7 +29,7 @@
 // View used to draw a bubble, containing an icon and a label. We use this as a
 // base for the classes that handle the location icon (including the EV bubble),
 // tab-to-search UI, and content settings.
-class IconLabelBubbleView : public views::View {
+class IconLabelBubbleView : public views::InkDropHostView {
  public:
   IconLabelBubbleView(int contained_image,
                       const gfx::FontList& font_list,
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index 7adaf3f..4776f97 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -179,19 +179,22 @@
   // not prepared for that.
   DCHECK(GetWidget());
 
-  if (!ui::MaterialDesignController::IsModeMaterial()) {
-    if (is_popup_mode_) {
-      const int kOmniboxPopupBorderImages[] =
-          IMAGE_GRID(IDR_OMNIBOX_POPUP_BORDER_AND_SHADOW);
-      border_painter_.reset(
-          views::Painter::CreateImageGridPainter(kOmniboxPopupBorderImages));
-    } else {
-      ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-      const gfx::Insets omnibox_border_insets(14, 9, 14, 9);
-      border_painter_.reset(views::Painter::CreateImagePainter(
-          *rb.GetImageSkiaNamed(IDR_OMNIBOX_BORDER), omnibox_border_insets));
-    }
-  }
+  if (ui::MaterialDesignController::IsModeMaterial()) {
+    // Make sure children with layers are clipped. See http://crbug.com/589497
+    SetPaintToLayer(true);
+    SetFillsBoundsOpaquely(false);
+    layer()->SetMasksToBounds(true);
+  } else if (is_popup_mode_) {
+    const int kOmniboxPopupBorderImages[] =
+        IMAGE_GRID(IDR_OMNIBOX_POPUP_BORDER_AND_SHADOW);
+    border_painter_.reset(
+        views::Painter::CreateImageGridPainter(kOmniboxPopupBorderImages));
+  } else {
+    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+    const gfx::Insets omnibox_border_insets(14, 9, 14, 9);
+    border_painter_.reset(views::Painter::CreateImagePainter(
+        *rb.GetImageSkiaNamed(IDR_OMNIBOX_BORDER), omnibox_border_insets));
+}
 
   // Determine the main font.
   gfx::FontList font_list = ResourceBundle::GetSharedInstance().GetFontList(
@@ -204,19 +207,18 @@
   }
   // Shrink large fonts to make them fit.
   // TODO(pkasting): Stretch the location bar instead in this case.
-  const int vertical_padding = GetVerticalEdgeThicknessWithPadding(false);
+  const int vertical_padding = GetVerticalEdgeThicknessWithPadding();
   const int location_height =
       std::max(GetPreferredSize().height() - (vertical_padding * 2), 0);
   font_list = font_list.DeriveWithHeightUpperBound(location_height);
 
-  // Determine the font for use inside the bubbles.  The bubble background
-  // images have 1 px thick edges, which we don't want to overlap.
-  const int kBubbleInteriorVerticalPadding =
+  // Determine the font for use inside the bubbles.
+  const int kBubbleFontVerticalPadding =
       ui::MaterialDesignController::IsModeMaterial() ? 2 : 1;
   const int bubble_padding =
-      GetVerticalEdgeThicknessWithPadding(true) +
-      kBubbleInteriorVerticalPadding;
-  const int bubble_height = GetPreferredSize().height() - (bubble_padding * 2);
+      GetLayoutConstant(LOCATION_BAR_BUBBLE_VERTICAL_PADDING) +
+      kBubbleFontVerticalPadding;
+  const int bubble_height = location_height - (bubble_padding * 2);
   gfx::FontList bubble_font_list =
       font_list.DeriveWithHeightUpperBound(bubble_height);
 
@@ -261,8 +263,7 @@
   AddChildView(suggested_text_view_);
 
   keyword_hint_view_ = new KeywordHintView(
-      profile(), font_list, bubble_font_list,
-      bubble_height + 2 * kBubbleInteriorVerticalPadding,
+      profile(), font_list, bubble_font_list, location_height,
       GetColor(LocationBarView::DEEMPHASIZED_TEXT), background_color);
   AddChildView(keyword_hint_view_);
 
@@ -592,19 +593,16 @@
   // to position our child views in this case, because other things may be
   // positioned relative to them (e.g. the "bookmark added" bubble if the user
   // hits ctrl-d).
-  const int bubble_vertical_padding = GetVerticalEdgeThicknessWithPadding(true);
-  const int bubble_height =
-      std::max(height() - (bubble_vertical_padding * 2), 0);
   const int bubble_horizontal_padding =
       GetLayoutConstant(LOCATION_BAR_BUBBLE_HORIZONTAL_PADDING);
-  const int vertical_padding = GetVerticalEdgeThicknessWithPadding(false);
+  const int vertical_padding = GetVerticalEdgeThicknessWithPadding();
   const int location_height = std::max(height() - (vertical_padding * 2), 0);
 
   location_icon_view_->SetLabel(base::string16());
   location_icon_view_->SetBackground(false);
   if (ShouldShowKeywordBubble()) {
-    leading_decorations.AddDecoration(bubble_vertical_padding, bubble_height,
-                                      true, 0, bubble_horizontal_padding,
+    leading_decorations.AddDecoration(vertical_padding, location_height, true,
+                                      0, bubble_horizontal_padding,
                                       item_padding, selected_keyword_view_);
     if (selected_keyword_view_->keyword() != keyword) {
       selected_keyword_view_->SetKeyword(keyword);
@@ -628,7 +626,7 @@
     // The largest fraction of the omnibox that can be taken by the EV bubble.
     const double kMaxBubbleFraction = 0.5;
     leading_decorations.AddDecoration(
-        bubble_vertical_padding, bubble_height, false, kMaxBubbleFraction,
+        vertical_padding, location_height, false, kMaxBubbleFraction,
         bubble_horizontal_padding, item_padding, location_icon_view_);
   } else {
     leading_decorations.AddDecoration(vertical_padding, location_height,
@@ -670,7 +668,7 @@
            content_setting_views_.rbegin()); i != content_setting_views_.rend();
        ++i) {
     if ((*i)->visible()) {
-      trailing_decorations.AddDecoration(bubble_vertical_padding, bubble_height,
+      trailing_decorations.AddDecoration(vertical_padding, location_height,
                                          false, 0, item_padding, item_padding,
                                          *i);
     }
@@ -858,11 +856,9 @@
                         : GetLayoutConstant(LOCATION_BAR_BORDER_THICKNESS);
 }
 
-int LocationBarView::GetVerticalEdgeThicknessWithPadding(
-    bool for_bubble) const {
+int LocationBarView::GetVerticalEdgeThicknessWithPadding() const {
   return GetVerticalEdgeThickness() +
-      GetLayoutConstant(for_bubble ? LOCATION_BAR_BUBBLE_VERTICAL_PADDING
-                                   : LOCATION_BAR_VERTICAL_PADDING);
+         GetLayoutConstant(LOCATION_BAR_VERTICAL_PADDING);
 }
 
 void LocationBarView::RefreshLocationIcon() {
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.h b/chrome/browser/ui/views/location_bar/location_bar_view.h
index a64807b..6192f60bb 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.h
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.h
@@ -277,10 +277,8 @@
   int GetVerticalEdgeThickness() const;
 
   // Returns the total amount of space reserved above or below the content,
-  // which is the vertical edge thickness plus the padding next to it.  If
-  // |for_bubble| is true, this computes the relevant value for bubbles as
-  // opposed to normal content (e.g. the omnibox).
-  int GetVerticalEdgeThicknessWithPadding(bool for_bubble) const;
+  // which is the vertical edge thickness plus the padding next to it.
+  int GetVerticalEdgeThicknessWithPadding() const;
 
   // Updates |location_icon_view_| based on the current state and theme.
   void RefreshLocationIcon();
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index fa57708..533f984 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -600,9 +600,9 @@
   GetInputMethod()->ShowImeIfNeeded();
 }
 
-void OmniboxViewViews::OnMatchOpened(const AutocompleteMatch& match) {
+void OmniboxViewViews::OnMatchOpened(AutocompleteMatch::Type match_type) {
   extensions::MaybeShowExtensionControlledSearchNotification(
-      profile_, location_bar_view_->GetWebContents(), match);
+      profile_, location_bar_view_->GetWebContents(), match_type);
 }
 
 int OmniboxViewViews::GetOmniboxTextLength() const {
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.h b/chrome/browser/ui/views/omnibox/omnibox_view_views.h
index f38b5c8..f5a5dcb 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.h
@@ -158,7 +158,7 @@
   int GetWidth() const override;
   bool IsImeShowingPopup() const override;
   void ShowImeIfNeeded() override;
-  void OnMatchOpened(const AutocompleteMatch& match) override;
+  void OnMatchOpened(AutocompleteMatch::Type match_type) override;
   int GetOmniboxTextLength() const override;
   void EmphasizeURLComponents() override;
 
diff --git a/chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc b/chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc
index 8a08e2e..fe617ff1 100644
--- a/chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc
+++ b/chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc
@@ -99,6 +99,11 @@
   return false;
 }
 
+void AccountChooserDialogView::WindowClosing() {
+  if (controller_)
+    controller_->OnCloseDialog();
+}
+
 int AccountChooserDialogView::GetDialogButtons() const {
   return ui::DIALOG_BUTTON_CANCEL;
 }
@@ -108,11 +113,6 @@
   return l10n_util::GetStringUTF16(IDS_APP_CANCEL);
 }
 
-void AccountChooserDialogView::OnClosed() {
-  if (controller_)
-    controller_->OnCloseDialog();
-}
-
 gfx::Size AccountChooserDialogView::GetPreferredSize() const {
   return gfx::Size(kDesiredWidth, GetHeightForWidth(kDesiredWidth));
 }
diff --git a/chrome/browser/ui/views/passwords/account_chooser_dialog_view.h b/chrome/browser/ui/views/passwords/account_chooser_dialog_view.h
index e91d4b0e..45fe4baf 100644
--- a/chrome/browser/ui/views/passwords/account_chooser_dialog_view.h
+++ b/chrome/browser/ui/views/passwords/account_chooser_dialog_view.h
@@ -36,11 +36,11 @@
   base::string16 GetWindowTitle() const override;
   bool ShouldShowWindowTitle() const override;
   bool ShouldShowCloseButton() const override;
+  void WindowClosing() override;
 
   // DialogDelegate:
   int GetDialogButtons() const override;
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
-  void OnClosed() override;
 
   // views::View
   gfx::Size GetPreferredSize() const override;
diff --git a/chrome/browser/ui/views/passwords/auto_signin_first_run_dialog_view.cc b/chrome/browser/ui/views/passwords/auto_signin_first_run_dialog_view.cc
index 4aef871..a25667c 100644
--- a/chrome/browser/ui/views/passwords/auto_signin_first_run_dialog_view.cc
+++ b/chrome/browser/ui/views/passwords/auto_signin_first_run_dialog_view.cc
@@ -34,8 +34,12 @@
   column_set->AddPaddingColumn(0, views::kButtonHEdgeMarginNew);
   switch (type) {
     case SINGLE_VIEW_COLUMN_SET:
-      column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
-                            views::GridLayout::USE_PREF, 0, 0);
+      column_set->AddColumn(views::GridLayout::FILL,
+                            views::GridLayout::FILL,
+                            1,
+                            views::GridLayout::USE_PREF,
+                            0,
+                            0);
       break;
     case DOUBLE_BUTTON_COLUMN_SET:
       column_set->AddColumn(views::GridLayout::TRAILING,
@@ -101,17 +105,19 @@
   return ok_button_;
 }
 
+void AutoSigninFirstRunDialogView::WindowClosing() {
+  if (controller_)
+    controller_->OnCloseDialog();
+}
+
 int AutoSigninFirstRunDialogView::GetDialogButtons() const {
   // None because ESC is equivalent to Cancel. It shouldn't turn off the auto
   // signin.
   return ui::DIALOG_BUTTON_NONE;
 }
 
-void AutoSigninFirstRunDialogView::OnClosed() {
-  if (controller_)
-    controller_->OnCloseDialog();
-  // This method is called twice. crbug.com/583330
-  controller_ = nullptr;
+gfx::Size AutoSigninFirstRunDialogView::GetPreferredSize() const {
+  return gfx::Size(kDesiredWidth, GetHeightForWidth(kDesiredWidth));
 }
 
 void AutoSigninFirstRunDialogView::ButtonPressed(views::Button* sender,
diff --git a/chrome/browser/ui/views/passwords/auto_signin_first_run_dialog_view.h b/chrome/browser/ui/views/passwords/auto_signin_first_run_dialog_view.h
index 9c370cb..ae76e65 100644
--- a/chrome/browser/ui/views/passwords/auto_signin_first_run_dialog_view.h
+++ b/chrome/browser/ui/views/passwords/auto_signin_first_run_dialog_view.h
@@ -31,10 +31,13 @@
   bool ShouldShowWindowTitle() const override;
   bool ShouldShowCloseButton() const override;
   views::View* GetInitiallyFocusedView() override;
+  void WindowClosing() override;
 
   // views::DialogDelegate:
   int GetDialogButtons() const override;
-  void OnClosed() override;
+
+  // views::View
+  gfx::Size GetPreferredSize() const override;
 
   // views::ButtonListener:
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view_interactive_uitest.cc b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view_interactive_uitest.cc
index eca1739..738e70c 100644
--- a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view_interactive_uitest.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/macros.h"
 #include "base/metrics/histogram_samples.h"
 #include "base/strings/utf_string_conversions.h"
@@ -22,7 +23,7 @@
 #include "chrome/test/base/interactive_test_utils.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_view_host.h"
-#include "content/public/common/content_switches.h"
+#include "content/public/common/content_features.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
@@ -291,9 +292,13 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ManagePasswordsBubbleViewTest, AutoSignin) {
-  // The switch enables the new UI.
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kEnableCredentialManagerAPI);
+  base::FeatureList::ClearInstanceForTesting();
+  scoped_ptr<base::FeatureList> feature_list(new base::FeatureList);
+  feature_list->InitializeFromCommandLine(
+      features::kCredentialManagementAPI.name, std::string());
+  base::FeatureList::SetInstance(std::move(feature_list));
+  ASSERT_TRUE(base::FeatureList::IsEnabled(features::kCredentialManagementAPI));
+
   ScopedVector<autofill::PasswordForm> local_credentials;
   test_form()->origin = GURL("https://example.com");
   test_form()->display_name = base::ASCIIToUTF16("Peter");
diff --git a/chrome/browser/ui/views/passwords/password_dialog_view_browsertest.cc b/chrome/browser/ui/views/passwords/password_dialog_view_browsertest.cc
index 7209458..63fef5a9 100644
--- a/chrome/browser/ui/views/passwords/password_dialog_view_browsertest.cc
+++ b/chrome/browser/ui/views/passwords/password_dialog_view_browsertest.cc
@@ -8,6 +8,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/passwords/account_chooser_dialog_view.h"
 #include "chrome/browser/ui/views/passwords/auto_signin_first_run_dialog_view.h"
 #include "chrome/test/base/in_process_browser_test.h"
@@ -200,7 +201,7 @@
                   &password_manager::CredentialInfo::type,
                   password_manager::CredentialType::CREDENTIAL_TYPE_EMPTY)));
   EXPECT_CALL(*controller(), OnDialogClosed());
-  EXPECT_TRUE(dialog->Close());
+  dialog->GetWidget()->Close();
 
   EXPECT_FALSE(controller()->current_autosignin_prompt());
 }
@@ -261,7 +262,7 @@
                   &password_manager::CredentialInfo::type,
                   password_manager::CredentialType::CREDENTIAL_TYPE_EMPTY)));
   EXPECT_CALL(*controller(), OnDialogClosed());
-  EXPECT_TRUE(dialog->Close());
+  dialog->GetWidget()->Close();
   EXPECT_FALSE(controller()->current_autosignin_prompt());
 }
 
@@ -292,7 +293,6 @@
   controller()->ChooseCredential(
       form, password_manager::CredentialType::CREDENTIAL_TYPE_PASSWORD);
 
-  EXPECT_CALL(*controller(), OnDialogClosed());
   EXPECT_TRUE(controller()->current_autosignin_prompt());
 }
 
@@ -377,12 +377,10 @@
   EXPECT_EQ(password_manager::ui::INACTIVE_STATE, controller()->GetState());
   AutoSigninFirstRunDialogView* dialog =
       controller()->current_autosignin_prompt();
-  // This is the way how ESC is processed. It's important to reproduce it
-  // because of double AutoSigninFirstRunDialogView::OnClosed call due to a bug
-  // http://crbug.com/583330.
   ui::Accelerator esc(ui::VKEY_ESCAPE, 0);
   EXPECT_CALL(*controller(), OnDialogClosed());
   EXPECT_TRUE(dialog->GetWidget()->client_view()->AcceleratorPressed(esc));
+  content::RunAllPendingInMessageLoop();
   testing::Mock::VerifyAndClearExpectations(controller());
   EXPECT_TRUE(
       password_bubble_experiment::ShouldShowAutoSignInPromptFirstRunExperience(
@@ -433,7 +431,6 @@
   blocked_form.reset(new autofill::PasswordForm(form));
   client()->NotifyUserAutoSigninBlockedOnFirstRun(std::move(blocked_form));
   client()->NotifySuccessfulLoginWithExistingPassword(form);
-  EXPECT_CALL(*controller(), OnDialogClosed());
   ASSERT_TRUE(controller()->current_autosignin_prompt());
 }
 
diff --git a/chrome/browser/ui/views/screen_capture_notification_ui_views.cc b/chrome/browser/ui/views/screen_capture_notification_ui_views.cc
index 65fc495..fdb11028 100644
--- a/chrome/browser/ui/views/screen_capture_notification_ui_views.cc
+++ b/chrome/browser/ui/views/screen_capture_notification_ui_views.cc
@@ -210,6 +210,7 @@
   widget->Show();
   // This has to be called after Show() to have effect.
   widget->SetOpacity(0xFF * kWindowAlphaValue);
+  widget->SetVisibleOnAllWorkspaces(true);
 
 #if defined(OS_WIN)
   return gfx::NativeViewId(views::HWNDForWidget(widget));
diff --git a/chrome/browser/ui/views/settings_api_bubble_helper_views.cc b/chrome/browser/ui/views/settings_api_bubble_helper_views.cc
index 81caa2c1..be6ff12e 100644
--- a/chrome/browser/ui/views/settings_api_bubble_helper_views.cc
+++ b/chrome/browser/ui/views/settings_api_bubble_helper_views.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/views/extensions/extension_message_bubble_view.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
-#include "chrome/browser/ui/views/settings_api_bubble_helper_views.h"
 #include "chrome/browser/ui/views/toolbar/app_menu_button.h"
 #include "chrome/browser/ui/views/toolbar/home_button.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
@@ -62,13 +61,13 @@
 void MaybeShowExtensionControlledSearchNotification(
     Profile* profile,
     content::WebContents* web_contents,
-    const AutocompleteMatch& match) {
+    AutocompleteMatch::Type match_type) {
 #if !defined(OS_WIN)
   return;
 #endif
 
-  if (AutocompleteMatch::IsSearchType(match.type) &&
-      match.type != AutocompleteMatchType::SEARCH_OTHER_ENGINE) {
+  if (AutocompleteMatch::IsSearchType(match_type) &&
+      match_type != AutocompleteMatchType::SEARCH_OTHER_ENGINE) {
     Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
     ToolbarView* toolbar =
         BrowserView::GetBrowserViewForBrowser(browser)->toolbar();
diff --git a/chrome/browser/ui/views/settings_api_bubble_helper_views.h b/chrome/browser/ui/views/settings_api_bubble_helper_views.h
index e5892f833..74d51e0 100644
--- a/chrome/browser/ui/views/settings_api_bubble_helper_views.h
+++ b/chrome/browser/ui/views/settings_api_bubble_helper_views.h
@@ -5,7 +5,8 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_SETTINGS_API_BUBBLE_HELPER_VIEWS_H_
 #define CHROME_BROWSER_UI_VIEWS_SETTINGS_API_BUBBLE_HELPER_VIEWS_H_
 
-struct AutocompleteMatch;
+#include "components/omnibox/browser/autocomplete_match.h"
+
 class Browser;
 class Profile;
 
@@ -26,7 +27,7 @@
 void MaybeShowExtensionControlledSearchNotification(
     Profile* profile,
     content::WebContents* web_contents,
-    const AutocompleteMatch& match);
+    AutocompleteMatch::Type match_type);
 
 // Shows a bubble notifying the user that the new tab page is controlled by an
 // extension. This bubble is shown only the first time the new tab page is shown
diff --git a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc
index 28a8faf..cc9f3ede 100644
--- a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc
+++ b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc
@@ -134,10 +134,6 @@
   return true;
 }
 
-void ProfileSigninConfirmationDialogViews::OnClosed() {
-  Cancel();
-}
-
 ui::ModalType ProfileSigninConfirmationDialogViews::GetModalType() const {
   return ui::MODAL_TYPE_WINDOW;
 }
@@ -230,6 +226,10 @@
       kPreferredWidth, explanation_label_->GetHeightForWidth(kPreferredWidth));
 }
 
+void ProfileSigninConfirmationDialogViews::WindowClosing() {
+  Cancel();
+}
+
 void ProfileSigninConfirmationDialogViews::StyledLabelLinkClicked(
     views::StyledLabel* label,
     const gfx::Range& range,
diff --git a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h
index c5d7eae8..41f11fb2 100644
--- a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h
+++ b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h
@@ -51,11 +51,13 @@
   views::View* CreateExtraView() override;
   bool Accept() override;
   bool Cancel() override;
-  void OnClosed() override;
   ui::ModalType GetModalType() const override;
   void ViewHierarchyChanged(
       const ViewHierarchyChangedDetails& details) override;
 
+  // views::WidgetDelegate::
+  void WindowClosing() override;
+
   // views::StyledLabelListener:
   void StyledLabelLinkClicked(views::StyledLabel* label,
                               const gfx::Range& range,
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index 61f2e22..893ffd4 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -68,9 +68,6 @@
 
 namespace {
 
-// How long the pulse throb takes.
-const int kPulseDurationMs = 200;
-
 // Width of touch tabs.
 const int kTouchWidth = 120;
 
@@ -93,16 +90,6 @@
 // Inactive selected tabs have their throb value scaled by this.
 const double kSelectedTabThrobScale = 0.95 - kSelectedTabOpacity;
 
-// Durations for the various parts of the pinned tab title animation.
-const int kPinnedTitleChangeAnimationDuration1MS = 1600;
-const int kPinnedTitleChangeAnimationStart1MS = 0;
-const int kPinnedTitleChangeAnimationEnd1MS = 1900;
-const int kPinnedTitleChangeAnimationDuration2MS = 0;
-const int kPinnedTitleChangeAnimationDuration3MS = 550;
-const int kPinnedTitleChangeAnimationStart3MS = 150;
-const int kPinnedTitleChangeAnimationEnd3MS = 800;
-const int kPinnedTitleChangeAnimationIntervalMS = 40;
-
 // Offset from the right edge for the start of the pinned title change
 // animation.
 const int kPinnedTitleChangeInitialXOffset = 6;
@@ -142,19 +129,11 @@
   return GetLayoutInsets(TAB).left() - 0.5f;
 }
 
-// Stop()s |animation| and then deletes it. We do this rather than just deleting
-// so that the delegate is notified before the destruction.
-void StopAndDeleteAnimation(scoped_ptr<gfx::Animation> animation) {
-  if (animation)
-    animation->Stop();
-}
-
 void DrawHighlight(gfx::Canvas* canvas,
                    const SkPoint& p,
                    SkScalar radius,
-                   SkAlpha alpha) {
-  const SkColor colors[2] = { SkColorSetA(SK_ColorWHITE, alpha),
-                              SkColorSetA(SK_ColorWHITE, 0) };
+                   SkColor color) {
+  const SkColor colors[2] = { color, SkColorSetA(color, 0) };
   skia::RefPtr<SkShader> shader = skia::AdoptRef(SkGradientShader::CreateRadial(
       p, radius, colors, nullptr, 2, SkShader::kClamp_TileMode));
   SkPaint paint;
@@ -504,7 +483,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 // Tab, public:
 
-Tab::Tab(TabController* controller)
+Tab::Tab(TabController* controller, gfx::AnimationContainer* container)
     : controller_(controller),
       closing_(false),
       dragging_(false),
@@ -512,6 +491,9 @@
       favicon_hiding_offset_(0),
       immersive_loading_step_(0),
       should_display_crashed_favicon_(false),
+      pulse_animation_(new gfx::ThrobAnimation(this)),
+      crash_icon_animation_(new FaviconCrashAnimation(this)),
+      animation_container_(container),
       throbber_(nullptr),
       media_indicator_button_(nullptr),
       close_button_(nullptr),
@@ -571,16 +553,45 @@
   AddChildView(close_button_);
 
   set_context_menu_controller(this);
+
+  const int kPulseDurationMs = 200;
+  pulse_animation_->SetSlideDuration(kPulseDurationMs);
+  pulse_animation_->SetContainer(animation_container_.get());
+
+  const int kPinnedTitleChangeAnimationDuration1MS = 1600;
+  const int kPinnedTitleChangeAnimationStart1MS = 0;
+  const int kPinnedTitleChangeAnimationEnd1MS = 1900;
+  const int kPinnedTitleChangeAnimationDuration2MS = 0;
+  const int kPinnedTitleChangeAnimationDuration3MS = 550;
+  const int kPinnedTitleChangeAnimationStart3MS = 150;
+  const int kPinnedTitleChangeAnimationEnd3MS = 800;
+  const int kPinnedTitleChangeAnimationIntervalMS = 40;
+  gfx::MultiAnimation::Parts parts;
+  parts.push_back(gfx::MultiAnimation::Part(
+      kPinnedTitleChangeAnimationDuration1MS,
+      kPinnedTitleChangeAnimationStart1MS,
+      kPinnedTitleChangeAnimationEnd1MS,
+      gfx::Tween::EASE_OUT));
+  parts.push_back(gfx::MultiAnimation::Part(
+      kPinnedTitleChangeAnimationDuration2MS,
+      gfx::Tween::ZERO));
+  parts.push_back(gfx::MultiAnimation::Part(
+      kPinnedTitleChangeAnimationDuration3MS,
+      kPinnedTitleChangeAnimationStart3MS,
+      kPinnedTitleChangeAnimationEnd3MS,
+      gfx::Tween::EASE_IN));
+  const base::TimeDelta timeout =
+      base::TimeDelta::FromMilliseconds(kPinnedTitleChangeAnimationIntervalMS);
+  pinned_title_change_animation_.reset(new gfx::MultiAnimation(parts, timeout));
+  pinned_title_change_animation_->SetContainer(animation_container_.get());
+  pinned_title_change_animation_->set_delegate(this);
+
+  hover_controller_.SetAnimationContainer(animation_container_.get());
 }
 
 Tab::~Tab() {
 }
 
-void Tab::SetAnimationContainer(gfx::AnimationContainer* container) {
-  animation_container_ = container;
-  hover_controller_.SetAnimationContainer(container);
-}
-
 bool Tab::IsActive() const {
   return controller_->IsActiveTab(this);
 }
@@ -619,17 +630,14 @@
   }
   title_->SetText(title);
 
-  if (data_.IsCrashed()) {
-    if (!should_display_crashed_favicon_ && !crash_icon_animation_) {
-      data_.media_state = TAB_MEDIA_STATE_NONE;
-      crash_icon_animation_.reset(new FaviconCrashAnimation(this));
-      crash_icon_animation_->Start();
-    }
-  } else {
-    if (crash_icon_animation_)
-        crash_icon_animation_.reset();
+  if (!data_.IsCrashed()) {
+    crash_icon_animation_->Stop();
     should_display_crashed_favicon_ = false;
     favicon_hiding_offset_ = 0;
+  } else if (!should_display_crashed_favicon_ &&
+             !crash_icon_animation_->is_animating()) {
+    data_.media_state = TAB_MEDIA_STATE_NONE;
+    crash_icon_animation_->Start();
   }
 
   if (data_.media_state != old.media_state)
@@ -657,48 +665,20 @@
 }
 
 void Tab::StartPulse() {
-  pulse_animation_.reset(new gfx::ThrobAnimation(this));
-  pulse_animation_->SetSlideDuration(kPulseDurationMs);
-  if (animation_container_.get())
-    pulse_animation_->SetContainer(animation_container_.get());
   pulse_animation_->StartThrobbing(std::numeric_limits<int>::max());
 }
 
 void Tab::StopPulse() {
-  StopAndDeleteAnimation(std::move(pulse_animation_));
+  pulse_animation_->Stop();
 }
 
 void Tab::StartPinnedTabTitleAnimation() {
-  if (!data().pinned)
-    return;
-  if (!pinned_title_change_animation_) {
-    gfx::MultiAnimation::Parts parts;
-    parts.push_back(
-        gfx::MultiAnimation::Part(kPinnedTitleChangeAnimationDuration1MS,
-                                 gfx::Tween::EASE_OUT));
-    parts.push_back(
-        gfx::MultiAnimation::Part(kPinnedTitleChangeAnimationDuration2MS,
-                                 gfx::Tween::ZERO));
-    parts.push_back(
-        gfx::MultiAnimation::Part(kPinnedTitleChangeAnimationDuration3MS,
-                                 gfx::Tween::EASE_IN));
-    parts[0].start_time_ms = kPinnedTitleChangeAnimationStart1MS;
-    parts[0].end_time_ms = kPinnedTitleChangeAnimationEnd1MS;
-    parts[2].start_time_ms = kPinnedTitleChangeAnimationStart3MS;
-    parts[2].end_time_ms = kPinnedTitleChangeAnimationEnd3MS;
-    base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(
-        kPinnedTitleChangeAnimationIntervalMS);
-    pinned_title_change_animation_.reset(
-        new gfx::MultiAnimation(parts, timeout));
-    if (animation_container_.get())
-      pinned_title_change_animation_->SetContainer(animation_container_.get());
-    pinned_title_change_animation_->set_delegate(this);
-  }
-  pinned_title_change_animation_->Start();
+  if (data().pinned)
+    pinned_title_change_animation_->Start();
 }
 
 void Tab::StopPinnedTabTitleAnimation() {
-  StopAndDeleteAnimation(std::move(pinned_title_change_animation_));
+  pinned_title_change_animation_->Stop();
 }
 
 int Tab::GetWidthOfLargestSelectableRegion() const {
@@ -780,9 +760,8 @@
 void Tab::AnimationProgressed(const gfx::Animation* animation) {
   // Ignore if the pulse animation is being performed on active tab because
   // it repaints the same image. See |Tab::PaintTabBackground()|.
-  if (animation == pulse_animation_.get() && IsActive())
-    return;
-  SchedulePaint();
+  if ((animation != pulse_animation_.get()) || !IsActive())
+    SchedulePaint();
 }
 
 void Tab::AnimationCanceled(const gfx::Animation* animation) {
@@ -797,21 +776,19 @@
 // Tab, views::ButtonListener overrides:
 
 void Tab::ButtonPressed(views::Button* sender, const ui::Event& event) {
-  if (media_indicator_button_ && media_indicator_button_->visible()) {
-    if (media_indicator_button_->enabled())
-      content::RecordAction(UserMetricsAction("CloseTab_MuteToggleAvailable"));
-    else if (data_.media_state == TAB_MEDIA_STATE_AUDIO_PLAYING)
-      content::RecordAction(UserMetricsAction("CloseTab_AudioIndicator"));
-    else
-      content::RecordAction(UserMetricsAction("CloseTab_RecordingIndicator"));
-  } else {
+  if (!media_indicator_button_ || !media_indicator_button_->visible())
     content::RecordAction(UserMetricsAction("CloseTab_NoMediaIndicator"));
-  }
+  else if (media_indicator_button_->enabled())
+    content::RecordAction(UserMetricsAction("CloseTab_MuteToggleAvailable"));
+  else if (data_.media_state == TAB_MEDIA_STATE_AUDIO_PLAYING)
+    content::RecordAction(UserMetricsAction("CloseTab_AudioIndicator"));
+  else
+    content::RecordAction(UserMetricsAction("CloseTab_RecordingIndicator"));
 
   const CloseTabSource source =
       (event.type() == ui::ET_MOUSE_RELEASED &&
-       (event.flags() & ui::EF_FROM_TOUCH) == 0) ? CLOSE_TAB_FROM_MOUSE :
-      CLOSE_TAB_FROM_TOUCH;
+       !(event.flags() & ui::EF_FROM_TOUCH)) ? CLOSE_TAB_FROM_MOUSE
+                                             : CLOSE_TAB_FROM_TOUCH;
   DCHECK_EQ(close_button_, sender);
   controller_->CloseTab(this, source);
   if (event.type() == ui::ET_GESTURE_TAP)
@@ -1230,9 +1207,9 @@
 void Tab::PaintImmersiveTab(gfx::Canvas* canvas) {
   // Use transparency for the draw-attention animation.
   int alpha = 255;
-  if (pulse_animation_ && pulse_animation_->is_animating() && !data().pinned) {
+  if (pulse_animation_->is_animating() && !data().pinned) {
     alpha = pulse_animation_->CurrentValueBetween(
-        255, static_cast<int>(255 * kImmersiveTabMinThrobOpacity));
+        255, gfx::ToRoundedInt(255 * kImmersiveTabMinThrobOpacity));
   }
 
   // Draw a gray rectangle to represent the tab. This works for pinned tabs as
@@ -1280,8 +1257,7 @@
     PaintTabBackgroundUsingFillId(canvas, true, kActiveTabFillId,
                                   has_custom_image, y_offset);
   } else {
-    if (pinned_title_change_animation_ &&
-        pinned_title_change_animation_->is_animating())
+    if (pinned_title_change_animation_->is_animating())
       PaintInactiveTabBackgroundWithTitleChange(canvas);
     else
       PaintInactiveTabBackground(canvas);
@@ -1301,13 +1277,16 @@
   const int kPinnedTitleChangeGradientRadius = 20;
   const float radius = kPinnedTitleChangeGradientRadius;
   double x = radius;
-  int alpha = 255;
+  SkColor hover_color =
+      GetThemeProvider()->GetColor(ThemeProperties::COLOR_TOOLBAR);
   if (pinned_title_change_animation_->current_part_index() == 0) {
     x = pinned_title_change_animation_->CurrentValueBetween(
             width() + radius - kPinnedTitleChangeInitialXOffset, radius);
   } else if (pinned_title_change_animation_->current_part_index() == 2) {
     x = pinned_title_change_animation_->CurrentValueBetween(radius, -radius);
-    alpha = pinned_title_change_animation_->CurrentValueBetween(255, 0);
+    const int alpha =
+        pinned_title_change_animation_->CurrentValueBetween(255, 0);
+    hover_color = SkColorSetA(hover_color, static_cast<SkAlpha>(alpha));
   }
   SkPoint p;
   p.set(SkDoubleToScalar(x), 0);
@@ -1319,14 +1298,14 @@
     GetFillPath(scale, &fill);
     canvas->ClipPath(fill, true);
     p.scale(SkFloatToScalar(scale));
-    DrawHighlight(canvas, p, SkFloatToScalar(radius * scale), alpha);
+    DrawHighlight(canvas, p, SkFloatToScalar(radius * scale), hover_color);
   } else {
     gfx::Canvas background_canvas(size(), canvas->image_scale(), false);
     PaintInactiveTabBackground(&background_canvas);
     gfx::ImageSkia background_image(background_canvas.ExtractImageRep());
     canvas->DrawImageInt(background_image, 0, 0);
     gfx::Canvas hover_canvas(size(), canvas->image_scale(), false);
-    DrawHighlight(&hover_canvas, p, SkFloatToScalar(radius), alpha);
+    DrawHighlight(&hover_canvas, p, SkFloatToScalar(radius), hover_color);
     gfx::ImageSkia hover_image = gfx::ImageSkiaOperations::CreateMaskedImage(
         gfx::ImageSkia(hover_canvas.ExtractImageRep()), background_image);
     canvas->DrawImageInt(hover_image, 0, 0);
@@ -1378,6 +1357,7 @@
                                         bool has_custom_image,
                                         int y_offset) {
   const ui::ThemeProvider* tp = GetThemeProvider();
+  const SkColor toolbar_color = tp->GetColor(ThemeProperties::COLOR_TOOLBAR);
   gfx::ImageSkia* fill_image = tp->GetImageSkiaNamed(fill_id);
   // The tab image needs to be lined up with the background image
   // so that it feels partially transparent.  These offsets represent the tab
@@ -1389,7 +1369,8 @@
       std::max(SkFloatToScalar(width() / 4.f), kMinHoverRadius);
   const bool draw_hover = !is_active && hover_controller_.ShouldDraw();
   SkPoint hover_location(PointToSkPoint(hover_controller_.location()));
-  const SkAlpha hover_alpha = hover_controller_.GetAlpha();
+  const SkColor hover_color =
+      SkColorSetA(toolbar_color, hover_controller_.GetAlpha());
 
   if (ui::MaterialDesignController::IsModeMaterial()) {
     gfx::ScopedCanvas scoped_canvas(canvas);
@@ -1409,15 +1390,15 @@
         canvas->TileImageInt(*fill_image, x_offset, y_offset, 0, 0, width(),
                              height());
       } else {
-        paint.setColor(tp->GetColor(is_active ?
-            static_cast<int>(ThemeProperties::COLOR_TOOLBAR) :
-            ThemeProperties::COLOR_BACKGROUND_TAB));
+        paint.setColor(
+            is_active ? toolbar_color
+                      : tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB));
         canvas->DrawRect(gfx::ScaleToEnclosingRect(GetLocalBounds(), scale),
                          paint);
       }
       if (draw_hover) {
         hover_location.scale(SkFloatToScalar(scale));
-        DrawHighlight(canvas, hover_location, radius * scale, hover_alpha);
+        DrawHighlight(canvas, hover_location, radius * scale, hover_color);
       }
     }
 
@@ -1444,7 +1425,7 @@
       canvas->DrawImageInt(background_image, 0, 0);
 
       gfx::Canvas hover_canvas(size(), canvas->image_scale(), false);
-      DrawHighlight(&hover_canvas, hover_location, radius, hover_alpha);
+      DrawHighlight(&hover_canvas, hover_location, radius, hover_color);
       gfx::ImageSkia result = gfx::ImageSkiaOperations::CreateMaskedImage(
           gfx::ImageSkia(hover_canvas.ExtractImageRep()), background_image);
       canvas->DrawImageInt(result, 0, 0);
@@ -1626,9 +1607,8 @@
 
   // Showing both the pulse and title change animation at the same time is too
   // much.
-  if (pulse_animation_ && pulse_animation_->is_animating() &&
-      (!pinned_title_change_animation_ ||
-       !pinned_title_change_animation_->is_animating())) {
+  if (pulse_animation_->is_animating() &&
+      !pinned_title_change_animation_->is_animating()) {
     val += pulse_animation_->GetCurrentValue() * offset;
   } else if (hover_controller_.ShouldDraw()) {
     val += hover_controller_.GetAnimationValue() * offset;
@@ -1670,7 +1650,7 @@
     return;
 
   // Extends the area to the bottom when the crash animation is in progress.
-  if (crash_icon_animation_)
+  if (crash_icon_animation_->is_animating())
     bounds.set_height(height() - bounds.y());
   bounds.set_x(GetMirroredXForRect(bounds));
   SchedulePaintInRect(bounds);
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h
index 67be96c..74d3430 100644
--- a/chrome/browser/ui/views/tabs/tab.h
+++ b/chrome/browser/ui/views/tabs/tab.h
@@ -52,7 +52,7 @@
   // The Tab's class name.
   static const char kViewClassName[];
 
-  explicit Tab(TabController* controller);
+  Tab(TabController* controller, gfx::AnimationContainer* container);
   ~Tab() override;
 
   TabController* controller() const { return controller_; }
@@ -72,9 +72,6 @@
 
   SkColor button_color() const { return button_color_; }
 
-  // Sets the container all animations run from.
-  void SetAnimationContainer(gfx::AnimationContainer* container);
-
   // Returns true if this tab is the active tab.
   bool IsActive() const;
 
@@ -247,7 +244,7 @@
   // Paint with the "immersive mode" light-bar style.
   void PaintImmersiveTab(gfx::Canvas* canvas);
 
-  // Paint various portions of the Tab
+  // Paint various portions of the Tab.
   void PaintTabBackground(gfx::Canvas* canvas);
   void PaintInactiveTabBackgroundWithTitleChange(gfx::Canvas* canvas);
   void PaintInactiveTabBackground(gfx::Canvas* canvas);
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index 32edbdc9..4348dd3 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -525,93 +525,98 @@
                              float scale,
                              const SkPath& fill,
                              gfx::Canvas* canvas) const {
+  // First we compute the background image coordinates and scale, in case we
+  // need to draw a custom background image.
+  const ui::ThemeProvider* tp = GetThemeProvider();
   bool custom_image;
   const int bg_id = tab_strip_->GetBackgroundResourceId(&custom_image);
-  const ui::ThemeProvider* tp = GetThemeProvider();
+  // For custom tab backgrounds the background starts at the top of the tab
+  // strip. Otherwise the background starts at the top of the frame.
+  const int offset_y = tp->HasCustomImage(bg_id) ?
+      -GetLayoutConstant(TAB_TOP_EXCLUSION_HEIGHT) : background_offset_.y();
+  // The new tab background is mirrored in RTL mode, but the theme background
+  // should never be mirrored. Mirror it here to compensate.
+  float x_scale = 1.0f;
+  int x = GetMirroredX() + background_offset_.x();
+  const gfx::Size size(GetLayoutSize(NEW_TAB_BUTTON));
+  if (base::i18n::IsRTL()) {
+    x_scale = -1.0f;
+    // Offset by |width| such that the same region is painted as if there was no
+    // flip.
+    x += size.width();
+  }
+  const int y = GetNewTabButtonTopOffset() + offset_y;
 
-  gfx::ScopedCanvas scoped_canvas(canvas);
-
-  const bool md = ui::MaterialDesignController::IsModeMaterial();
-  if (md) {
+  if (ui::MaterialDesignController::IsModeMaterial()) {
+    gfx::ScopedCanvas scoped_canvas(canvas);
     canvas->UndoDeviceScaleFactor();
 
     // For unpressed buttons, draw the fill and its shadow.
     if (!pressed) {
-      gfx::ScopedCanvas scoped_canvas(canvas);
-
-      // For custom themes, clip out the fill path itself so only the shadow
-      // around it is drawn.  We'll draw the fill image below.
-      if (custom_image)
-        canvas->sk_canvas()->clipPath(fill, SkRegion::kDifference_Op, true);
-
       SkPaint paint;
       paint.setAntiAlias(true);
+      if (custom_image) {
+        const bool succeeded = canvas->InitSkPaintForTiling(
+            *tp->GetImageSkiaNamed(bg_id), x, y, x_scale * scale, scale, 0, 0,
+            &paint);
+        DCHECK(succeeded);
+      } else {
+        paint.setColor(tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB));
+      }
       skia::RefPtr<SkDrawLooper> looper = CreateShadowDrawLooper(0x26);
       paint.setLooper(looper.get());
-      paint.setColor(tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB));
       canvas->DrawPath(fill, paint);
     }
 
-    // Clip to just the fill region for any theme drawing and hover/pressed
-    // state overlay drawing below.  In non-MD mode, this is done on the caller
-    // side using image masking operations.
-    canvas->ClipPath(fill, true);
-    canvas->sk_canvas()->scale(scale, scale);
-  }
-
-  // Draw the fill background image.
-  const gfx::Size size(GetLayoutSize(NEW_TAB_BUTTON));
-  if (custom_image || !md) {
-    gfx::ImageSkia* background = tp->GetImageSkiaNamed(bg_id);
-    // For custom tab backgrounds the background starts at the top of the tab
-    // strip. Otherwise the background starts at the top of the frame.
-    const int offset_y = tp->HasCustomImage(bg_id) ?
-        -GetLayoutConstant(TAB_TOP_EXCLUSION_HEIGHT) : background_offset_.y();
-
-    // The new tab background is mirrored in RTL mode, but the theme background
-    // should never be mirrored. Mirror it here to compensate.
-    float x_scale = 1.0f;
-    int x = GetMirroredX() + background_offset_.x();
-    if (base::i18n::IsRTL()) {
-      x_scale = -1.0f;
-      // Offset by |width| such that the same region is painted as if there was
-      // no flip.
-      x += size.width();
+    // Draw a white highlight on hover.
+    SkPaint paint;
+    paint.setAntiAlias(true);
+    const SkAlpha hover_alpha = static_cast<SkAlpha>(
+        hover_animation().CurrentValueBetween(0x00, 0x4D));
+    if (hover_alpha != SK_AlphaTRANSPARENT) {
+      paint.setColor(SkColorSetA(SK_ColorWHITE, hover_alpha));
+      canvas->DrawPath(fill, paint);
     }
-    canvas->TileImageInt(*background, x, GetNewTabButtonTopOffset() + offset_y,
-                         x_scale, 1.0f, 0, 0, size.width(), size.height());
 
-    // For non-MD, adjust the alpha of the fill to match that of inactive tabs
-    // (except for pressed buttons, which get a different value).  For MD, we do
-    // this with an opacity recorder in TabStrip::PaintChildren() so the fill
-    // and stroke are both affected, to better match how tabs are handled, but
-    // in non-MD, the button stroke is already lighter than the tab stroke, and
-    // using the opacity recorder washes it out too much.
+    // Most states' opacities are adjusted using an opacity recorder in
+    // TabStrip::PaintChildren(), but the pressed state is excluded there and
+    // instead rendered using a dark overlay here.  This produces a different
+    // effect than for non-MD, and avoiding the use of the opacity recorder
+    // keeps the stroke more visible in this state.
+    if (pressed) {
+      paint.setColor(SkColorSetA(SK_ColorBLACK, 0x14));
+      canvas->DrawPath(fill, paint);
+    }
+  } else {
+    // Draw the fill image.
+    canvas->TileImageInt(*tp->GetImageSkiaNamed(bg_id), x, y, x_scale, 1.0f,
+                         0, 0, size.width(), size.height());
+
+    // Adjust the alpha of the fill to match that of inactive tabs (except for
+    // pressed buttons, which get a different value).  For MD, we do this with
+    // an opacity recorder in TabStrip::PaintChildren() so the fill and stroke
+    // are both affected, to better match how tabs are handled, but in non-MD,
+    // the button stroke is already lighter than the tab stroke, and using the
+    // opacity recorder washes it out too much.
     static const SkAlpha kPressedAlpha = 145;
-    const SkAlpha alpha =
+    const SkAlpha fill_alpha =
         pressed ? kPressedAlpha : tab_strip_->GetInactiveAlpha(true);
-    if (alpha != 255 && !md) {
+    if (fill_alpha != 255) {
       SkPaint paint;
-      paint.setAlpha(alpha);
+      paint.setAlpha(fill_alpha);
       paint.setXfermodeMode(SkXfermode::kDstIn_Mode);
       paint.setStyle(SkPaint::kFill_Style);
       canvas->DrawRect(gfx::Rect(size), paint);
     }
+
+    // Draw a white highlight on hover.
+    const SkAlpha hover_alpha = static_cast<SkAlpha>(
+        hover_animation().CurrentValueBetween(0x00, 0x40));
+    if (hover_alpha != SK_AlphaTRANSPARENT) {
+      canvas->FillRect(GetLocalBounds(),
+                       SkColorSetA(SK_ColorWHITE, hover_alpha));
+    }
   }
-
-  // White highlight on hover.
-  const SkAlpha alpha = static_cast<SkAlpha>(
-      hover_animation().CurrentValueBetween(0x00, md ? 0x4D : 0x40));
-  if (alpha != SK_AlphaTRANSPARENT)
-    canvas->FillRect(GetLocalBounds(), SkColorSetA(SK_ColorWHITE, alpha));
-
-  // For MD, most states' opacities are adjusted using an opacity recorder in
-  // TabStrip::PaintChildren(), but the pressed state is excluded there and
-  // instead rendered using a dark overlay here.  This produces a different
-  // effect than for non-MD, and avoiding the use of the opacity recorder keeps
-  // the stroke more visible in this state.
-  if (md && pressed)
-    canvas->FillRect(GetLocalBounds(), SkColorSetA(SK_ColorBLACK, 0x14));
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -756,7 +761,7 @@
 void TabStrip::AddTabAt(int model_index,
                         const TabRendererData& data,
                         bool is_active) {
-  Tab* tab = CreateTab();
+  Tab* tab = new Tab(this, animation_container_.get());
   AddChildView(tab);
   tab->SetData(data);
   UpdateTabsClosingMap(model_index, 1);
@@ -1093,18 +1098,16 @@
 }
 
 SkAlpha TabStrip::GetInactiveAlpha(bool for_new_tab_button) const {
-  static const SkAlpha kInactiveTabAlphaOpaque = 255;
-  static const double kMultiSelectionMultiplier = 0.6;
-
-  SkAlpha base_alpha = kInactiveTabAlphaOpaque;
 #if defined(USE_ASH)
   static const SkAlpha kInactiveTabAlphaAsh = 230;
-  base_alpha = kInactiveTabAlphaAsh;
+  const SkAlpha base_alpha = kInactiveTabAlphaAsh;
 #else
   static const SkAlpha kInactiveTabAlphaGlass = 200;
-  if (GetWidget()->ShouldWindowContentsBeTransparent())
-    base_alpha = kInactiveTabAlphaGlass;
+  static const SkAlpha kInactiveTabAlphaOpaque = 255;
+  const SkAlpha base_alpha = GetWidget()->ShouldWindowContentsBeTransparent() ?
+      kInactiveTabAlphaGlass : kInactiveTabAlphaOpaque;
 #endif  // USE_ASH
+  static const double kMultiSelectionMultiplier = 0.6;
   return (for_new_tab_button || (GetSelectionModel().size() <= 1)) ?
       base_alpha : static_cast<SkAlpha>(kMultiSelectionMultiplier * base_alpha);
 }
@@ -1402,9 +1405,9 @@
   const bool incognito = controller()->IsIncognito();
   const int id = incognito ?
       IDR_THEME_TAB_BACKGROUND_INCOGNITO : IDR_THEME_TAB_BACKGROUND;
-  const int frame_id = incognito ? IDR_THEME_FRAME_INCOGNITO : IDR_THEME_FRAME;
-  *custom_image = tp->HasCustomImage(id) || tp->HasCustomImage(frame_id) ||
-      (incognito && tp->HasCustomImage(IDR_THEME_FRAME));
+  *custom_image =
+      tp->HasCustomImage(id) || tp->HasCustomImage(IDR_THEME_FRAME) ||
+      (incognito && tp->HasCustomImage(IDR_THEME_FRAME_INCOGNITO));
   return id;
 }
 
@@ -1704,12 +1707,6 @@
   }
 }
 
-Tab* TabStrip::CreateTab() {
-  Tab* tab = new Tab(this);
-  tab->SetAnimationContainer(animation_container_.get());
-  return tab;
-}
-
 void TabStrip::StartInsertTabAnimation(int model_index) {
   PrepareForAnimation();
 
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h
index c63d140..4d9161a 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.h
+++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -310,9 +310,6 @@
 
   void Init();
 
-  // Creates and returns a new tab. The caller owners the returned tab.
-  Tab* CreateTab();
-
   // Invoked from |AddTabAt| after the newly created tab has been inserted.
   void StartInsertTabAnimation(int model_index);
 
diff --git a/chrome/browser/ui/views/tabs/tab_unittest.cc b/chrome/browser/ui/views/tabs/tab_unittest.cc
index f001038..f7cf417 100644
--- a/chrome/browser/ui/views/tabs/tab_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_unittest.cc
@@ -251,7 +251,7 @@
   InitWidget(&widget);
 
   FakeTabController tab_controller;
-  Tab tab(&tab_controller);
+  Tab tab(&tab_controller, nullptr);
   widget.GetContentsView()->AddChildView(&tab);
   tab.SetBoundsRect(gfx::Rect(gfx::Point(0, 0), Tab::GetStandardSize()));
 
@@ -286,7 +286,7 @@
   InitWidget(&widget);
 
   FakeTabController controller;
-  Tab tab(&controller);
+  Tab tab(&controller, nullptr);
   widget.GetContentsView()->AddChildView(&tab);
 
   SkBitmap bitmap;
@@ -341,7 +341,7 @@
   InitWidget(&widget);
 
   FakeTabController controller;
-  Tab tab(&controller);
+  Tab tab(&controller, nullptr);
   widget.GetContentsView()->AddChildView(&tab);
   tab.SetBoundsRect(gfx::Rect(Tab::GetStandardSize()));
 
@@ -391,7 +391,7 @@
 // shouldn't change the insets of the close button.
 TEST_F(TabTest, CloseButtonLayout) {
   FakeTabController tab_controller;
-  Tab tab(&tab_controller);
+  Tab tab(&tab_controller, nullptr);
   tab.SetBounds(0, 0, 100, 50);
   LayoutTab(&tab);
   gfx::Insets close_button_insets = GetCloseButton(tab)->GetInsets();
@@ -413,7 +413,7 @@
   InitWidget(&widget);
 
   FakeTabController tab_controller;
-  Tab tab(&tab_controller);
+  Tab tab(&tab_controller, nullptr);
   widget.GetContentsView()->AddChildView(&tab);
   tab.SetBoundsRect(gfx::Rect(Tab::GetStandardSize()));
 
@@ -464,7 +464,7 @@
 
 TEST_F(TabTest, TitleHiddenWhenSmall) {
   FakeTabController tab_controller;
-  Tab tab(&tab_controller);
+  Tab tab(&tab_controller, nullptr);
   tab.SetBounds(0, 0, 100, 50);
   EXPECT_GT(GetTitleWidth(tab), 0);
   tab.SetBounds(0, 0, 0, 50);
diff --git a/chrome/browser/ui/views/toolbar/app_menu_button.cc b/chrome/browser/ui/views/toolbar/app_menu_button.cc
index 7865760..f30ceec7 100644
--- a/chrome/browser/ui/views/toolbar/app_menu_button.cc
+++ b/chrome/browser/ui/views/toolbar/app_menu_button.cc
@@ -47,14 +47,6 @@
   set_ink_drop_delegate(ink_drop_delegate_.get());
   if (!ui::MaterialDesignController::IsModeMaterial())
     icon_painter_.reset(new AppMenuIconPainter(this));
-
-  const int kInkDropLargeSize = 32;
-  const int kInkDropLargeCornerRadius = 5;
-  const int kInkDropSmallSize = 24;
-  const int kInkDropSmallCornerRadius = 2;
-  ink_drop_delegate()->SetInkDropSize(
-      kInkDropLargeSize, kInkDropLargeCornerRadius, kInkDropSmallSize,
-      kInkDropSmallCornerRadius);
 }
 
 AppMenuButton::~AppMenuButton() {
@@ -208,7 +200,7 @@
   image()->SetPaintToLayer(false);
 }
 
-gfx::Point AppMenuButton::CalculateInkDropCenter() const {
+gfx::Point AppMenuButton::GetInkDropCenter() const {
   // ToolbarView extends the bounds of the app button to the right in maximized
   // mode. So instead of using the center point of local bounds, we use the
   // center point (adjusted for RTL layouts) of the preferred size, which
diff --git a/chrome/browser/ui/views/toolbar/app_menu_button.h b/chrome/browser/ui/views/toolbar/app_menu_button.h
index 92a4f2d..f02b6db1 100644
--- a/chrome/browser/ui/views/toolbar/app_menu_button.h
+++ b/chrome/browser/ui/views/toolbar/app_menu_button.h
@@ -72,7 +72,7 @@
   // views::MenuButton:
   void AddInkDropLayer(ui::Layer* ink_drop_layer) override;
   void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override;
-  gfx::Point CalculateInkDropCenter() const override;
+  gfx::Point GetInkDropCenter() const override;
 
   // views::MenuButton:
   const char* GetClassName() const override;
diff --git a/chrome/browser/ui/views/toolbar/back_button.cc b/chrome/browser/ui/views/toolbar/back_button.cc
index 0a0f51d..05618a9 100644
--- a/chrome/browser/ui/views/toolbar/back_button.cc
+++ b/chrome/browser/ui/views/toolbar/back_button.cc
@@ -29,7 +29,7 @@
   InvalidateLayout();
 }
 
-gfx::Point BackButton::CalculateInkDropCenter() const {
+gfx::Point BackButton::GetInkDropCenter() const {
   int visible_width = GetPreferredSize().width();
   return gfx::Point(
       GetMirroredXWithWidthInView(margin_leading_, visible_width) +
diff --git a/chrome/browser/ui/views/toolbar/back_button.h b/chrome/browser/ui/views/toolbar/back_button.h
index ddbe2f34..0f11c344 100644
--- a/chrome/browser/ui/views/toolbar/back_button.h
+++ b/chrome/browser/ui/views/toolbar/back_button.h
@@ -34,15 +34,12 @@
   // to make the focus rectangle centered.
   void SetLeadingMargin(int margin);
 
- protected:
-  // ToolbarButton:
-  gfx::Point CalculateInkDropCenter() const override;
-
  private:
   // ToolbarButton:
   const char* GetClassName() const override;
   scoped_ptr<views::LabelButtonBorder> CreateDefaultBorder() const override;
   gfx::Rect GetThemePaintRect() const override;
+  gfx::Point GetInkDropCenter() const override;
 
   // Any leading margin to be applied. Used when the back button is in
   // a maximized state to extend to the full window width.
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
index 30777b8..bff4184 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_action_view.cc
@@ -70,14 +70,6 @@
 
   set_context_menu_controller(this);
 
-  const int kInkDropLargeSize = 32;
-  const int kInkDropLargeCornerRadius = 5;
-  const int kInkDropSmallSize = 24;
-  const int kInkDropSmallCornerRadius = 2;
-  ink_drop_delegate()->SetInkDropSize(
-      kInkDropLargeSize, kInkDropLargeCornerRadius, kInkDropSmallSize,
-      kInkDropSmallCornerRadius);
-
   // If the button is within a menu, we need to make it focusable in order to
   // have it accessible via keyboard navigation, but it shouldn't request focus
   // (because that would close the menu).
diff --git a/chrome/browser/ui/views/toolbar/toolbar_button.cc b/chrome/browser/ui/views/toolbar/toolbar_button.cc
index 3e33387..38731ca8 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_button.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_button.cc
@@ -42,14 +42,6 @@
   set_ink_drop_delegate(ink_drop_delegate_.get());
   set_has_ink_drop_action_on_click(true);
   set_context_menu_controller(this);
-
-  const int kInkDropLargeSize = 32;
-  const int kInkDropLargeCornerRadius = 5;
-  const int kInkDropSmallSize = 24;
-  const int kInkDropSmallCornerRadius = 2;
-  ink_drop_delegate()->SetInkDropSize(
-      kInkDropLargeSize, kInkDropLargeCornerRadius, kInkDropSmallSize,
-      kInkDropSmallCornerRadius);
 }
 
 ToolbarButton::~ToolbarButton() {}
diff --git a/chrome/browser/ui/views/website_settings/chooser_bubble_ui_view.cc b/chrome/browser/ui/views/website_settings/chooser_bubble_ui_view.cc
index 4a412c6..b69e4c9 100644
--- a/chrome/browser/ui/views/website_settings/chooser_bubble_ui_view.cc
+++ b/chrome/browser/ui/views/website_settings/chooser_bubble_ui_view.cc
@@ -4,8 +4,11 @@
 
 #include "chrome/browser/ui/views/website_settings/chooser_bubble_ui_view.h"
 
+#include <stddef.h>
+
 #include <algorithm>
 #include <string>
+#include <vector>
 
 #include "base/macros.h"
 #include "base/strings/string16.h"
@@ -30,10 +33,14 @@
 #include "ui/views/bubble/bubble_frame_view.h"
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/button/label_button_border.h"
+#include "ui/views/controls/separator.h"
+#include "ui/views/controls/styled_label.h"
+#include "ui/views/controls/styled_label_listener.h"
 #include "ui/views/controls/table/table_view.h"
 #include "ui/views/controls/table/table_view_observer.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/grid_layout.h"
+#include "ui/views/layout/layout_constants.h"
 
 namespace {
 
@@ -43,16 +50,6 @@
 // Chooser permission bubble height
 const int kChooserPermissionBubbleHeight = 200;
 
-// Spacing constant for outer margin. This is added to the
-// bubble margin itself to equalize the margins at 13px.
-const int kBubbleOuterMargin = 5;
-
-// Spacing between major items should be 9px.
-const int kItemMajorSpacing = 9;
-
-// Button border size, draws inside the spacing distance.
-const int kButtonBorderSize = 2;
-
 }  // namespace
 
 scoped_ptr<BubbleUi> ChooserBubbleDelegate::BuildBubbleUi() {
@@ -65,6 +62,7 @@
 // View implementation for the chooser bubble.
 class ChooserBubbleUiViewDelegate : public views::BubbleDelegateView,
                                     public views::ButtonListener,
+                                    public views::StyledLabelListener,
                                     public views::TableViewObserver {
  public:
   ChooserBubbleUiViewDelegate(views::View* anchor_view,
@@ -75,14 +73,19 @@
 
   void Close();
 
-  // BubbleDelegateView:
+  // views::BubbleDelegateView:
   bool ShouldShowWindowTitle() const override;
   base::string16 GetWindowTitle() const override;
   void OnWidgetDestroying(views::Widget* widget) override;
 
-  // ButtonListener:
+  // views::ButtonListener:
   void ButtonPressed(views::Button* button, const ui::Event& event) override;
 
+  // views::StyledLabelListener:
+  void StyledLabelLinkClicked(views::StyledLabel* label,
+                              const gfx::Range& range,
+                              int event_flags) override;
+
   // views::TableViewObserver:
   void OnSelectionChanged() override;
 
@@ -98,7 +101,6 @@
   ChooserBubbleDelegate* chooser_bubble_delegate_;
 
   views::LabelButton* connect_button_;
-  views::LabelButton* cancel_button_;
   views::TableView* table_view_;
   ChooserTableModel* chooser_table_model_;
   bool button_pressed_;
@@ -146,6 +148,24 @@
       owner_(owner),
       chooser_bubble_delegate_(chooser_bubble_delegate),
       button_pressed_(false) {
+  // TODO(juncai): try using DialogClientView to build the chooser UI view since
+  // they look similar.
+  // https://crbug.com/587545
+  // ------------------------------------
+  // | Chooser bubble title             |
+  // | -------------------------------- |
+  // | | option 0                     | |
+  // | | option 1                     | |
+  // | | option 2                     | |
+  // | |                              | |
+  // | |                              | |
+  // | |                              | |
+  // | -------------------------------- |
+  // |           [ Connect ] [ Cancel ] |
+  // |----------------------------------|
+  // | Not seeing your device? Get help |
+  // ------------------------------------
+
   views::GridLayout* layout = new views::GridLayout(this);
   SetLayoutManager(layout);
 
@@ -153,9 +173,8 @@
   column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
                         views::GridLayout::USE_PREF, 0, 0);
 
-  layout->StartRow(1, 0);
-
-  // Create a table view
+  // Lay out the table view.
+  layout->StartRow(0, 0);
   std::vector<ui::TableColumn> table_columns;
   table_columns.push_back(ChooserTableColumn(
       0, "" /* Empty string makes the column title invisible */));
@@ -165,33 +184,22 @@
   table_view_->set_select_on_remove(false);
   chooser_table_model_->SetObserver(table_view_);
   table_view_->SetObserver(this);
+  table_view_->SetEnabled(chooser_bubble_delegate_->NumOptions() > 0);
   layout->AddView(table_view_->CreateParentIfNecessary(), 1, 1,
                   views::GridLayout::FILL, views::GridLayout::FILL,
                   kChooserPermissionBubbleWidth,
                   kChooserPermissionBubbleHeight);
-  if (chooser_bubble_delegate_->NumOptions() == 0) {
-    table_view_->SetEnabled(false);
-  }
 
-  layout->AddPaddingRow(0, kItemMajorSpacing);
-
-  views::View* button_row = new views::View();
-  views::GridLayout* button_layout = new views::GridLayout(button_row);
-  views::ColumnSet* button_columns = button_layout->AddColumnSet(0);
-  button_row->SetLayoutManager(button_layout);
-  layout->StartRow(1, 0);
-  layout->AddView(button_row);
+  layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
 
   // Lay out the Connect/Cancel buttons.
-  button_columns->AddColumn(views::GridLayout::TRAILING,
-                            views::GridLayout::FILL, 100,
-                            views::GridLayout::USE_PREF, 0, 0);
-  button_columns->AddPaddingColumn(0,
-                                   kItemMajorSpacing - (2 * kButtonBorderSize));
-  button_columns->AddColumn(views::GridLayout::TRAILING,
-                            views::GridLayout::FILL, 0,
-                            views::GridLayout::USE_PREF, 0, 0);
-  button_layout->StartRow(0, 0);
+  layout->StartRow(0, 0);
+  views::View* button_row = new views::View();
+  views::BoxLayout* button_layout = new views::BoxLayout(
+      views::BoxLayout::kHorizontal, 0, 0, views::kRelatedButtonHSpacing);
+  button_layout->set_main_axis_alignment(
+      views::BoxLayout::MAIN_AXIS_ALIGNMENT_END);
+  button_row->SetLayoutManager(button_layout);
 
   base::string16 connect_text =
       l10n_util::GetStringUTF16(IDS_CHOOSER_BUBBLE_CONNECT_BUTTON_TEXT);
@@ -199,16 +207,35 @@
   connect_button_->SetStyle(views::Button::STYLE_BUTTON);
   // Disable the connect button at the beginning since no device selected yet.
   connect_button_->SetEnabled(false);
-  button_layout->AddView(connect_button_);
+  button_row->AddChildView(connect_button_);
   chooser_table_model_->SetConnectButton(connect_button_);
 
   base::string16 cancel_text =
       l10n_util::GetStringUTF16(IDS_CHOOSER_BUBBLE_CANCEL_BUTTON_TEXT);
-  cancel_button_ = new views::LabelButton(this, cancel_text);
-  cancel_button_->SetStyle(views::Button::STYLE_BUTTON);
-  button_layout->AddView(cancel_button_);
+  views::LabelButton* cancel_button = new views::LabelButton(this, cancel_text);
+  cancel_button->SetStyle(views::Button::STYLE_BUTTON);
+  button_row->AddChildView(cancel_button);
+  layout->AddView(button_row);
 
-  button_layout->AddPaddingRow(0, kBubbleOuterMargin);
+  layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
+
+  // Lay out the separator.
+  layout->StartRow(0, 0);
+  layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
+
+  layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
+
+  // Lay out the styled label.
+  layout->StartRow(0, 0);
+  base::string16 link =
+      l10n_util::GetStringUTF16(IDS_CHOOSER_BUBBLE_GET_HELP_LINK_TEXT);
+  size_t offset;
+  base::string16 text = l10n_util::GetStringFUTF16(
+      IDS_CHOOSER_BUBBLE_FOOTNOTE_TEXT, link, &offset);
+  views::StyledLabel* label = new views::StyledLabel(text, this);
+  label->AddStyleRange(gfx::Range(offset, offset + link.length()),
+                       views::StyledLabel::RangeStyleInfo::CreateForLink());
+  layout->AddView(label);
 }
 
 ChooserBubbleUiViewDelegate::~ChooserBubbleUiViewDelegate() {
@@ -256,6 +283,13 @@
   }
 }
 
+void ChooserBubbleUiViewDelegate::StyledLabelLinkClicked(
+    views::StyledLabel* label,
+    const gfx::Range& range,
+    int event_flags) {
+  chooser_bubble_delegate_->OpenHelpCenterUrl();
+}
+
 void ChooserBubbleUiViewDelegate::OnSelectionChanged() {
   connect_button_->SetEnabled(!table_view_->selection_model().empty());
 }
diff --git a/chrome/browser/ui/website_settings/chooser_bubble_delegate.cc b/chrome/browser/ui/website_settings/chooser_bubble_delegate.cc
index 8b20975..7622b5d 100644
--- a/chrome/browser/ui/website_settings/chooser_bubble_delegate.cc
+++ b/chrome/browser/ui/website_settings/chooser_bubble_delegate.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/browser/net/referrer.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/website_settings/chooser_bubble_delegate.h"
 #include "content/public/browser/web_contents.h"
@@ -13,6 +14,12 @@
 
 ChooserBubbleDelegate::~ChooserBubbleDelegate() {}
 
+void ChooserBubbleDelegate::OpenHelpCenterUrl() const {
+  browser_->OpenURL(content::OpenURLParams(
+      GetHelpCenterUrl(), content::Referrer(), NEW_FOREGROUND_TAB,
+      ui::PAGE_TRANSITION_AUTO_TOPLEVEL, false /* is_renderer_initiated */));
+}
+
 std::string ChooserBubbleDelegate::GetName() const {
   return "ChooserBubble";
 }
diff --git a/chrome/browser/ui/website_settings/chooser_bubble_delegate.h b/chrome/browser/ui/website_settings/chooser_bubble_delegate.h
index 1dd4074..93afa892 100644
--- a/chrome/browser/ui/website_settings/chooser_bubble_delegate.h
+++ b/chrome/browser/ui/website_settings/chooser_bubble_delegate.h
@@ -12,6 +12,7 @@
 #include "components/bubble/bubble_delegate.h"
 
 class Browser;
+class GURL;
 
 // Subclass ChooserBubbleDelegate to implement a chooser bubble, which has
 // some introductory text and a list of options that users can pick one of.
@@ -23,6 +24,10 @@
 // collecting metrics.
 // After Select/Cancel/Close is called, this object is destroyed and call back
 // into it is not allowed.
+// TODO(juncai): Change class name ChooserBubbleDelegate to
+// ChooserBubbleController since it better reflects its responsibilities and
+// clarifies the roles of this class.
+// https://crbug.com/588933
 class ChooserBubbleDelegate : public BubbleDelegate {
  public:
   explicit ChooserBubbleDelegate(content::RenderFrameHost* owner);
@@ -52,6 +57,9 @@
     virtual ~Observer() {}
   };
 
+  // Open help center URL.
+  void OpenHelpCenterUrl() const;
+
   // BubbleDelegate:
   std::string GetName() const override;
   scoped_ptr<BubbleUi> BuildBubbleUi() override;
@@ -77,6 +85,9 @@
   // closes without the user taking an explicit action.
   virtual void Close() = 0;
 
+  // Get help center URL.
+  virtual GURL GetHelpCenterUrl() const = 0;
+
   // Only one observer may be registered at a time.
   void set_observer(Observer* observer) { observer_ = observer; }
   Observer* observer() const { return observer_; }
diff --git a/chrome/browser/ui/website_settings/permission_bubble_manager_browsertest.cc b/chrome/browser/ui/website_settings/permission_bubble_manager_browsertest.cc
index d603e2e..eeacf8d8 100644
--- a/chrome/browser/ui/website_settings/permission_bubble_manager_browsertest.cc
+++ b/chrome/browser/ui/website_settings/permission_bubble_manager_browsertest.cc
@@ -5,17 +5,29 @@
 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
 
 #include "base/command_line.h"
+#include "base/metrics/field_trial.h"
 #include "build/build_config.h"
+#include "chrome/browser/permissions/permission_context_base.h"
+#include "chrome/browser/permissions/permission_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/website_settings/mock_permission_bubble_factory.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/variations/variations_associated_data.h"
+#include "content/public/browser/permission_type.h"
+#include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 
 namespace {
 
+const char* kPermissionsKillSwitchFieldStudy =
+    PermissionContextBase::kPermissionsKillSwitchFieldStudy;
+const char* kPermissionsKillSwitchBlockedValue =
+    PermissionContextBase::kPermissionsKillSwitchBlockedValue;
+const char kPermissionsKillSwitchTestGroup[] = "TestGroup";
+
 class PermissionBubbleManagerBrowserTest : public InProcessBrowserTest {
  public:
   PermissionBubbleManagerBrowserTest() = default;
@@ -49,6 +61,17 @@
     return mock_permission_bubble_factory_.get();
   }
 
+  void EnableKillSwitch(content::PermissionType permission_type) {
+    std::map<std::string, std::string> params;
+    params[PermissionUtil::GetPermissionString(permission_type)] =
+        kPermissionsKillSwitchBlockedValue;
+    variations::AssociateVariationParams(
+        kPermissionsKillSwitchFieldStudy, kPermissionsKillSwitchTestGroup,
+        params);
+    base::FieldTrialList::CreateFieldTrial(kPermissionsKillSwitchFieldStudy,
+                                           kPermissionsKillSwitchTestGroup);
+  }
+
  private:
   scoped_ptr<MockPermissionBubbleFactory> mock_permission_bubble_factory_;
 };
@@ -165,4 +188,70 @@
   EXPECT_EQ(1, bubble_factory()->total_request_count());
 }
 
+// Bubble requests should not be shown when the killswitch is on.
+IN_PROC_BROWSER_TEST_F(PermissionBubbleManagerBrowserTest,
+                       KillSwitchGeolocation) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  ui_test_utils::NavigateToURL(
+      browser(),
+      embedded_test_server()->GetURL("/permissions/killswitch_tester.html"));
+
+  // Now enable the geolocation killswitch.
+  EnableKillSwitch(content::PermissionType::GEOLOCATION);
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  std::string result;
+  EXPECT_TRUE(content::ExecuteScriptAndExtractString(
+      web_contents, "requestGeolocation();", &result));
+  EXPECT_EQ("denied", result);
+  EXPECT_EQ(0, bubble_factory()->show_count());
+  EXPECT_EQ(0, bubble_factory()->total_request_count());
+
+  // Disable the trial.
+  variations::testing::ClearAllVariationParams();
+
+  // Reload the page to get around blink layer caching for geolocation
+  // requests.
+  ui_test_utils::NavigateToURL(
+      browser(),
+      embedded_test_server()->GetURL("/permissions/killswitch_tester.html"));
+
+  EXPECT_TRUE(content::ExecuteScript(web_contents, "requestGeolocation();"));
+  WaitForPermissionBubble();
+  EXPECT_EQ(1, bubble_factory()->show_count());
+  EXPECT_EQ(1, bubble_factory()->total_request_count());
+}
+
+// Bubble requests should not be shown when the killswitch is on.
+IN_PROC_BROWSER_TEST_F(PermissionBubbleManagerBrowserTest,
+                       KillSwitchNotifications) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  ui_test_utils::NavigateToURL(
+      browser(),
+      embedded_test_server()->GetURL("/permissions/killswitch_tester.html"));
+
+  // Now enable the notifications killswitch.
+  EnableKillSwitch(content::PermissionType::NOTIFICATIONS);
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  std::string result;
+  EXPECT_TRUE(content::ExecuteScriptAndExtractString(
+      web_contents, "requestNotification();", &result));
+  EXPECT_EQ("denied", result);
+  EXPECT_EQ(0, bubble_factory()->show_count());
+  EXPECT_EQ(0, bubble_factory()->total_request_count());
+
+  // Disable the trial.
+  variations::testing::ClearAllVariationParams();
+
+  EXPECT_TRUE(content::ExecuteScript(web_contents, "requestNotification();"));
+  WaitForPermissionBubble();
+  EXPECT_EQ(1, bubble_factory()->show_count());
+  EXPECT_EQ(1, bubble_factory()->total_request_count());
+}
+
 }  // anonymous namespace
diff --git a/chrome/browser/ui/webui/app_launcher_login_handler.cc b/chrome/browser/ui/webui/app_launcher_login_handler.cc
index f99e987..5d048926 100644
--- a/chrome/browser/ui/webui/app_launcher_login_handler.cc
+++ b/chrome/browser/ui/webui/app_launcher_login_handler.cc
@@ -16,7 +16,8 @@
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_info_cache.h"
+#include "chrome/browser/profiles/profile_attributes_entry.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/profile_metrics.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
@@ -178,19 +179,18 @@
   std::string icon_url;
   Profile* profile = Profile::FromWebUI(web_ui());
   if (!username.empty()) {
-    ProfileInfoCache& cache =
-        g_browser_process->profile_manager()->GetProfileInfoCache();
-    size_t profile_index = cache.GetIndexOfProfileWithPath(profile->GetPath());
-    if (profile_index != std::string::npos) {
+    ProfileAttributesStorage& storage =
+        g_browser_process->profile_manager()->GetProfileAttributesStorage();
+    ProfileAttributesEntry* entry;
+    if (storage.GetProfileAttributesWithPath(profile->GetPath(), &entry)) {
       // Only show the profile picture and full name for the single profile
       // case. In the multi-profile case the profile picture is visible in the
       // title bar and the full name can be ambiguous.
-      if (cache.GetNumberOfProfiles() == 1) {
-        base::string16 name = cache.GetGAIANameOfProfileAtIndex(profile_index);
+      if (storage.GetNumberOfProfiles() == 1) {
+        base::string16 name = entry->GetGAIAName();
         if (!name.empty())
           header = CreateElementWithClass(name, "span", "profile-name", "");
-        const gfx::Image* image =
-            cache.GetGAIAPictureOfProfileAtIndex(profile_index);
+        const gfx::Image* image = entry->GetGAIAPicture();
         if (image)
           icon_url = webui::GetBitmapDataUrl(GetGAIAPictureForNTP(*image));
       }
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index 9e6afd5d1..12882b3 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -97,8 +97,16 @@
 #include "chrome/browser/ui/webui/media_router/media_router_ui.h"
 #endif
 
-#if !defined(OS_ANDROID)
+#if defined(OS_ANDROID)
+#include "chrome/browser/ui/webui/net_export_ui.h"
+#include "chrome/browser/ui/webui/popular_sites_internals_ui.h"
+#else
+#include "chrome/browser/signin/easy_unlock_service.h"
+#include "chrome/browser/signin/easy_unlock_service_factory.h"
+#include "chrome/browser/ui/webui/copresence_ui.h"
+#include "chrome/browser/ui/webui/devtools_ui.h"
 #include "chrome/browser/ui/webui/engagement/site_engagement_ui.h"
+#include "chrome/browser/ui/webui/inspect_ui.h"
 #include "chrome/browser/ui/webui/md_downloads/md_downloads_ui.h"
 #include "chrome/browser/ui/webui/md_history_ui.h"
 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
@@ -108,26 +116,6 @@
 #include "chrome/browser/ui/webui/uber/uber_ui.h"
 #endif
 
-#if defined(OS_ANDROID) || defined(OS_IOS)
-#include "chrome/browser/ui/webui/net_export_ui.h"
-#else
-#include "chrome/browser/signin/easy_unlock_service.h"
-#include "chrome/browser/signin/easy_unlock_service_factory.h"
-#include "chrome/browser/ui/webui/copresence_ui.h"
-#include "chrome/browser/ui/webui/devtools_ui.h"
-#include "chrome/browser/ui/webui/inspect_ui.h"
-#endif
-
-#if defined(OS_ANDROID)
-#include "chrome/browser/ui/webui/popular_sites_internals_ui.h"
-#endif
-
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_IOS)
-#include "chrome/browser/ui/webui/signin/inline_login_ui.h"
-#include "chrome/browser/ui/webui/signin/sync_confirmation_ui.h"
-#include "chrome/browser/ui/webui/signin/user_manager_ui.h"
-#endif
-
 #if defined(OS_CHROMEOS)
 #include "base/sys_info.h"
 #include "chrome/browser/ui/webui/chromeos/bluetooth_pairing_ui.h"
@@ -162,6 +150,9 @@
 
 #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
 #include "chrome/browser/ui/sync/sync_promo_ui.h"
+#include "chrome/browser/ui/webui/signin/inline_login_ui.h"
+#include "chrome/browser/ui/webui/signin/sync_confirmation_ui.h"
+#include "chrome/browser/ui/webui/signin/user_manager_ui.h"
 #endif
 
 #if defined(OS_WIN)
@@ -494,9 +485,11 @@
   }
 #endif  // !defined(GOOGLE_CHROME_BUILD) && !defined(NDEBUG)
 #endif  // defined(OS_CHROMEOS)
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_ANDROID)
   if (url.host() == chrome::kChromeUINetExportHost)
     return &NewWebUI<NetExportUI>;
+  if (url.host() == chrome::kChromeUIPopularSitesInternalsHost)
+    return &NewWebUI<PopularSitesInternalsUI>;
 #else
   if (url.host() == chrome::kChromeUICopresenceHost)
     return &NewWebUI<CopresenceUI>;
@@ -509,17 +502,15 @@
   if (url.host() == chrome::kChromeUIInspectHost)
     return &NewWebUI<InspectUI>;
 #endif
-#if defined(OS_ANDROID)
-  if (url.host() == chrome::kChromeUIPopularSitesInternalsHost)
-    return &NewWebUI<PopularSitesInternalsUI>;
-#endif
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
   if (url.host() == chrome::kChromeUIChromeSigninHost)
     return &NewWebUI<InlineLoginUI>;
   if (url.host() == chrome::kChromeUIUserManagerHost)
     return &NewWebUI<UserManagerUI>;
   if (url.host() == chrome::kChromeUISyncConfirmationHost)
     return &NewWebUI<SyncConfirmationUI>;
+  if (url.host() == chrome::kChromeUIProfileSigninConfirmationHost)
+    return &NewWebUI<ProfileSigninConfirmationUI>;
 #endif
 
   /****************************************************************************
@@ -550,10 +541,6 @@
       switches::MdPolicyPageEnabled()) {
     return &NewWebUI<PolicyMaterialDesignUI>;
   }
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
-  if (url.host() == chrome::kChromeUIProfileSigninConfirmationHost)
-    return &NewWebUI<ProfileSigninConfirmationUI>;
-#endif
 #endif  // defined(ENABLE_CONFIGURATION_POLICY)
 
 #if defined(ENABLE_APP_LIST)
diff --git a/chrome/browser/ui/webui/chromeos/image_source.cc b/chrome/browser/ui/webui/chromeos/image_source.cc
index 1a4fb9c..3e059d8 100644
--- a/chrome/browser/ui/webui/chromeos/image_source.cc
+++ b/chrome/browser/ui/webui/chromeos/image_source.cc
@@ -72,8 +72,7 @@
   }
 
   if (!image_loader_) {
-    image_loader_ = new UserImageLoader(ImageDecoder::DEFAULT_CODEC,
-                                        task_runner_);
+    image_loader_ = new UserImageLoader(task_runner_);
   }
 
   const base::FilePath asset_dir(FILE_PATH_LITERAL(chrome::kChromeOSAssetPath));
@@ -93,6 +92,7 @@
   if (path_exists) {
     image_loader_->StartWithFilePath(
         image_path,
+        ImageDecoder::DEFAULT_CODEC,
         0,  // Do not crop.
         base::Bind(&ImageLoaded, got_data_callback));
   } else {
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
index 3e97019..e6b0cbd 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
@@ -200,6 +200,8 @@
 const char OobeUI::kScreenControllerPairing[] = "controller-pairing";
 const char OobeUI::kScreenHostPairing[] = "host-pairing";
 const char OobeUI::kScreenDeviceDisabled[] = "device-disabled";
+const char OobeUI::kScreenUnrecoverableCryptohomeError[] =
+    "unrecoverable-cryptohome-error";
 
 OobeUI::OobeUI(content::WebUI* web_ui, const GURL& url)
     : WebUIController(web_ui),
@@ -549,6 +551,8 @@
   screen_names_[SCREEN_OOBE_CONTROLLER_PAIRING] = kScreenControllerPairing;
   screen_names_[SCREEN_OOBE_HOST_PAIRING] = kScreenHostPairing;
   screen_names_[SCREEN_DEVICE_DISABLED] = kScreenDeviceDisabled;
+  screen_names_[SCREEN_UNRECOVERABLE_CRYPTOHOME_ERROR] =
+      kScreenUnrecoverableCryptohomeError;
 
   dim_overlay_screen_ids_.push_back(SCREEN_CONFIRM_PASSWORD);
   dim_overlay_screen_ids_.push_back(SCREEN_GAIA_SIGNIN);
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.h b/chrome/browser/ui/webui/chromeos/login/oobe_ui.h
index 7ddc98b..407fd6e 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.h
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.h
@@ -94,6 +94,7 @@
   static const char kScreenControllerPairing[];
   static const char kScreenHostPairing[];
   static const char kScreenDeviceDisabled[];
+  static const char kScreenUnrecoverableCryptohomeError[];
 
   OobeUI(content::WebUI* web_ui, const GURL& url);
   ~OobeUI() override;
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
index f911bf7..8acefa5 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -18,6 +18,7 @@
 #include "base/macros.h"
 #include "base/metrics/histogram.h"
 #include "base/strings/string16.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"
@@ -28,6 +29,7 @@
 #include "chrome/browser/browser_shutdown.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
+#include "chrome/browser/chromeos/feedback_util.h"
 #include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "chrome/browser/chromeos/login/error_screens_histogram_helper.h"
 #include "chrome/browser/chromeos/login/hwid_checker.h"
@@ -449,6 +451,13 @@
                IDS_ENTERPRISE_ENROLLMENT_AUTH_FATAL_ERROR);
   builder->Add("insecureURLEnrollmentError",
                IDS_ENTERPRISE_ENROLLMENT_AUTH_INSECURE_URL_ERROR);
+
+  builder->Add("unrecoverableCryptohomeErrorMessage",
+               IDS_LOGIN_UNRECOVERABLE_CRYPTOHOME_ERROR_MESSAGE);
+  builder->Add("unrecoverableCryptohomeErrorContinue",
+               IDS_LOGIN_UNRECOVERABLE_CRYPTOHOME_ERROR_CONTINUE);
+  builder->Add("unrecoverableCryptohomeErrorSendFeedback",
+               IDS_LOGIN_UNRECOVERABLE_CRYPTOHOME_ERROR_SEND_FEEDBACK);
 }
 
 void SigninScreenHandler::RegisterMessages() {
@@ -499,6 +508,8 @@
               &SigninScreenHandler::HandleFirstIncorrectPasswordAttempt);
   AddCallback("maxIncorrectPasswordAttempts",
               &SigninScreenHandler::HandleMaxIncorrectPasswordAttempts);
+  AddCallback("sendFeedbackAndResyncUserData",
+              &SigninScreenHandler::HandleSendFeedbackAndResyncUserData);
 
   // This message is sent by the kiosk app menu, but is handled here
   // so we can tell the delegate to launch the app.
@@ -928,6 +939,11 @@
   gaia_screen_handler_->ShowWhitelistCheckFailedError();
 }
 
+void SigninScreenHandler::ShowUnrecoverableCrypthomeErrorDialog(
+    const std::string& email) {
+  CallJS("login.UnrecoverableCryptohomeErrorScreen.show", email);
+}
+
 void SigninScreenHandler::Observe(int type,
                                   const content::NotificationSource& source,
                                   const content::NotificationDetails& details) {
@@ -1297,6 +1313,17 @@
   RecordReauthReason(account_id, ReauthReason::INCORRECT_PASSWORD_ENTERED);
 }
 
+void SigninScreenHandler::HandleSendFeedbackAndResyncUserData() {
+  const std::string description = base::StringPrintf(
+      "Auto generated feedback for http://crbug.com/547857.\n"
+      "(uniquifier:%s)",
+      base::Int64ToString(base::Time::Now().ToInternalValue()).c_str());
+  feedback_util::SendSysLogFeedback(
+      Profile::FromWebUI(web_ui()), description,
+      base::Bind(&SigninScreenHandler::OnSysLogFeedbackSent,
+                 weak_factory_.GetWeakPtr()));
+}
+
 bool SigninScreenHandler::AllWhitelistedUsersPresent() {
   CrosSettings* cros_settings = CrosSettings::Get();
   bool allow_new_user = false;
@@ -1392,4 +1419,10 @@
     CallJS("login.AccountPickerScreen.setCapsLockState", caps_lock_enabled_);
 }
 
+void SigninScreenHandler::OnSysLogFeedbackSent(bool sent) {
+  LOG_IF(ERROR, !sent) << "Failed to send syslog feedback.";
+  // Recreate user's cryptohome after the feedkback is attempted.
+  HandleResyncUserData();
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
index f7ca0f4..50a542a 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
@@ -95,6 +95,8 @@
   virtual void ShowSigninScreenForCreds(const std::string& username,
                                         const std::string& password) = 0;
   virtual void ShowWhitelistCheckFailedError() = 0;
+  virtual void ShowUnrecoverableCrypthomeErrorDialog(
+      const std::string& email) = 0;
   virtual void LoadUsers(const base::ListValue& users_list,
                          bool show_guest) = 0;
  protected:
@@ -302,6 +304,7 @@
   void ShowSigninScreenForCreds(const std::string& username,
                                 const std::string& password) override;
   void ShowWhitelistCheckFailedError() override;
+  void ShowUnrecoverableCrypthomeErrorDialog(const std::string& email) override;
   void LoadUsers(const base::ListValue& users_list, bool show_guest) override;
 
   // content::NotificationObserver implementation:
@@ -362,6 +365,7 @@
   void HandleLogRemoveUserWarningShown();
   void HandleFirstIncorrectPasswordAttempt(const AccountId& account_id);
   void HandleMaxIncorrectPasswordAttempts(const AccountId& account_id);
+  void HandleSendFeedbackAndResyncUserData();
 
   // Sends the list of |keyboard_layouts| available for the |locale| that is
   // currently selected for the public session identified by |user_id|.
@@ -412,10 +416,8 @@
   // Returns OobeUI object of NULL.
   OobeUI* GetOobeUI() const;
 
-  // Gets the easy unlock service associated with the user. Can return NULL if
-  // user cannot be found, or there is not associated service.
-  EasyUnlockService* GetEasyUnlockServiceForUser(
-      const std::string& username) const;
+  // Callback invoked after the syslog feedback is sent.
+  void OnSysLogFeedbackSent(bool sent);
 
   // Current UI state of the signin screen.
   UIState ui_state_ = UI_STATE_UNKNOWN;
diff --git a/chrome/browser/ui/webui/history_ui.cc b/chrome/browser/ui/webui/history_ui.cc
index af48f5a..c07d39c 100644
--- a/chrome/browser/ui/webui/history_ui.cc
+++ b/chrome/browser/ui/webui/history_ui.cc
@@ -31,7 +31,7 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 #include "chrome/browser/ui/webui/foreign_session_handler.h"
 #include "chrome/browser/ui/webui/history_login_handler.h"
 #endif
@@ -139,7 +139,7 @@
       switches::kHistoryEnableGroupByDomain);
   // Supervised users get the "group by domain" version, but not on mobile,
   // because that version isn't adjusted for small screens yet. crbug.com/452859
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   group_by_domain = group_by_domain || profile->IsSupervised();
 #endif
   source->AddBoolean("groupByDomain", group_by_domain);
@@ -168,7 +168,7 @@
   web_ui->AddMessageHandler(new MetricsHandler());
 
   // On mobile we deal with foreign sessions differently.
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   if (search::IsInstantExtendedAPIEnabled()) {
     web_ui->AddMessageHandler(new browser_sync::ForeignSessionHandler());
     web_ui->AddMessageHandler(new HistoryLoginHandler());
diff --git a/chrome/browser/ui/webui/md_history_ui.cc b/chrome/browser/ui/webui/md_history_ui.cc
index 0f2b162..c0936575 100644
--- a/chrome/browser/ui/webui/md_history_ui.cc
+++ b/chrome/browser/ui/webui/md_history_ui.cc
@@ -57,6 +57,8 @@
   source->AddResourcePath("history_toolbar.js",
                           IDR_MD_HISTORY_HISTORY_TOOLBAR_JS);
   source->AddResourcePath("history.js", IDR_MD_HISTORY_HISTORY_JS);
+  source->AddResourcePath("shared_style.html",
+                          IDR_MD_HISTORY_SHARED_STYLE_HTML);
 
   source->SetDefaultResource(IDR_MD_HISTORY_HISTORY_HTML);
   source->SetJsonPath("strings.js");
diff --git a/chrome/browser/ui/webui/net_internals/net_internals_ui.cc b/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
index b0000c2..3b0d9ec 100644
--- a/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
+++ b/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
@@ -64,7 +64,6 @@
 #include "content/public/browser/web_ui_message_handler.h"
 #include "grit/net_internals_resources.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/disk_cache/disk_cache.h"
 #include "net/dns/host_cache.h"
 #include "net/dns/host_resolver.h"
diff --git a/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc
index 1396536f..f661f78 100644
--- a/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc
@@ -334,10 +334,10 @@
   scoped_ptr<base::Value> layout_value = base::Value::CreateNullValue();
   scoped_ptr<base::Value> offset_value = base::Value::CreateNullValue();
   if (display_manager->GetNumDisplays() > 1) {
-    const ash::DisplayLayout& layout =
-        display_manager->GetCurrentDisplayLayout();
-    layout_value.reset(new base::FundamentalValue(layout.placement.position));
-    offset_value.reset(new base::FundamentalValue(layout.placement.offset));
+    const ash::DisplayPlacement* placement =
+        display_manager->GetCurrentDisplayLayout().placement_list[0];
+    layout_value.reset(new base::FundamentalValue(placement->position));
+    offset_value.reset(new base::FundamentalValue(placement->offset));
   }
 
   web_ui()->CallJavascriptFunction(
diff --git a/chrome/browser/ui/webui/options/password_manager_handler.cc b/chrome/browser/ui/webui/options/password_manager_handler.cc
index 1f6caa3..77256a7 100644
--- a/chrome/browser/ui/webui/options/password_manager_handler.cc
+++ b/chrome/browser/ui/webui/options/password_manager_handler.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/ui/webui/options/password_manager_handler.h"
 
 #include "base/bind.h"
-#include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/macros.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
@@ -32,9 +32,8 @@
 #include "content/public/browser/user_metrics.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
-#include "content/public/common/content_switches.h"
+#include "content/public/common/content_features.h"
 #include "content/public/common/origin_util.h"
-#include "net/base/net_util.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if defined(OS_WIN) && defined(USE_ASH)
@@ -150,8 +149,7 @@
   localized_strings->SetBoolean("disableShowPasswords", disable_show_passwords);
   localized_strings->SetBoolean(
       "enableCredentialManagerAPI",
-      base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kEnableCredentialManagerAPI));
+      base::FeatureList::IsEnabled(features::kCredentialManagementAPI));
 }
 
 void PasswordManagerHandler::RegisterMessages() {
diff --git a/chrome/browser/ui/webui/options/sync_setup_handler.cc b/chrome/browser/ui/webui/options/sync_setup_handler.cc
index 61be9d1..259acdd9 100644
--- a/chrome/browser/ui/webui/options/sync_setup_handler.cc
+++ b/chrome/browser/ui/webui/options/sync_setup_handler.cc
@@ -22,7 +22,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_info_cache.h"
 #include "chrome/browser/profiles/profile_metrics.h"
 #include "chrome/browser/signin/chrome_signin_helper.h"
 #include "chrome/browser/signin/signin_error_controller_factory.h"
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui_browsertest.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui_browsertest.cc
index f7e4d732..6e3b693 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui_browsertest.cc
@@ -85,7 +85,7 @@
 }
 
 // Disable the test for mac, see http://crbug/367665.
-#if (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_LINUX)
+#if defined(OS_MACOSX) || defined(OS_LINUX)
 #define MAYBE_TaskManagerNewPrintPreview DISABLED_TaskManagerNewPrintPreview
 #else
 #define MAYBE_TaskManagerNewPrintPreview TaskManagerNewPrintPreview
diff --git a/chrome/browser/ui/webui/profile_info_watcher.cc b/chrome/browser/ui/webui/profile_info_watcher.cc
index b49ca13..3286a9f 100644
--- a/chrome/browser/ui/webui/profile_info_watcher.cc
+++ b/chrome/browser/ui/webui/profile_info_watcher.cc
@@ -8,7 +8,6 @@
 #include "base/bind_helpers.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_info_cache.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/common/pref_names.h"
@@ -25,7 +24,7 @@
   ProfileManager* profile_manager = g_browser_process->profile_manager();
   // The profile_manager might be NULL in testing environments.
   if (profile_manager)
-    profile_manager->GetProfileInfoCache().AddObserver(this);
+    profile_manager->GetProfileAttributesStorage().AddObserver(this);
 
   signin_allowed_pref_.Init(prefs::kSigninAllowed, profile_->GetPrefs(),
       base::Bind(&ProfileInfoWatcher::RunCallback, base::Unretained(this)));
@@ -35,7 +34,7 @@
   ProfileManager* profile_manager = g_browser_process->profile_manager();
   // The profile_manager might be NULL in testing environments.
   if (profile_manager)
-    profile_manager->GetProfileInfoCache().RemoveObserver(this);
+    profile_manager->GetProfileAttributesStorage().RemoveObserver(this);
 }
 
 void ProfileInfoWatcher::OnProfileAuthInfoChanged(
diff --git a/chrome/browser/ui/webui/profile_info_watcher.h b/chrome/browser/ui/webui/profile_info_watcher.h
index dc93645..114282d6 100644
--- a/chrome/browser/ui/webui/profile_info_watcher.h
+++ b/chrome/browser/ui/webui/profile_info_watcher.h
@@ -9,7 +9,7 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
-#include "chrome/browser/profiles/profile_info_cache_observer.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "components/prefs/pref_member.h"
 
 class Profile;
@@ -17,7 +17,7 @@
 
 // Watches profiles for changes in their cached info (e.g. the authenticated
 // username changes).
-class ProfileInfoWatcher : public ProfileInfoCacheObserver {
+class ProfileInfoWatcher : public ProfileAttributesStorage::Observer {
  public:
   ProfileInfoWatcher(Profile* profile, const base::Closure& callback);
   ~ProfileInfoWatcher() override;
@@ -26,7 +26,7 @@
   std::string GetAuthenticatedUsername() const;
 
  private:
-  // ProfileInfoCacheObserver:
+  // ProfileAttributesStorage::Observer:
   void OnProfileAuthInfoChanged(const base::FilePath& profile_path) override;
 
   // Gets the SigninManagerBase for |profile_|.
diff --git a/chrome/browser/ui/webui/quota_internals/quota_internals_handler.cc b/chrome/browser/ui/webui/quota_internals/quota_internals_handler.cc
index 4012583..8938c69 100644
--- a/chrome/browser/ui/webui/quota_internals/quota_internals_handler.cc
+++ b/chrome/browser/ui/webui/quota_internals/quota_internals_handler.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/ui/webui/quota_internals/quota_internals_types.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_ui.h"
-#include "net/base/net_util.h"
 
 using content::BrowserContext;
 
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index e05e9f7..bb01d4b5 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -41,6 +41,7 @@
 void AddCommonStrings(content::WebUIDataSource* html_source) {
   html_source->AddLocalizedString("add", IDS_ADD);
   html_source->AddLocalizedString("cancel", IDS_CANCEL);
+  html_source->AddLocalizedString("disable", IDS_DISABLE);
   html_source->AddLocalizedString("learnMore", IDS_LEARN_MORE);
   html_source->AddLocalizedString("ok", IDS_OK);
   html_source->AddLocalizedString("save", IDS_SAVE);
@@ -273,8 +274,6 @@
   html_source->AddLocalizedString(
       "defaultBrowserDefault", IDS_SETTINGS_DEFAULT_BROWSER_DEFAULT);
   html_source->AddLocalizedString(
-      "defaultBrowserNotDefault", IDS_SETTINGS_DEFAULT_BROWSER_NOT_DEFAULT);
-  html_source->AddLocalizedString(
       "defaultBrowserMakeDefault", IDS_SETTINGS_DEFAULT_BROWSER_MAKE_DEFAULT);
   html_source->AddLocalizedString(
       "defaultBrowserUnknown", IDS_SETTINGS_DEFAULT_BROWSER_UNKNOWN);
@@ -708,9 +707,15 @@
   html_source->AddLocalizedString("searchEngines",
                                   IDS_SETTINGS_SEARCH_ENGINES);
   html_source->AddLocalizedString(
+      "searchEnginesDefault",
+      IDS_SETTINGS_SEARCH_ENGINES_DEFAULT_ENGINES);
+  html_source->AddLocalizedString(
       "searchEnginesOther",
       IDS_SETTINGS_SEARCH_ENGINES_OTHER_ENGINES);
   html_source->AddLocalizedString(
+      "searchEnginesExtension",
+      IDS_SETTINGS_SEARCH_ENGINES_EXTENSION_ENGINES);
+  html_source->AddLocalizedString(
       "searchEnginesSearchEngine",
       IDS_SETTINGS_SEARCH_ENGINES_SEARCH_ENGINE);
   html_source->AddLocalizedString("searchEnginesKeyword",
@@ -727,6 +732,9 @@
   html_source->AddLocalizedString(
       "searchEnginesRemoveFromList",
       IDS_SETTINGS_SEARCH_ENGINES_REMOVE_FROM_LIST);
+  html_source->AddLocalizedString(
+      "searchEnginesManageExtension",
+      IDS_SETTINGS_SEARCH_ENGINES_MANAGE_EXTENSION);
 }
 
 void AddSiteSettingsStrings(content::WebUIDataSource* html_source) {
diff --git a/chrome/browser/ui/webui/settings/people_handler.cc b/chrome/browser/ui/webui/settings/people_handler.cc
index 009cb31a..09539ce 100644
--- a/chrome/browser/ui/webui/settings/people_handler.cc
+++ b/chrome/browser/ui/webui/settings/people_handler.cc
@@ -19,8 +19,8 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_attributes_entry.h"
 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
-#include "chrome/browser/profiles/profile_info_cache.h"
 #include "chrome/browser/profiles/profile_metrics.h"
 #include "chrome/browser/profiles/profile_window.h"
 #include "chrome/browser/signin/chrome_signin_helper.h"
@@ -183,10 +183,9 @@
       chromeos::options::UserImageSource::GetUserImage(account_id);
   *icon_url = webui::GetPngDataUrl(image->front(), image->size());
 #else   // !defined(OS_CHROMEOS)
-  ProfileInfoCache& cache =
-      g_browser_process->profile_manager()->GetProfileInfoCache();
-  ProfileAttributesEntry* entry = nullptr;
-  if (cache.GetProfileAttributesWithPath(profile.GetPath(), &entry)) {
+  ProfileAttributesEntry* entry;
+  if (g_browser_process->profile_manager()->GetProfileAttributesStorage().
+          GetProfileAttributesWithPath(profile.GetPath(), &entry)) {
     *name = base::UTF16ToUTF8(entry->GetName());
 
     if (entry->IsUsingGAIAPicture() && entry->GetGAIAPicture()) {
@@ -221,7 +220,8 @@
   if (sync_service)
     sync_service_observer_.Add(sync_service);
 
-  g_browser_process->profile_manager()->GetProfileInfoCache().AddObserver(this);
+  g_browser_process->profile_manager()->
+      GetProfileAttributesStorage().AddObserver(this);
 
 #if defined(OS_CHROMEOS)
   registrar_.Add(this, chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
@@ -231,7 +231,7 @@
 
 PeopleHandler::~PeopleHandler() {
   g_browser_process->profile_manager()->
-      GetProfileInfoCache().RemoveObserver(this);
+      GetProfileAttributesStorage().RemoveObserver(this);
 
   // Early exit if running unit tests (no actual WebUI is attached).
   if (!web_ui())
diff --git a/chrome/browser/ui/webui/settings/people_handler.h b/chrome/browser/ui/webui/settings/people_handler.h
index 5a5a4ae..0ae1476 100644
--- a/chrome/browser/ui/webui/settings/people_handler.h
+++ b/chrome/browser/ui/webui/settings/people_handler.h
@@ -12,7 +12,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/timer/timer.h"
 #include "build/build_config.h"
-#include "chrome/browser/profiles/profile_info_cache_observer.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/sync/sync_startup_tracker.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
 #include "components/prefs/pref_change_registrar.h"
@@ -48,7 +48,7 @@
 #if defined(OS_CHROMEOS)
                       public content::NotificationObserver,
 #endif
-                      public ProfileInfoCacheObserver {
+                      public ProfileAttributesStorage::Observer {
  public:
   explicit PeopleHandler(Profile* profile);
   ~PeopleHandler() override;
@@ -81,7 +81,7 @@
                const content::NotificationDetails& details) override;
 #endif
 
-  // ProfileInfoCacheObserver implementation.
+  // ProfileAttributesStorage::Observer implementation.
   void OnProfileNameChanged(const base::FilePath& profile_path,
                             const base::string16& old_profile_name) override;
   void OnProfileAvatarChanged(const base::FilePath& profile_path) override;
diff --git a/chrome/browser/ui/webui/settings/settings_manage_profile_handler.cc b/chrome/browser/ui/webui/settings/settings_manage_profile_handler.cc
index 3d0bf21..8030be6 100644
--- a/chrome/browser/ui/webui/settings/settings_manage_profile_handler.cc
+++ b/chrome/browser/ui/webui/settings/settings_manage_profile_handler.cc
@@ -15,8 +15,8 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/gaia_info_update_service.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_attributes_entry.h"
 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
-#include "chrome/browser/profiles/profile_info_cache.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/profile_metrics.h"
 #include "chrome/browser/profiles/profile_shortcut_manager.h"
@@ -44,12 +44,13 @@
 
 ManageProfileHandler::ManageProfileHandler(Profile* profile)
     : profile_(profile), weak_factory_(this) {
-  g_browser_process->profile_manager()->GetProfileInfoCache().AddObserver(this);
+  g_browser_process->profile_manager()->
+      GetProfileAttributesStorage().AddObserver(this);
 }
 
 ManageProfileHandler::~ManageProfileHandler() {
   g_browser_process->profile_manager()->
-      GetProfileInfoCache().RemoveObserver(this);
+      GetProfileAttributesStorage().RemoveObserver(this);
 }
 
 void ManageProfileHandler::RegisterMessages() {
@@ -94,14 +95,12 @@
 
 void ManageProfileHandler::SendAvailableIcons() {
   base::ListValue image_url_list;
-  const ProfileInfoCache& cache =
-      g_browser_process->profile_manager()->GetProfileInfoCache();
 
   // First add the GAIA picture if it is available.
-  size_t profile_index = cache.GetIndexOfProfileWithPath(profile_->GetPath());
-  if (profile_index != std::string::npos) {
-    const gfx::Image* icon =
-        cache.GetGAIAPictureOfProfileAtIndex(profile_index);
+  ProfileAttributesEntry* entry;
+  if (g_browser_process->profile_manager()->GetProfileAttributesStorage().
+          GetProfileAttributesWithPath(profile_->GetPath(), &entry)) {
+    const gfx::Image* icon = entry->GetGAIAPicture();
     if (icon) {
       gfx::Image icon2 = profiles::GetAvatarIconForWebUI(*icon, true);
       gaia_picture_url_ = webui::GetBitmapDataUrl(icon2.AsBitmap());
@@ -181,19 +180,18 @@
   // If the selection is the GAIA picture then also show the profile name in the
   // text field. This will display either the GAIA given name, if available,
   // or the first name.
-  ProfileInfoCache& cache =
-      g_browser_process->profile_manager()->GetProfileInfoCache();
-  size_t profile_index = cache.GetIndexOfProfileWithPath(profile_->GetPath());
-  if (profile_index == std::string::npos)
+  ProfileAttributesEntry* entry;
+  if (!g_browser_process->profile_manager()->GetProfileAttributesStorage().
+          GetProfileAttributesWithPath(profile_->GetPath(), &entry)) {
     return;
-  base::string16 gaia_name = cache.GetNameOfProfileAtIndex(profile_index);
+  }
+  base::string16 gaia_name = entry->GetName();
   if (gaia_name.empty())
     return;
 
-  base::StringValue gaia_name_value(gaia_name);
   web_ui()->CallJavascriptFunction(
       "settings.SyncPrivateApi.setProfileName",
-      gaia_name_value);
+      base::StringValue(gaia_name));
 }
 
 void ManageProfileHandler::RequestHasProfileShortcuts(
@@ -201,23 +199,22 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(ProfileShortcutManager::IsFeatureEnabled());
 
-  const ProfileInfoCache& cache =
-      g_browser_process->profile_manager()->GetProfileInfoCache();
-  size_t profile_index = cache.GetIndexOfProfileWithPath(profile_->GetPath());
-  if (profile_index == std::string::npos)
+  ProfileAttributesStorage& storage =
+      g_browser_process->profile_manager()->GetProfileAttributesStorage();
+  ProfileAttributesEntry* entry;
+  if (!storage.GetProfileAttributesWithPath(profile_->GetPath(), &entry))
     return;
 
   // Don't show the add/remove desktop shortcut button in the single user case.
-  if (cache.GetNumberOfProfiles() <= 1)
+  if (storage.GetNumberOfProfiles() <= 1u)
     return;
 
-  const base::FilePath profile_path =
-      cache.GetPathOfProfileAtIndex(profile_index);
   ProfileShortcutManager* shortcut_manager =
       g_browser_process->profile_manager()->profile_shortcut_manager();
   shortcut_manager->HasProfileShortcuts(
-      profile_path, base::Bind(&ManageProfileHandler::OnHasProfileShortcuts,
-                               weak_factory_.GetWeakPtr()));
+      profile_->GetPath(),
+      base::Bind(&ManageProfileHandler::OnHasProfileShortcuts,
+                 weak_factory_.GetWeakPtr()));
 }
 
 void ManageProfileHandler::OnHasProfileShortcuts(bool has_shortcuts) {
diff --git a/chrome/browser/ui/webui/settings/settings_manage_profile_handler.h b/chrome/browser/ui/webui/settings/settings_manage_profile_handler.h
index 11f250eb..eb2bcc4 100644
--- a/chrome/browser/ui/webui/settings/settings_manage_profile_handler.h
+++ b/chrome/browser/ui/webui/settings/settings_manage_profile_handler.h
@@ -8,7 +8,7 @@
 #include <string>
 
 #include "base/memory/weak_ptr.h"
-#include "chrome/browser/profiles/profile_info_cache_observer.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/ui/webui/settings/md_settings_ui.h"
 
 namespace base {
@@ -21,7 +21,7 @@
 
 // Chrome personal stuff profiles manage overlay UI handler.
 class ManageProfileHandler : public settings::SettingsPageUIHandler,
-                             public ProfileInfoCacheObserver {
+                             public ProfileAttributesStorage::Observer {
  public:
   explicit ManageProfileHandler(Profile* profile);
   ~ManageProfileHandler() override;
@@ -29,7 +29,7 @@
   // settings::SettingsPageUIHandler:
   void RegisterMessages() override;
 
-  // ProfileInfoCacheObserver:
+  // ProfileAttributesStorage::Observer:
   void OnProfileNameChanged(const base::FilePath& profile_path,
                             const base::string16& old_profile_name) override;
   void OnProfileAvatarChanged(const base::FilePath& profile_path) override;
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
index e6c5a20..37292035 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
@@ -7,6 +7,7 @@
 #include <stddef.h>
 
 #include <string>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
@@ -22,6 +23,8 @@
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_attributes_entry.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_window.h"
 #include "chrome/browser/signin/about_signin_internals_factory.h"
 #include "chrome/browser/signin/account_tracker_service_factory.h"
@@ -553,14 +556,17 @@
     if (g_browser_process && !same_email) {
       ProfileManager* profile_manager = g_browser_process->profile_manager();
       if (profile_manager) {
-        ProfileInfoCache& cache = profile_manager->GetProfileInfoCache();
-        for (size_t i = 0; i < cache.GetNumberOfProfiles(); ++i) {
-          // For backward compatibility, need to also check the username of the
-          // profile, since the GAIA ID may not have been set yet for the
-          // profile cache info.  It will get set once the profile is opened.
-          std::string profile_gaia_id = cache.GetGAIAIdOfProfileAtIndex(i);
-          std::string profile_email =
-              base::UTF16ToUTF8(cache.GetUserNameOfProfileAtIndex(i));
+        std::vector<ProfileAttributesEntry*> entries =
+            profile_manager->GetProfileAttributesStorage().
+                GetAllProfilesAttributes();
+
+        for (const ProfileAttributesEntry* entry : entries) {
+          // For backward compatibility, need to check also the username of the
+          // profile, since the GAIA ID may not have been set yet in the
+          // ProfileAttributesStorage.  It will be set once the profile
+          // is opened.
+          std::string profile_gaia_id = entry->GetGAIAId();
+          std::string profile_email = base::UTF16ToUTF8(entry->GetUserName());
           if (gaia_id == profile_gaia_id ||
               gaia::AreEmailsSame(email, profile_email)) {
             if (error_message) {
@@ -834,8 +840,8 @@
     ProfileManager* profile_manager = g_browser_process->profile_manager();
     if (profile_manager) {
       ProfileAttributesEntry* entry;
-      if (profile_manager->GetProfileInfoCache()
-            .GetProfileAttributesWithPath(params.profile_path, &entry)) {
+      if (profile_manager->GetProfileAttributesStorage()
+              .GetProfileAttributesWithPath(params.profile_path, &entry)) {
         entry->SetIsSigninRequired(false);
       }
     }
diff --git a/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc b/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc
index 0e88c61..41ce878 100644
--- a/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc
+++ b/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc
@@ -6,6 +6,7 @@
 
 #include <stddef.h>
 #include <utility>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/location.h"
@@ -111,16 +112,14 @@
       chrome::startup::IS_FIRST_RUN, false);
 }
 
-std::string GetAvatarImageAtIndex(
-    size_t index, ProfileInfoCache* info_cache) {
-  bool is_gaia_picture =
-      info_cache->IsUsingGAIAPictureOfProfileAtIndex(index) &&
-      info_cache->GetGAIAPictureOfProfileAtIndex(index);
+std::string GetAvatarImage(const ProfileAttributesEntry* entry) {
+  bool is_gaia_picture = entry->IsUsingGAIAPicture() &&
+                         entry->GetGAIAPicture() != nullptr;
 
   // If the avatar is too small (i.e. the old-style low resolution avatar),
   // it will be pixelated when displayed in the User Manager, so we should
   // return the placeholder avatar instead.
-  gfx::Image avatar_image = info_cache->GetAvatarIconOfProfileAtIndex(index);
+  gfx::Image avatar_image = entry->GetAvatarIcon();
   if (avatar_image.Width() <= profiles::kAvatarIconWidth ||
       avatar_image.Height() <= profiles::kAvatarIconHeight ) {
     avatar_image = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
@@ -224,7 +223,7 @@
 // ProfileUpdateObserver ------------------------------------------------------
 
 class UserManagerScreenHandler::ProfileUpdateObserver
-    : public ProfileInfoCacheObserver {
+    : public ProfileAttributesStorage::Observer {
  public:
   ProfileUpdateObserver(
       ProfileManager* profile_manager, UserManagerScreenHandler* handler)
@@ -232,16 +231,16 @@
         user_manager_handler_(handler) {
     DCHECK(profile_manager_);
     DCHECK(user_manager_handler_);
-    profile_manager_->GetProfileInfoCache().AddObserver(this);
+    profile_manager_->GetProfileAttributesStorage().AddObserver(this);
   }
 
   ~ProfileUpdateObserver() override {
     DCHECK(profile_manager_);
-    profile_manager_->GetProfileInfoCache().RemoveObserver(this);
+    profile_manager_->GetProfileAttributesStorage().RemoveObserver(this);
   }
 
  private:
-  // ProfileInfoCacheObserver implementation:
+  // ProfileAttributesStorage::Observer implementation:
   // If any change has been made to a profile, propagate it to all the
   // visible user manager screens.
   void OnProfileAdded(const base::FilePath& profile_path) override {
@@ -294,7 +293,7 @@
 // UserManagerScreenHandler ---------------------------------------------------
 
 UserManagerScreenHandler::UserManagerScreenHandler() : weak_ptr_factory_(this) {
-  profileInfoCacheObserver_.reset(
+  profile_attributes_storage_observer_.reset(
       new UserManagerScreenHandler::ProfileUpdateObserver(
           g_browser_process->profile_manager(), this));
 }
@@ -410,12 +409,11 @@
   if (!base::GetValueAsFilePath(*profile_path_value, &profile_path))
     return;
 
-  ProfileInfoCache& info_cache =
-      g_browser_process->profile_manager()->GetProfileInfoCache();
-
   ProfileAttributesEntry* entry;
-  if (!info_cache.GetProfileAttributesWithPath(profile_path, &entry))
+  if (!g_browser_process->profile_manager()->GetProfileAttributesStorage().
+          GetProfileAttributesWithPath(profile_path, &entry)) {
     return;
+  }
 
   base::string16 email_address;
   if (!args->GetString(1, &email_address))
@@ -430,12 +428,8 @@
 
   // Only try to validate locally or check the password change detection
   // if we actually have a local credential saved.
-  size_t profile_index = info_cache.GetIndexOfProfileWithPath(profile_path);
-  const bool has_local_credential =
-      !info_cache.GetLocalAuthCredentialsOfProfileAtIndex(profile_index)
-          .empty();
-  if (has_local_credential) {
-    if (LocalAuth::ValidateLocalAuthCredentials(profile_index, password)) {
+  if (!entry->GetLocalAuthCredentials().empty()) {
+    if (LocalAuth::ValidateLocalAuthCredentials(entry, password)) {
       ReportAuthenticationResult(true, ProfileMetrics::AUTH_LOCAL);
       return;
     }
@@ -508,11 +502,9 @@
   if (!base::GetValueAsFilePath(*profile_path_value, &profile_path))
     return;
 
-  const ProfileInfoCache& info_cache =
-      g_browser_process->profile_manager()->GetProfileInfoCache();
-  size_t profile_index = info_cache.GetIndexOfProfileWithPath(profile_path);
-
-  if (profile_index == std::string::npos) {
+  ProfileAttributesEntry* entry;
+  if (!g_browser_process->profile_manager()->GetProfileAttributesStorage().
+          GetProfileAttributesWithPath(profile_path, &entry)) {
     NOTREACHED();
     return;
   }
@@ -522,7 +514,7 @@
   // unauthenticated version of "launch" instead of the proper one.  Thus,
   // we have to validate in (secure) C++ code that it really is a profile
   // not needing authentication.  If it is, just ignore the "launch" request.
-  if (info_cache.ProfileIsSigninRequiredAtIndex(profile_index))
+  if (entry->IsSigninRequired())
     return;
   ProfileMetrics::LogProfileAuthResult(ProfileMetrics::AUTH_UNNECESSARY);
 
@@ -574,10 +566,11 @@
 
   if (!chrome::FindAnyBrowser(profile, true)) {
     // If no windows are open for that profile, the statistics in
-    // ProfileInfoCache are up to date. The statistics in ProfileInfoCache are
-    // returned because the copy in user_pod_row.js may be outdated. However, if
-    // some statistics are missing in ProfileInfoCache (i.e. |item.success| is
-    // false), then the actual statistics are queried instead.
+    // ProfileAttributesStorage are up to date. The statistics in
+    // ProfileAttributesStorage are returned because the copy in user_pod_row.js
+    // may be outdated. However, if some statistics are missing in
+    // ProfileAttributesStorage (i.e. |item.success| is false), then the actual
+    // statistics are queried instead.
     base::DictionaryValue return_value;
     profiles::ProfileCategoryStats stats =
         profiles::GetProfileStatisticsFromCache(profile_path);
@@ -847,8 +840,9 @@
 
 void UserManagerScreenHandler::SendUserList() {
   base::ListValue users_list;
-  ProfileInfoCache* info_cache =
-      &g_browser_process->profile_manager()->GetProfileInfoCache();
+  std::vector<ProfileAttributesEntry*> entries =
+      g_browser_process->profile_manager()->GetProfileAttributesStorage().
+          GetAllProfilesAttributesSortedByName();
   user_auth_type_map_.clear();
 
   // Profile deletion is not allowed in Metro mode.
@@ -857,39 +851,32 @@
   can_remove = !ash::Shell::HasInstance();
 #endif
 
-  for (size_t i = 0; i < info_cache->GetNumberOfProfiles(); ++i) {
+  for (const ProfileAttributesEntry* entry : entries) {
     // Don't show profiles still in the middle of being set up as new legacy
     // supervised users.
-    if (info_cache->IsOmittedProfileAtIndex(i))
+    if (entry->IsOmitted())
       continue;
 
     base::DictionaryValue* profile_value = new base::DictionaryValue();
-    base::FilePath profile_path = info_cache->GetPathOfProfileAtIndex(i);
+    base::FilePath profile_path = entry->GetPath();
 
-    profile_value->SetString(
-        kKeyUsername, info_cache->GetUserNameOfProfileAtIndex(i));
-    profile_value->SetString(
-        kKeyEmailAddress, info_cache->GetUserNameOfProfileAtIndex(i));
-    profile_value->SetString(
-        kKeyDisplayName,
-        profiles::GetAvatarNameForProfile(profile_path));
-    profile_value->Set(
-        kKeyProfilePath, base::CreateFilePathValue(profile_path));
+    profile_value->SetString(kKeyUsername, entry->GetUserName());
+    profile_value->SetString(kKeyEmailAddress, entry->GetUserName());
+    profile_value->SetString(kKeyDisplayName,
+                             profiles::GetAvatarNameForProfile(profile_path));
+    profile_value->Set(kKeyProfilePath,
+                       base::CreateFilePathValue(profile_path));
     profile_value->SetBoolean(kKeyPublicAccount, false);
     profile_value->SetBoolean(kKeyLegacySupervisedUser,
-                              info_cache->ProfileIsLegacySupervisedAtIndex(i));
-    profile_value->SetBoolean(
-        kKeyChildUser, info_cache->ProfileIsChildAtIndex(i));
-    profile_value->SetBoolean(
-        kKeyNeedsSignin, info_cache->ProfileIsSigninRequiredAtIndex(i));
-    profile_value->SetBoolean(
-        kKeyHasLocalCreds,
-        !info_cache->GetLocalAuthCredentialsOfProfileAtIndex(i).empty());
+                              entry->IsLegacySupervised());
+    profile_value->SetBoolean(kKeyChildUser, entry->IsChild());
+    profile_value->SetBoolean(kKeyNeedsSignin, entry->IsSigninRequired());
+    profile_value->SetBoolean(kKeyHasLocalCreds,
+                              !entry->GetLocalAuthCredentials().empty());
     profile_value->SetBoolean(kKeyIsOwner, false);
     profile_value->SetBoolean(kKeyCanRemove, can_remove);
     profile_value->SetBoolean(kKeyIsDesktop, true);
-    profile_value->SetString(
-        kKeyAvatarUrl, GetAvatarImageAtIndex(i, info_cache));
+    profile_value->SetString(kKeyAvatarUrl, GetAvatarImage(entry));
 
     profiles::ProfileCategoryStats stats =
         profiles::GetProfileStatisticsFromCache(profile_path);
@@ -953,11 +940,12 @@
   // Unlock the profile after browser opens so startup can read the lock bit.
   // Any necessary authentication must have been successful to reach this point.
   if (!browser->profile()->IsGuestSession()) {
-    ProfileInfoCache& info_cache =
-        g_browser_process->profile_manager()->GetProfileInfoCache();
-    size_t index = info_cache.GetIndexOfProfileWithPath(
-        browser->profile()->GetPath());
-    info_cache.SetProfileSigninRequiredAtIndex(index, false);
+    ProfileAttributesEntry* entry = nullptr;
+    bool has_entry = g_browser_process->profile_manager()->
+        GetProfileAttributesStorage().
+        GetProfileAttributesWithPath(browser->profile()->GetPath(), &entry);
+    DCHECK(has_entry);
+    entry->SetIsSigninRequired(false);
   }
 
   if (!url_hash_.empty()) {
diff --git a/chrome/browser/ui/webui/signin/user_manager_screen_handler.h b/chrome/browser/ui/webui/signin/user_manager_screen_handler.h
index 72dc64dc..b2fcb09b 100644
--- a/chrome/browser/ui/webui/signin/user_manager_screen_handler.h
+++ b/chrome/browser/ui/webui/signin/user_manager_screen_handler.h
@@ -45,8 +45,8 @@
   void GetLocalizedValues(base::DictionaryValue* localized_strings);
 
  private:
-  // An observer for any changes to Profiles in the ProfileInfoCache so that
-  // all the visible user manager screens can be updated.
+  // An observer for any changes to Profiles in the ProfileAttributesStorage so
+  // that all the visible user manager screens can be updated.
   class ProfileUpdateObserver;
 
   // WebUIMessageHandler implementation.
@@ -112,9 +112,9 @@
   void OnSwitchToProfileComplete(Profile* profile,
                                  Profile::CreateStatus profile_create_status);
 
-  // Observes the ProfileInfoCache and gets notified when a profile has been
-  // modified, so that the displayed user pods can be updated.
-  scoped_ptr<ProfileUpdateObserver> profileInfoCacheObserver_;
+  // Observes the ProfileAttributesStorage and gets notified when a profile has
+  // been modified, so that the displayed user pods can be updated.
+  scoped_ptr<ProfileUpdateObserver> profile_attributes_storage_observer_;
 
   // Authenticator used when local-auth fails.
   scoped_ptr<gaia::GaiaOAuthClient> oauth_client_;
diff --git a/chrome/browser/ui/webui/test_files_request_filter.cc b/chrome/browser/ui/webui/test_files_request_filter.cc
index 2a57b48..4c69de5 100644
--- a/chrome/browser/ui/webui/test_files_request_filter.cc
+++ b/chrome/browser/ui/webui/test_files_request_filter.cc
@@ -26,7 +26,7 @@
   PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
   if (!base::ReadFileToString(
           test_data_dir.AppendASCII("webui").AppendASCII(url_substr[1]),
-          &contents, std::string::npos))
+          &contents))
     return false;
 
   base::RefCountedString* ref_contents = new base::RefCountedString();
diff --git a/chrome/browser/usb/usb_chooser_bubble_delegate.cc b/chrome/browser/usb/usb_chooser_bubble_delegate.cc
index 61549c4..026641d 100644
--- a/chrome/browser/usb/usb_chooser_bubble_delegate.cc
+++ b/chrome/browser/usb/usb_chooser_bubble_delegate.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/usb/usb_chooser_context.h"
 #include "chrome/browser/usb/usb_chooser_context_factory.h"
+#include "chrome/common/url_constants.h"
 #include "components/bubble/bubble_controller.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
@@ -161,6 +162,10 @@
   }
 }
 
+GURL UsbChooserBubbleDelegate::GetHelpCenterUrl() const {
+  return GURL(chrome::kChooserUsbOverviewURL);
+}
+
 void UsbChooserBubbleDelegate::OnDeviceRemoved(
     scoped_refptr<device::UsbDevice> device) {
   for (auto it = devices_.begin(); it != devices_.end(); ++it) {
diff --git a/chrome/browser/usb/usb_chooser_bubble_delegate.h b/chrome/browser/usb/usb_chooser_bubble_delegate.h
index 9d18a975..58cc1a2 100644
--- a/chrome/browser/usb/usb_chooser_bubble_delegate.h
+++ b/chrome/browser/usb/usb_chooser_bubble_delegate.h
@@ -45,6 +45,7 @@
   void Select(size_t index) override;
   void Cancel() override;
   void Close() override;
+  GURL GetHelpCenterUrl() const override;
 
   // device::UsbService::Observer:
   void OnDeviceAdded(scoped_refptr<device::UsbDevice> device) override;
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 0fd181d..37b84983 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -591,6 +591,7 @@
             '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_javalib',
             '../third_party/gif_player/gif_player.gyp:gif_player_java',
             '../third_party/jsr-305/jsr-305.gyp:jsr_305_javalib',
+            '../third_party/leakcanary/leakcanary.gyp:leakcanary_java',
             '../ui/android/ui_android.gyp:ui_java',
           ],
           'variables': {
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 68c7de9..5dfafa9 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -109,6 +109,8 @@
       'browser/browsing_data/history_counter.h',
       'browser/browsing_data/local_data_container.cc',
       'browser/browsing_data/local_data_container.h',
+      'browser/browsing_data/origin_filter_builder.cc',
+      'browser/browsing_data/origin_filter_builder.h',
       'browser/browsing_data/passwords_counter.cc',
       'browser/browsing_data/passwords_counter.h',
       'browser/character_encoding.cc',
@@ -713,6 +715,8 @@
       'browser/android/contextualsearch/contextual_search_context.h',
       'browser/android/contextualsearch/contextual_search_delegate.cc',
       'browser/android/contextualsearch/contextual_search_delegate.h',
+      'browser/android/contextualsearch/contextual_search_field_trial.cc',
+      'browser/android/contextualsearch/contextual_search_field_trial.h',
       'browser/android/contextualsearch/contextual_search_manager.cc',
       'browser/android/contextualsearch/contextual_search_manager.h',
       'browser/android/contextualsearch/contextual_search_tab_helper.cc',
@@ -829,6 +833,10 @@
       'browser/android/new_tab_page_prefs.h',
       'browser/android/new_tab_page_url_handler.cc',
       'browser/android/new_tab_page_url_handler.h',
+      'browser/android/ntp_snippets_bridge.cc',
+      'browser/android/ntp_snippets_bridge.h',
+      'browser/android/ntp_snippets_controller.cc',
+      'browser/android/ntp_snippets_controller.h',
       'browser/android/omnibox/answers_image_bridge.cc',
       'browser/android/omnibox/answers_image_bridge.h',
       'browser/android/omnibox/autocomplete_controller_android.cc',
@@ -948,6 +956,8 @@
       'browser/net/spdyproxy/data_reduction_proxy_settings_android.cc',
       'browser/net/spdyproxy/data_reduction_proxy_settings_android.h',
       'browser/password_manager/account_chooser_dialog_android.cc',
+      'browser/password_manager/update_password_infobar_delegate.cc',
+      'browser/password_manager/update_password_infobar_delegate.h',
       'browser/password_manager/account_chooser_dialog_android.h',
       'browser/password_manager/auto_signin_first_run_dialog_android.cc',
       'browser/password_manager/auto_signin_first_run_dialog_android.h',
@@ -1875,10 +1885,12 @@
       'android/java/src/org/chromium/chrome/browser/net/spdyproxy/DataReductionProxySettings.java',
       'android/java/src/org/chromium/chrome/browser/notifications/NotificationUIManager.java',
       'android/java/src/org/chromium/chrome/browser/ntp/ForeignSessionHelper.java',
+      'android/java/src/org/chromium/chrome/browser/ntp/interests/InterestsService.java',
       'android/java/src/org/chromium/chrome/browser/ntp/LogoBridge.java',
       'android/java/src/org/chromium/chrome/browser/ntp/NewTabPagePrefs.java',
       'android/java/src/org/chromium/chrome/browser/ntp/RecentlyClosedBridge.java',
-      'android/java/src/org/chromium/chrome/browser/ntp/interests/InterestsService.java',
+      'android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java',
+      'android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsController.java',
       'android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java',
       'android/java/src/org/chromium/chrome/browser/omnibox/AnswersImage.java',
       'android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteController.java',
@@ -1944,6 +1956,7 @@
       'android/java/src/org/chromium/chrome/browser/infobar/PermissionUpdateInfoBarDelegate.java',
       'android/java/src/org/chromium/chrome/browser/infobar/SavePasswordInfoBar.java',
       'android/java/src/org/chromium/chrome/browser/infobar/SimpleConfirmInfoBarBuilder.java',
+      'android/java/src/org/chromium/chrome/browser/infobar/UpdatePasswordInfoBar.java',
       'android/java/src/org/chromium/chrome/browser/invalidation/InvalidationServiceFactory.java',
       'android/java/src/org/chromium/chrome/browser/metrics/LaunchMetrics.java',
       'android/java/src/org/chromium/chrome/browser/ssl/SecurityStateModel.java',
@@ -3337,11 +3350,11 @@
             '../mojo/mojo_base.gyp:mojo_application_base',
             '../mojo/mojo_base.gyp:mojo_common_lib',
             '../mojo/mojo_base.gyp:mojo_environment_chromium',
-            '../mojo/mojo_base.gyp:mojo_message_pump_lib',
             '../mojo/mojo_base.gyp:mojo_url_type_converters',
             '../mojo/mojo_edk.gyp:mojo_system_impl',
             '../mojo/mojo_public.gyp:mojo_cpp_bindings',
             '../mojo/mojo_public.gyp:mojo_js_bindings',
+            '../mojo/mojo_public.gyp:mojo_message_pump_lib',
             '../net/net.gyp:net_extras',
             '../net/net.gyp:net_with_v8',
             '../storage/storage_browser.gyp:storage',
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi
index f5924411..d2d8349 100644
--- a/chrome/chrome_browser_extensions.gypi
+++ b/chrome/chrome_browser_extensions.gypi
@@ -299,6 +299,8 @@
       'browser/extensions/api/feedback_private/feedback_service.h',
       'browser/extensions/api/file_handlers/app_file_handler_util.cc',
       'browser/extensions/api/file_handlers/app_file_handler_util.h',
+      'browser/extensions/api/file_handlers/directory_util.cc',
+      'browser/extensions/api/file_handlers/directory_util.h',
       'browser/extensions/api/file_handlers/mime_util.cc',
       'browser/extensions/api/file_handlers/mime_util.h',
       'browser/extensions/api/file_system/file_system_api.cc',
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index 33f3d83..2d717753 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -463,6 +463,8 @@
       'browser/ui/android/infobars/simple_confirm_infobar_builder.h',
       'browser/ui/android/infobars/translate_infobar.cc',
       'browser/ui/android/infobars/translate_infobar.h',
+      'browser/ui/android/infobars/update_password_infobar.cc',
+      'browser/ui/android/infobars/update_password_infobar.h',
       'browser/ui/android/javascript_app_modal_dialog_android.cc',
       'browser/ui/android/login_prompt_android.cc',
       'browser/ui/android/omnibox/omnibox_url_emphasizer.cc',
diff --git a/chrome/chrome_dll.gypi b/chrome/chrome_dll.gypi
index de456dd..9ee23c53 100644
--- a/chrome/chrome_dll.gypi
+++ b/chrome/chrome_dll.gypi
@@ -121,6 +121,7 @@
           ],
           'dependencies': [
             '<@(chromium_browser_dependencies)',
+            'chrome_features.gyp:chrome_common_features',
             '../content/content.gyp:content_app_browser',
           ],
           'conditions': [
@@ -347,6 +348,7 @@
             '../components/components.gyp:browser_watcher_client',
             '../content/content.gyp:content_app_child',
             '../third_party/kasko/kasko.gyp:kasko',
+            'chrome_features.gyp:chrome_common_features',
             'chrome_version_resources',
             'policy_path_parser',
           ],
diff --git a/chrome/chrome_exe.gypi b/chrome/chrome_exe.gypi
index 9e7009ad..a49d51f 100644
--- a/chrome/chrome_exe.gypi
+++ b/chrome/chrome_exe.gypi
@@ -202,6 +202,7 @@
             '../content/content.gyp:content_app_both',
             # Needed for chrome_main.cc initialization of libraries.
             '../build/linux/system.gyp:pangocairo',
+            'chrome_features.gyp:chrome_common_features',
             # Needed to use the master_preferences functions
             'installer_util',
           ],
diff --git a/chrome/chrome_features.gyp b/chrome/chrome_features.gyp
index deb1b98b..a26021fc 100644
--- a/chrome/chrome_features.gyp
+++ b/chrome/chrome_features.gyp
@@ -15,8 +15,10 @@
         'buildflag_header_path': 'chrome/common/features.h',
         'buildflag_flags': [
           'ENABLE_GOOGLE_NOW=<(enable_google_now)',
+          'ENABLE_ONE_CLICK_SIGNIN=<(enable_one_click_signin)',
           'ANDROID_JAVA_UI=<(android_java_ui)',
           'USE_VULCANIZE=<(use_vulcanize)',
+          'ENABLE_PACKAGE_MASH_SERVICES=<(enable_package_mash_services)',
         ],
       },
     },
diff --git a/chrome/chrome_features.gypi b/chrome/chrome_features.gypi
index b78a4dae..b93f6a5c 100644
--- a/chrome/chrome_features.gypi
+++ b/chrome/chrome_features.gypi
@@ -33,6 +33,9 @@
     'android_java_ui%': '<(android_java_ui)',
     'use_vulcanize%': '<(use_vulcanize)',
 
+    # GN only, but defined here so BUILDFLAG works without ifdef.
+    'enable_package_mash_services%': 0,
+
     # Grit defines based on the feature flags. These must be manually added to
     # grit targets.
     'chrome_grit_defines': [
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 87bfb56..c67fd7c 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1445,7 +1445,6 @@
       'browser/sync/test/integration/migration_test.cc',
       'browser/sync/test/integration/single_client_app_list_sync_test.cc',
       'browser/sync/test/integration/single_client_apps_sync_test.cc',
-      'browser/sync/test/integration/single_client_backup_rollback_test.cc',
       'browser/sync/test/integration/single_client_bookmarks_sync_test.cc',
       'browser/sync/test/integration/single_client_dictionary_sync_test.cc',
       'browser/sync/test/integration/single_client_directory_sync_test.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 50b7bab..3be1264 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -13,6 +13,7 @@
       'browser/after_startup_task_utils_unittest.cc',
       'browser/android/bookmarks/partner_bookmarks_shim_unittest.cc',
       'browser/android/contextualsearch/contextual_search_delegate_unittest.cc',
+      'browser/android/contextualsearch/contextual_search_field_trial_unittest.cc',
       'browser/android/data_usage/data_use_matcher_unittest.cc',
       'browser/android/data_usage/data_use_tab_model_unittest.cc',
       'browser/android/data_usage/data_use_ui_tab_model_unittest.cc',
@@ -56,6 +57,7 @@
       'browser/browsing_data/browsing_data_remover_unittest.cc',
       'browser/browsing_data/browsing_data_service_worker_helper_unittest.cc',
       'browser/browsing_data/cookies_tree_model_unittest.cc',
+      'browser/browsing_data/origin_filter_builder_unittest.cc',
       'browser/chrome_browser_application_mac_unittest.mm',
       'browser/chrome_content_browser_client_unittest.cc',
       'browser/chrome_elf_init_unittest_win.cc',
@@ -230,7 +232,6 @@
       'browser/status_icons/status_icon_unittest.cc',
       'browser/status_icons/status_tray_unittest.cc',
       'browser/storage/durable_storage_permission_context_unittest.cc',
-      'browser/sync/profile_sync_service_bookmark_unittest.cc',
       'browser/sync/profile_sync_service_factory_unittest.cc',
       'browser/sync/sync_startup_tracker_unittest.cc',
       'browser/task_profiler/task_profiler_data_serializer_unittest.cc',
@@ -419,6 +420,7 @@
       'browser/extensions/api/extension_action/browser_action_unittest.cc',
       'browser/extensions/api/extension_action/extension_action_prefs_unittest.cc',
       'browser/extensions/api/file_handlers/api_file_handler_util_unittest.cc',
+      'browser/extensions/api/file_handlers/directory_util_unittest.cc',
       'browser/extensions/api/file_handlers/mime_util_unittest.cc',
       'browser/extensions/api/file_system/file_system_api_unittest.cc',
       'browser/extensions/api/identity/extension_token_key_unittest.cc',
@@ -2222,7 +2224,6 @@
         'test_support_unit',
         # 3) anything tests directly depend on
         '../components/components.gyp:generate_version_info',
-        '../components/components.gyp:sync_driver_features',
         '../courgette/courgette.gyp:courgette_lib',
         '../google_apis/google_apis.gyp:google_apis',
         '../skia/skia.gyp:skia',
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index d454606..dd04326 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -41,8 +41,10 @@
 buildflag_header("features") {
   header = "features.h"
   flags = [
-    "ENABLE_GOOGLE_NOW=$enable_google_now",
     "ANDROID_JAVA_UI=$android_java_ui",
+    "ENABLE_GOOGLE_NOW=$enable_google_now",
+    "ENABLE_ONE_CLICK_SIGNIN=$enable_one_click_signin",
+    "ENABLE_PACKAGE_MASH_SERVICES=$enable_package_mash_services",
     "USE_VULCANIZE=$use_vulcanize",
   ]
 }
diff --git a/chrome/common/chrome_content_client.cc b/chrome/common/chrome_content_client.cc
index 779c8a5..f79b019 100644
--- a/chrome/common/chrome_content_client.cc
+++ b/chrome/common/chrome_content_client.cc
@@ -602,7 +602,7 @@
   return "Unknown";
 }
 
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
 bool ChromeContentClient::GetSandboxProfileForSandboxType(
     int sandbox_type,
     int* sandbox_profile_resource_id) const {
diff --git a/chrome/common/chrome_content_client.h b/chrome/common/chrome_content_client.h
index 21a8bbda..c5b7d2d 100644
--- a/chrome/common/chrome_content_client.h
+++ b/chrome/common/chrome_content_client.h
@@ -74,7 +74,7 @@
   gfx::Image& GetNativeImageNamed(int resource_id) const override;
   std::string GetProcessTypeNameInEnglish(int type) override;
 
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
   bool GetSandboxProfileForSandboxType(
       int sandbox_type,
       int* sandbox_profile_resource_id) const override;
diff --git a/chrome/common/chrome_paths.cc b/chrome/common/chrome_paths.cc
index 970dc6b..fbb116a 100644
--- a/chrome/common/chrome_paths.cc
+++ b/chrome/common/chrome_paths.cc
@@ -40,7 +40,7 @@
 const base::FilePath::CharType kPepperFlashBaseDirectory[] =
     FILE_PATH_LITERAL("PepperFlash");
 
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
 const base::FilePath::CharType kPepperFlashSystemBaseDirectory[] =
     FILE_PATH_LITERAL("Internet Plug-Ins/PepperFlashPlayer");
 const base::FilePath::CharType kFlashSystemBaseDirectory[] =
@@ -73,7 +73,7 @@
 
 // Gets the path for internal plugins.
 bool GetInternalPluginsDirectory(base::FilePath* result) {
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
   // If called from Chrome, get internal plugins from a subdirectory of the
   // framework.
   if (base::mac::AmIBundled()) {
@@ -278,7 +278,7 @@
 #if defined(OS_WIN)
       if (!GetSystemFlashFilename(&cur, false))
         return false;
-#elif defined(OS_MACOSX) && !defined(OS_IOS)
+#elif defined(OS_MACOSX)
       if (!GetLocalLibraryDirectory(&cur))
         return false;
       cur = cur.Append(kPepperFlashSystemBaseDirectory);
@@ -293,7 +293,7 @@
 #if defined(OS_WIN)
       if (!GetSystemFlashFilename(&cur, true))
         return false;
-#elif defined(OS_MACOSX) && !defined(OS_IOS)
+#elif defined(OS_MACOSX)
       if (!GetLocalLibraryDirectory(&cur))
         return false;
       cur = cur.Append(kFlashSystemBaseDirectory);
@@ -380,7 +380,7 @@
       break;
 #endif  // defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS)
     case chrome::FILE_RESOURCES_PACK:
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
       if (base::mac::AmIBundled()) {
         cur = base::mac::FrameworkBundlePath();
         cur = cur.Append(FILE_PATH_LITERAL("Resources"))
@@ -480,7 +480,7 @@
       break;
     }
 #endif
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
     case chrome::DIR_USER_LIBRARY: {
       if (!GetUserLibraryDirectory(&cur))
         return false;
@@ -497,7 +497,7 @@
     }
 #endif
 #if defined(OS_CHROMEOS) || (defined(OS_LINUX) && defined(CHROMIUM_BUILD)) || \
-    (defined(OS_MACOSX) && !defined(OS_IOS))
+    defined(OS_MACOSX)
     case chrome::DIR_USER_EXTERNAL_EXTENSIONS: {
       if (!PathService::Get(chrome::DIR_USER_DATA, &cur))
         return false;
@@ -512,7 +512,7 @@
     }
 #endif
     case chrome::DIR_EXTERNAL_EXTENSIONS:
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
       if (!chrome::GetGlobalApplicationSupportDirectory(&cur))
         return false;
 
@@ -540,7 +540,7 @@
 #endif
       break;
 
-#if defined(OS_LINUX) || (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_LINUX) || defined(OS_MACOSX)
     case chrome::DIR_NATIVE_MESSAGING:
 #if defined(OS_MACOSX)
 #if defined(GOOGLE_CHROME_BUILD)
@@ -566,7 +566,7 @@
         return false;
       cur = cur.Append(FILE_PATH_LITERAL("NativeMessagingHosts"));
       break;
-#endif  // defined(OS_LINUX) || (defined(OS_MACOSX) && !defined(OS_IOS))
+#endif  // defined(OS_LINUX) || defined(OS_MACOSX)
 #if !defined(OS_ANDROID)
     case chrome::DIR_GLOBAL_GCM_STORE:
       if (!PathService::Get(chrome::DIR_USER_DATA, &cur))
diff --git a/chrome/common/chrome_paths.h b/chrome/common/chrome_paths.h
index 581fdc06..4c488cc 100644
--- a/chrome/common/chrome_paths.h
+++ b/chrome/common/chrome_paths.h
@@ -46,12 +46,12 @@
                                 // to set policies for chrome. This directory
                                 // contains subdirectories.
 #endif
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
   DIR_USER_APPLICATIONS,        // ~/Applications
   DIR_USER_LIBRARY,             // ~/Library
 #endif
 #if defined(OS_CHROMEOS) || (defined(OS_LINUX) && defined(CHROMIUM_BUILD)) || \
-    (defined(OS_MACOSX) && !defined(OS_IOS))
+    defined(OS_MACOSX)
   DIR_USER_EXTERNAL_EXTENSIONS,  // Directory for per-user external extensions
                                  // on Chrome Mac and Chromium Linux.
                                  // On Chrome OS, this path is used for OEM
@@ -117,7 +117,7 @@
   DIR_SUPERVISED_USER_INSTALLED_WHITELISTS,  // Directory where sanitized
                                              // supervised user whitelists are
                                              // installed.
-#if defined(OS_LINUX) || (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_LINUX) || defined(OS_MACOSX)
   DIR_NATIVE_MESSAGING,         // System directory where native messaging host
                                 // manifest files are stored.
   DIR_USER_NATIVE_MESSAGING,    // Directory with Native Messaging Hosts
diff --git a/chrome/common/chrome_paths_internal.h b/chrome/common/chrome_paths_internal.h
index 70618287..a5c14f1 100644
--- a/chrome/common/chrome_paths_internal.h
+++ b/chrome/common/chrome_paths_internal.h
@@ -56,7 +56,7 @@
 // Gets the path to the user's videos directory.
 bool GetUserVideosDirectory(base::FilePath* result);
 
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
 // The "versioned directory" is a directory in the browser .app bundle.  It
 // contains the bulk of the application, except for the things that the system
 // requires be located at spepcific locations.  The versioned directory is
@@ -102,8 +102,7 @@
 bool GetUserDataDirectoryForBrowserBundle(NSBundle* bundle,
                                           base::FilePath* result);
 
-#endif  // OS_MACOSX && !OS_IOS
-
+#endif  // OS_MACOSX
 // Checks if the |process_type| has the rights to access the profile.
 bool ProcessNeedsProfileDir(const std::string& process_type);
 
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 53b8509..b1be5b96 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -1318,7 +1318,16 @@
 const char kMarketUrlForTesting[] = "market-url-for-testing";
 
 // Specifies a particular tab management experiment to enable.
-const char kTabManagementExperimentType[] = "tab-management-experiment-type";
+const char kTabManagementExperimentTypeDisabled[] =
+    "tab-management-experiment-type-disabled";
+const char kTabManagementExperimentTypeAnise[] =
+    "tab-management-experiment-type-anise";
+const char kTabManagementExperimentTypeBasil[] =
+    "tab-management-experiment-type-basil";
+const char kTabManagementExperimentTypeChive[] =
+    "tab-management-experiment-type-chive";
+const char kTabManagementExperimentTypeDill[] =
+    "tab-management-experiment-type-dill";
 #endif  // defined(OS_ANDROID)
 
 #if defined(OS_WIN) || defined(OS_LINUX)
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 03ad8231..c3fb63f 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -306,7 +306,11 @@
 extern const char kForceShowUpdateMenuItemCustomSummary[];
 extern const char kForceShowUpdateMenuBadge[];
 extern const char kMarketUrlForTesting[];
-extern const char kTabManagementExperimentType[];
+extern const char kTabManagementExperimentTypeDisabled[];
+extern const char kTabManagementExperimentTypeAnise[];
+extern const char kTabManagementExperimentTypeBasil[];
+extern const char kTabManagementExperimentTypeChive[];
+extern const char kTabManagementExperimentTypeDill[];
 #endif  // defined(OS_ANDROID)
 
 #if defined(USE_ASH)
diff --git a/chrome/common/extensions/api/input_method_private.json b/chrome/common/extensions/api/input_method_private.json
index 8da283ae..70881dd 100644
--- a/chrome/common/extensions/api/input_method_private.json
+++ b/chrome/common/extensions/api/input_method_private.json
@@ -258,6 +258,11 @@
             "description": "Whether the IME menu is currently active."
           }
         ]
+      }, {
+        "name": "onImeMenuListChanged",
+        "type": "function",
+        "description": "Fired when the input method or the list of active input method IDs is changed.",
+        "parameters": []
       }
     ]
   }
diff --git a/chrome/common/features.gni b/chrome/common/features.gni
index 7095deb3..13755f9 100644
--- a/chrome/common/features.gni
+++ b/chrome/common/features.gni
@@ -17,8 +17,14 @@
   # Use vulcanized HTML/CSS/JS resources to speed up WebUI (chrome://)
   # pages. https://github.com/polymer/vulcanize
   use_vulcanize = true
+
+  # Set to true to bundle all the mash related mojo services into chrome.
+  # Specify --mash to chrome to have chrome start the mash environment.
+  enable_package_mash_services = is_chromeos
 }
 
+enable_one_click_signin = is_win || is_mac || (is_linux && !is_chromeos)
+
 chrome_grit_defines = [
   "enable_google_now=$enable_google_now",
   "use_vulcanize=$use_vulcanize",
diff --git a/chrome/common/net/x509_certificate_model_openssl.cc b/chrome/common/net/x509_certificate_model_openssl.cc
index cf99faa..86476bf 100644
--- a/chrome/common/net/x509_certificate_model_openssl.cc
+++ b/chrome/common/net/x509_certificate_model_openssl.cc
@@ -26,7 +26,6 @@
 #include "crypto/openssl_util.h"
 #include "crypto/scoped_openssl_types.h"
 #include "net/base/address_family.h"
-#include "net/base/net_util.h"
 #include "net/cert/x509_util_openssl.h"
 #include "ui/base/l10n/l10n_util.h"
 
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index e628ecf..eea95a4 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -414,7 +414,7 @@
 // Prefs for persisting HttpServerProperties.
 const char kHttpServerProperties[] = "net.http_server_properties";
 
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_ANDROID)
 // Last time that a check for cloud policy management was done. This time is
 // recorded on Android so that retries aren't attempted on every startup.
 // Instead the cloud policy registration is retried at least 1 or 3 days later.
@@ -1348,8 +1348,7 @@
 // upgrade a unsafe location to a safe location.
 const char kDownloadDirUpgraded[] = "download.directory_upgrade";
 
-#if defined(OS_WIN) || defined(OS_LINUX) || \
-    (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MACOSX)
 const char kOpenPdfDownloadInSystemReader[] =
     "download.open_pdf_in_system_reader";
 #endif
@@ -1425,7 +1424,7 @@
 // before shutting everything down.
 const char kRestartLastSessionOnShutdown[] = "restart.last.session.on.shutdown";
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 // Set before autorestarting Chrome, cleared on clean exit.
 const char kWasRestarted[] = "was.restarted";
 #endif
@@ -1519,7 +1518,7 @@
 // when on-line authentication is not available.
 const char kGoogleServicesPasswordHash[] = "google.services.password_hash";
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 // Tracks the number of times that we have shown the sign in promo at startup.
 const char kSignInPromoStartupCount[] = "sync_promo.startup_count";
 
@@ -1537,7 +1536,7 @@
 const char kSignInPromoShowNTPBubble[] = "sync_promo.show_ntp_bubble";
 #endif
 
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
 // Boolean tracking whether the user chose to opt out of the x-device promo.
 const char kCrossDevicePromoOptedOut[] = "x_device_promo.opted_out";
 
@@ -1953,7 +1952,7 @@
 // by the cloud policy subsystem.
 const char kDevicePolicyRefreshRate[] = "policy.device_refresh_rate";
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 // A boolean where true means that the browser has previously attempted to
 // enable autoupdate and failed, so the next out-of-date browser start should
 // not prompt the user to enable autoupdate, it should offer to reinstall Chrome
@@ -1971,7 +1970,7 @@
 
 // The last time a media scan completed.
 const char kMediaGalleriesLastScanTime[] = "media_galleries.last_scan_time";
-#endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif  // !defined(OS_ANDROID)
 
 #if defined(USE_ASH)
 // |kShelfAlignment| and |kShelfAutoHideBehavior| have a local variant. The
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 4933bed..4f2e79a4 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -163,7 +163,7 @@
 extern const char kDnsPrefetchingHostReferralList[];
 extern const char kDisableSpdy[];
 extern const char kHttpServerProperties[];
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_ANDROID)
 extern const char kLastPolicyCheckTime[];
 #endif
 extern const char kInstantUIZeroSuggestUrlPrefix[];
@@ -464,8 +464,7 @@
 extern const char kDownloadDefaultDirectory[];
 extern const char kDownloadExtensionsToOpen[];
 extern const char kDownloadDirUpgraded[];
-#if defined(OS_WIN) || defined(OS_LINUX) || \
-    (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MACOSX)
 extern const char kOpenPdfDownloadInSystemReader[];
 #endif
 
@@ -497,7 +496,7 @@
 extern const char kShutdownNumProcessesSlow[];
 
 extern const char kRestartLastSessionOnShutdown[];
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 extern const char kWasRestarted[];
 #endif
 
@@ -539,14 +538,14 @@
 
 extern const char kGoogleServicesPasswordHash[];
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 extern const char kSignInPromoStartupCount[];
 extern const char kSignInPromoUserSkipped[];
 extern const char kSignInPromoShowOnFirstRunAllowed[];
 extern const char kSignInPromoShowNTPBubble[];
 #endif
 
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
 extern const char kCrossDevicePromoOptedOut[];
 extern const char kCrossDevicePromoShouldBeShown[];
 extern const char kCrossDevicePromoObservedSingleAccountCookie[];
@@ -690,13 +689,13 @@
 extern const char kResolveDeviceTimezoneByGeolocation[];
 #endif  // defined(OS_CHROMEOS)
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 extern const char kAttemptedToEnableAutoupdate[];
 
 extern const char kMediaGalleriesUniqueId[];
 extern const char kMediaGalleriesRememberedGalleries[];
 extern const char kMediaGalleriesLastScanTime[];
-#endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
+#endif  // !defined(OS_ANDROID)
 
 #if defined(USE_ASH)
 extern const char kShelfAlignment[];
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index 3d65326..e7178770 100644
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -189,7 +189,7 @@
 // RenderView messages
 // These are messages sent from the browser to the renderer process.
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 // For WebUI testing, this message requests JavaScript to be executed at a time
 // which is late enough to not be thrown out, and early enough to be before
 // onload events are fired.
diff --git a/chrome/common/safe_browsing/csd.proto b/chrome/common/safe_browsing/csd.proto
index 1b6dd1b..a9460f3c 100644
--- a/chrome/common/safe_browsing/csd.proto
+++ b/chrome/common/safe_browsing/csd.proto
@@ -483,8 +483,7 @@
     message ResourceRequestIncident {
       enum Type {
         UNKNOWN = 0;
-        TYPE_SCRIPT = 1;
-        TYPE_DOMAIN = 2;
+        TYPE_PATTERN = 3;
       }
       optional bytes digest = 1;
       optional string origin = 2;
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index 3f9676b..ff9aa54 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -136,7 +136,7 @@
     "chrome://tab-modal-confirm-dialog/";
 #endif
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 const char kChromeUICopresenceURL[] = "chrome://copresence/";
 #endif
 
@@ -321,7 +321,7 @@
 const char kChromeUITabModalConfirmDialogHost[] = "tab-modal-confirm-dialog";
 #endif
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 const char kChromeUICopresenceHost[] = "copresence";
 #endif
 
@@ -427,13 +427,13 @@
     "/chromevox/background/options.html";
 #endif  // defined(OS_CHROMEOS)
 
-#if defined(ENABLE_ONE_CLICK_SIGNIN)
+#if BUILDFLAG(ENABLE_ONE_CLICK_SIGNIN)
 const char kChromeSyncLearnMoreURL[] =
     "https://support.google.com/chrome/answer/165139";
 
 const char kChromeSyncMergeTroubleshootingURL[] =
     "https://support.google.com/chrome/answer/1181420#merge";
-#endif  // defined(ENABLE_ONE_CLICK_SIGNIN)
+#endif  // BUILDFLAG(ENABLE_ONE_CLICK_SIGNIN)
 
 #if defined(OS_MACOSX)
 const char kChromeEnterpriseSignInLearnMoreURL[] =
@@ -652,7 +652,7 @@
   kChromeUISystemInfoHost,
   kChromeUIUberHost,
 #endif
-#if defined(OS_ANDROID) || defined(OS_IOS)
+#if defined(OS_ANDROID)
   kChromeUINetExportHost,
 #else  // non-mobile
   kChromeUICopresenceHost,
@@ -769,4 +769,7 @@
 const char kChooserBluetoothOverviewURL[] =
     "https://support.google.com/chrome?p=bluetooth";
 
+const char kChooserUsbOverviewURL[] =
+    "https://support.google.com/chrome?p=webusb";
+
 }  // namespace chrome
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index d57d6eaf..f3f51d0 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -125,7 +125,7 @@
 extern const char kChromeUITabModalConfirmDialogURL[];
 #endif
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 extern const char kChromeUICopresenceURL[];
 extern const char kChromeUICopresenceHost[];
 #endif
@@ -364,7 +364,7 @@
 extern const char kChromeAccessibilitySettingsURL[];
 #endif
 
-#if defined (ENABLE_ONE_CLICK_SIGNIN)
+#if BUILDFLAG(ENABLE_ONE_CLICK_SIGNIN)
 // "Learn more" URL for the one click signin infobar.
 extern const char kChromeSyncLearnMoreURL[];
 
@@ -578,6 +578,9 @@
 // Chooser.
 extern const char kChooserBluetoothOverviewURL[];
 
+// The URL for the WebUsb help center article.
+extern const char kChooserUsbOverviewURL[];
+
 }  // namespace chrome
 
 #endif  // CHROME_COMMON_URL_CONSTANTS_H_
diff --git a/chrome/installer/mini_installer/BUILD.gn b/chrome/installer/mini_installer/BUILD.gn
index 363c13f..ada08a98 100644
--- a/chrome/installer/mini_installer/BUILD.gn
+++ b/chrome/installer/mini_installer/BUILD.gn
@@ -7,6 +7,7 @@
 import("//build_overrides/v8.gni")
 import("//chrome/version.gni")
 import("//third_party/icu/config.gni")
+import("//ui/base/ui_features.gni")
 
 config("mini_installer_compiler_flags") {
   cflags = [
diff --git a/chrome/renderer/autofill/password_generation_agent_browsertest.cc b/chrome/renderer/autofill/password_generation_agent_browsertest.cc
index 34c9bd6e..1b92b5a 100644
--- a/chrome/renderer/autofill/password_generation_agent_browsertest.cc
+++ b/chrome/renderer/autofill/password_generation_agent_browsertest.cc
@@ -73,7 +73,7 @@
 
   void ShowGenerationPopUpManually(const char* element_id) {
     FocusField(element_id);
-    AutofillMsg_GeneratePassword msg(0);
+    AutofillMsg_UserTriggeredGeneratePassword msg(0);
     password_generation_->OnMessageReceived(msg);
   }
 
diff --git a/chrome/renderer/chrome_content_renderer_client.h b/chrome/renderer/chrome_content_renderer_client.h
index 58a702f..c56c2bbd 100644
--- a/chrome/renderer/chrome_content_renderer_client.h
+++ b/chrome/renderer/chrome_content_renderer_client.h
@@ -67,10 +67,6 @@
 class WebSecurityOrigin;
 }
 
-namespace password_manager {
-class CredentialManagerClient;
-}
-
 #if defined(ENABLE_WEBRTC)
 class WebRtcLoggingMessageFilter;
 #endif
@@ -205,8 +201,6 @@
 
   scoped_ptr<network_hints::PrescientNetworkingDispatcher>
       prescient_networking_dispatcher_;
-  scoped_ptr<password_manager::CredentialManagerClient>
-      credential_manager_client_;
 
   OriginTrialKeyManager origin_trial_key_manager_;
 
diff --git a/chrome/renderer/chrome_render_frame_observer.cc b/chrome/renderer/chrome_render_frame_observer.cc
index 9085354..af94139 100644
--- a/chrome/renderer/chrome_render_frame_observer.cc
+++ b/chrome/renderer/chrome_render_frame_observer.cc
@@ -25,7 +25,7 @@
 #include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_view.h"
 #include "extensions/common/constants.h"
-#include "net/base/net_util.h"
+#include "net/base/url_util.h"
 #include "skia/ext/image_operations.h"
 #include "third_party/WebKit/public/platform/WebImage.h"
 #include "third_party/WebKit/public/platform/modules/app_banner/WebAppBannerPromptReply.h"
diff --git a/chrome/renderer/chrome_render_process_observer.cc b/chrome/renderer/chrome_render_process_observer.cc
index 6b2c147..89a1339 100644
--- a/chrome/renderer/chrome_render_process_observer.cc
+++ b/chrome/renderer/chrome_render_process_observer.cc
@@ -29,6 +29,7 @@
 #include "chrome/common/child_process_logging.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/media/media_resource_provider.h"
 #include "chrome/common/net/net_resource_provider.h"
 #include "chrome/common/render_messages.h"
 #include "chrome/common/resource_usage_reporter.mojom.h"
@@ -42,6 +43,7 @@
 #include "content/public/renderer/render_thread.h"
 #include "content/public/renderer/render_view.h"
 #include "content/public/renderer/render_view_visitor.h"
+#include "media/base/media_resources.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "net/base/net_errors.h"
 #include "net/base/net_module.h"
@@ -56,11 +58,6 @@
 #include "chrome/renderer/extensions/extension_localization_peer.h"
 #endif
 
-#if !defined(OS_IOS)
-#include "chrome/common/media/media_resource_provider.h"
-#include "media/base/media_resources.h"
-#endif
-
 using blink::WebCache;
 using blink::WebRuntimeFeatures;
 using blink::WebSecurityPolicy;
@@ -271,10 +268,8 @@
 
   // Configure modules that need access to resources.
   net::NetModule::SetResourceProvider(chrome_common_net::NetResourceProvider);
-#if !defined(OS_IOS)
   media::SetLocalizedStringProvider(
       chrome_common_media::LocalizedStringProvider);
-#endif
 
   InitFieldTrialObserving(command_line);
 }
diff --git a/chrome/renderer/chrome_render_view_observer.cc b/chrome/renderer/chrome_render_view_observer.cc
index 8c7e303..55a1a569 100644
--- a/chrome/renderer/chrome_render_view_observer.cc
+++ b/chrome/renderer/chrome_render_view_observer.cc
@@ -52,7 +52,7 @@
 bool ChromeRenderViewObserver::OnMessageReceived(const IPC::Message& message) {
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(ChromeRenderViewObserver, message)
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
     IPC_MESSAGE_HANDLER(ChromeViewMsg_WebUIJavaScript, OnWebUIJavaScript)
 #endif
 #if defined(ENABLE_EXTENSIONS)
@@ -72,7 +72,7 @@
   return handled;
 }
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 void ChromeRenderViewObserver::OnWebUIJavaScript(
     const base::string16& javascript) {
   webui_javascript_.push_back(javascript);
diff --git a/chrome/renderer/chrome_render_view_observer.h b/chrome/renderer/chrome_render_view_observer.h
index 4115596..cdc15f3 100644
--- a/chrome/renderer/chrome_render_view_observer.h
+++ b/chrome/renderer/chrome_render_view_observer.h
@@ -45,7 +45,7 @@
   void DidStartLoading() override;
   void Navigate(const GURL& url) override;
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   void OnWebUIJavaScript(const base::string16& javascript);
 #endif
 #if defined(ENABLE_EXTENSIONS)
diff --git a/chrome/renderer/extensions/automation_internal_custom_bindings.cc b/chrome/renderer/extensions/automation_internal_custom_bindings.cc
index e14f43e..44bfb90 100644
--- a/chrome/renderer/extensions/automation_internal_custom_bindings.cc
+++ b/chrome/renderer/extensions/automation_internal_custom_bindings.cc
@@ -1060,7 +1060,6 @@
   }
 
   for (int id : text_changed_node_ids_) {
-    LOG(ERROR) << "got id!" << id;
     SendTreeChangeEvent(api::automation::TREE_CHANGE_TYPE_TEXTCHANGED, tree,
                         tree->GetFromId(id));
   }
diff --git a/chrome/renderer/media/cast_receiver_audio_valve.cc b/chrome/renderer/media/cast_receiver_audio_valve.cc
index 785d90d..6efb23d 100644
--- a/chrome/renderer/media/cast_receiver_audio_valve.cc
+++ b/chrome/renderer/media/cast_receiver_audio_valve.cc
@@ -4,26 +4,55 @@
 
 #include "chrome/renderer/media/cast_receiver_audio_valve.h"
 
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "media/audio/audio_parameters.h"
+
 CastReceiverAudioValve::CastReceiverAudioValve(
+    const media::AudioParameters& params,
     media::AudioCapturerSource::CaptureCallback* cb)
-    : cb_(cb) {
+    : cb_(cb),
+      fifo_(base::Bind(&CastReceiverAudioValve::DeliverRebufferedAudio,
+                       base::Unretained(this))),
+      sample_rate_(params.sample_rate()) {
+  fifo_.Reset(params.frames_per_buffer());
 }
+
 CastReceiverAudioValve::~CastReceiverAudioValve() {}
 
-void CastReceiverAudioValve::Capture(const media::AudioBus* audio_source,
-                                     int audio_delay_milliseconds,
-                                     double volume,
-                                     bool key_pressed) {
-  base::AutoLock lock(lock_);
-  if (cb_) {
-    cb_->Capture(audio_source, audio_delay_milliseconds, volume, key_pressed);
-  }
+void CastReceiverAudioValve::DeliverDecodedAudio(
+    const media::AudioBus* audio_bus,
+    base::TimeTicks playout_time) {
+  current_playout_time_ = playout_time;
+  // The following will result in zero, one, or multiple synchronous calls to
+  // DeliverRebufferedAudio().
+  fifo_.Push(*audio_bus);
 }
 
-void CastReceiverAudioValve::OnCaptureError(const std::string& message) {
+void CastReceiverAudioValve::DeliverRebufferedAudio(
+    const media::AudioBus& audio_bus,
+    int frame_delay) {
+  const base::TimeTicks playout_time =
+      current_playout_time_ +
+      base::TimeDelta::FromMicroseconds(
+          frame_delay * base::Time::kMicrosecondsPerSecond / sample_rate_);
+
   base::AutoLock lock(lock_);
   if (cb_) {
-    cb_->OnCaptureError(message);
+    // The AudioCapturerSource::Callback interface provides timing information
+    // only as a relative delay value that means "captured N milliseconds ago."
+    // Therefore, translate the playout time to these semantics.  Since playout
+    // time is generally in the future, because audio should be decoded well
+    // ahead of when it should be played out, the audio delay value will
+    // generally be negative.
+    //
+    // TimeTicks::Now() is being called after the |lock_| was acquired in order
+    // to provide the most accurate delay value.
+    const int audio_delay_milliseconds =
+        (base::TimeTicks::Now() - playout_time).InMilliseconds();
+
+    cb_->Capture(&audio_bus, audio_delay_milliseconds, 1.0 /* volume */,
+                 false /* key_pressed */);
   }
 }
 
diff --git a/chrome/renderer/media/cast_receiver_audio_valve.h b/chrome/renderer/media/cast_receiver_audio_valve.h
index ebc1209..f6c09a7 100644
--- a/chrome/renderer/media/cast_receiver_audio_valve.h
+++ b/chrome/renderer/media/cast_receiver_audio_valve.h
@@ -6,37 +6,53 @@
 #define CHROME_RENDERER_MEDIA_CAST_RECEIVER_AUDIO_VALVE_H_
 
 #include "base/synchronization/lock.h"
+#include "base/time/time.h"
 #include "media/base/audio_capturer_source.h"
+#include "media/base/audio_push_fifo.h"
 
 namespace media {
 class AudioBus;
 }
 
-// Forwards calls to |cb| until Stop is called.
+// Forwards calls to |cb| until Stop is called.  If the client requested a
+// different buffer size than that provided by the Cast Receiver, AudioPushFifo
+// is used to rectify that.
+//
 // Thread-safe.
 // All functions may block depending on contention.
 class CastReceiverAudioValve :
-    public media::AudioCapturerSource::CaptureCallback,
     public base::RefCountedThreadSafe<CastReceiverAudioValve> {
  public:
-  explicit CastReceiverAudioValve(
-      media::AudioCapturerSource::CaptureCallback* cb);
+  CastReceiverAudioValve(const media::AudioParameters& params,
+                         media::AudioCapturerSource::CaptureCallback* cb);
 
-  // AudioCapturerSource::CaptureCallback implementation.
-  void Capture(const media::AudioBus* audio_source,
-               int audio_delay_milliseconds,
-               double volume,
-               bool key_pressed) override;
-  void OnCaptureError(const std::string& message) override;
+  // Called on an unknown thread to provide more decoded audio data from the
+  // Cast Receiver.
+  void DeliverDecodedAudio(const media::AudioBus* audio_bus,
+                           base::TimeTicks playout_time);
 
   // When this returns, no more calls will be forwarded to |cb|.
   void Stop();
 
  private:
   friend class base::RefCountedThreadSafe<CastReceiverAudioValve>;
-  ~CastReceiverAudioValve() override;
+
+  ~CastReceiverAudioValve();
+
+  // Called by AudioPushFifo zero or more times during the call to Capture().
+  // Delivers audio data in the required buffer size to |cb_|.
+  void DeliverRebufferedAudio(const media::AudioBus& audio_bus,
+                              int frame_delay);
+
   media::AudioCapturerSource::CaptureCallback* cb_;
   base::Lock lock_;
+
+  media::AudioPushFifo fifo_;
+  const int sample_rate_;
+
+  // Used to pass the current playout time between DeliverDecodedAudio() and
+  // DeviliverRebufferedAudio().
+  base::TimeTicks current_playout_time_;
 };
 
 #endif  // CHROME_RENDERER_MEDIA_CAST_RECEIVER_AUDIO_VALVE_H_
diff --git a/chrome/renderer/media/cast_receiver_session.cc b/chrome/renderer/media/cast_receiver_session.cc
index 583be4d0..921b300d 100644
--- a/chrome/renderer/media/cast_receiver_session.cc
+++ b/chrome/renderer/media/cast_receiver_session.cc
@@ -169,7 +169,7 @@
     callback->OnCaptureError(std::string());
     return;
   }
-  audio_valve_ = new CastReceiverAudioValve(callback);
+  audio_valve_ = new CastReceiverAudioValve(params, callback);
 }
 
 void CastReceiverSession::AudioCapturerSource::Start() {
diff --git a/chrome/renderer/media/cast_receiver_session_delegate.cc b/chrome/renderer/media/cast_receiver_session_delegate.cc
index fee59ec..cea79a6 100644
--- a/chrome/renderer/media/cast_receiver_session_delegate.cc
+++ b/chrome/renderer/media/cast_receiver_session_delegate.cc
@@ -63,16 +63,10 @@
   // operations. Since we don't know what the Capture callback
   // will do exactly, we need to jump to a different thread.
   // Let's re-use the audio decoder thread.
-  base::TimeTicks now = cast_environment_->Clock()->NowTicks();
   cast_environment_->PostTask(
-      media::cast::CastEnvironment::AUDIO,
-      FROM_HERE,
-      base::Bind(&CastReceiverAudioValve::Capture,
-                 audio_valve_,
-                 base::Owned(audio_bus.release()),
-                 (playout_time - now).InMilliseconds(),
-                 1.0,
-                 false));
+      media::cast::CastEnvironment::AUDIO, FROM_HERE,
+      base::Bind(&CastReceiverAudioValve::DeliverDecodedAudio, audio_valve_,
+                 base::Owned(audio_bus.release()), playout_time));
   cast_receiver_->RequestDecodedAudioFrame(on_audio_decoded_cb_);
 }
 
diff --git a/chrome/renderer/media/cast_rtp_stream.cc b/chrome/renderer/media/cast_rtp_stream.cc
index 755cfd3..9fe4f0a 100644
--- a/chrome/renderer/media/cast_rtp_stream.cc
+++ b/chrome/renderer/media/cast_rtp_stream.cc
@@ -27,7 +27,6 @@
 #include "media/audio/audio_parameters.h"
 #include "media/base/audio_bus.h"
 #include "media/base/audio_converter.h"
-#include "media/base/audio_fifo.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/limits.h"
 #include "media/base/video_frame.h"
diff --git a/chrome/renderer/media/cast_transport_sender_ipc.h b/chrome/renderer/media/cast_transport_sender_ipc.h
index af66c036..2903d31 100644
--- a/chrome/renderer/media/cast_transport_sender_ipc.h
+++ b/chrome/renderer/media/cast_transport_sender_ipc.h
@@ -62,6 +62,8 @@
       const media::cast::RtpReceiverStatistics* rtp_receiver_statistics)
       override;
 
+  void SetOptions(const base::DictionaryValue& options) final {}
+
   void OnNotifyStatusChange(
       media::cast::CastTransportStatus status);
   void OnRawEvents(const std::vector<media::cast::PacketEvent>& packet_events,
diff --git a/chrome/renderer/resources/extensions/searchbox_api.js b/chrome/renderer/resources/extensions/searchbox_api.js
index 5120ff6..751d16a6 100644
--- a/chrome/renderer/resources/extensions/searchbox_api.js
+++ b/chrome/renderer/resources/extensions/searchbox_api.js
@@ -177,8 +177,8 @@
         LogMostVisitedNavigation(position, provider);
       };
 
-      this.navigateContentWindow = function(destination, disposition) {
-        NavigateContentWindow(destination, disposition);
+      this.navigateContentWindow = function(rid, disposition) {
+        NavigateContentWindow(rid, disposition);
       };
 
       this.undoAllMostVisitedDeletions = function() {
diff --git a/chrome/renderer/searchbox/searchbox_extension.cc b/chrome/renderer/searchbox/searchbox_extension.cc
index b8c5e6c0..66665ec8 100644
--- a/chrome/renderer/searchbox/searchbox_extension.cc
+++ b/chrome/renderer/searchbox/searchbox_extension.cc
@@ -239,12 +239,6 @@
   return render_view;
 }
 
-// Returns the current URL.
-GURL GetCurrentURL(content::RenderView* render_view) {
-  blink::WebView* webview = render_view->GetWebView();
-  return webview ? GURL(webview->mainFrame()->document().url()) : GURL();
-}
-
 }  // namespace
 
 namespace internal {  // for testing.
@@ -486,8 +480,7 @@
   static void LogMostVisitedNavigation(
       const v8::FunctionCallbackInfo<v8::Value>& args);
 
-  // Navigates the window to a URL represented by either a URL string or a
-  // restricted ID.
+  // Navigates the window to a URL represented by a restricted ID.
   static void NavigateContentWindow(
       const v8::FunctionCallbackInfo<v8::Value>& args);
 
@@ -1140,25 +1133,17 @@
   content::RenderView* render_view = GetRenderView();
   if (!render_view) return;
 
-  if (!args.Length()) {
+  if (!args.Length() || !args[0]->IsNumber()) {
     ThrowInvalidParameters(args);
     return;
   }
 
-  GURL destination_url;
-  // Check if the url is a rid
-  if (args[0]->IsNumber()) {
-    InstantMostVisitedItem item;
-    if (SearchBox::Get(render_view)->GetMostVisitedItemWithID(
-            args[0]->IntegerValue(), &item)) {
-      destination_url = item.url;
-    }
-  } else {
-    // Resolve the URL
-    const base::string16& possibly_relative_url = V8ValueToUTF16(args[0]);
-    GURL current_url = GetCurrentURL(render_view);
-    destination_url = internal::ResolveURL(current_url, possibly_relative_url);
-  }
+  InstantRestrictedID rid = args[0]->Int32Value();
+  InstantMostVisitedItem item;
+  if (!SearchBox::Get(render_view)->GetMostVisitedItemWithID(rid, &item))
+    return;
+
+  GURL destination_url = item.url;
 
   DVLOG(1) << render_view << " NavigateContentWindow: " << destination_url;
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index e18cdff..da5984af 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -8,6 +8,7 @@
 import("//build/config/features.gni")
 import("//build/config/ui.gni")
 import("//chrome/chrome_tests.gni")
+import("//chrome/common/features.gni")
 import("//chrome/test/base/js2gtest.gni")
 import("//testing/test.gni")
 
@@ -138,7 +139,6 @@
       "//components/guest_view/browser:test_support",
       "//components/infobars/core",
       "//components/sessions:test_support",
-      "//components/user_manager:test_support",
       "//components/web_resource:test_support",
       "//content/public/child",
       "//content/public/common",
@@ -204,7 +204,10 @@
     }
   }
   if (is_chromeos) {
-    public_deps += [ "//components/ownership" ]
+    public_deps += [
+      "//components/ownership",
+      "//components/user_manager:test_support",
+    ]
   }
 
   if (use_aura) {
@@ -873,7 +876,6 @@
       "//components/safe_browsing_db:test_database_manager",
       "//components/strings",
       "//components/translate/core/common",
-      "//components/user_manager:test_support",
       "//content/test:browsertest_base",
       "//crypto:platform",
       "//crypto:test_support",
@@ -1042,6 +1044,7 @@
       ]
       deps += [
         "//chromeos/ime:gencode",
+        "//components/user_manager:test_support",
         "//dbus",
         "//dbus:test_support",
         "//ui/login:resources",
diff --git a/chrome/test/android/BUILD.gn b/chrome/test/android/BUILD.gn
index 0573501..43dc969 100644
--- a/chrome/test/android/BUILD.gn
+++ b/chrome/test/android/BUILD.gn
@@ -7,7 +7,56 @@
 # GYP: //chrome/chrome_tests.gypi:chrome_java_test_support
 android_library("chrome_java_test_support") {
   testonly = true
-  DEPRECATED_java_in_dir = "javatests/src"
+  java_files = [
+    "javatests/src/org/chromium/chrome/test/ChromeActivityTestCaseBase.java",
+    "javatests/src/org/chromium/chrome/test/ChromeInstrumentationTestRunner.java",
+    "javatests/src/org/chromium/chrome/test/ChromeTabbedActivityTestBase.java",
+    "javatests/src/org/chromium/chrome/test/DocumentActivityTestBase.java",
+    "javatests/src/org/chromium/chrome/test/gcore/MockChromeGoogleApiClient.java",
+    "javatests/src/org/chromium/chrome/test/invalidation/IntentSavingContext.java",
+    "javatests/src/org/chromium/chrome/test/MultiActivityTestBase.java",
+    "javatests/src/org/chromium/chrome/test/omaha/AttributeFinder.java",
+    "javatests/src/org/chromium/chrome/test/omaha/MockRequestGenerator.java",
+    "javatests/src/org/chromium/chrome/test/partnercustomizations/TestPartnerBrowserCustomizationsDelayedProvider.java",
+    "javatests/src/org/chromium/chrome/test/partnercustomizations/TestPartnerBrowserCustomizationsProvider.java",
+    "javatests/src/org/chromium/chrome/test/TestContentProvider.java",
+    "javatests/src/org/chromium/chrome/test/util/ActivityUtils.java",
+    "javatests/src/org/chromium/chrome/test/util/ApplicationData.java",
+    "javatests/src/org/chromium/chrome/test/util/ApplicationTestUtils.java",
+    "javatests/src/org/chromium/chrome/test/util/BookmarkTestUtil.java",
+    "javatests/src/org/chromium/chrome/test/util/browser/contextmenu/ContextMenuUtils.java",
+    "javatests/src/org/chromium/chrome/test/util/browser/LocationSettingsTestUtil.java",
+    "javatests/src/org/chromium/chrome/test/util/browser/notifications/MockNotificationManagerProxy.java",
+    "javatests/src/org/chromium/chrome/test/util/browser/signin/MockChangeEventChecker.java",
+    "javatests/src/org/chromium/chrome/test/util/browser/signin/SigninTestUtil.java",
+    "javatests/src/org/chromium/chrome/test/util/browser/sync/SyncTestUtil.java",
+    "javatests/src/org/chromium/chrome/test/util/browser/TabLoadObserver.java",
+    "javatests/src/org/chromium/chrome/test/util/browser/tabmodel/document/MockActivityDelegate.java",
+    "javatests/src/org/chromium/chrome/test/util/browser/tabmodel/document/MockDocumentTabCreatorManager.java",
+    "javatests/src/org/chromium/chrome/test/util/browser/tabmodel/document/MockStorageDelegate.java",
+    "javatests/src/org/chromium/chrome/test/util/browser/tabmodel/document/MockTabDelegate.java",
+    "javatests/src/org/chromium/chrome/test/util/browser/tabmodel/document/TestInitializationObserver.java",
+    "javatests/src/org/chromium/chrome/test/util/browser/tabmodel/MockTabModel.java",
+    "javatests/src/org/chromium/chrome/test/util/browser/tabmodel/MockTabModelSelector.java",
+    "javatests/src/org/chromium/chrome/test/util/browser/TabTitleObserver.java",
+    "javatests/src/org/chromium/chrome/test/util/ChromeRestriction.java",
+    "javatests/src/org/chromium/chrome/test/util/ChromeSigninUtils.java",
+    "javatests/src/org/chromium/chrome/test/util/ChromeTabUtils.java",
+    "javatests/src/org/chromium/chrome/test/util/DisableInTabbedMode.java",
+    "javatests/src/org/chromium/chrome/test/util/FullscreenTestUtils.java",
+    "javatests/src/org/chromium/chrome/test/util/InfoBarTestAnimationListener.java",
+    "javatests/src/org/chromium/chrome/test/util/InfoBarUtil.java",
+    "javatests/src/org/chromium/chrome/test/util/MenuUtils.java",
+    "javatests/src/org/chromium/chrome/test/util/NewTabPageTestUtils.java",
+    "javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java",
+    "javatests/src/org/chromium/chrome/test/util/OverviewModeBehaviorWatcher.java",
+    "javatests/src/org/chromium/chrome/test/util/parameters/AddFakeAccountToAppParameter.java",
+    "javatests/src/org/chromium/chrome/test/util/parameters/AddFakeAccountToOsParameter.java",
+    "javatests/src/org/chromium/chrome/test/util/parameters/AddGoogleAccountToOsParameter.java",
+    "javatests/src/org/chromium/chrome/test/util/PrerenderTestHelper.java",
+    "javatests/src/org/chromium/chrome/test/util/TabStripUtils.java",
+    "javatests/src/org/chromium/chrome/test/util/TranslateUtil.java",
+  ]
   deps = [
     "//base:base_java",
     "//base:base_java_test_support",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestCaseBase.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestCaseBase.java
index 139aad819..9c812fce 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestCaseBase.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestCaseBase.java
@@ -118,7 +118,6 @@
     }
 
     protected boolean mSkipClearAppData = false;
-    protected boolean mSkipCheckHttpServer = false;
 
     private Thread.UncaughtExceptionHandler mDefaultUncaughtExceptionHandler;
 
@@ -144,8 +143,7 @@
         super.setUp();
         mDefaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
         Thread.setDefaultUncaughtExceptionHandler(new ChromeUncaughtExceptionHandler());
-        ApplicationTestUtils.setUp(
-                getInstrumentation().getTargetContext(), !mSkipClearAppData, !mSkipCheckHttpServer);
+        ApplicationTestUtils.setUp(getInstrumentation().getTargetContext(), !mSkipClearAppData);
         setActivityInitialTouchMode(false);
         startMainActivity();
     }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/MultiActivityTestBase.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/MultiActivityTestBase.java
index 7ad6795..fdf96385 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/MultiActivityTestBase.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/MultiActivityTestBase.java
@@ -139,7 +139,7 @@
         RecordHistogram.disableForTests();
         mContext = getInstrumentation().getTargetContext();
         CommandLineFlags.setUp(mContext, getClass().getMethod(getName()));
-        ApplicationTestUtils.setUp(mContext, true, true);
+        ApplicationTestUtils.setUp(mContext, true);
 
         // Make the DocumentTabModelSelector use a mocked out directory so that test runs don't
         // interfere with each other.
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationTestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationTestUtils.java
index 6ad36689..128b8b4 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationTestUtils.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationTestUtils.java
@@ -32,7 +32,7 @@
 
     // TODO(jbudorick): fix deprecation warning crbug.com/537347
     @SuppressWarnings("deprecation")
-    public static void setUp(Context context, boolean clearAppData, boolean checkHttpServer)
+    public static void setUp(Context context, boolean clearAppData)
             throws Exception {
         if (clearAppData) {
             // Clear data and remove any tasks listed in Android's Overview menu between test runs.
@@ -51,8 +51,6 @@
         // Disable Omaha related activities.
         OmahaClient.setEnableCommunication(false);
         OmahaClient.setEnableUpdateDetection(false);
-
-        if (checkHttpServer) TestHttpServerClient.checkServerIsUp();
     }
 
     public static void tearDown(Context context) throws Exception {
@@ -173,4 +171,4 @@
             }
         }, waitTimeInMs, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/PrerenderTestHelper.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/PrerenderTestHelper.java
index 57b2776..2a7a8ecc 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/PrerenderTestHelper.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/PrerenderTestHelper.java
@@ -78,15 +78,14 @@
     }
 
     /**
-     * Trains the autocomplete action predictor to pre-render a url.
+     * Prerenders a url.
      *
      * @param testUrl Url to prerender
-     * @param testBase ChromeTabbedActivityTestBase instance.
+     * @param tab The tab to add the prerender to.
      */
-    public static ExternalPrerenderHandler prerenderUrlAndFocusOmnibox(
-            final String testUrl, final ChromeTabbedActivityTestBase testBase)
-                    throws InterruptedException {
-        final Tab currentTab = testBase.getActivity().getActivityTab();
+    public static ExternalPrerenderHandler prerenderUrl(final String testUrl, Tab tab)
+            throws InterruptedException {
+        final Tab currentTab = tab;
 
         ExternalPrerenderHandler prerenderHandler = ThreadUtils.runOnUiThreadBlockingNoException(
                 new Callable<ExternalPrerenderHandler>() {
@@ -104,7 +103,6 @@
                     }
                 });
 
-        testBase.typeInOmnibox(testUrl, false);
         Assert.assertTrue("URL was not prerendered.",
                 PrerenderTestHelper.waitForPrerenderUrl(currentTab, testUrl, false));
 
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/TestHttpServerClient.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/TestHttpServerClient.java
deleted file mode 100644
index 4da560b..0000000
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/TestHttpServerClient.java
+++ /dev/null
@@ -1,78 +0,0 @@
-// 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.
-
-package org.chromium.chrome.test.util;
-
-import junit.framework.Assert;
-
-import org.chromium.base.StreamUtil;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
-
-/**
- * A test utility class to get URLs that point to the test HTTP server, and to verify that it is up
- * and giving expected responses to given URLs.
- */
-public final class TestHttpServerClient {
-    private static final int SERVER_PORT = 8000;
-
-    private TestHttpServerClient() {
-    }
-
-    /**
-     * Construct a suitable URL for loading a test data file from the hosts' HTTP server.
-     *
-     * @param path path relative to the document root.
-     * @return an HTTP url.
-     */
-    public static String getUrl(String path) {
-        return "http://localhost:" + SERVER_PORT + "/" + path;
-    }
-
-    /**
-     * Construct a URL for loading a test data file with HTTP authentication fields.
-     *
-     * @param path path relative to the document root.
-     * @return an HTTP url.
-     */
-    public static String getUrl(String path, String username, String password) {
-        return "http://" + username + ":" + password + "@localhost:" + SERVER_PORT + "/" + path;
-    }
-
-    /**
-     * Establishes a connection with the test server at default URL and verifies that it is running.
-     */
-    public static void checkServerIsUp() {
-        checkServerIsUp(getUrl("chrome/test/data/android/ok.txt"), "OK Computer");
-    }
-
-    /**
-     * Establishes a connection with the test server at a given URL and verifies that it is running
-     * by making sure that the expected response is received.
-     */
-    public static void checkServerIsUp(String serverUrl, String expectedResponse) {
-        InputStream is = null;
-        try {
-            URL testUrl = new URL(serverUrl);
-            is = testUrl.openStream();
-            byte[] buffer = new byte[128];
-            int length = is.read(buffer);
-            Assert.assertNotSame("Failed to access test HTTP Server at URL: " + serverUrl,
-                    -1, expectedResponse.length());
-            Assert.assertEquals("Failed to access test HTTP Server at URL: " + serverUrl,
-                    expectedResponse, new String(buffer, 0, length).trim());
-        } catch (MalformedURLException e) {
-            Assert.fail(
-                    "Failed to check test HTTP server at URL: " + serverUrl + ". Status: " + e);
-        } catch (IOException e) {
-            Assert.fail(
-                    "Failed to check test HTTP server at URL: " + serverUrl + ". Status: " + e);
-        } finally {
-            StreamUtil.closeQuietly(is);
-        }
-    }
-}
diff --git a/chrome/test/base/chrome_test_suite.cc b/chrome/test/base/chrome_test_suite.cc
index ff47114b..eb679bae2c 100644
--- a/chrome/test/base/chrome_test_suite.cc
+++ b/chrome/test/base/chrome_test_suite.cc
@@ -22,6 +22,7 @@
 #include "components/content_settings/core/common/content_settings_pattern.h"
 #include "content/public/test/test_launcher.h"
 #include "extensions/common/constants.h"
+#include "media/base/media.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if BUILDFLAG(ANDROID_JAVA_UI)
@@ -37,13 +38,7 @@
 #if defined(OS_MACOSX)
 #include "base/mac/bundle_locations.h"
 #include "base/mac/scoped_nsautorelease_pool.h"
-#if !defined(OS_IOS)
 #include "chrome/browser/chrome_browser_application_mac.h"
-#endif  // !defined(OS_IOS)
-#endif
-
-#if !defined(OS_IOS)
-#include "media/base/media.h"
 #endif
 
 namespace {
@@ -74,9 +69,7 @@
 void ChromeTestSuite::Initialize() {
 #if defined(OS_MACOSX)
   base::mac::ScopedNSAutoreleasePool autorelease_pool;
-#if !defined(OS_IOS)
   chrome_browser_application_mac::RegisterBrowserCrApp();
-#endif  // !defined(OS_IOS)
 #endif
 
   if (!browser_dir_.empty()) {
@@ -89,13 +82,11 @@
       base::android::AttachCurrentThread()));
 #endif
 
-#if !defined(OS_IOS)
   // Disable external libraries load if we are under python process in
   // ChromeOS.  That means we are autotest and, if ASAN is used,
   // external libraries load crashes.
   if (!IsCrosPythonProcess())
     media::InitializeMediaLibrary();
-#endif
 
   // Initialize after overriding paths as some content paths depend on correct
   // values for DIR_EXE and DIR_MODULE.
@@ -104,7 +95,7 @@
   ContentSettingsPattern::SetNonWildcardDomainNonPortScheme(
       extensions::kExtensionScheme);
 
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
   // Look in the framework bundle for resources.
   base::FilePath path;
   PathService::Get(base::DIR_EXE, &path);
@@ -114,7 +105,7 @@
 }
 
 void ChromeTestSuite::Shutdown() {
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
   base::mac::SetOverrideFrameworkBundle(NULL);
 #endif
 
diff --git a/chrome/test/base/chrome_unit_test_suite.cc b/chrome/test/base/chrome_unit_test_suite.cc
index ff1fbb5..5942f49 100644
--- a/chrome/test/base/chrome_unit_test_suite.cc
+++ b/chrome/test/base/chrome_unit_test_suite.cc
@@ -10,6 +10,7 @@
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
 #include "chrome/browser/chrome_content_browser_client.h"
+#include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
 #include "chrome/browser/update_client/chrome_update_query_params_delegate.h"
 #include "chrome/common/chrome_content_client.h"
 #include "chrome/common/chrome_paths.h"
@@ -24,16 +25,12 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/resource/resource_handle.h"
 #include "ui/base/ui_base_paths.h"
+#include "ui/gl/test/gl_surface_test_support.h"
 
 #if defined(OS_CHROMEOS)
 #include "chromeos/chromeos_paths.h"
 #endif
 
-#if !defined(OS_IOS)
-#include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
-#include "ui/gl/test/gl_surface_test_support.h"
-#endif
-
 #if defined(ENABLE_EXTENSIONS)
 #include "chrome/common/extensions/chrome_extensions_client.h"
 #include "extensions/common/extension_paths.h"
@@ -50,23 +47,17 @@
   void OnTestStart(const testing::TestInfo& test_info) override {
     content_client_.reset(new ChromeContentClient);
     content::SetContentClient(content_client_.get());
-    // TODO(ios): Bring this back once ChromeContentBrowserClient is building.
-#if !defined(OS_IOS)
     browser_content_client_.reset(new ChromeContentBrowserClient());
     content::SetBrowserClientForTesting(browser_content_client_.get());
     utility_content_client_.reset(new ChromeContentUtilityClient());
     content::SetUtilityClientForTesting(utility_content_client_.get());
-#endif
 
     TestingBrowserProcess::CreateInstance();
   }
 
   void OnTestEnd(const testing::TestInfo& test_info) override {
-    // TODO(ios): Bring this back once ChromeContentBrowserClient is building.
-#if !defined(OS_IOS)
     browser_content_client_.reset();
     utility_content_client_.reset();
-#endif
     content_client_.reset();
     content::SetContentClient(NULL);
 
@@ -76,11 +67,8 @@
  private:
   // Client implementations for the content module.
   scoped_ptr<ChromeContentClient> content_client_;
-  // TODO(ios): Bring this back once ChromeContentBrowserClient is building.
-#if !defined(OS_IOS)
   scoped_ptr<ChromeContentBrowserClient> browser_content_client_;
   scoped_ptr<ChromeContentUtilityClient> utility_content_client_;
-#endif
 
   DISALLOW_COPY_AND_ASSIGN(ChromeUnitTestSuiteInitializer);
 };
@@ -143,7 +131,6 @@
       extensions::ChromeExtensionsClient::GetInstance());
 #endif
 
-#if !defined(OS_IOS)
   content::WebUIControllerFactory::RegisterFactory(
       ChromeWebUIControllerFactory::GetInstance());
 
@@ -151,7 +138,6 @@
 
   update_client::UpdateQueryParams::SetDelegate(
       ChromeUpdateQueryParamsDelegate::GetInstance());
-#endif
 }
 
 void ChromeUnitTestSuite::InitializeResourceBundle() {
@@ -160,7 +146,7 @@
   ui::ResourceBundle::InitSharedInstanceWithLocale(
       "en-US", NULL, ui::ResourceBundle::LOAD_COMMON_RESOURCES);
   base::FilePath resources_pack_path;
-#if defined(OS_MACOSX) && !defined(OS_IOS)
+#if defined(OS_MACOSX)
   PathService::Get(base::DIR_MODULE, &resources_pack_path);
   resources_pack_path =
       resources_pack_path.Append(FILE_PATH_LITERAL("resources.pak"));
diff --git a/chrome/test/base/dialog_test_browser_window.cc b/chrome/test/base/dialog_test_browser_window.cc
index 7d73785..bf88d63 100644
--- a/chrome/test/base/dialog_test_browser_window.cc
+++ b/chrome/test/base/dialog_test_browser_window.cc
@@ -8,11 +8,22 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "content/public/browser/web_contents.h"
+#include "ui/views/widget/widget.h"
 
 using web_modal::WebContentsModalDialogHost;
 using web_modal::ModalDialogHostObserver;
 
 DialogTestBrowserWindow::DialogTestBrowserWindow() {
+#if defined(OS_MACOSX)
+  // Create a dummy Widget on Mac for parenting dialogs. On Aura, just parent
+  // using the WebContents since creating a Widget here requires an Aura
+  // RootWindow for context and it's tricky to get one here.
+  host_window_.reset(new views::Widget);
+  views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
+  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  host_window_->Init(params);
+  // Leave the window hidden: unit tests shouldn't need it to be visible.
+#endif
 }
 
 DialogTestBrowserWindow::~DialogTestBrowserWindow() {
@@ -27,6 +38,9 @@
 // The web contents modal dialog must be parented to *something*; use the
 // WebContents window since there is no true browser window for unit tests.
 gfx::NativeView DialogTestBrowserWindow::GetHostView() const {
+  if (host_window_)
+    return host_window_->GetNativeView();
+
   return FindBrowser()
       ->tab_strip_model()
       ->GetActiveWebContents()
diff --git a/chrome/test/base/dialog_test_browser_window.h b/chrome/test/base/dialog_test_browser_window.h
index 5b1aa4f..237f1d10 100644
--- a/chrome/test/base/dialog_test_browser_window.h
+++ b/chrome/test/base/dialog_test_browser_window.h
@@ -6,9 +6,14 @@
 #define CHROME_TEST_BASE_DIALOG_TEST_BROWSER_WINDOW_H_
 
 #include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
 #include "chrome/test/base/test_browser_window.h"
 #include "components/web_modal/web_contents_modal_dialog_host.h"
 
+namespace views {
+class Widget;
+}
+
 class Browser;
 
 // Custom test browser window to provide a parent view to a modal dialog.
@@ -32,6 +37,9 @@
  private:
   Browser* FindBrowser() const;
 
+  // Dummy window for parenting dialogs.
+  scoped_ptr<views::Widget> host_window_;
+
   DISALLOW_COPY_AND_ASSIGN(DialogTestBrowserWindow);
 };
 
diff --git a/chrome/test/base/in_process_browser_test.cc b/chrome/test/base/in_process_browser_test.cc
index 0a01a5e1..38b0ba4 100644
--- a/chrome/test/base/in_process_browser_test.cc
+++ b/chrome/test/base/in_process_browser_test.cc
@@ -76,7 +76,7 @@
 #include "chrome/browser/captive_portal/captive_portal_service.h"
 #endif
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
 #include "components/storage_monitor/test_storage_monitor.h"
 #endif
 
@@ -525,7 +525,7 @@
         browser_->tab_strip_model()->GetActiveWebContents());
   }
 
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   // Do not use the real StorageMonitor for tests, which introduces another
   // source of variability and potential slowness.
   ASSERT_TRUE(storage_monitor::TestStorageMonitor::CreateForBrowserTests());
diff --git a/chrome/test/base/test_browser_window.h b/chrome/test/base/test_browser_window.h
index c4261b2..49e7c4a 100644
--- a/chrome/test/base/test_browser_window.h
+++ b/chrome/test/base/test_browser_window.h
@@ -12,6 +12,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/location_bar/location_bar.h"
+#include "chrome/common/features.h"
 
 class LocationBarTesting;
 class OmniboxView;
@@ -108,7 +109,7 @@
                            translate::TranslateStep step,
                            translate::TranslateErrors::Type error_type,
                            bool is_user_gesture) override {}
-#if defined(ENABLE_ONE_CLICK_SIGNIN)
+#if BUILDFLAG(ENABLE_ONE_CLICK_SIGNIN)
   void ShowOneClickSigninBubble(
       OneClickSigninBubbleType type,
       const base::string16& email,
diff --git a/chrome/test/base/testing_browser_process.cc b/chrome/test/base/testing_browser_process.cc
index b52f0cc..2d76f126 100644
--- a/chrome/test/base/testing_browser_process.cc
+++ b/chrome/test/base/testing_browser_process.cc
@@ -9,8 +9,10 @@
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_impl.h"
+#include "chrome/browser/notifications/notification_ui_manager.h"
 #include "chrome/browser/printing/print_job_manager.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/test/base/testing_browser_process_platform_part.h"
 #include "components/network_time/network_time_tracker.h"
 #include "components/prefs/pref_service.h"
@@ -19,10 +21,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/message_center/message_center.h"
 
-#if !defined(OS_IOS)
-#include "chrome/browser/notifications/notification_ui_manager.h"
-#include "chrome/browser/safe_browsing/safe_browsing_service.h"
-#endif
 
 #if defined(ENABLE_BACKGROUND)
 #include "chrome/browser/background/background_mode_manager.h"
@@ -125,16 +123,10 @@
 }
 
 ProfileManager* TestingBrowserProcess::profile_manager() {
-#if defined(OS_IOS)
-  NOTIMPLEMENTED();
-  return nullptr;
-#else
   return profile_manager_.get();
-#endif
 }
 
 void TestingBrowserProcess::SetProfileManager(ProfileManager* profile_manager) {
-#if !defined(OS_IOS)
   // NotificationUIManager can contain references to elements in the current
   // ProfileManager (for example, the MessageCenterSettingsController maintains
   // a pointer to the ProfileInfoCache). So when we change the ProfileManager
@@ -143,7 +135,6 @@
   // similar situation.
   notification_ui_manager_.reset();
   profile_manager_.reset(profile_manager);
-#endif
 }
 
 PrefService* TestingBrowserProcess::local_state() {
@@ -174,10 +165,7 @@
 }
 
 policy::PolicyService* TestingBrowserProcess::policy_service() {
-#if defined(OS_IOS)
-  NOTIMPLEMENTED();
-  return nullptr;
-#elif defined(ENABLE_CONFIGURATION_POLICY)
+#if defined(ENABLE_CONFIGURATION_POLICY)
   return browser_policy_connector()->GetPolicyService();
 #else
   if (!policy_service_)
@@ -213,12 +201,7 @@
 
 safe_browsing::SafeBrowsingService*
 TestingBrowserProcess::safe_browsing_service() {
-#if defined(OS_IOS)
-  NOTIMPLEMENTED();
-  return nullptr;
-#else
   return sb_service_.get();
-#endif
 }
 
 safe_browsing::ClientSideDetectionService*
@@ -359,7 +342,7 @@
 }
 
 MediaFileSystemRegistry* TestingBrowserProcess::media_file_system_registry() {
-#if defined(OS_IOS) || defined(OS_ANDROID)
+#if defined(OS_ANDROID)
   NOTIMPLEMENTED();
   return nullptr;
 #else
@@ -424,9 +407,7 @@
     // any components owned by TestingBrowserProcess that depend on local_state
     // are also freed.
     network_time_tracker_.reset();
-#if !defined(OS_IOS)
     notification_ui_manager_.reset();
-#endif
 #if defined(ENABLE_CONFIGURATION_POLICY)
     ShutdownBrowserPolicyConnector();
     created_browser_policy_connector_ = false;
@@ -451,11 +432,7 @@
 
 void TestingBrowserProcess::SetSafeBrowsingService(
     safe_browsing::SafeBrowsingService* sb_service) {
-#if defined(OS_IOS)
-  NOTIMPLEMENTED();
-#else
   sb_service_ = sb_service;
-#endif
 }
 
 void TestingBrowserProcess::SetRapporService(
diff --git a/chrome/test/base/testing_browser_process.h b/chrome/test/base/testing_browser_process.h
index 6613c65..99e5dcfc 100644
--- a/chrome/test/base/testing_browser_process.h
+++ b/chrome/test/base/testing_browser_process.h
@@ -150,8 +150,6 @@
   unsigned int module_ref_count_;
   std::string app_locale_;
 
-  // TODO(ios): Add back members as more code is compiled.
-#if !defined(OS_IOS)
 #if defined(ENABLE_CONFIGURATION_POLICY)
   scoped_ptr<policy::BrowserPolicyConnector> browser_policy_connector_;
   bool created_browser_policy_connector_ = false;
@@ -172,7 +170,6 @@
 #endif
 
   scoped_refptr<safe_browsing::SafeBrowsingService> sb_service_;
-#endif  // !defined(OS_IOS)
 
   scoped_ptr<network_time::NetworkTimeTracker> network_time_tracker_;
 
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index 88ff0672..defda283 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -40,6 +40,7 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/storage_partition_descriptor.h"
 #include "chrome/browser/search_engines/template_url_fetcher_factory.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/sync/glue/sync_start_util.h"
 #include "chrome/browser/ui/zoom/chrome_zoom_level_prefs.h"
 #include "chrome/browser/web_data_service_factory.h"
@@ -199,6 +200,7 @@
       BookmarkModelFactory::GetForProfile(profile),
       HistoryServiceFactory::GetForProfile(profile,
                                            ServiceAccessType::IMPLICIT_ACCESS),
+      TemplateURLServiceFactory::GetForProfile(profile),
       content::BrowserThread::GetBlockingPool(), profile->GetPath(),
       profile->GetPrefs()->GetString(prefs::kAcceptLanguages),
       SchemeSet()));
diff --git a/chrome/test/base/testing_profile_manager.cc b/chrome/test/base/testing_profile_manager.cc
index 2727a7d..1f363318 100644
--- a/chrome/test/base/testing_profile_manager.cc
+++ b/chrome/test/base/testing_profile_manager.cc
@@ -216,7 +216,7 @@
 }
 
 void TestingProfileManager::UpdateLastUser(Profile* last_active) {
-#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#if !defined(OS_ANDROID)
   profile_manager_->UpdateLastUser(last_active);
 #endif
 }
diff --git a/chrome/test/chromedriver/capabilities.cc b/chrome/test/chromedriver/capabilities.cc
index e9fe8402..3e0edd1 100644
--- a/chrome/test/chromedriver/capabilities.cc
+++ b/chrome/test/chromedriver/capabilities.cc
@@ -22,7 +22,6 @@
 #include "chrome/test/chromedriver/chrome/mobile_device.h"
 #include "chrome/test/chromedriver/chrome/status.h"
 #include "chrome/test/chromedriver/logging.h"
-#include "net/base/net_util.h"
 
 namespace {
 
diff --git a/chrome/test/chromedriver/chrome/javascript_dialog_manager.cc b/chrome/test/chromedriver/chrome/javascript_dialog_manager.cc
index a1b1631f..f95d517 100644
--- a/chrome/test/chromedriver/chrome/javascript_dialog_manager.cc
+++ b/chrome/test/chromedriver/chrome/javascript_dialog_manager.cc
@@ -15,7 +15,7 @@
 
 JavaScriptDialogManager::~JavaScriptDialogManager() {}
 
-bool JavaScriptDialogManager::IsDialogOpen() {
+bool JavaScriptDialogManager::IsDialogOpen() const {
   return !unhandled_dialog_queue_.empty();
 }
 
diff --git a/chrome/test/chromedriver/chrome/javascript_dialog_manager.h b/chrome/test/chromedriver/chrome/javascript_dialog_manager.h
index 489544c6..598e1b45 100644
--- a/chrome/test/chromedriver/chrome/javascript_dialog_manager.h
+++ b/chrome/test/chromedriver/chrome/javascript_dialog_manager.h
@@ -25,7 +25,7 @@
   explicit JavaScriptDialogManager(DevToolsClient* client);
   ~JavaScriptDialogManager() override;
 
-  bool IsDialogOpen();
+  bool IsDialogOpen() const;
 
   Status GetDialogMessage(std::string* message);
 
diff --git a/chrome/test/chromedriver/chrome/navigation_tracker.cc b/chrome/test/chromedriver/chrome/navigation_tracker.cc
index a0f26a8..4af1a919 100644
--- a/chrome/test/chromedriver/chrome/navigation_tracker.cc
+++ b/chrome/test/chromedriver/chrome/navigation_tracker.cc
@@ -8,6 +8,7 @@
 #include "base/values.h"
 #include "chrome/test/chromedriver/chrome/browser_info.h"
 #include "chrome/test/chromedriver/chrome/devtools_client.h"
+#include "chrome/test/chromedriver/chrome/javascript_dialog_manager.h"
 #include "chrome/test/chromedriver/chrome/status.h"
 
 namespace {
@@ -18,23 +19,29 @@
 
 }  // namespace
 
-NavigationTracker::NavigationTracker(DevToolsClient* client,
-                                     const BrowserInfo* browser_info)
+NavigationTracker::NavigationTracker(
+    DevToolsClient* client,
+    const BrowserInfo* browser_info,
+    const JavaScriptDialogManager* dialog_manager)
     : client_(client),
       loading_state_(kUnknown),
       browser_info_(browser_info),
+      dialog_manager_(dialog_manager),
       dummy_execution_context_id_(0),
       load_event_fired_(true),
       timed_out_(false) {
   client_->AddListener(this);
 }
 
-NavigationTracker::NavigationTracker(DevToolsClient* client,
-                                     LoadingState known_state,
-                                     const BrowserInfo* browser_info)
+NavigationTracker::NavigationTracker(
+    DevToolsClient* client,
+    LoadingState known_state,
+    const BrowserInfo* browser_info,
+    const JavaScriptDialogManager* dialog_manager)
     : client_(client),
       loading_state_(known_state),
       browser_info_(browser_info),
+      dialog_manager_(dialog_manager),
       dummy_execution_context_id_(0),
       load_event_fired_(true),
       timed_out_(false) {
@@ -63,6 +70,13 @@
       // events from it until we reconnect.
       *is_pending = false;
       return Status(kOk);
+    } else if (status.IsError() && dialog_manager_->IsDialogOpen()) {
+      // When a dialog is open, DevTools returns "Internal error: result is not
+      // an Object" for this request. If this happens, we assume that we're
+      // talking to the right renderer process, and determine whether a
+      // navigation is pending based on the number of scheduled and pending
+      // frames.
+      LOG(WARNING) << "Failed to evaluate expression while dialog was open";
     } else if (status.IsError() ||
                !result->GetInteger("result.value", &value) ||
                value != 1) {
diff --git a/chrome/test/chromedriver/chrome/navigation_tracker.h b/chrome/test/chromedriver/chrome/navigation_tracker.h
index b48dad4..5e9661246 100644
--- a/chrome/test/chromedriver/chrome/navigation_tracker.h
+++ b/chrome/test/chromedriver/chrome/navigation_tracker.h
@@ -20,6 +20,7 @@
 
 struct BrowserInfo;
 class DevToolsClient;
+class JavaScriptDialogManager;
 class Status;
 
 // Tracks the navigation state of the page.
@@ -31,11 +32,14 @@
     kNotLoading,
   };
 
-  NavigationTracker(DevToolsClient* client, const BrowserInfo* browser_info);
+  NavigationTracker(DevToolsClient* client,
+                    const BrowserInfo* browser_info,
+                    const JavaScriptDialogManager* dialog_manager);
 
   NavigationTracker(DevToolsClient* client,
                     LoadingState known_state,
-                    const BrowserInfo* browser_info);
+                    const BrowserInfo* browser_info,
+                    const JavaScriptDialogManager* dialog_manager);
 
   ~NavigationTracker() override;
 
@@ -58,6 +62,7 @@
   DevToolsClient* client_;
   LoadingState loading_state_;
   const BrowserInfo* browser_info_;
+  const JavaScriptDialogManager* dialog_manager_;
   std::set<std::string> pending_frame_set_;
   std::set<std::string> scheduled_frame_set_;
   std::set<int> execution_context_set_;
diff --git a/chrome/test/chromedriver/chrome/navigation_tracker_unittest.cc b/chrome/test/chromedriver/chrome/navigation_tracker_unittest.cc
index d929b93..5c55f4c9 100644
--- a/chrome/test/chromedriver/chrome/navigation_tracker_unittest.cc
+++ b/chrome/test/chromedriver/chrome/navigation_tracker_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/json/json_reader.h"
 #include "base/values.h"
 #include "chrome/test/chromedriver/chrome/browser_info.h"
+#include "chrome/test/chromedriver/chrome/javascript_dialog_manager.h"
 #include "chrome/test/chromedriver/chrome/navigation_tracker.h"
 #include "chrome/test/chromedriver/chrome/status.h"
 #include "chrome/test/chromedriver/chrome/stub_devtools_client.h"
@@ -60,10 +61,12 @@
     }
 
     if (send_event_first_.length()) {
-      Status status = listeners_.front()
-          ->OnEvent(this, send_event_first_, *send_event_first_params_);
-      if (status.IsError())
-        return status;
+      for (DevToolsEventListener* listener : listeners_) {
+        Status status = listener->OnEvent(
+            this, send_event_first_, *send_event_first_params_);
+        if (status.IsError())
+          return status;
+      }
     }
 
     base::DictionaryValue result_dict;
@@ -85,7 +88,8 @@
   base::DictionaryValue dict;
   DeterminingLoadStateDevToolsClient client(false, true, std::string(), &dict);
   BrowserInfo browser_info;
-  NavigationTracker tracker(&client, &browser_info);
+  JavaScriptDialogManager dialog_manager(&client);
+  NavigationTracker tracker(&client, &browser_info, &dialog_manager);
 
   base::DictionaryValue params;
   params.SetString("frameId", "f");
@@ -105,7 +109,8 @@
   base::DictionaryValue dict;
   DeterminingLoadStateDevToolsClient client(false, true, std::string(), &dict);
   BrowserInfo browser_info;
-  NavigationTracker tracker(&client, &browser_info);
+  JavaScriptDialogManager dialog_manager(&client);
+  NavigationTracker tracker(&client, &browser_info, &dialog_manager);
 
   base::DictionaryValue params;
   params.SetString("frameId", "f");
@@ -125,7 +130,8 @@
   base::DictionaryValue dict;
   DeterminingLoadStateDevToolsClient client(false, true, std::string(), &dict);
   BrowserInfo browser_info;
-  NavigationTracker tracker(&client, &browser_info);
+  JavaScriptDialogManager dialog_manager(&client);
+  NavigationTracker tracker(&client, &browser_info, &dialog_manager);
   base::DictionaryValue params;
 
   // pending_frames_set_.size() == 0
@@ -164,8 +170,9 @@
   base::DictionaryValue dict;
   DeterminingLoadStateDevToolsClient client(false, true, std::string(), &dict);
   BrowserInfo browser_info;
+  JavaScriptDialogManager dialog_manager(&client);
   NavigationTracker tracker(
-      &client, NavigationTracker::kNotLoading, &browser_info);
+      &client, NavigationTracker::kNotLoading, &browser_info, &dialog_manager);
   base::DictionaryValue params;
   params.SetString("frameId", "f");
   base::DictionaryValue params_scheduled;
@@ -194,8 +201,9 @@
   base::DictionaryValue dict;
   DeterminingLoadStateDevToolsClient client(false, true, std::string(), &dict);
   BrowserInfo browser_info;
+  JavaScriptDialogManager dialog_manager(&client);
   NavigationTracker tracker(
-      &client, NavigationTracker::kNotLoading, &browser_info);
+      &client, NavigationTracker::kNotLoading, &browser_info, &dialog_manager);
   base::DictionaryValue params_scheduled;
   params_scheduled.SetInteger("delay", 0);
   params_scheduled.SetString("frameId", "other");
@@ -211,8 +219,9 @@
   base::DictionaryValue dict;
   DeterminingLoadStateDevToolsClient client(false, true, std::string(), &dict);
   BrowserInfo browser_info;
+  JavaScriptDialogManager dialog_manager(&client);
   NavigationTracker tracker(
-      &client, NavigationTracker::kNotLoading, &browser_info);
+      &client, NavigationTracker::kNotLoading, &browser_info, &dialog_manager);
   base::DictionaryValue params;
   params.SetString("frameId", "f");
   base::DictionaryValue params_scheduled;
@@ -235,8 +244,9 @@
   base::DictionaryValue dict;
   DeterminingLoadStateDevToolsClient client(false, true, std::string(), &dict);
   BrowserInfo browser_info;
+  JavaScriptDialogManager dialog_manager(&client);
   NavigationTracker tracker(
-      &client, NavigationTracker::kNotLoading, &browser_info);
+      &client, NavigationTracker::kNotLoading, &browser_info, &dialog_manager);
 
   base::DictionaryValue params_scheduled;
   params_scheduled.SetInteger("delay", 10);
@@ -252,8 +262,9 @@
   base::DictionaryValue dict;
   DeterminingLoadStateDevToolsClient client(false, true, std::string(), &dict);
   BrowserInfo browser_info;
+  JavaScriptDialogManager dialog_manager(&client);
   NavigationTracker tracker(
-      &client, NavigationTracker::kNotLoading, &browser_info);
+      &client, NavigationTracker::kNotLoading, &browser_info, &dialog_manager);
 
   base::DictionaryValue params_scheduled;
   params_scheduled.SetString("frameId", "subframe");
@@ -311,7 +322,8 @@
 TEST(NavigationTracker, UnknownStateFailsToDetermineState) {
   FailToEvalScriptDevToolsClient client;
   BrowserInfo browser_info;
-  NavigationTracker tracker(&client, &browser_info);
+  JavaScriptDialogManager dialog_manager(&client);
+  NavigationTracker tracker(&client, &browser_info, &dialog_manager);
   bool is_pending;
   ASSERT_EQ(kUnknownError,
             tracker.IsPendingNavigation("f", &is_pending).code());
@@ -322,7 +334,8 @@
   DeterminingLoadStateDevToolsClient client(
       true, true, std::string(), &params);
   BrowserInfo browser_info;
-  NavigationTracker tracker(&client, &browser_info);
+  JavaScriptDialogManager dialog_manager(&client);
+  NavigationTracker tracker(&client, &browser_info, &dialog_manager);
   ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", true));
 }
 
@@ -331,7 +344,8 @@
   DeterminingLoadStateDevToolsClient client(
       false, true, std::string(), &params);
   BrowserInfo browser_info;
-  NavigationTracker tracker(&client, &browser_info);
+  JavaScriptDialogManager dialog_manager(&client);
+  NavigationTracker tracker(&client, &browser_info, &dialog_manager);
   ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", true));
 }
 
@@ -341,7 +355,8 @@
   DeterminingLoadStateDevToolsClient client(
       false, true, "Page.frameStoppedLoading", &params);
   BrowserInfo browser_info;
-  NavigationTracker tracker(&client, &browser_info);
+  JavaScriptDialogManager dialog_manager(&client);
+  NavigationTracker tracker(&client, &browser_info, &dialog_manager);
   ASSERT_NO_FATAL_FAILURE(AssertPendingState(&tracker, "f", false));
 }
 
@@ -353,8 +368,9 @@
   std::string version_string = "{\"Browser\": \"Chrome/44.0.2403.125\","
                                " \"WebKit-Version\": \"537.36 (@199461)\"}";
   ASSERT_TRUE(ParseBrowserInfo(version_string, &browser_info).IsOk());
+  JavaScriptDialogManager dialog_manager(&client);
   NavigationTracker tracker(
-      &client, NavigationTracker::kNotLoading, &browser_info);
+      &client, NavigationTracker::kNotLoading, &browser_info, &dialog_manager);
   base::DictionaryValue result;
   result.SetString("frameId", "f");
   tracker.OnCommandSuccess(&client, "Page.navigate", result);
diff --git a/chrome/test/chromedriver/chrome/web_view_impl.cc b/chrome/test/chromedriver/chrome/web_view_impl.cc
index 39446d9..23b13a6 100644
--- a/chrome/test/chromedriver/chrome/web_view_impl.cc
+++ b/chrome/test/chromedriver/chrome/web_view_impl.cc
@@ -125,8 +125,10 @@
       browser_info_(browser_info),
       dom_tracker_(new DomTracker(client.get())),
       frame_tracker_(new FrameTracker(client.get())),
-      navigation_tracker_(new NavigationTracker(client.get(), browser_info)),
       dialog_manager_(new JavaScriptDialogManager(client.get())),
+      navigation_tracker_(new NavigationTracker(client.get(),
+                                                browser_info,
+                                                dialog_manager_.get())),
       mobile_emulation_override_manager_(
           new MobileEmulationOverrideManager(client.get(), device_metrics)),
       geolocation_override_manager_(
diff --git a/chrome/test/chromedriver/chrome/web_view_impl.h b/chrome/test/chromedriver/chrome/web_view_impl.h
index ba639b7..f2faa90 100644
--- a/chrome/test/chromedriver/chrome/web_view_impl.h
+++ b/chrome/test/chromedriver/chrome/web_view_impl.h
@@ -126,8 +126,8 @@
   const BrowserInfo* browser_info_;
   scoped_ptr<DomTracker> dom_tracker_;
   scoped_ptr<FrameTracker> frame_tracker_;
-  scoped_ptr<NavigationTracker> navigation_tracker_;
   scoped_ptr<JavaScriptDialogManager> dialog_manager_;
+  scoped_ptr<NavigationTracker> navigation_tracker_;
   scoped_ptr<MobileEmulationOverrideManager> mobile_emulation_override_manager_;
   scoped_ptr<GeolocationOverrideManager> geolocation_override_manager_;
   scoped_ptr<NetworkConditionsOverrideManager>
diff --git a/chrome/test/chromedriver/net/adb_client_socket.cc b/chrome/test/chromedriver/net/adb_client_socket.cc
index caa31d3..f772f5fc 100644
--- a/chrome/test/chromedriver/net/adb_client_socket.cc
+++ b/chrome/test/chromedriver/net/adb_client_socket.cc
@@ -15,7 +15,6 @@
 #include "net/base/address_list.h"
 #include "net/base/completion_callback.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/socket/tcp_client_socket.h"
 
 namespace {
diff --git a/chrome/test/chromedriver/net/port_server.cc b/chrome/test/chromedriver/net/port_server.cc
index 391415f7..d496a0b 100644
--- a/chrome/test/chromedriver/net/port_server.cc
+++ b/chrome/test/chromedriver/net/port_server.cc
@@ -18,7 +18,6 @@
 #include "build/build_config.h"
 #include "chrome/test/chromedriver/chrome/status.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/sys_addrinfo.h"
 #include "net/log/net_log.h"
 #include "net/socket/tcp_server_socket.h"
diff --git a/chrome/test/chromedriver/net/websocket.cc b/chrome/test/chromedriver/net/websocket.cc
index 096191e..38272a9 100644
--- a/chrome/test/chromedriver/net/websocket.cc
+++ b/chrome/test/chromedriver/net/websocket.cc
@@ -22,7 +22,6 @@
 #include "net/base/io_buffer.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/sys_addrinfo.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_util.h"
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index 09ba0f7..4edca008 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -18,6 +18,7 @@
 import threading
 import time
 import unittest
+import urllib
 import urllib2
 import uuid
 
@@ -1216,6 +1217,20 @@
     self._driver.Load('http://invalid./')
     self.assertEquals('http://invalid./', self._driver.GetCurrentUrl())
 
+  def testCanClickAlertInIframes(self):
+    # This test requires that the page be loaded from a file:// URI, rather than
+    # the test HTTP server.
+    path = os.path.join(chrome_paths.GetTestData(), 'chromedriver',
+      'page_with_frame.html')
+    url = 'file://' + urllib.pathname2url(path)
+    self._driver.Load(url)
+    frame = self._driver.FindElement('id', 'frm')
+    self._driver.SwitchToFrame(frame)
+    a = self._driver.FindElement('id', 'btn')
+    a.Click()
+    self.WaitForCondition(lambda: self._driver.IsAlertOpen())
+    self._driver.HandleAlert(False)
+
 
 class ChromeDriverAndroidTest(ChromeDriverBaseTest):
   """End to end tests for Android-specific tests."""
diff --git a/chrome/test/data/chromedriver/frame_with_button.html b/chrome/test/data/chromedriver/frame_with_button.html
new file mode 100644
index 0000000..a582262
--- /dev/null
+++ b/chrome/test/data/chromedriver/frame_with_button.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <button id="btn" onclick="alert('this is an alert')">alert</button>
+  </body>
+</html>
diff --git a/chrome/test/data/chromedriver/page_with_frame.html b/chrome/test/data/chromedriver/page_with_frame.html
new file mode 100644
index 0000000..3673cd59
--- /dev/null
+++ b/chrome/test/data/chromedriver/page_with_frame.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <iframe id="frm" width="200" height="200" src="frame_with_button.html">
+    </iframe>
+  </body>
+</html>
diff --git a/chrome/test/data/extensions/api_test/file_browser/app_file_handler_multi/manifest.json b/chrome/test/data/extensions/api_test/file_browser/app_file_handler_multi/manifest.json
index 2642a752..8fde887 100644
--- a/chrome/test/data/extensions/api_test/file_browser/app_file_handler_multi/manifest.json
+++ b/chrome/test/data/extensions/api_test/file_browser/app_file_handler_multi/manifest.json
@@ -12,7 +12,8 @@
   },
   "file_handlers": {
     "textAction": {
-      "extensions": ["txt"]
+      "extensions": ["txt"],
+      "include_directories": true
     }
   },
   "permissions": [
diff --git a/chrome/test/data/extensions/api_test/file_browser/app_file_handler_multi/test.js b/chrome/test/data/extensions/api_test/file_browser/app_file_handler_multi/test.js
index b37a663..4dd2c99 100644
--- a/chrome/test/data/extensions/api_test/file_browser/app_file_handler_multi/test.js
+++ b/chrome/test/data/extensions/api_test/file_browser/app_file_handler_multi/test.js
@@ -52,6 +52,22 @@
 }
 
 /**
+ * Prepares a directory on the file system.
+ * @param {FileSystem} filesystem File system.
+ * @param {string} name Name of the directory.
+ * @param {Blob} contents Contents of the file.
+ * @return {Promise} Promise to be fulfilled with DirectoryEntry of the new
+ *     directory.
+ */
+function prepareDirectory(filesystem, name) {
+  return new Promise(function(fulfill, reject) {
+    filesystem.root.getDirectory(name, {create: true}, function(dirEntry) {
+      fulfill(dirEntry);
+    }, reject);
+  });
+}
+
+/**
  * Prepares two test files on the file system.
  * @param {FileSystem} filesystem File system.
  * @return {Promise} Promise to be fullfilled with an object {filesystem:
@@ -69,6 +85,21 @@
 }
 
 /**
+ * Prepares two test directories on the file system.
+ * @param {FileSystem} filesystem File system.
+ * @return {Promise} Promise to be fullfilled with an object {filesystem:
+ *     FileSystem, entries: Array<DirectoryEntry>} that contains the passed file
+ *     system and the created entries.
+ */
+function prepareDirectories(filesystem) {
+  var testDirA = prepareDirectory(filesystem, 'dir1');
+  var testDirB = prepareDirectory(filesystem, 'dir2');
+  return Promise.all([testDirA, testDirB]).then(function(entries) {
+    return {filesystem: filesystem, entries: entries};
+  });
+}
+
+/**
  * Contents of the test file.
  * @type {Blob}
  * @const
@@ -76,18 +107,30 @@
 var TEST_FILE_CONTENTS = new Blob(['This is a test file.']);
 
 /**
- * File system of the drive volume.
+ * File system of the drive volume for files.
  * @type {Promise}
  */
 var driveFileSystemPromise = getFileSystem('drive').then(prepareFiles);
 
 /**
- * File system of the local volume.
+ * File system of the local volume for files.
  * @type {Promise}
  */
 var localFileSystemPromise = getFileSystem('testing').then(prepareFiles);
 
 /**
+ * File system of the drive volume for directories.
+ * @type {Promise}
+ */
+var driveDirSystemPromise = getFileSystem('drive').then(prepareDirectories);
+
+/**
+ * File system of the local volume for directories.
+ * @type {Promise}
+ */
+var localDirSystemPromise = getFileSystem('drive').then(prepareDirectories);
+
+/**
  * Calls test functions depends on the result of the promise.
  * @param {Promise} promise Promise to be fulfilled or to be rejected depends on
  *     the test results.
@@ -195,14 +238,34 @@
 }
 
 /**
- * Tests the file handler with entries both on the local and on the drive
- * volumes.
+ * Tests the directory handler feature with entries on the local volume.
  */
-function testForMixedFiles() {
+function testForLocalDirectories() {
+  testPromise(localDirSystemPromise.then(function(volume) {
+    return launchWithEntries(volume.entries);
+  }));
+}
+
+/**
+ * Tests the directory handler feature with entries on the local volume.
+ */
+function testForDriveDirectories() {
+  testPromise(driveDirSystemPromise.then(function(volume) {
+    return launchWithEntries(volume.entries);
+  }));
+}
+
+/**
+ * Tests the file and directory handler with entries both on the local and on
+ * the drive volumes.
+ */
+function testForMixedFilesAndDirectories() {
   testPromise(
-      Promise.all([localFileSystemPromise, driveFileSystemPromise]).then(
+      Promise.all([localFileSystemPromise, driveFileSystemPromise,
+                   localDirSystemPromise, driveDirSystemPromise]).then(
           function(args) {
-            return launchWithEntries(args[0].entries.concat(args[1].entries));
+            return launchWithEntries(args[0].entries.concat(args[1].entries)
+                .concat(args[2].entries).concat(args[3].entries));
           }));
 }
 
@@ -210,5 +273,7 @@
 chrome.test.runTests([
   testForLocalFiles,
   testForDriveFiles,
-  testForMixedFiles
+  testForLocalDirectories,
+  testForDriveDirectories,
+  testForMixedFilesAndDirectories,
 ]);
diff --git a/chrome/test/data/local_ntp_browsertest.js b/chrome/test/data/local_ntp_browsertest.js
index a7b6640c..62a673b 100644
--- a/chrome/test/data/local_ntp_browsertest.js
+++ b/chrome/test/data/local_ntp_browsertest.js
@@ -101,7 +101,8 @@
     navigateContentWindowCalls++;
   }
 
-  var params = {};
+  // Most Visited links have an rid (restricted id).
+  var params = { 'rid' : 1 };
   var href = 'file:///some/local/file';
   var title = 'Title';
   var text = 'text';
@@ -113,3 +114,30 @@
   ntpHandle.navigateContentWindow = originalNavigateContentWindow;
   assert(navigateContentWindowCalls > 0);
 }
+
+
+/**
+ * Tests that clicking on a Most Likely link does not call
+ * navigateContentWindow (it's a regular link).
+ */
+function testMostLikelyLinkDoesNotCallNavigateContentWindow() {
+  var ntpHandle = chrome.embeddedSearch.newTabPage;
+  var originalNavigateContentWindow = ntpHandle.navigateContentWindow;
+
+  var navigateContentWindowCalls = 0;
+  ntpHandle.navigateContentWindow = function() {
+    navigateContentWindowCalls++;
+  }
+
+  var params = {};
+  var href = 'https://www.site.com';
+  var title = 'Title';
+  var text = 'text';
+  var provider = 'foobar';
+  var link = createMostVisitedLink(params, href, title, text, provider);
+
+  link.click();
+
+  ntpHandle.navigateContentWindow = originalNavigateContentWindow;
+  assert(navigateContentWindowCalls == 0);
+}
diff --git a/chrome/test/data/permissions/killswitch_tester.html b/chrome/test/data/permissions/killswitch_tester.html
new file mode 100644
index 0000000..7169a9878
--- /dev/null
+++ b/chrome/test/data/permissions/killswitch_tester.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<!--killswitch_tester.html
+Script with javascript functions for requesting notification and geolocation
+permissions.
+-->
+<script>
+function requestGeolocation() {
+  navigator.geolocation.getCurrentPosition(function(){}, geoErrorCallback);
+}
+
+function requestNotification() {
+  Notification.requestPermission(notificationCallback);
+}
+
+function geoErrorCallback(error) {
+  switch(error.code) {
+    case error.PERMISSION_DENIED:
+      sendResultToTest("denied");
+      break;
+    default:
+      sendResultToTest(error.code);
+  }
+}
+
+function notificationCallback(status) {
+  sendResultToTest(status);
+}
+
+// Sends a result back to the main test logic.
+function sendResultToTest(result) {
+  // Convert the result to a string.
+  var stringResult = "" + result;
+  if (typeof stringResult != "string")
+    stringResult = JSON.stringify(result);
+  window.domAutomationController.send(stringResult);
+}
+</script>
+<body>
+</body>
+</html>
diff --git a/chrome/test/data/webui/promise_resolver.js b/chrome/test/data/webui/promise_resolver.js
new file mode 100644
index 0000000..0c0e226
--- /dev/null
+++ b/chrome/test/data/webui/promise_resolver.js
@@ -0,0 +1,34 @@
+// Copyright 2016 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.
+
+/**
+ * @fileoverview PromiseResolver is a helper class that allows creating a
+ * Promise that will be fulfilled (resolved or rejected) some time later.
+ *
+ * Example:
+ *  var resolver = new PromiseResolver();
+ *  resolver.promise.then(function(result) {
+ *    console.log('resolved with', result);
+ *  });
+ *  ...
+ *  ...
+ *  resolver.resolve({hello: 'world'});
+ */
+
+/**
+ * @constructor
+ */
+function PromiseResolver() {
+  /** @type {!Function} */
+  this.resolve;
+
+  /** @type {!Function} */
+  this.reject;
+
+  /** @type {!Promise} */
+  this.promise = new Promise(function(resolve, reject) {
+    this.resolve = resolve;
+    this.reject = reject;
+  }.bind(this));
+}
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index a82d8a72..93f72a6 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -115,6 +115,7 @@
 
   /** @override */
   extraLibraries: PolymerTest.getLibraries(ROOT_PATH).concat([
+    '../promise_resolver.js',
     'search_engines_page_test.js',
   ]),
 };
diff --git a/chrome/test/data/webui/settings/search_engines_page_test.js b/chrome/test/data/webui/settings/search_engines_page_test.js
index 48042bcc..f1f623a 100644
--- a/chrome/test/data/webui/settings/search_engines_page_test.js
+++ b/chrome/test/data/webui/settings/search_engines_page_test.js
@@ -4,18 +4,6 @@
 
 cr.define('settings_search_engines_page', function() {
   /**
-   * TODO(dpapad): Similar class exists in webui_resource_async_browsertest.js.
-   * Move somewhere else and re-use.
-   * @constructor
-   */
-  var PromiseResolver = function() {
-    this.promise = new Promise(function(resolve, reject) {
-      this.resolve = resolve;
-      this.reject = reject;
-    }.bind(this));
-  };
-
-  /**
    * A test version of SearchEnginesBrowserProxy. Provides helper methods
    * for allowing tests to know when a method was called, as well as
    * specifying mock responses.
diff --git a/chrome/test/data/webui/webui_resource_async_browsertest.js b/chrome/test/data/webui/webui_resource_async_browsertest.js
index 30916a09..81baa17 100644
--- a/chrome/test/data/webui/webui_resource_async_browsertest.js
+++ b/chrome/test/data/webui/webui_resource_async_browsertest.js
@@ -35,6 +35,7 @@
   extraLibraries: [
     ROOT_PATH + 'third_party/mocha/mocha.js',
     ROOT_PATH + 'chrome/test/data/webui/mocha_adapter.js',
+    ROOT_PATH + 'chrome/test/data/webui/promise_resolver.js',
     ROOT_PATH + 'ui/webui/resources/js/cr.js',
   ],
 };
@@ -153,14 +154,6 @@
     });
 
     test('addWebUIListener_MulitpleListeners', function() {
-      /** @constructor */
-      var PromiseResolver = function() {
-        this.promise = new Promise(function(resolve, reject) {
-          this.resolve = resolve;
-          this.reject = reject;
-        }.bind(this));
-      };
-
       var resolver1 = new PromiseResolver();
       var resolver2 = new PromiseResolver();
       listener1 = cr.addWebUIListener(EVENT_NAME, resolver1.resolve);
diff --git a/chrome/test/media_router/e2e_tests.gyp b/chrome/test/media_router/e2e_tests.gyp
index 56aad73..fd7a1eb 100644
--- a/chrome/test/media_router/e2e_tests.gyp
+++ b/chrome/test/media_router/e2e_tests.gyp
@@ -19,6 +19,19 @@
             'media_router_tests.isolate',
           ],
         },  # target_name: 'media_router_e2e_tests_run'
+        {
+          'target_name': 'media_router_perf_tests_run',
+          'type': 'none',
+          'dependencies': [
+            '../../chrome.gyp:chrome',
+          ],
+          'includes': [
+            '../../../build/isolate.gypi',
+          ],
+          'sources': [
+            'media_router_perf_tests.isolate',
+          ],
+        },  # target_name: 'media_router_perf_tests_run'
       ],
     }],
   ],
diff --git a/chrome/test/media_router/media_router_perf_tests.isolate b/chrome/test/media_router/media_router_perf_tests.isolate
new file mode 100644
index 0000000..2bece4e2
--- /dev/null
+++ b/chrome/test/media_router/media_router_perf_tests.isolate
@@ -0,0 +1,51 @@
+# Copyright (c) 2016 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.
+{
+  'conditions': [
+    ['OS=="linux"', {
+      'variables': {
+        'command': [
+          'telemetry/run_benchmark',
+          '--browser=exact',
+          '--browser-executable=<(PRODUCT_DIR)/chrome<(EXECUTABLE_SUFFIX)',
+          '--also-run-disabled-tests',
+          '-v',
+          '--output-format=chartjson',
+          '--output-dir=${ISOLATED_OUTDIR}',
+        ],
+        'files': [
+          '../../../third_party/catapult/',
+          '../../../tools/perf/',
+          '../../../tools/variations/fieldtrial_util.py',
+          '<(PRODUCT_DIR)/chrome<(EXECUTABLE_SUFFIX)',
+          '<(PRODUCT_DIR)/chrome_100_percent.pak',
+          '<(PRODUCT_DIR)/chrome_200_percent.pak',
+          '<(PRODUCT_DIR)/libosmesa.so',
+          '<(PRODUCT_DIR)/locales/en-US.pak',
+          '<(PRODUCT_DIR)/mr_extension/',
+          '<(PRODUCT_DIR)/nacl_helper',
+          '<(PRODUCT_DIR)/nacl_helper_bootstrap',
+          '<(PRODUCT_DIR)/nacl_irt_x86_64.nexe',
+          '<(PRODUCT_DIR)/natives_blob.bin',
+          '<(PRODUCT_DIR)/pnacl/',
+          '<(PRODUCT_DIR)/resources.pak',
+          '<(PRODUCT_DIR)/snapshot_blob.bin',
+          '<(PRODUCT_DIR)/xdisplaycheck<(EXECUTABLE_SUFFIX)',
+          'telemetry/',
+        ],
+      },
+    }],
+    ['OS=="linux" and component=="shared_library"', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/lib/',
+          '<(PRODUCT_DIR)/lib64/',
+        ],
+      },
+    }],
+  ],
+  'includes': [
+    '../../../base/base.isolate',
+  ],
+}
diff --git a/chrome/test/nacl/nacl_browsertest_util.cc b/chrome/test/nacl/nacl_browsertest_util.cc
index 0b5fd48..e9e7c810 100644
--- a/chrome/test/nacl/nacl_browsertest_util.cc
+++ b/chrome/test/nacl/nacl_browsertest_util.cc
@@ -19,7 +19,6 @@
 #include "content/public/browser/plugin_service.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/webplugininfo.h"
-#include "net/base/net_util.h"
 
 typedef content::TestMessageHandler::MessageResponse MessageResponse;
 
@@ -284,7 +283,7 @@
 void NaClBrowserTestPnaclSubzero::SetUpCommandLine(
     base::CommandLine* command_line) {
   NaClBrowserTestPnacl::SetUpCommandLine(command_line);
-  command_line->AppendSwitch(switches::kEnablePNaClSubzero);
+  command_line->AppendSwitch(switches::kForcePNaClSubzero);
 }
 
 base::FilePath::StringType NaClBrowserTestNonSfiMode::Variant() {
diff --git a/chrome/test/ppapi/ppapi_filechooser_browsertest.cc b/chrome/test/ppapi/ppapi_filechooser_browsertest.cc
index 181d109..74de60a8 100644
--- a/chrome/test/ppapi/ppapi_filechooser_browsertest.cc
+++ b/chrome/test/ppapi/ppapi_filechooser_browsertest.cc
@@ -239,7 +239,7 @@
 
   ASSERT_TRUE(base::PathExists(actual_filename));
   std::string file_contents;
-  ASSERT_TRUE(base::ReadFileToString(actual_filename, &file_contents, 100));
+  ASSERT_TRUE(base::ReadFileToString(actual_filename, &file_contents));
   EXPECT_EQ("Hello from PPAPI", file_contents);
 }
 
@@ -260,7 +260,7 @@
 
   ASSERT_TRUE(base::PathExists(actual_filename));
   std::string file_contents;
-  ASSERT_TRUE(base::ReadFileToString(actual_filename, &file_contents, 100));
+  ASSERT_TRUE(base::ReadFileToString(actual_filename, &file_contents));
   EXPECT_EQ("Hello from PPAPI", file_contents);
 }
 
@@ -295,7 +295,7 @@
 
   ASSERT_TRUE(base::PathExists(actual_filename));
   std::string file_contents;
-  ASSERT_TRUE(base::ReadFileToString(actual_filename, &file_contents, 100));
+  ASSERT_TRUE(base::ReadFileToString(actual_filename, &file_contents));
   EXPECT_EQ("Hello from PPAPI", file_contents);
 }
 
@@ -343,7 +343,7 @@
 
   ASSERT_TRUE(base::PathExists(actual_filename));
   std::string file_contents;
-  ASSERT_TRUE(base::ReadFileToString(actual_filename, &file_contents, 100));
+  ASSERT_TRUE(base::ReadFileToString(actual_filename, &file_contents));
   EXPECT_EQ("Hello from PPAPI", file_contents);
 }
 
diff --git a/chrome/test/remoting/page_load_notification_observer.cc b/chrome/test/remoting/page_load_notification_observer.cc
index 51ec300..3236c7d6 100644
--- a/chrome/test/remoting/page_load_notification_observer.cc
+++ b/chrome/test/remoting/page_load_notification_observer.cc
@@ -5,6 +5,7 @@
 #include "chrome/test/remoting/page_load_notification_observer.h"
 
 #include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/web_contents.h"
 
@@ -16,7 +17,8 @@
           base::Bind(&PageLoadNotificationObserver::IsTargetLoaded,
                      base::Unretained(this))),
       target_(target),
-      ignore_url_parameters_(false) {
+      ignore_url_parameters_(false),
+      matched_source_(content::NotificationService::AllSources()) {
 }
 
 PageLoadNotificationObserver::~PageLoadNotificationObserver() {}
@@ -25,14 +27,19 @@
   content::NavigationController* controller =
       content::Source<content::NavigationController>(source()).ptr();
   GURL current_url = controller->GetWebContents()->GetURL();
+  bool result = false;
   if (ignore_url_parameters_) {
     GURL::Replacements strip_query;
     strip_query.ClearQuery();
-    return current_url.ReplaceComponents(strip_query) ==
+    result = current_url.ReplaceComponents(strip_query) ==
         target_.ReplaceComponents(strip_query);
   } else {
-    return current_url == target_;
+    result = current_url == target_;
   }
+  if (result) {
+    matched_source_ = source();
+  }
+  return result;
 }
 
 }  // namespace remoting
diff --git a/chrome/test/remoting/page_load_notification_observer.h b/chrome/test/remoting/page_load_notification_observer.h
index 670bb02..3e3e8619 100644
--- a/chrome/test/remoting/page_load_notification_observer.h
+++ b/chrome/test/remoting/page_load_notification_observer.h
@@ -28,11 +28,19 @@
     ignore_url_parameters_ = ignore_url_parameters;
   }
 
+  // WindowedNotificationObserver caches the source parameter whenever
+  // a page load occurs. Since we're only interested in the one for which
+  // IsTargetLoaded returns true, we have to cache it separately.
+  const content::NotificationSource& matched_source() {
+    return matched_source_;
+  }
+
  private:
   bool IsTargetLoaded();
 
   GURL target_;
   bool ignore_url_parameters_;
+  content::NotificationSource matched_source_;
 
   DISALLOW_COPY_AND_ASSIGN(PageLoadNotificationObserver);
 };
diff --git a/chrome/test/remoting/remote_desktop_browsertest.cc b/chrome/test/remoting/remote_desktop_browsertest.cc
index 9d02bb5..da6b6fa8 100644
--- a/chrome/test/remoting/remote_desktop_browsertest.cc
+++ b/chrome/test/remoting/remote_desktop_browsertest.cc
@@ -210,7 +210,8 @@
   // The active WebContents instance should be the source of the LOAD_STOP
   // notification.
   content::NavigationController* controller =
-      content::Source<content::NavigationController>(observer.source()).ptr();
+      content::Source<content::NavigationController>(
+          observer.matched_source()).ptr();
 
   content::WebContents* web_contents = controller->GetWebContents();
   _ASSERT_TRUE(web_contents);
diff --git a/chrome/tools/build/win/create_installer_archive.py b/chrome/tools/build/win/create_installer_archive.py
index 29bfd4c..d320363d 100755
--- a/chrome/tools/build/win/create_installer_archive.py
+++ b/chrome/tools/build/win/create_installer_archive.py
@@ -522,11 +522,14 @@
   for component_dll in [dll for dll in build_dlls if \
                         os.path.basename(dll) not in staged_dll_basenames]:
     component_dll_name = os.path.basename(component_dll)
-    # remoting_*.dll's don't belong in the archive (it doesn't depend on them
-    # in gyp). Trying to copy them causes a build race when creating the
-    # installer archive in component mode. See: crbug.com/180996
-    if component_dll_name.startswith('remoting_'):
+    # ash*.dll remoting_*.dll's don't belong in the archive (it doesn't depend
+    # on them in gyp). Trying to copy them causes a build race when creating the
+    # installer archive in component mode. See: crbug.com/180996 and
+    # crbug.com/586967
+    if (component_dll_name.startswith('remoting_') or
+        component_dll_name.startswith('ash')):
       continue
+
     component_dll_filenames.append(component_dll_name)
     g_archive_inputs.append(component_dll)
     shutil.copy(component_dll, version_dir)
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc
index e6c9cd6..b9dbc4f5 100644
--- a/chromecast/browser/cast_content_browser_client.cc
+++ b/chromecast/browser/cast_content_browser_client.cc
@@ -73,7 +73,7 @@
     CastContentBrowserClient* browser_client) {
   scoped_ptr<::media::MojoMediaClient> mojo_media_client(
       new media::CastMojoMediaClient(
-          browser_client->CreateCmaMediaPipelineClient()));
+          browser_client->GetCmaMediaPipelineClient()));
   return scoped_ptr<mojo::ShellClient>(
       new ::media::MojoMediaApplication(std::move(mojo_media_client)));
 }
@@ -107,8 +107,10 @@
 
 #if !defined(OS_ANDROID)
 scoped_refptr<media::CmaMediaPipelineClient>
-CastContentBrowserClient::CreateCmaMediaPipelineClient() {
-  return make_scoped_refptr(new media::CmaMediaPipelineClient());
+CastContentBrowserClient::GetCmaMediaPipelineClient() {
+  if (!cma_media_pipeline_client_.get())
+    cma_media_pipeline_client_ = CreateCmaMediaPipelineClient();
+  return cma_media_pipeline_client_;
 }
 #endif  // OS_ANDROID
 
@@ -142,11 +144,9 @@
 void CastContentBrowserClient::RenderProcessWillLaunch(
     content::RenderProcessHost* host) {
 #if !defined(OS_ANDROID)
-  if (!cma_media_pipeline_client_.get())
-    cma_media_pipeline_client_ = CreateCmaMediaPipelineClient();
   scoped_refptr<media::CmaMessageFilterHost> cma_message_filter(
       new media::CmaMessageFilterHost(host->GetID(),
-                                      cma_media_pipeline_client_));
+                                      GetCmaMediaPipelineClient()));
   host->AddFilter(cma_message_filter.get());
 #endif  // !defined(OS_ANDROID)
 
@@ -161,6 +161,13 @@
                  base::Unretained(this), host->GetID()));
 }
 
+#if !defined(OS_ANDROID)
+scoped_refptr<media::CmaMediaPipelineClient>
+CastContentBrowserClient::CreateCmaMediaPipelineClient() {
+  return make_scoped_refptr(new media::CmaMediaPipelineClient());
+}
+#endif  // OS_ANDROID
+
 void CastContentBrowserClient::AddNetworkHintsMessageFilter(
     int render_process_id, net::URLRequestContext* context) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
diff --git a/chromecast/browser/cast_content_browser_client.h b/chromecast/browser/cast_content_browser_client.h
index 7bfd0405..74ead6af 100644
--- a/chromecast/browser/cast_content_browser_client.h
+++ b/chromecast/browser/cast_content_browser_client.h
@@ -65,13 +65,9 @@
       net::URLRequestContextGetter* request_context_getter);
 
 #if !defined(OS_ANDROID)
-  // Creates a CmaMediaPipelineClient which is responsible to create (CMA
-  // backend)
-  // for media playback and watch media pipeline status, called once per media
-  // player
-  // instance.
-  virtual scoped_refptr<media::CmaMediaPipelineClient>
-  CreateCmaMediaPipelineClient();
+  // Returns CmaMediaPipelineClient which is responsible to create
+  // CMA backend for media playback and watch media pipeline status.
+  scoped_refptr<media::CmaMediaPipelineClient> GetCmaMediaPipelineClient();
 #endif
 
   // Performs cleanup for process exit (but before AtExitManager cleanup).
@@ -164,9 +160,8 @@
   CastContentBrowserClient();
 
 #if !defined(OS_ANDROID)
-  media::CmaMediaPipelineClient* cma_media_pipeline_client() const {
-    return cma_media_pipeline_client_.get();
-  }
+  virtual scoped_refptr<media::CmaMediaPipelineClient>
+  CreateCmaMediaPipelineClient();
 #endif  // !defined(OS_ANDROID)
 
   URLRequestContextFactory* url_request_context_factory() const {
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index b6b25614..11d9f18e 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-7951.0.0
\ No newline at end of file
+7955.0.0
\ No newline at end of file
diff --git a/chromeos/accelerometer/accelerometer_reader.cc b/chromeos/accelerometer/accelerometer_reader.cc
index bf96443..4cc0bfd 100644
--- a/chromeos/accelerometer/accelerometer_reader.cc
+++ b/chromeos/accelerometer/accelerometer_reader.cc
@@ -91,7 +91,7 @@
 bool ReadFileToInt(const base::FilePath& path, int* value) {
   std::string s;
   DCHECK(value);
-  if (!base::ReadFileToString(path, &s, kMaxAsciiUintLength)) {
+  if (!base::ReadFileToStringWithMaxSize(path, &s, kMaxAsciiUintLength)) {
     return false;
   }
   base::TrimWhitespaceASCII(s, base::TRIM_ALL, &s);
diff --git a/chromeos/hugepage_text/hugepage_text.cc b/chromeos/hugepage_text/hugepage_text.cc
index ccae53f..cb005fd 100644
--- a/chromeos/hugepage_text/hugepage_text.cc
+++ b/chromeos/hugepage_text/hugepage_text.cc
@@ -32,8 +32,6 @@
 const int kHpageMask = (~(kHpageSize - 1));
 
 const int kProtection = (PROT_READ | PROT_WRITE);
-const int kMmapFlags = (MAP_ANONYMOUS | MAP_SHARED);
-const int kMmapHtlbFlags = (kMmapFlags | MAP_HUGETLB);
 const int kMremapFlags = (MREMAP_MAYMOVE | MREMAP_FIXED);
 
 // The number of hugepages we want to use to map chrome text section
@@ -41,47 +39,6 @@
 // in to a small area of the binary.
 const int kNumHugePages = 15;
 
-// mremap syscall is always supported for small page segment on all kernels.
-// However, it is not the case for hugepage.
-// If not used carefully, mremap() a hugepage segment directly onto small page
-// text segment will cause irreversible damage to the existing text mapping
-// and cause process to segfault. This function will dynamically at run time
-// determine whether a process can safely execute mremap on a hugepage segment
-// without taking the process down.
-//
-// Inputs: none
-// Return: true if mremap on hugepage segment is supported on the host OS.
-static int HugetlbMremapSupported(void) {
-  void *haddr = 0, *raddr = 0, *taddr;
-  const size_t size = kHpageSize;
-  int ret = 0;
-
-  // use a pair of hugepage memory segments to test whether mremap() is
-  // supported
-  haddr = mmap(NULL, size, kProtection, kMmapHtlbFlags | MAP_NORESERVE, 0, 0);
-  if (haddr == MAP_FAILED) {
-    return 0;
-  }
-  taddr = mmap(NULL, size, kProtection, kMmapHtlbFlags | MAP_NORESERVE, 0, 0);
-  if (taddr == MAP_FAILED) {
-    munmap(haddr, size);
-    return 0;
-  }
-
-  raddr = mremap(haddr, size, size, kMremapFlags, taddr);
-  if (raddr != MAP_FAILED) {
-    ret = 1;
-    // clean up.  raddr == taddr; also haddr is implicitly unmapped
-    munmap(raddr, size);
-  } else {
-    // mremap fail, clean up both src and dst segments
-    munmap(haddr, size);
-    munmap(taddr, size);
-  }
-
-  return ret;
-}
-
 // Get an anonymous mapping backed by explicit transparent hugepage
 // Return NULL if such mapping can not be established.
 static void* GetTransparentHugepageMapping(const size_t hsize) {
@@ -129,21 +86,10 @@
 // Effect: physical backing page changed from small page to hugepage. If there
 //         are error condition, the remapping operation is aborted.
 static void MremapHugetlbText(void* vaddr, const size_t hsize) {
-  void* haddr = MAP_FAILED;
-
-  if ((reinterpret_cast<intptr_t>(vaddr) & ~kHpageMask) == 0 &&
-      HugetlbMremapSupported()) {
-    // Try anon hugepage from static hugepage pool only if the source address
-    // is hugepage aligned, otherwise, mremap below has non-recoverable error.
-    haddr = mmap(NULL, hsize, kProtection, kMmapHtlbFlags, 0, 0);
-  }
-
-  if (haddr == MAP_FAILED) {
-    PLOG(INFO) << "static hugepage not available, trying transparent hugepage";
-    haddr = GetTransparentHugepageMapping(hsize);
-    if (haddr == NULL)
-      return;
-  }
+  DCHECK_EQ(0ul, reinterpret_cast<uintptr_t>(vaddr) & ~kHpageMask);
+  void* haddr = GetTransparentHugepageMapping(hsize);
+  if (haddr == NULL)
+    return;
 
   // Copy text segment to hugepage mapping. We are using a non-asan memcpy,
   // otherwise it would be flagged as a bunch of out of bounds reads.
@@ -167,20 +113,30 @@
 // Top level text remapping function.
 //
 // Inputs: vaddr, the starting virtual address to remap to hugepage
-//         hsize, size of the memory segment to remap in bytes
+//         segsize, size of the memory segment to remap in bytes
 // Return: none
 // Effect: physical backing page changed from small page to hugepage. If there
 //         are error condition, the remaping operation is aborted.
 static void RemapHugetlbText(void* vaddr, const size_t segsize) {
-  int hsize = segsize;
-  if (segsize > kHpageSize * kNumHugePages)
-    hsize = kHpageSize * kNumHugePages;
+  // remove unaligned head regions
+  uintptr_t head_gap =
+      (kHpageSize - reinterpret_cast<uintptr_t>(vaddr) % kHpageSize) %
+      kHpageSize;
+  uintptr_t addr = reinterpret_cast<uintptr_t>(vaddr) + head_gap;
+
+  if (segsize < head_gap)
+    return;
+
+  size_t hsize = segsize - head_gap;
   hsize = hsize & kHpageMask;
 
+  if (hsize > kHpageSize * kNumHugePages)
+    hsize = kHpageSize * kNumHugePages;
+
   if (hsize == 0)
     return;
 
-  MremapHugetlbText(vaddr, hsize);
+  MremapHugetlbText(reinterpret_cast<void*>(addr), hsize);
 }
 
 // For a given ELF program header descriptor, iterates over all segments within
diff --git a/chromeos/network/host_resolver_impl_chromeos.cc b/chromeos/network/host_resolver_impl_chromeos.cc
index 61a9da9..6f06aa90 100644
--- a/chromeos/network/host_resolver_impl_chromeos.cc
+++ b/chromeos/network/host_resolver_impl_chromeos.cc
@@ -17,7 +17,6 @@
 #include "chromeos/network/network_state_handler_observer.h"
 #include "net/base/address_list.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
 namespace chromeos {
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 0125273..4fc532d 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -4,7 +4,6 @@
 
 import("//build/config/features.gni")
 import("//build/config/ui.gni")
-import("//build_overrides/webrtc.gni")
 import("//testing/test.gni")
 import("//tools/grit/repack.gni")
 
@@ -52,6 +51,7 @@
     "//components/metrics:unit_tests",
     "//components/net_log:unit_tests",
     "//components/network_time:unit_tests",
+    "//components/ntp_snippets:unit_tests",
     "//components/open_from_clipboard:unit_tests",
     "//components/os_crypt:unit_tests",
     "//components/prefs:unit_tests",
@@ -77,7 +77,10 @@
   ]
 
   if (is_ios) {
-    deps += [ "//components/translate/ios/browser:unit_tests" ]
+    deps += [
+      "//components/signin/ios/browser:unit_tests",
+      "//components/translate/ios/browser:unit_tests",
+    ]
 
     if (target_cpu != "arm") {
       # TODO(GYP): iOS arm builds of libwebp don't work yet.
@@ -88,6 +91,9 @@
       "//components/auto_login_parser:unit_tests",
       "//components/autofill/content/browser:unit_tests",
       "//components/autofill/content/renderer:unit_tests",
+      "//components/autofill/core/browser:unit_tests",
+      "//components/autofill/core/common:unit_tests",
+      "//components/browser_sync/browser:unit_tests",
       "//components/bubble:unit_tests",
       "//components/captive_portal:unit_tests",
       "//components/certificate_transparency:unit_tests",
@@ -104,9 +110,15 @@
       "//components/domain_reliability:unit_tests",
       "//components/error_page/renderer:unit_tests",
       "//components/favicon/content:unit_tests",
+      "//components/favicon/core:unit_tests",
+      "//components/favicon_base:unit_tests",
+      "//components/gcm_driver:unit_tests",
       "//components/gcm_driver/crypto:unit_tests",
       "//components/guest_view/browser:unit_tests",
       "//components/history/content/browser:unit_tests",
+      "//components/history/core/browser:unit_tests",
+      "//components/history/core/common:unit_tests",
+      "//components/invalidation/impl:unit_tests",
       "//components/json_schema:unit_tests",
       "//components/keyed_service/content:unit_tests",
       "//components/language_usage_metrics:unit_tests",
@@ -116,22 +128,29 @@
       "//components/navigation_interception:unit_tests",
       "//components/network_hints/renderer:unit_tests",
       "//components/offline_pages:unit_tests",
+      "//components/omnibox/browser:unit_tests",
       "//components/packed_ct_ev_whitelist:unit_tests",
       "//components/page_load_metrics/browser:unit_tests",
       "//components/page_load_metrics/renderer:unit_tests",
       "//components/password_manager/content/browser:unit_tests",
+      "//components/password_manager/core/browser:unit_tests",
+      "//components/password_manager/core/common:unit_tests",
+      "//components/password_manager/sync/browser:unit_tests",
       "//components/power:unit_tests",
       "//components/precache/content:unit_tests",
       "//components/precache/core:unit_tests",
       "//components/query_parser:unit_tests",
+      "//components/rappor:unit_tests",
       "//components/safe_browsing_db:unit_tests",
       "//components/safe_json:unit_tests",
       "//components/scheduler:unit_tests",
       "//components/search:unit_tests",
       "//components/search_engines:unit_tests",
       "//components/search_provider_logos:unit_tests",
+      "//components/signin/core/browser:unit_tests",
       "//components/ssl_config:unit_tests",
       "//components/sync_bookmarks:unit_tests",
+      "//components/sync_driver:unit_tests",
       "//components/sync_sessions:unit_tests",
       "//components/test_runner:test_runner",
       "//components/tracing:unit_tests",
@@ -204,6 +223,7 @@
     deps += [
       "//components/arc:unit_tests",
       "//components/ownership:unit_tests",
+      "//components/user_manager:unit_tests",
     ]
   }
 
@@ -217,32 +237,6 @@
     ]
   }
 
-  if (!is_ios || ios_use_webrtc) {
-    deps += [
-      "//components/autofill/core/browser:unit_tests",
-      "//components/autofill/core/common:unit_tests",
-      "//components/browser_sync/browser:unit_tests",
-      "//components/favicon/core:unit_tests",
-      "//components/favicon_base:unit_tests",
-      "//components/gcm_driver:unit_tests",
-      "//components/history/core/browser:unit_tests",
-      "//components/history/core/common:unit_tests",
-      "//components/invalidation/impl:unit_tests",
-      "//components/omnibox/browser:unit_tests",
-      "//components/password_manager/core/browser:unit_tests",
-      "//components/password_manager/core/common:unit_tests",
-      "//components/password_manager/sync/browser:unit_tests",
-      "//components/rappor:unit_tests",
-      "//components/search:unit_tests",
-      "//components/signin/core/browser:unit_tests",
-      "//components/sync_driver:unit_tests",
-    ]
-  }
-
-  if (ios_use_webrtc) {
-    deps += [ "//components/signin/ios/browser:unit_tests" ]
-  }
-
   if (toolkit_views) {
     # TODO bug 522654 Enable this when the undefined symbol is fixed in
     # web_modal such that this links.
diff --git a/components/app_modal/javascript_dialog_manager.cc b/components/app_modal/javascript_dialog_manager.cc
index 3940e5a..ec47620 100644
--- a/components/app_modal/javascript_dialog_manager.cc
+++ b/components/app_modal/javascript_dialog_manager.cc
@@ -21,7 +21,6 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/javascript_message_type.h"
 #include "grit/components_strings.h"
-#include "net/base/net_util.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/font_list.h"
 
diff --git a/components/app_modal/views/javascript_app_modal_dialog_views.cc b/components/app_modal/views/javascript_app_modal_dialog_views.cc
index b45ccbd..a56abe2 100644
--- a/components/app_modal/views/javascript_app_modal_dialog_views.cc
+++ b/components/app_modal/views/javascript_app_modal_dialog_views.cc
@@ -111,18 +111,6 @@
   return true;
 }
 
-void JavaScriptAppModalDialogViews::OnClosed() {
-  parent_->OnClose();
-}
-
-views::Widget* JavaScriptAppModalDialogViews::GetWidget() {
-  return message_box_view_->GetWidget();
-}
-
-const views::Widget* JavaScriptAppModalDialogViews::GetWidget() const {
-  return message_box_view_->GetWidget();
-}
-
 base::string16 JavaScriptAppModalDialogViews::GetDialogButtonLabel(
     ui::DialogButton button) const {
   if (parent_->is_before_unload_dialog()) {
@@ -158,4 +146,16 @@
   return views::DialogDelegate::GetInitiallyFocusedView();
 }
 
+void JavaScriptAppModalDialogViews::WindowClosing() {
+  parent_->OnClose();
+}
+
+views::Widget* JavaScriptAppModalDialogViews::GetWidget() {
+  return message_box_view_->GetWidget();
+}
+
+const views::Widget* JavaScriptAppModalDialogViews::GetWidget() const {
+  return message_box_view_->GetWidget();
+}
+
 }  // namespace app_modal
diff --git a/components/app_modal/views/javascript_app_modal_dialog_views.h b/components/app_modal/views/javascript_app_modal_dialog_views.h
index 32d6daa6..8ca0bbfd 100644
--- a/components/app_modal/views/javascript_app_modal_dialog_views.h
+++ b/components/app_modal/views/javascript_app_modal_dialog_views.h
@@ -46,7 +46,7 @@
   ui::ModalType GetModalType() const override;
   views::View* GetContentsView() override;
   views::View* GetInitiallyFocusedView() override;
-  void OnClosed() override;
+  void WindowClosing() override;
   views::Widget* GetWidget() override;
   const views::Widget* GetWidget() const override;
 
diff --git a/components/arc/arc_bridge_bootstrap.cc b/components/arc/arc_bridge_bootstrap.cc
index 1b0edda..1d7a94f 100644
--- a/components/arc/arc_bridge_bootstrap.cc
+++ b/components/arc/arc_bridge_bootstrap.cc
@@ -5,6 +5,8 @@
 #include "components/arc/arc_bridge_bootstrap.h"
 
 #include <fcntl.h>
+#include <grp.h>
+#include <unistd.h>
 
 #include <utility>
 
@@ -45,6 +47,8 @@
 const base::FilePath::CharType kArcBridgeSocketPath[] =
     FILE_PATH_LITERAL("/var/run/chrome/arc_bridge.sock");
 
+const char kArcBridgeSocketGroup[] = "arc-bridge";
+
 class ArcBridgeBootstrapImpl : public ArcBridgeBootstrap {
  public:
   // The possible states of the bootstrap connection.  In the normal flow,
@@ -172,9 +176,28 @@
     return base::ScopedFD();
   }
 
-  // TODO(lhchavez): Tighten the security around the socket by tying it to
-  // the user the instance will run as.
-  if (!base::SetPosixFilePermissions(socket_path, 0777)) {
+  // Change permissions on the socket.
+  struct group arc_bridge_group;
+  struct group* arc_bridge_group_res = nullptr;
+  char buf[10000];
+  if (HANDLE_EINTR(getgrnam_r(kArcBridgeSocketGroup, &arc_bridge_group, buf,
+                              sizeof(buf), &arc_bridge_group_res)) < 0) {
+    PLOG(ERROR) << "getgrnam_r";
+    return base::ScopedFD();
+  }
+
+  if (!arc_bridge_group_res) {
+    LOG(ERROR) << "Group '" << kArcBridgeSocketGroup << "' not found";
+    return base::ScopedFD();
+  }
+
+  if (HANDLE_EINTR(chown(kArcBridgeSocketPath, -1, arc_bridge_group.gr_gid)) <
+      0) {
+    PLOG(ERROR) << "chown";
+    return base::ScopedFD();
+  }
+
+  if (!base::SetPosixFilePermissions(socket_path, 0660)) {
     PLOG(ERROR) << "Could not set permissions: " << socket_path.value();
     return base::ScopedFD();
   }
diff --git a/components/arc/arc_bridge_service.h b/components/arc/arc_bridge_service.h
index 56179d02..fac6523 100644
--- a/components/arc/arc_bridge_service.h
+++ b/components/arc/arc_bridge_service.h
@@ -176,6 +176,7 @@
   int32_t ime_version() const { return ime_ptr_.version(); }
   int32_t input_version() const { return input_ptr_.version(); }
   int32_t intent_helper_version() const { return intent_helper_ptr_.version(); }
+  int32_t net_version() const { return net_ptr_.version(); }
   int32_t notifications_version() const { return notifications_ptr_.version(); }
   int32_t power_version() const { return power_ptr_.version(); }
   int32_t process_version() const { return process_ptr_.version(); }
diff --git a/components/arc/common/net.mojom b/components/arc/common/net.mojom
index 53cf893..b35ad7a 100644
--- a/components/arc/common/net.mojom
+++ b/components/arc/common/net.mojom
@@ -41,4 +41,7 @@
 interface NetInstance {
   // Establishes full-duplex communication with the host.
   Init@0(NetHost host_ptr);
+
+  // Notifies the instance of a WiFI AP scan being completed.
+  [MinVersion=1] ScanCompleted@1();
 };
diff --git a/components/arc/net/arc_net_host_impl.cc b/components/arc/net/arc_net_host_impl.cc
index e523c3c0..da7f402 100644
--- a/components/arc/net/arc_net_host_impl.cc
+++ b/components/arc/net/arc_net_host_impl.cc
@@ -7,6 +7,7 @@
 #include <string>
 #include <vector>
 
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/thread_task_runner_handle.h"
@@ -32,11 +33,15 @@
 ArcNetHostImpl::ArcNetHostImpl(ArcBridgeService* bridge_service)
     : ArcService(bridge_service), binding_(this) {
   arc_bridge_service()->AddObserver(this);
+  GetStateHandler()->AddObserver(this, FROM_HERE);
 }
 
 ArcNetHostImpl::~ArcNetHostImpl() {
   DCHECK(thread_checker_.CalledOnValidThread());
   arc_bridge_service()->RemoveObserver(this);
+  if (chromeos::NetworkHandler::IsInitialized()) {
+    GetStateHandler()->RemoveObserver(this, FROM_HERE);
+  }
 }
 
 void ArcNetHostImpl::OnNetInstanceReady() {
@@ -113,4 +118,17 @@
   GetStateHandler()->RequestScan();
 }
 
+void ArcNetHostImpl::ScanCompleted(const chromeos::DeviceState* /*unused*/) {
+  if (arc_bridge_service()->net_version() < 1) {
+    VLOG(1) << "ArcBridgeService does not support ScanCompleted.";
+    return;
+  }
+
+  arc_bridge_service()->net_instance()->ScanCompleted();
+}
+
+void ArcNetHostImpl::OnShuttingDown() {
+  GetStateHandler()->RemoveObserver(this, FROM_HERE);
+}
+
 }  // namespace arc
diff --git a/components/arc/net/arc_net_host_impl.h b/components/arc/net/arc_net_host_impl.h
index 1704d27..f078ede 100644
--- a/components/arc/net/arc_net_host_impl.h
+++ b/components/arc/net/arc_net_host_impl.h
@@ -12,6 +12,7 @@
 #include "base/files/scoped_file.h"
 #include "base/macros.h"
 #include "base/threading/thread_checker.h"
+#include "chromeos/network/network_state_handler_observer.h"
 #include "components/arc/arc_bridge_service.h"
 #include "components/arc/arc_service.h"
 #include "components/arc/common/net.mojom.h"
@@ -24,6 +25,7 @@
 // Private implementation of ArcNetHost.
 class ArcNetHostImpl : public ArcService,
                        public ArcBridgeService::Observer,
+                       public chromeos::NetworkStateHandlerObserver,
                        public NetHost {
  public:
   // The constructor will register an Observer with ArcBridgeService.
@@ -42,6 +44,12 @@
   // Called when a StartScan call is sent from ARC.
   void StartScan() override;
 
+  // Overriden from chromeos::NetworkStateHandlerObserver.
+  void ScanCompleted(const chromeos::DeviceState* /*unused*/) override;
+
+  // Overriden from chromeos::NetworkStateHandlerObserver.
+  void OnShuttingDown() override;
+
   // Overridden from ArcBridgeService::Observer:
   void OnNetInstanceReady() override;
 
diff --git a/components/autofill.gypi b/components/autofill.gypi
index ca9e8e0..8c5396dd 100644
--- a/components/autofill.gypi
+++ b/components/autofill.gypi
@@ -161,6 +161,8 @@
         'autofill/core/browser/dialog_section.h',
         'autofill/core/browser/email_field.cc',
         'autofill/core/browser/email_field.h',
+        'autofill/core/browser/field_candidates.h',
+        'autofill/core/browser/field_candidates.cc',
         'autofill/core/browser/field_types.h',
         'autofill/core/browser/form_field.cc',
         'autofill/core/browser/form_field.h',
diff --git a/components/autofill/content/common/autofill_messages.h b/components/autofill/content/common/autofill_messages.h
index a3de142..8ddc5d8 100644
--- a/components/autofill/content/common/autofill_messages.h
+++ b/components/autofill/content/common/autofill_messages.h
@@ -193,7 +193,7 @@
 // Tells the renderer to find a focused element, and if it is a password field
 // eligible for generation then to trigger generation by responding to the
 // browser with the message |AutofillHostMsg_ShowPasswordGenerationPopup|.
-IPC_MESSAGE_ROUTED0(AutofillMsg_GeneratePassword)
+IPC_MESSAGE_ROUTED0(AutofillMsg_UserTriggeredGeneratePassword)
 
 // Tells the renderer that this password form is not blacklisted.  A form can
 // be blacklisted if a user chooses "never save passwords for this site".
@@ -322,9 +322,11 @@
 // Instructs the browser to show the password generation popup at the
 // specified location. This location should be specified in the renderers
 // coordinate system. Form is the form associated with the password field.
-IPC_MESSAGE_ROUTED3(AutofillHostMsg_ShowPasswordGenerationPopup,
+IPC_MESSAGE_ROUTED5(AutofillHostMsg_ShowPasswordGenerationPopup,
                     gfx::RectF /* source location */,
                     int /* max length of the password */,
+                    base::string16, /* password field */
+                    bool,           /* is manually triggered */
                     autofill::PasswordForm)
 
 // Instructs the browser to show the popup for editing a generated password.
diff --git a/components/autofill/content/renderer/password_generation_agent.cc b/components/autofill/content/renderer/password_generation_agent.cc
index ded1af0..c161dbc 100644
--- a/components/autofill/content/renderer/password_generation_agent.cc
+++ b/components/autofill/content/renderer/password_generation_agent.cc
@@ -120,6 +120,7 @@
     PasswordAutofillAgent* password_agent)
     : content::RenderFrameObserver(render_frame),
       password_is_generated_(false),
+      is_manually_triggered_(false),
       password_edited_(false),
       generation_popup_shown_(false),
       editing_popup_shown_(false),
@@ -253,7 +254,8 @@
                         OnPasswordAccepted)
     IPC_MESSAGE_HANDLER(AutofillMsg_FoundFormsEligibleForGeneration,
                         OnFormsEligibleForGenerationFound);
-    IPC_MESSAGE_HANDLER(AutofillMsg_GeneratePassword, OnGeneratePassword);
+    IPC_MESSAGE_HANDLER(AutofillMsg_UserTriggeredGeneratePassword,
+                        OnUserTriggeredGeneratePassword);
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -438,11 +440,13 @@
 
 void PasswordGenerationAgent::ShowGenerationPopup() {
   Send(new AutofillHostMsg_ShowPasswordGenerationPopup(
-           routing_id(),
-           render_frame()->GetRenderView()->ElementBoundsInWindow(
-               generation_element_),
-           generation_element_.maxLength(),
-           *generation_form_data_->form));
+      routing_id(),
+      render_frame()->GetRenderView()->ElementBoundsInWindow(
+          generation_element_),
+      generation_element_.maxLength(),
+      generation_element_.nameForAutofill(),
+      is_manually_triggered_,
+      *generation_form_data_->form));
   generation_popup_shown_ = true;
 }
 
@@ -459,7 +463,7 @@
   Send(new AutofillHostMsg_HidePasswordGenerationPopup(routing_id()));
 }
 
-void PasswordGenerationAgent::OnGeneratePassword() {
+void PasswordGenerationAgent::OnUserTriggeredGeneratePassword() {
   blink::WebDocument doc = render_frame()->GetWebFrame()->document();
   if (doc.isNull())
     return;
@@ -485,6 +489,7 @@
       password_elements, element->nameForAutofill());
   generation_form_data_.reset(new AccountCreationFormData(
       make_linked_ptr(password_form.release()), password_elements));
+  is_manually_triggered_ = true;
   ShowGenerationPopup();
 }
 
diff --git a/components/autofill/content/renderer/password_generation_agent.h b/components/autofill/content/renderer/password_generation_agent.h
index b9c7f3c..e2a239f 100644
--- a/components/autofill/content/renderer/password_generation_agent.h
+++ b/components/autofill/content/renderer/password_generation_agent.h
@@ -104,7 +104,7 @@
 
   // Sets |generation_element_| to the focused password field and shows a
   // generation popup at this field.
-  void OnGeneratePassword();
+  void OnUserTriggeredGeneratePassword();
 
   // Stores forms that are candidates for account creation.
   AccountCreationFormDataList possible_account_creation_forms_;
@@ -129,6 +129,9 @@
   // password.
   bool password_is_generated_;
 
+  // True if password generation was manually triggered.
+  bool is_manually_triggered_;
+
   // True if a password was generated and the user edited it. Used for UMA
   // stats.
   bool password_edited_;
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index b0008d4..014414b 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -78,6 +78,8 @@
     "dialog_section.h",
     "email_field.cc",
     "email_field.h",
+    "field_candidates.cc",
+    "field_candidates.h",
     "field_types.h",
     "form_field.cc",
     "form_field.h",
@@ -274,6 +276,7 @@
     "country_names_unittest.cc",
     "credit_card_field_unittest.cc",
     "credit_card_unittest.cc",
+    "field_candidates_unittest.cc",
     "form_field_unittest.cc",
     "form_structure_unittest.cc",
     "legal_message_line_unittest.cc",
diff --git a/components/autofill/core/browser/address_field.cc b/components/autofill/core/browser/address_field.cc
index 3bd5987..7fbc2cf 100644
--- a/components/autofill/core/browser/address_field.cc
+++ b/components/autofill/core/browser/address_field.cc
@@ -126,7 +126,8 @@
       country_(NULL) {
 }
 
-bool AddressField::ClassifyField(ServerFieldTypeMap* map) const {
+void AddressField::AddClassifications(
+    FieldCandidatesMap* field_candidates) const {
   // The page can request the address lines as a single textarea input or as
   // multiple text fields (or not at all), but it shouldn't be possible to
   // request both.
@@ -134,15 +135,24 @@
   DCHECK(!(address2_ && street_address_));
   DCHECK(!(address3_ && street_address_));
 
-  return AddClassification(company_, COMPANY_NAME, map) &&
-         AddClassification(address1_, ADDRESS_HOME_LINE1, map) &&
-         AddClassification(address2_, ADDRESS_HOME_LINE2, map) &&
-         AddClassification(address3_, ADDRESS_HOME_LINE3, map) &&
-         AddClassification(street_address_, ADDRESS_HOME_STREET_ADDRESS, map) &&
-         AddClassification(city_, ADDRESS_HOME_CITY, map) &&
-         AddClassification(state_, ADDRESS_HOME_STATE, map) &&
-         AddClassification(zip_, ADDRESS_HOME_ZIP, map) &&
-         AddClassification(country_, ADDRESS_HOME_COUNTRY, map);
+  AddClassification(company_, COMPANY_NAME, kBaseAddressParserScore,
+                    field_candidates);
+  AddClassification(address1_, ADDRESS_HOME_LINE1, kBaseAddressParserScore,
+                    field_candidates);
+  AddClassification(address2_, ADDRESS_HOME_LINE2, kBaseAddressParserScore,
+                    field_candidates);
+  AddClassification(address3_, ADDRESS_HOME_LINE3, kBaseAddressParserScore,
+                    field_candidates);
+  AddClassification(street_address_, ADDRESS_HOME_STREET_ADDRESS,
+                    kBaseAddressParserScore, field_candidates);
+  AddClassification(city_, ADDRESS_HOME_CITY, kBaseAddressParserScore,
+                    field_candidates);
+  AddClassification(state_, ADDRESS_HOME_STATE, kBaseAddressParserScore,
+                    field_candidates);
+  AddClassification(zip_, ADDRESS_HOME_ZIP, kBaseAddressParserScore,
+                    field_candidates);
+  AddClassification(country_, ADDRESS_HOME_COUNTRY, kBaseAddressParserScore,
+                    field_candidates);
 }
 
 bool AddressField::ParseCompany(AutofillScanner* scanner) {
@@ -271,6 +281,39 @@
                              &state_);
 }
 
+AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelSeparately(
+    AutofillScanner* scanner,
+    const base::string16& pattern,
+    int match_type,
+    AutofillField** match) {
+  if (scanner->IsEnd())
+    return RESULT_MATCH_NONE;
+
+  AutofillField* cur_match = nullptr;
+  size_t saved_cursor = scanner->SaveCursor();
+  bool parsed_name = ParseFieldSpecifics(scanner,
+                                         pattern,
+                                         match_type & ~MATCH_LABEL,
+                                         &cur_match);
+  scanner->RewindTo(saved_cursor);
+  bool parsed_label = ParseFieldSpecifics(scanner,
+                                          pattern,
+                                          match_type & ~MATCH_NAME,
+                                          &cur_match);
+  if (parsed_name && parsed_label) {
+    if (match)
+      *match = cur_match;
+    return RESULT_MATCH_NAME_LABEL;
+  }
+
+  scanner->RewindTo(saved_cursor);
+  if (parsed_name)
+    return RESULT_MATCH_NAME;
+  if (parsed_label)
+    return RESULT_MATCH_LABEL;
+  return RESULT_MATCH_NONE;
+}
+
 bool AddressField::ParseCityStateZipCode(AutofillScanner* scanner) {
   // Simple cases.
   if (scanner->IsEnd())
diff --git a/components/autofill/core/browser/address_field.h b/components/autofill/core/browser/address_field.h
index 5a4ae9c..9afb770 100644
--- a/components/autofill/core/browser/address_field.h
+++ b/components/autofill/core/browser/address_field.h
@@ -25,10 +25,17 @@
   static scoped_ptr<FormField> Parse(AutofillScanner* scanner);
 
  protected:
-  // FormField:
-  bool ClassifyField(ServerFieldTypeMap* map) const override;
+  void AddClassifications(FieldCandidatesMap* field_candidates) const override;
 
  private:
+  // When parsing a field's label and name separately with a given pattern:
+  enum ParseNameLabelResult {
+    RESULT_MATCH_NONE,       // No match with the label or name.
+    RESULT_MATCH_LABEL,      // Only the label matches the pattern.
+    RESULT_MATCH_NAME,       // Only the name matches the pattern.
+    RESULT_MATCH_NAME_LABEL  // Name and label both match the pattern.
+  };
+
   FRIEND_TEST_ALL_PREFIXES(AddressFieldTest, ParseOneLineAddress);
   FRIEND_TEST_ALL_PREFIXES(AddressFieldTest, ParseTwoLineAddress);
   FRIEND_TEST_ALL_PREFIXES(AddressFieldTest, ParseThreeLineAddress);
@@ -58,6 +65,17 @@
   // to figure out whether the field's type: city, state, zip, or none of those.
   bool ParseCityStateZipCode(AutofillScanner* scanner);
 
+  // Like ParseFieldSpecifics(), but applies |pattern| against the name and
+  // label of the current field separately. If the return value is
+  // RESULT_MATCH_NAME_LABEL, then |scanner| advances and |match| is filled if
+  // it is non-NULL. Otherwise |scanner| does not advance and |match| does not
+  // change.
+  ParseNameLabelResult ParseNameAndLabelSeparately(
+      AutofillScanner* scanner,
+      const base::string16& pattern,
+      int match_type,
+      AutofillField** match);
+
   // Run matches on the name and label separately. If the return result is
   // RESULT_MATCH_NAME_LABEL, then |scanner| advances and the field is set.
   // Otherwise |scanner| rewinds and the field is cleared.
diff --git a/components/autofill/core/browser/address_field_unittest.cc b/components/autofill/core/browser/address_field_unittest.cc
index 7293f7a..858a468 100644
--- a/components/autofill/core/browser/address_field_unittest.cc
+++ b/components/autofill/core/browser/address_field_unittest.cc
@@ -24,7 +24,7 @@
  protected:
   ScopedVector<AutofillField> list_;
   scoped_ptr<AddressField> field_;
-  ServerFieldTypeMap field_type_map_;
+  FieldCandidatesMap field_candidates_map_;
 
   // Downcast for tests.
   static scoped_ptr<AddressField> Parse(AutofillScanner* scanner) {
@@ -60,10 +60,11 @@
   AutofillScanner scanner(list_.get());
   field_ = Parse(&scanner);
   ASSERT_NE(nullptr, field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("addr1")) != field_type_map_.end());
-  EXPECT_EQ(ADDRESS_HOME_LINE1, field_type_map_[ASCIIToUTF16("addr1")]);
+  field_->AddClassifications(&field_candidates_map_);
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("addr1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(ADDRESS_HOME_LINE1,
+            field_candidates_map_[ASCIIToUTF16("addr1")].BestHeuristicType());
 }
 
 TEST_F(AddressFieldTest, ParseTwoLineAddress) {
@@ -81,13 +82,15 @@
   AutofillScanner scanner(list_.get());
   field_ = Parse(&scanner);
   ASSERT_NE(nullptr, field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
-  ASSERT_TRUE(field_type_map_.find(ASCIIToUTF16("addr1")) !=
-              field_type_map_.end());
-  EXPECT_EQ(ADDRESS_HOME_LINE1, field_type_map_[ASCIIToUTF16("addr1")]);
-  ASSERT_TRUE(field_type_map_.find(ASCIIToUTF16("addr2")) !=
-              field_type_map_.end());
-  EXPECT_EQ(ADDRESS_HOME_LINE2, field_type_map_[ASCIIToUTF16("addr2")]);
+  field_->AddClassifications(&field_candidates_map_);
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("addr1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(ADDRESS_HOME_LINE1,
+            field_candidates_map_[ASCIIToUTF16("addr1")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("addr2")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(ADDRESS_HOME_LINE2,
+            field_candidates_map_[ASCIIToUTF16("addr2")].BestHeuristicType());
 }
 
 TEST_F(AddressFieldTest, ParseThreeLineAddress) {
@@ -109,16 +112,19 @@
   AutofillScanner scanner(list_.get());
   field_ = Parse(&scanner);
   ASSERT_NE(nullptr, field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("addr1")) != field_type_map_.end());
-  EXPECT_EQ(ADDRESS_HOME_LINE1, field_type_map_[ASCIIToUTF16("addr1")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("addr2")) != field_type_map_.end());
-  EXPECT_EQ(ADDRESS_HOME_LINE2, field_type_map_[ASCIIToUTF16("addr2")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("addr3")) != field_type_map_.end());
-  EXPECT_EQ(ADDRESS_HOME_LINE3, field_type_map_[ASCIIToUTF16("addr3")]);
+  field_->AddClassifications(&field_candidates_map_);
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("addr1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(ADDRESS_HOME_LINE1,
+            field_candidates_map_[ASCIIToUTF16("addr1")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("addr2")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(ADDRESS_HOME_LINE2,
+            field_candidates_map_[ASCIIToUTF16("addr2")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("addr3")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(ADDRESS_HOME_LINE3,
+            field_candidates_map_[ASCIIToUTF16("addr3")].BestHeuristicType());
 }
 
 TEST_F(AddressFieldTest, ParseStreetAddressFromTextArea) {
@@ -132,10 +138,11 @@
   AutofillScanner scanner(list_.get());
   field_ = Parse(&scanner);
   ASSERT_NE(nullptr, field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("addr")) != field_type_map_.end());
-  EXPECT_EQ(ADDRESS_HOME_STREET_ADDRESS, field_type_map_[ASCIIToUTF16("addr")]);
+  field_->AddClassifications(&field_candidates_map_);
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("addr")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(ADDRESS_HOME_STREET_ADDRESS,
+            field_candidates_map_[ASCIIToUTF16("addr")].BestHeuristicType());
 }
 
 TEST_F(AddressFieldTest, ParseCity) {
@@ -149,10 +156,11 @@
   AutofillScanner scanner(list_.get());
   field_ = Parse(&scanner);
   ASSERT_NE(nullptr, field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("city1")) != field_type_map_.end());
-  EXPECT_EQ(ADDRESS_HOME_CITY, field_type_map_[ASCIIToUTF16("city1")]);
+  field_->AddClassifications(&field_candidates_map_);
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("city1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(ADDRESS_HOME_CITY,
+            field_candidates_map_[ASCIIToUTF16("city1")].BestHeuristicType());
 }
 
 TEST_F(AddressFieldTest, ParseState) {
@@ -166,10 +174,11 @@
   AutofillScanner scanner(list_.get());
   field_ = Parse(&scanner);
   ASSERT_NE(nullptr, field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("state1")) != field_type_map_.end());
-  EXPECT_EQ(ADDRESS_HOME_STATE, field_type_map_[ASCIIToUTF16("state1")]);
+  field_->AddClassifications(&field_candidates_map_);
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("state1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(ADDRESS_HOME_STATE,
+            field_candidates_map_[ASCIIToUTF16("state1")].BestHeuristicType());
 }
 
 TEST_F(AddressFieldTest, ParseZip) {
@@ -183,10 +192,11 @@
   AutofillScanner scanner(list_.get());
   field_ = Parse(&scanner);
   ASSERT_NE(nullptr, field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("zip1")) != field_type_map_.end());
-  EXPECT_EQ(ADDRESS_HOME_ZIP, field_type_map_[ASCIIToUTF16("zip1")]);
+  field_->AddClassifications(&field_candidates_map_);
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("zip1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(ADDRESS_HOME_ZIP,
+            field_candidates_map_[ASCIIToUTF16("zip1")].BestHeuristicType());
 }
 
 TEST_F(AddressFieldTest, ParseStateAndZipOneLabel) {
@@ -204,13 +214,15 @@
   AutofillScanner scanner(list_.get());
   field_ = Parse(&scanner);
   ASSERT_NE(nullptr, field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("state")) != field_type_map_.end());
-  EXPECT_EQ(ADDRESS_HOME_STATE, field_type_map_[ASCIIToUTF16("state")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("zip")) != field_type_map_.end());
-  EXPECT_EQ(ADDRESS_HOME_ZIP, field_type_map_[ASCIIToUTF16("zip")]);
+  field_->AddClassifications(&field_candidates_map_);
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("state")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(ADDRESS_HOME_STATE,
+            field_candidates_map_[ASCIIToUTF16("state")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("zip")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(ADDRESS_HOME_ZIP,
+            field_candidates_map_[ASCIIToUTF16("zip")].BestHeuristicType());
 }
 
 TEST_F(AddressFieldTest, ParseCountry) {
@@ -224,10 +236,12 @@
   AutofillScanner scanner(list_.get());
   field_ = Parse(&scanner);
   ASSERT_NE(nullptr, field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("country1")) != field_type_map_.end());
-  EXPECT_EQ(ADDRESS_HOME_COUNTRY, field_type_map_[ASCIIToUTF16("country1")]);
+  field_->AddClassifications(&field_candidates_map_);
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("country1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(
+      ADDRESS_HOME_COUNTRY,
+      field_candidates_map_[ASCIIToUTF16("country1")].BestHeuristicType());
 }
 
 TEST_F(AddressFieldTest, ParseCompany) {
@@ -241,10 +255,12 @@
   AutofillScanner scanner(list_.get());
   field_ = Parse(&scanner);
   ASSERT_NE(nullptr, field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("company1")) != field_type_map_.end());
-  EXPECT_EQ(COMPANY_NAME, field_type_map_[ASCIIToUTF16("company1")]);
+  field_->AddClassifications(&field_candidates_map_);
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("company1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(
+      COMPANY_NAME,
+      field_candidates_map_[ASCIIToUTF16("company1")].BestHeuristicType());
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_download_manager.cc b/components/autofill/core/browser/autofill_download_manager.cc
index 62193e8..4046a84d 100644
--- a/components/autofill/core/browser/autofill_download_manager.cc
+++ b/components/autofill/core/browser/autofill_download_manager.cc
@@ -133,6 +133,8 @@
       out << "\n type: " << field.type();
     if (!field.label().empty())
       out << "\n label: " << field.label();
+    if (field.generation_type())
+      out << "\n generation_type: " << field.generation_type();
   }
   return out;
 }
diff --git a/components/autofill/core/browser/autofill_field.cc b/components/autofill/core/browser/autofill_field.cc
index 754ec017..8967cc5 100644
--- a/components/autofill/core/browser/autofill_field.cc
+++ b/components/autofill/core/browser/autofill_field.cc
@@ -20,6 +20,7 @@
 #include "components/autofill/core/browser/country_names.h"
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/phone_number.h"
+#include "components/autofill/core/browser/proto/server.pb.h"
 #include "components/autofill/core/browser/state_names.h"
 #include "components/autofill/core/common/autofill_l10n_util.h"
 #include "components/autofill/core/common/autofill_switches.h"
@@ -443,7 +444,8 @@
       html_mode_(HTML_MODE_NONE),
       phone_part_(IGNORED),
       credit_card_number_offset_(0),
-      previously_autofilled_(false) {}
+      previously_autofilled_(false),
+      generation_type_(AutofillUploadContents::Field::NO_GENERATION) {}
 
 AutofillField::AutofillField(const FormFieldData& field,
                              const base::string16& unique_name)
@@ -456,7 +458,8 @@
       phone_part_(IGNORED),
       credit_card_number_offset_(0),
       previously_autofilled_(false),
-      parseable_name_(field.name) {}
+      parseable_name_(field.name),
+      generation_type_(AutofillUploadContents::Field::NO_GENERATION) {}
 
 AutofillField::~AutofillField() {}
 
@@ -493,8 +496,12 @@
 }
 
 AutofillType AutofillField::Type() const {
-  if (html_type_ != HTML_TYPE_UNSPECIFIED)
+  // Use the html type specified by the website unless it is unrecognized and
+  // autofill predicts a credit card type.
+  if (html_type_ != HTML_TYPE_UNSPECIFIED &&
+      !(html_type_ == HTML_TYPE_UNRECOGNIZED && IsCreditCardPrediction())) {
     return AutofillType(html_type_, html_mode_);
+  }
 
   if (server_type_ != NO_SERVER_DATA) {
     // See http://crbug.com/429236 for background on why we might not always
@@ -630,4 +637,9 @@
   return false;
 }
 
+bool AutofillField::IsCreditCardPrediction() const {
+  return AutofillType(server_type_).group() == CREDIT_CARD ||
+         AutofillType(heuristic_type_).group() == CREDIT_CARD;
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_field.h b/components/autofill/core/browser/autofill_field.h
index d869ab86..e2a2365 100644
--- a/components/autofill/core/browser/autofill_field.h
+++ b/components/autofill/core/browser/autofill_field.h
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/strings/string16.h"
 #include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/proto/server.pb.h"
 #include "components/autofill/core/common/form_field_data.h"
 
 namespace autofill {
@@ -82,6 +83,15 @@
     return credit_card_number_offset_;
   }
 
+  void set_generation_type(
+      AutofillUploadContents::Field::PasswordGenerationType type) {
+    generation_type_ = type;
+  }
+  AutofillUploadContents::Field::PasswordGenerationType generation_type()
+      const {
+    return generation_type_;
+  }
+
   // Set |field_data|'s value to |value|. Uses |field|, |address_language_code|,
   // and |app_locale| as hints when filling exceptional cases like phone number
   // values and <select> fields. Returns |true| if the field has been filled,
@@ -107,6 +117,9 @@
                                        size_t* index);
 
  private:
+  // Whether the heuristics or server predict a credit card field.
+  bool IsCreditCardPrediction() const;
+
   // The unique name of this field, generated by Autofill.
   base::string16 unique_name_;
 
@@ -148,6 +161,9 @@
   // parsing.
   base::string16 parseable_name_;
 
+  // The type of password generation event, if it happened.
+  AutofillUploadContents::Field::PasswordGenerationType generation_type_;
+
   DISALLOW_COPY_AND_ASSIGN(AutofillField);
 };
 
diff --git a/components/autofill/core/browser/autofill_field_unittest.cc b/components/autofill/core/browser/autofill_field_unittest.cc
index fa86205..0ca39c03 100644
--- a/components/autofill/core/browser/autofill_field_unittest.cc
+++ b/components/autofill/core/browser/autofill_field_unittest.cc
@@ -168,6 +168,52 @@
   EXPECT_EQ(NAME, field.Type().group());
 }
 
+// Tests that a credit card related prediction made by the heuristics overrides
+// an unrecognized autocomplete attribute.
+TEST_F(AutofillFieldTest, Type_CreditCardOverrideHtml_Heuristics) {
+  AutofillField field;
+
+  field.SetHtmlType(HTML_TYPE_UNRECOGNIZED, HTML_MODE_NONE);
+
+  // A credit card heuristic prediction overrides the unrecognized type.
+  field.set_heuristic_type(CREDIT_CARD_NUMBER);
+  EXPECT_EQ(CREDIT_CARD_NUMBER, field.Type().GetStorableType());
+
+  // A non credit card heuristic prediction doesn't override the unrecognized
+  // type.
+  field.set_heuristic_type(NAME_FIRST);
+  EXPECT_EQ(UNKNOWN_TYPE, field.Type().GetStorableType());
+
+  // A credit card heuristic prediction doesn't override a known specified html
+  // type.
+  field.SetHtmlType(HTML_TYPE_NAME, HTML_MODE_NONE);
+  field.set_heuristic_type(CREDIT_CARD_NUMBER);
+  EXPECT_EQ(NAME_FULL, field.Type().GetStorableType());
+}
+
+// Tests that a credit card related prediction made by the server overrides an
+// unrecognized autocomplete attribute.
+TEST_F(AutofillFieldTest, Type_CreditCardOverrideHtml_ServerPredicitons) {
+  AutofillField field;
+
+  field.SetHtmlType(HTML_TYPE_UNRECOGNIZED, HTML_MODE_NONE);
+
+  // A credit card server prediction overrides the unrecognized type.
+  field.set_server_type(CREDIT_CARD_NUMBER);
+  EXPECT_EQ(CREDIT_CARD_NUMBER, field.Type().GetStorableType());
+
+  // A non credit card server prediction doesn't override the unrecognized
+  // type.
+  field.set_server_type(NAME_FIRST);
+  EXPECT_EQ(UNKNOWN_TYPE, field.Type().GetStorableType());
+
+  // A credit card server prediction doesn't override a known specified html
+  // type.
+  field.SetHtmlType(HTML_TYPE_NAME, HTML_MODE_NONE);
+  field.set_server_type(CREDIT_CARD_NUMBER);
+  EXPECT_EQ(NAME_FULL, field.Type().GetStorableType());
+}
+
 TEST_F(AutofillFieldTest, IsEmpty) {
   AutofillField field;
   ASSERT_EQ(base::string16(), field.value);
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc
index 1922724..54b49d9 100644
--- a/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -2116,7 +2116,8 @@
   }
 }
 
-// Test that a field with an unrecognized autocomplete attribute is not filled.
+// Test that a credit card field with an unrecognized autocomplete attribute
+// gets filled.
 TEST_F(AutofillManagerTest, FillCreditCardForm_UnrecognizedAttribute) {
   // Set up the form data.
   FormData form;
@@ -2153,8 +2154,8 @@
   ExpectFilledField("Card Number", "cardnumber", "4234567890123456", "text",
                     response_data.fields[1]);
 
-  // The expiration month should not be filled.
-  ExpectFilledField("Expiration Date", "ccmonth", "", "text",
+  // The expiration month should be filled.
+  ExpectFilledField("Expiration Date", "ccmonth", "04/2012", "text",
                     response_data.fields[2]);
 }
 
@@ -3666,7 +3667,8 @@
   autofill_manager_->WaitForAsyncUploadProcess();
 }
 
-// Test that no suggestions are returned for a field with an unrecognized
+// Test that suggestions are returned for credit card fields with an
+// unrecognized
 // autocomplete attribute.
 TEST_F(AutofillManagerTest, GetCreditCardSuggestions_UnrecognizedAttribute) {
   // Set up the form data.
@@ -3697,10 +3699,10 @@
   GetAutofillSuggestions(form, form.fields[1]);
   EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
 
-  // Suggestions should not be returned for the third field because of its
-  // unrecognized autocomplete attribute.
+  // Suggestions should still be returned for the third field because it is a
+  // credit card field.
   GetAutofillSuggestions(form, form.fields[2]);
-  EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
+  EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
 }
 
 // Test to verify suggestions appears for forms having credit card number split
diff --git a/components/autofill/core/browser/autofill_scanner.cc b/components/autofill/core/browser/autofill_scanner.cc
index c233c1d..47a8c4c 100644
--- a/components/autofill/core/browser/autofill_scanner.cc
+++ b/components/autofill/core/browser/autofill_scanner.cc
@@ -9,7 +9,7 @@
 
 namespace autofill {
 
-AutofillScanner::AutofillScanner(std::vector<AutofillField*>& fields)
+AutofillScanner::AutofillScanner(const std::vector<AutofillField*>& fields)
     : cursor_(fields.begin()),
       saved_cursor_(fields.begin()),
       begin_(fields.begin()),
diff --git a/components/autofill/core/browser/autofill_scanner.h b/components/autofill/core/browser/autofill_scanner.h
index 8a2bceb0e..f30d5abc 100644
--- a/components/autofill/core/browser/autofill_scanner.h
+++ b/components/autofill/core/browser/autofill_scanner.h
@@ -19,7 +19,7 @@
 // A helper class for parsing a stream of |AutofillField|'s with lookahead.
 class AutofillScanner {
  public:
-  explicit AutofillScanner(std::vector<AutofillField*>& fields);
+  explicit AutofillScanner(const std::vector<AutofillField*>& fields);
   ~AutofillScanner();
 
   // Advances the cursor by one step, if possible.
@@ -50,10 +50,10 @@
   std::vector<AutofillField*>::const_iterator saved_cursor_;
 
   // The beginning pointer for the stream.
-  const std::vector<AutofillField*>::iterator begin_;
+  const std::vector<AutofillField*>::const_iterator begin_;
 
   // The past-the-end pointer for the stream.
-  const std::vector<AutofillField*>::iterator end_;
+  const std::vector<AutofillField*>::const_iterator end_;
 
   DISALLOW_COPY_AND_ASSIGN(AutofillScanner);
 };
diff --git a/components/autofill/core/browser/credit_card_field.cc b/components/autofill/core/browser/credit_card_field.cc
index 3ac65c0cf..89d35635 100644
--- a/components/autofill/core/browser/credit_card_field.cc
+++ b/components/autofill/core/browser/credit_card_field.cc
@@ -312,35 +312,37 @@
 CreditCardField::~CreditCardField() {
 }
 
-bool CreditCardField::ClassifyField(ServerFieldTypeMap* map) const {
-  bool ok = true;
+void CreditCardField::AddClassifications(
+    FieldCandidatesMap* field_candidates) const {
   for (size_t index = 0; index < numbers_.size(); ++index) {
-    ok = ok && AddClassification(numbers_[index], CREDIT_CARD_NUMBER, map);
+    AddClassification(numbers_[index], CREDIT_CARD_NUMBER,
+                      kBaseCreditCardParserScore, field_candidates);
   }
 
-  ok = ok && AddClassification(type_, CREDIT_CARD_TYPE, map);
-  ok = ok &&
-       AddClassification(verification_, CREDIT_CARD_VERIFICATION_CODE, map);
+  AddClassification(type_, CREDIT_CARD_TYPE, kBaseCreditCardParserScore,
+                    field_candidates);
+  AddClassification(verification_, CREDIT_CARD_VERIFICATION_CODE,
+                    kBaseCreditCardParserScore, field_candidates);
 
   // If the heuristics detected first and last name in separate fields,
   // then ignore both fields. Putting them into separate fields is probably
   // wrong, because the credit card can also contain a middle name or middle
   // initial.
   if (cardholder_last_ == nullptr)
-    ok = ok && AddClassification(cardholder_, CREDIT_CARD_NAME, map);
+    AddClassification(cardholder_, CREDIT_CARD_NAME, kBaseCreditCardParserScore,
+                      field_candidates);
 
   if (expiration_date_) {
     DCHECK(!expiration_month_);
     DCHECK(!expiration_year_);
-    ok =
-        ok && AddClassification(expiration_date_, GetExpirationYearType(), map);
+    AddClassification(expiration_date_, GetExpirationYearType(),
+                      kBaseCreditCardParserScore, field_candidates);
   } else {
-    ok = ok && AddClassification(expiration_month_, CREDIT_CARD_EXP_MONTH, map);
-    ok =
-        ok && AddClassification(expiration_year_, GetExpirationYearType(), map);
+    AddClassification(expiration_month_, CREDIT_CARD_EXP_MONTH,
+                      kBaseCreditCardParserScore, field_candidates);
+    AddClassification(expiration_year_, GetExpirationYearType(),
+                      kBaseCreditCardParserScore, field_candidates);
   }
-
-  return ok;
 }
 
 bool CreditCardField::ParseExpirationDate(AutofillScanner* scanner) {
diff --git a/components/autofill/core/browser/credit_card_field.h b/components/autofill/core/browser/credit_card_field.h
index ce4ee75..269a115 100644
--- a/components/autofill/core/browser/credit_card_field.h
+++ b/components/autofill/core/browser/credit_card_field.h
@@ -24,8 +24,7 @@
   static scoped_ptr<FormField> Parse(AutofillScanner* scanner);
 
  protected:
-  // FormField:
-  bool ClassifyField(ServerFieldTypeMap* map) const override;
+  void AddClassifications(FieldCandidatesMap* field_candidates) const override;
 
  private:
   friend class CreditCardFieldTest;
diff --git a/components/autofill/core/browser/credit_card_field_unittest.cc b/components/autofill/core/browser/credit_card_field_unittest.cc
index 83d23c7..a68c6688 100644
--- a/components/autofill/core/browser/credit_card_field_unittest.cc
+++ b/components/autofill/core/browser/credit_card_field_unittest.cc
@@ -24,7 +24,7 @@
  protected:
   ScopedVector<AutofillField> list_;
   scoped_ptr<const CreditCardField> field_;
-  ServerFieldTypeMap field_type_map_;
+  FieldCandidatesMap field_candidates_map_;
 
   // Parses the contents of |list_| as a form, and stores the result into
   // |field_|.
@@ -36,8 +36,8 @@
 
   // Associates fields with their corresponding types, based on the previous
   // call to Parse().
-  bool ClassifyField() {
-    return field_->ClassifyField(&field_type_map_);
+  void AddClassifications() {
+    return field_->AddClassifications(&field_candidates_map_);
   }
 
  private:
@@ -101,17 +101,19 @@
 
   Parse();
   ASSERT_NE(nullptr, field_.get());
-  EXPECT_TRUE(ClassifyField());
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("number1")) != field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NUMBER, field_type_map_[ASCIIToUTF16("number1")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("month2")) != field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_EXP_MONTH, field_type_map_[ASCIIToUTF16("month2")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("year3")) != field_type_map_.end());
+  AddClassifications();
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NUMBER,
+            field_candidates_map_[ASCIIToUTF16("number1")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("month2")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_EXP_MONTH,
+            field_candidates_map_[ASCIIToUTF16("month2")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("year3")) !=
+              field_candidates_map_.end());
   EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR,
-      field_type_map_[ASCIIToUTF16("year3")]);
+            field_candidates_map_[ASCIIToUTF16("year3")].BestHeuristicType());
 }
 
 TEST_F(CreditCardFieldTest, ParseFullCreditCard) {
@@ -147,27 +149,31 @@
 
   Parse();
   ASSERT_NE(nullptr, field_.get());
-  EXPECT_TRUE(ClassifyField());
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("type")) != field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_TYPE, field_type_map_[ASCIIToUTF16("type")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name")) != field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NAME, field_type_map_[ASCIIToUTF16("name")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("number")) != field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NUMBER, field_type_map_[ASCIIToUTF16("number")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("month")) != field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_EXP_MONTH, field_type_map_[ASCIIToUTF16("month")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("year")) != field_type_map_.end());
+  AddClassifications();
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("type")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_TYPE,
+            field_candidates_map_[ASCIIToUTF16("type")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NAME,
+            field_candidates_map_[ASCIIToUTF16("name")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NUMBER,
+            field_candidates_map_[ASCIIToUTF16("number")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("month")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_EXP_MONTH,
+            field_candidates_map_[ASCIIToUTF16("month")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("year")) !=
+              field_candidates_map_.end());
   EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR,
-      field_type_map_[ASCIIToUTF16("year")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("cvc")) != field_type_map_.end());
+            field_candidates_map_[ASCIIToUTF16("year")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("cvc")) !=
+              field_candidates_map_.end());
   EXPECT_EQ(CREDIT_CARD_VERIFICATION_CODE,
-      field_type_map_[ASCIIToUTF16("cvc")]);
+            field_candidates_map_[ASCIIToUTF16("cvc")].BestHeuristicType());
 }
 
 TEST_F(CreditCardFieldTest, ParseExpMonthYear) {
@@ -192,20 +198,23 @@
 
   Parse();
   ASSERT_NE(nullptr, field_.get());
-  EXPECT_TRUE(ClassifyField());
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NAME, field_type_map_[ASCIIToUTF16("name1")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("number2")) != field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NUMBER, field_type_map_[ASCIIToUTF16("number2")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("month3")) != field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_EXP_MONTH, field_type_map_[ASCIIToUTF16("month3")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("year4")) != field_type_map_.end());
+  AddClassifications();
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NAME,
+            field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number2")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NUMBER,
+            field_candidates_map_[ASCIIToUTF16("number2")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("month3")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_EXP_MONTH,
+            field_candidates_map_[ASCIIToUTF16("month3")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("year4")) !=
+              field_candidates_map_.end());
   EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR,
-      field_type_map_[ASCIIToUTF16("year4")]);
+            field_candidates_map_[ASCIIToUTF16("year4")].BestHeuristicType());
 }
 
 TEST_F(CreditCardFieldTest, ParseExpMonthYear2) {
@@ -230,20 +239,23 @@
 
   Parse();
   ASSERT_NE(nullptr, field_.get());
-  EXPECT_TRUE(ClassifyField());
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NAME, field_type_map_[ASCIIToUTF16("name1")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("number2")) != field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NUMBER, field_type_map_[ASCIIToUTF16("number2")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("month3")) != field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_EXP_MONTH, field_type_map_[ASCIIToUTF16("month3")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("year4")) != field_type_map_.end());
+  AddClassifications();
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NAME,
+            field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number2")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NUMBER,
+            field_candidates_map_[ASCIIToUTF16("number2")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("month3")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_EXP_MONTH,
+            field_candidates_map_[ASCIIToUTF16("month3")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("year4")) !=
+              field_candidates_map_.end());
   EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR,
-      field_type_map_[ASCIIToUTF16("year4")]);
+            field_candidates_map_[ASCIIToUTF16("year4")].BestHeuristicType());
 }
 
 TEST_F(CreditCardFieldTest, ParseExpField) {
@@ -264,17 +276,19 @@
 
   Parse();
   ASSERT_NE(nullptr, field_.get());
-  EXPECT_TRUE(ClassifyField());
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NAME, field_type_map_[ASCIIToUTF16("name1")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("number2")) != field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NUMBER, field_type_map_[ASCIIToUTF16("number2")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("exp3")) != field_type_map_.end());
+  AddClassifications();
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NAME,
+            field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number2")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NUMBER,
+            field_candidates_map_[ASCIIToUTF16("number2")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("exp3")) !=
+              field_candidates_map_.end());
   EXPECT_EQ(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR,
-            field_type_map_[ASCIIToUTF16("exp3")]);
+            field_candidates_map_[ASCIIToUTF16("exp3")].BestHeuristicType());
 }
 
 TEST_F(CreditCardFieldTest, ParseExpField2DigitYear) {
@@ -295,17 +309,19 @@
 
   Parse();
   ASSERT_NE(nullptr, field_.get());
-  EXPECT_TRUE(ClassifyField());
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NAME, field_type_map_[ASCIIToUTF16("name1")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("number2")) != field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NUMBER, field_type_map_[ASCIIToUTF16("number2")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("exp3")) != field_type_map_.end());
+  AddClassifications();
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NAME,
+            field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number2")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NUMBER,
+            field_candidates_map_[ASCIIToUTF16("number2")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("exp3")) !=
+              field_candidates_map_.end());
   EXPECT_EQ(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR,
-            field_type_map_[ASCIIToUTF16("exp3")]);
+            field_candidates_map_[ASCIIToUTF16("exp3")].BestHeuristicType());
 }
 
 TEST_F(CreditCardFieldTest, ParseExpField2DigitYearDueToMaxLength) {
@@ -327,17 +343,19 @@
 
   Parse();
   ASSERT_NE(nullptr, field_.get());
-  EXPECT_TRUE(ClassifyField());
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NAME, field_type_map_[ASCIIToUTF16("name1")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("number2")) != field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NUMBER, field_type_map_[ASCIIToUTF16("number2")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("exp3")) != field_type_map_.end());
+  AddClassifications();
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NAME,
+            field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number2")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NUMBER,
+            field_candidates_map_[ASCIIToUTF16("number2")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("exp3")) !=
+              field_candidates_map_.end());
   EXPECT_EQ(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR,
-            field_type_map_[ASCIIToUTF16("exp3")]);
+            field_candidates_map_[ASCIIToUTF16("exp3")].BestHeuristicType());
 }
 
 TEST_F(CreditCardFieldTest, ParseExpField4DigitYear) {
@@ -358,17 +376,19 @@
 
   Parse();
   ASSERT_NE(nullptr, field_.get());
-  EXPECT_TRUE(ClassifyField());
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NAME, field_type_map_[ASCIIToUTF16("name1")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("number2")) != field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NUMBER, field_type_map_[ASCIIToUTF16("number2")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("exp3")) != field_type_map_.end());
+  AddClassifications();
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NAME,
+            field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number2")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NUMBER,
+            field_candidates_map_[ASCIIToUTF16("number2")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("exp3")) !=
+              field_candidates_map_.end());
   EXPECT_EQ(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR,
-            field_type_map_[ASCIIToUTF16("exp3")]);
+            field_candidates_map_[ASCIIToUTF16("exp3")].BestHeuristicType());
 }
 
 TEST_F(CreditCardFieldTest, ParseCreditCardHolderNameWithCCFullName) {
@@ -381,10 +401,11 @@
 
   Parse();
   ASSERT_NE(nullptr, field_.get());
-  EXPECT_TRUE(ClassifyField());
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NAME, field_type_map_[ASCIIToUTF16("name1")]);
+  AddClassifications();
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NAME,
+            field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
 }
 
 // Verifies that <input type="month"> controls are able to be parsed correctly.
@@ -403,15 +424,15 @@
 
   Parse();
   ASSERT_NE(nullptr, field_.get());
-  EXPECT_TRUE(ClassifyField());
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("number1")) != field_type_map_.end());
+  AddClassifications();
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number1")) !=
+              field_candidates_map_.end());
   EXPECT_EQ(CREDIT_CARD_NUMBER,
-            field_type_map_[ASCIIToUTF16("number1")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("date2")) != field_type_map_.end());
+            field_candidates_map_[ASCIIToUTF16("number1")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("date2")) !=
+              field_candidates_map_.end());
   EXPECT_EQ(CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR,
-            field_type_map_[ASCIIToUTF16("date2")]);
+            field_candidates_map_[ASCIIToUTF16("date2")].BestHeuristicType());
 }
 
 // Verify that heuristics <input name="ccyear" maxlength="2"/> considers
@@ -434,17 +455,19 @@
 
   Parse();
   ASSERT_NE(nullptr, field_.get());
-  EXPECT_TRUE(ClassifyField());
-  ASSERT_TRUE(field_type_map_.find(ASCIIToUTF16("number")) !=
-              field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NUMBER, field_type_map_[ASCIIToUTF16("number")]);
-  ASSERT_TRUE(field_type_map_.find(ASCIIToUTF16("month")) !=
-              field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_EXP_MONTH, field_type_map_[ASCIIToUTF16("month")]);
-  ASSERT_TRUE(field_type_map_.find(ASCIIToUTF16("year")) !=
-              field_type_map_.end());
+  AddClassifications();
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NUMBER,
+            field_candidates_map_[ASCIIToUTF16("number")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("month")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_EXP_MONTH,
+            field_candidates_map_[ASCIIToUTF16("month")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("year")) !=
+              field_candidates_map_.end());
   EXPECT_EQ(CREDIT_CARD_EXP_2_DIGIT_YEAR,
-            field_type_map_[ASCIIToUTF16("year")]);
+            field_candidates_map_[ASCIIToUTF16("year")].BestHeuristicType());
 }
 
 TEST_F(CreditCardFieldTest, ParseCreditCardNumberWithSplit) {
@@ -484,35 +507,40 @@
 
   Parse();
   ASSERT_NE(nullptr, field_.get());
-  EXPECT_TRUE(ClassifyField());
+  AddClassifications();
 
-  ASSERT_TRUE(field_type_map_.find(ASCIIToUTF16("number1")) !=
-              field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NUMBER, field_type_map_[ASCIIToUTF16("number1")]);
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NUMBER,
+            field_candidates_map_[ASCIIToUTF16("number1")].BestHeuristicType());
   EXPECT_EQ(0U, list_[0]->credit_card_number_offset());
 
-  ASSERT_TRUE(field_type_map_.find(ASCIIToUTF16("number2")) !=
-              field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NUMBER, field_type_map_[ASCIIToUTF16("number2")]);
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number2")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NUMBER,
+            field_candidates_map_[ASCIIToUTF16("number2")].BestHeuristicType());
   EXPECT_EQ(4U, list_[1]->credit_card_number_offset());
 
-  ASSERT_TRUE(field_type_map_.find(ASCIIToUTF16("number3")) !=
-              field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NUMBER, field_type_map_[ASCIIToUTF16("number3")]);
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number3")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NUMBER,
+            field_candidates_map_[ASCIIToUTF16("number3")].BestHeuristicType());
   EXPECT_EQ(8U, list_[2]->credit_card_number_offset());
 
-  ASSERT_TRUE(field_type_map_.find(ASCIIToUTF16("number4")) !=
-              field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NUMBER, field_type_map_[ASCIIToUTF16("number4")]);
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number4")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NUMBER,
+            field_candidates_map_[ASCIIToUTF16("number4")].BestHeuristicType());
   EXPECT_EQ(12U, list_[3]->credit_card_number_offset());
 
-  ASSERT_TRUE(field_type_map_.find(ASCIIToUTF16("month5")) !=
-              field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_EXP_MONTH, field_type_map_[ASCIIToUTF16("month5")]);
-  ASSERT_TRUE(field_type_map_.find(ASCIIToUTF16("year6")) !=
-              field_type_map_.end());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("month5")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_EXP_MONTH,
+            field_candidates_map_[ASCIIToUTF16("month5")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("year6")) !=
+              field_candidates_map_.end());
   EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR,
-            field_type_map_[ASCIIToUTF16("year6")]);
+            field_candidates_map_[ASCIIToUTF16("year6")].BestHeuristicType());
 }
 
 TEST_F(CreditCardFieldTest, ParseMultipleCreditCardNumbers) {
@@ -541,24 +569,28 @@
 
   Parse();
   ASSERT_NE(nullptr, field_.get());
-  EXPECT_TRUE(ClassifyField());
+  AddClassifications();
 
-  ASSERT_TRUE(field_type_map_.find(ASCIIToUTF16("name1")) !=
-              field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NAME, field_type_map_[ASCIIToUTF16("name1")]);
-  ASSERT_TRUE(field_type_map_.find(ASCIIToUTF16("number2")) !=
-              field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NUMBER, field_type_map_[ASCIIToUTF16("number2")]);
-  ASSERT_TRUE(field_type_map_.find(ASCIIToUTF16("number3")) !=
-              field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_NUMBER, field_type_map_[ASCIIToUTF16("number3")]);
-  ASSERT_TRUE(field_type_map_.find(ASCIIToUTF16("month4")) !=
-              field_type_map_.end());
-  EXPECT_EQ(CREDIT_CARD_EXP_MONTH, field_type_map_[ASCIIToUTF16("month4")]);
-  ASSERT_TRUE(field_type_map_.find(ASCIIToUTF16("year5")) !=
-              field_type_map_.end());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NAME,
+            field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number2")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NUMBER,
+            field_candidates_map_[ASCIIToUTF16("number2")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("number3")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_NUMBER,
+            field_candidates_map_[ASCIIToUTF16("number3")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("month4")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(CREDIT_CARD_EXP_MONTH,
+            field_candidates_map_[ASCIIToUTF16("month4")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("year5")) !=
+              field_candidates_map_.end());
   EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR,
-            field_type_map_[ASCIIToUTF16("year5")]);
+            field_candidates_map_[ASCIIToUTF16("year5")].BestHeuristicType());
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/email_field.cc b/components/autofill/core/browser/email_field.cc
index cfe4a1a..d0830c4 100644
--- a/components/autofill/core/browser/email_field.cc
+++ b/components/autofill/core/browser/email_field.cc
@@ -24,8 +24,10 @@
 EmailField::EmailField(const AutofillField* field) : field_(field) {
 }
 
-bool EmailField::ClassifyField(ServerFieldTypeMap* map) const {
-  return AddClassification(field_, EMAIL_ADDRESS, map);
+void EmailField::AddClassifications(
+    FieldCandidatesMap* field_candidates) const {
+  AddClassification(field_, EMAIL_ADDRESS, kBaseEmailParserScore,
+                    field_candidates);
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/email_field.h b/components/autofill/core/browser/email_field.h
index df76387..f4a2cc4d 100644
--- a/components/autofill/core/browser/email_field.h
+++ b/components/autofill/core/browser/email_field.h
@@ -17,8 +17,7 @@
   static scoped_ptr<FormField> Parse(AutofillScanner* scanner);
 
  protected:
-  // FormField:
-  bool ClassifyField(ServerFieldTypeMap* map) const override;
+  void AddClassifications(FieldCandidatesMap* field_candidates) const override;
 
  private:
   explicit EmailField(const AutofillField* field);
diff --git a/components/autofill/core/browser/field_candidates.cc b/components/autofill/core/browser/field_candidates.cc
new file mode 100644
index 0000000..6f18aae
--- /dev/null
+++ b/components/autofill/core/browser/field_candidates.cc
@@ -0,0 +1,47 @@
+// Copyright 2016 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 "components/autofill/core/browser/field_candidates.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "base/logging.h"
+
+namespace autofill {
+
+FieldCandidates::FieldCandidates() {}
+
+FieldCandidates::~FieldCandidates() {}
+
+FieldCandidates::FieldCandidate::FieldCandidate(ServerFieldType field_type,
+                                                float field_score)
+    : type(field_type), score(field_score) {}
+
+void FieldCandidates::AddFieldCandidate(ServerFieldType type, float score) {
+  field_candidates_.emplace_back(type, score);
+}
+
+// We currently select the type with the biggest sum.
+ServerFieldType FieldCandidates::BestHeuristicType() const {
+  if (field_candidates_.empty())
+    return UNKNOWN_TYPE;
+
+  // Scores for each type. The index is their ServerFieldType enum value.
+  std::vector<float> type_scores(MAX_VALID_FIELD_TYPE, 0.0f);
+
+  for (const auto& field_candidate : field_candidates_) {
+    VLOG(1) << "type: " << field_candidate.type
+            << " score: " << field_candidate.score;
+    type_scores[field_candidate.type] += field_candidate.score;
+  }
+
+  const auto best_type_iter =
+      std::max_element(type_scores.begin(), type_scores.end());
+  const size_t index = std::distance(type_scores.begin(), best_type_iter);
+
+  return static_cast<ServerFieldType>(index);
+}
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/field_candidates.h b/components/autofill/core/browser/field_candidates.h
new file mode 100644
index 0000000..6a34d7f2
--- /dev/null
+++ b/components/autofill/core/browser/field_candidates.h
@@ -0,0 +1,56 @@
+// Copyright 2016 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 COMPONENTS_AUTOFILL_CORE_BROWSER_FIELD_CANDIDATES_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_FIELD_CANDIDATES_H_
+
+#include <map>
+#include <vector>
+
+#include "components/autofill/core/browser/field_types.h"
+
+namespace autofill {
+
+// Each field can be of different types. This class collects all these possible
+// types and determines which type is the most likely.
+class FieldCandidates {
+ public:
+  FieldCandidates();
+  ~FieldCandidates();
+
+  // Includes a possible |type| for a given field.
+  //
+  // Callers are responsible for the scores they add. FieldCandidates is
+  // agnostic to the source of these scores and will select the best candidate
+  // based solely on their numeric values. BestHeuristicType() uses |score| to
+  // determine the most likely type for this given field. Please see
+  // field_candidates.cc for details on how this type is actually chosen.
+  void AddFieldCandidate(ServerFieldType type, float score);
+
+  // Determines the best type based on the current possible types.
+  ServerFieldType BestHeuristicType() const;
+
+ private:
+  // Represents a possible type for a given field.
+  struct FieldCandidate {
+    FieldCandidate(ServerFieldType field_type, float field_score);
+
+    // The associated type for this candidate.
+    ServerFieldType type = UNKNOWN_TYPE;
+
+    // A non-negative number indicating how sure the type is for this specific
+    // candidate. The higher the more confidence.
+    float score = 0.0f;
+  };
+
+  // Internal storage for all the possible types for a given field.
+  std::vector<FieldCandidate> field_candidates_;
+};
+
+// A map from the field's unique name to its possible candidates.
+using FieldCandidatesMap = std::map<base::string16, FieldCandidates>;
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_FIELD_CANDIDATES_H_
diff --git a/components/autofill/core/browser/field_candidates_unittest.cc b/components/autofill/core/browser/field_candidates_unittest.cc
new file mode 100644
index 0000000..7539558
--- /dev/null
+++ b/components/autofill/core/browser/field_candidates_unittest.cc
@@ -0,0 +1,45 @@
+// Copyright 2016 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 "components/autofill/core/browser/field_candidates.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+namespace {
+
+// An empty FieldCandidates does not have any material to work with and should
+// return UNKNOWN_TYPE.
+TEST(FieldCandidatesTest, EmptyFieldCandidates) {
+  FieldCandidates field_candidates;
+  EXPECT_EQ(UNKNOWN_TYPE, field_candidates.BestHeuristicType());
+}
+
+// A FieldCandidates with a single candidate should always return the type of
+// the only candidate.
+TEST(FieldCandidatesTest, SingleCandidate) {
+  FieldCandidates field_candidates;
+  field_candidates.AddFieldCandidate(COMPANY_NAME, 1.0f);
+  EXPECT_EQ(COMPANY_NAME, field_candidates.BestHeuristicType());
+}
+
+// Simple case with two candidates. The one with higher score should win.
+TEST(FieldCandidatesTest, TwoCandidates) {
+  FieldCandidates field_candidates;
+  field_candidates.AddFieldCandidate(NAME_LAST, 1.01f);
+  field_candidates.AddFieldCandidate(NAME_FIRST, 0.99f);
+  EXPECT_EQ(NAME_LAST, field_candidates.BestHeuristicType());
+}
+
+// Same as TwoCandidates but added in the opposite order, which should not
+// interfere with the outcome.
+TEST(FieldCandidatesTest, TwoCandidatesOppositeOrder) {
+  FieldCandidates field_candidates;
+  field_candidates.AddFieldCandidate(NAME_FIRST, 0.99f);
+  field_candidates.AddFieldCandidate(NAME_LAST, 1.01f);
+  EXPECT_EQ(NAME_LAST, field_candidates.BestHeuristicType());
+}
+
+}  // namespace
+}  // namespace autofill
diff --git a/components/autofill/core/browser/field_types.h b/components/autofill/core/browser/field_types.h
index a3787e0..4edce98 100644
--- a/components/autofill/core/browser/field_types.h
+++ b/components/autofill/core/browser/field_types.h
@@ -247,7 +247,6 @@
 };
 
 typedef std::set<ServerFieldType> ServerFieldTypeSet;
-typedef std::map<base::string16, ServerFieldType> ServerFieldTypeMap;
 
 }  // namespace autofill
 
diff --git a/components/autofill/core/browser/form_field.cc b/components/autofill/core/browser/form_field.cc
index 0b78e44..81da9bd0 100644
--- a/components/autofill/core/browser/form_field.cc
+++ b/components/autofill/core/browser/form_field.cc
@@ -40,44 +40,55 @@
 
 }  // namespace
 
+// There's an implicit precedence determined by the values assigned here. Email
+// is currently the most important followed by Phone, Address, Credit Card and
+// finally Name.
+const float FormField::kBaseEmailParserScore = 1.4f;
+const float FormField::kBasePhoneParserScore = 1.3f;
+const float FormField::kBaseAddressParserScore = 1.2f;
+const float FormField::kBaseCreditCardParserScore = 1.1f;
+const float FormField::kBaseNameParserScore = 1.0f;
+
 // static
-ServerFieldTypeMap FormField::ParseFormFields(
+FieldCandidatesMap FormField::ParseFormFields(
     const std::vector<AutofillField*>& fields,
     bool is_form_tag) {
-  ServerFieldTypeMap map;
-
   // Set up a working copy of the fields to be processed.
   std::vector<AutofillField*> remaining_fields;
   std::copy_if(fields.begin(), fields.end(),
                std::back_inserter(remaining_fields), ShouldBeProcessed);
 
+  FieldCandidatesMap field_candidates;
+
   // Email pass.
-  ParseFormFieldsPass(EmailField::Parse, &remaining_fields, &map);
-  const size_t email_count = map.size();
+  ParseFormFieldsPass(EmailField::Parse, &remaining_fields, &field_candidates);
+  const size_t email_count = field_candidates.size();
 
   // Phone pass.
-  ParseFormFieldsPass(PhoneField::Parse, &remaining_fields, &map);
+  ParseFormFieldsPass(PhoneField::Parse, &remaining_fields, &field_candidates);
 
   // Address pass.
-  ParseFormFieldsPass(AddressField::Parse, &remaining_fields, &map);
+  ParseFormFieldsPass(AddressField::Parse, &remaining_fields,
+                      &field_candidates);
 
   // Credit card pass.
-  ParseFormFieldsPass(CreditCardField::Parse, &remaining_fields, &map);
+  ParseFormFieldsPass(CreditCardField::Parse, &remaining_fields,
+                      &field_candidates);
 
   // Name pass.
-  ParseFormFieldsPass(NameField::Parse, &remaining_fields, &map);
+  ParseFormFieldsPass(NameField::Parse, &remaining_fields, &field_candidates);
 
   // Do not autofill a form if there are less than 3 recognized fields.
   // Otherwise it is very easy to have false positives. http://crbug.com/447332
   // For <form> tags, make an exception for email fields, which are commonly the
   // only recognized field on account registration sites.
   static const size_t kThreshold = 3;
-  const bool accept_parsing =
-      (map.size() >= kThreshold || (is_form_tag && email_count > 0));
+  const bool accept_parsing = (field_candidates.size() >= kThreshold ||
+                               (is_form_tag && email_count > 0));
   if (!accept_parsing)
-    map.clear();
+    field_candidates.clear();
 
-  return map;
+  return field_candidates;
 }
 
 // static
@@ -104,40 +115,6 @@
 }
 
 // static
-FormField::ParseNameLabelResult FormField::ParseNameAndLabelSeparately(
-    AutofillScanner* scanner,
-    const base::string16& pattern,
-    int match_type,
-    AutofillField** match) {
-  if (scanner->IsEnd())
-    return RESULT_MATCH_NONE;
-
-  AutofillField* cur_match = nullptr;
-  size_t saved_cursor = scanner->SaveCursor();
-  bool parsed_name = ParseFieldSpecifics(scanner,
-                                         pattern,
-                                         match_type & ~MATCH_LABEL,
-                                         &cur_match);
-  scanner->RewindTo(saved_cursor);
-  bool parsed_label = ParseFieldSpecifics(scanner,
-                                          pattern,
-                                          match_type & ~MATCH_NAME,
-                                          &cur_match);
-  if (parsed_name && parsed_label) {
-    if (match)
-      *match = cur_match;
-    return RESULT_MATCH_NAME_LABEL;
-  }
-
-  scanner->RewindTo(saved_cursor);
-  if (parsed_name)
-    return RESULT_MATCH_NAME;
-  if (parsed_label)
-    return RESULT_MATCH_LABEL;
-  return RESULT_MATCH_NONE;
-}
-
-// static
 bool FormField::ParseEmptyLabel(AutofillScanner* scanner,
                                 AutofillField** match) {
   return ParseFieldSpecifics(scanner,
@@ -147,14 +124,16 @@
 }
 
 // static
-bool FormField::AddClassification(const AutofillField* field,
+void FormField::AddClassification(const AutofillField* field,
                                   ServerFieldType type,
-                                  ServerFieldTypeMap* map) {
+                                  float score,
+                                  FieldCandidatesMap* field_candidates) {
   // Several fields are optional.
-  if (!field)
-    return true;
+  if (field == nullptr)
+    return;
 
-  return map->insert(make_pair(field->unique_name(), type)).second;
+  FieldCandidates& candidates = (*field_candidates)[field->unique_name()];
+  candidates.AddFieldCandidate(type, score);
 }
 
 // static.
@@ -193,22 +172,21 @@
 // static
 void FormField::ParseFormFieldsPass(ParseFunction parse,
                                     std::vector<AutofillField*>* fields,
-                                    ServerFieldTypeMap* map) {
+                                    FieldCandidatesMap* field_candidates) {
   // Store unmatched fields for further processing by the caller.
   std::vector<AutofillField*> remaining_fields;
 
   AutofillScanner scanner(*fields);
   while (!scanner.IsEnd()) {
     scoped_ptr<FormField> form_field(parse(&scanner));
-    if (!form_field) {
+    if (form_field == nullptr) {
       remaining_fields.push_back(scanner.Cursor());
       scanner.Advance();
-      continue;
+    } else {
+      // Add entries into |field_candidates| for each field type found in
+      // |fields|.
+      form_field->AddClassifications(field_candidates);
     }
-
-    // Add entries into the map for each field type found in |form_field|.
-    bool ok = form_field->ClassifyField(map);
-    DCHECK(ok);
   }
 
   std::swap(*fields, remaining_fields);
diff --git a/components/autofill/core/browser/form_field.h b/components/autofill/core/browser/form_field.h
index a923d9b..683e0fc 100644
--- a/components/autofill/core/browser/form_field.h
+++ b/components/autofill/core/browser/form_field.h
@@ -11,6 +11,7 @@
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
+#include "components/autofill/core/browser/field_candidates.h"
 #include "components/autofill/core/browser/field_types.h"
 
 namespace autofill {
@@ -27,8 +28,8 @@
 
   // Classifies each field in |fields| with its heuristically detected type.
   // Each field has a derived unique name that is used as the key into the
-  // returned ServerFieldTypeMap.
-  static ServerFieldTypeMap ParseFormFields(
+  // returned FieldCandidatesMap.
+  static FieldCandidatesMap ParseFormFields(
       const std::vector<AutofillField*>& fields,
       bool is_form_tag);
 
@@ -55,13 +56,12 @@
     MATCH_DEFAULT    = MATCH_LABEL | MATCH_NAME | MATCH_TEXT,
   };
 
-  // When parsing a field's label and name separately with a given pattern:
-  enum ParseNameLabelResult {
-    RESULT_MATCH_NONE,       // No match with the label or name.
-    RESULT_MATCH_LABEL,      // Only the label matches the pattern.
-    RESULT_MATCH_NAME,       // Only the name matches the pattern.
-    RESULT_MATCH_NAME_LABEL  // Name and label both match the pattern.
-  };
+  // Initial values assigned to FieldCandidates by their corresponding parsers.
+  static const float kBaseEmailParserScore;
+  static const float kBasePhoneParserScore;
+  static const float kBaseAddressParserScore;
+  static const float kBaseCreditCardParserScore;
+  static const float kBaseNameParserScore;
 
   // Only derived classes may instantiate.
   FormField() {}
@@ -82,25 +82,17 @@
                                   int match_type,
                                   AutofillField** match);
 
-  // Like ParseFieldSpecifics(), but applies |pattern| against the name and
-  // label of the current field separately. If the return value is
-  // RESULT_MATCH_NAME_LABEL, then |scanner| advances and |match| is filled if
-  // it is non-NULL. Otherwise |scanner| does not advance and |match| does not
-  // change.
-  static ParseNameLabelResult ParseNameAndLabelSeparately(
-      AutofillScanner* scanner,
-      const base::string16& pattern,
-      int match_type,
-      AutofillField** match);
-
   // Attempts to parse a field with an empty label.  Returns true
   // on success and fills |match| with a pointer to the field.
   static bool ParseEmptyLabel(AutofillScanner* scanner, AutofillField** match);
 
-  // Adds an association between a field and a type to |map|.
-  static bool AddClassification(const AutofillField* field,
+  // Adds an association between a |field| and a |type| into |field_candidates|.
+  // This association is weighted by |score|, the higher the stronger the
+  // association.
+  static void AddClassification(const AutofillField* field,
                                 ServerFieldType type,
-                                ServerFieldTypeMap* map);
+                                float score,
+                                FieldCandidatesMap* field_candidates);
 
   // Returns true iff |type| matches |match_type|.
   static bool MatchesFormControlType(const std::string& type, int match_type);
@@ -109,7 +101,8 @@
   // information.  |ParseFormFields| coordinates the parsing and extraction
   // of types from an input vector of |AutofillField| objects and delegates
   // the type extraction via this method.
-  virtual bool ClassifyField(ServerFieldTypeMap* map) const = 0;
+  virtual void AddClassifications(
+      FieldCandidatesMap* field_candidates) const = 0;
 
  private:
   FRIEND_TEST_ALL_PREFIXES(FormFieldTest, Match);
@@ -137,10 +130,11 @@
   // |parse| method to match content to a given field type.
   // |fields| is both an input and an output parameter.  Upon exit |fields|
   // holds any remaining unclassified fields for further processing.
-  // Classification results of the processed fields are stored in |map|.
+  // Classification results of the processed fields are stored in
+  // |field_candidates|.
   static void ParseFormFieldsPass(ParseFunction parse,
                                   std::vector<AutofillField*>* fields,
-                                  ServerFieldTypeMap* map);
+                                  FieldCandidatesMap* field_candidates);
 
   DISALLOW_COPY_AND_ASSIGN(FormField);
 };
diff --git a/components/autofill/core/browser/form_field_unittest.cc b/components/autofill/core/browser/form_field_unittest.cc
index 043b5ff..52f7bc5 100644
--- a/components/autofill/core/browser/form_field_unittest.cc
+++ b/components/autofill/core/browser/form_field_unittest.cc
@@ -148,14 +148,16 @@
   fields.push_back(new AutofillField(field_data, field_data.label));
 
   // Checkable element shouldn't interfere with inference of Address line2.
-  const ServerFieldTypeMap field_type_map =
+  const FieldCandidatesMap field_candidates_map =
       FormField::ParseFormFields(fields.get(), true);
-  ASSERT_EQ(3U, field_type_map.size());
+  ASSERT_EQ(3U, field_candidates_map.size());
 
   EXPECT_EQ(ADDRESS_HOME_LINE1,
-            field_type_map.find(ASCIIToUTF16("Address line1"))->second);
+            field_candidates_map.find(ASCIIToUTF16("Address line1"))
+                ->second.BestHeuristicType());
   EXPECT_EQ(ADDRESS_HOME_LINE2,
-            field_type_map.find(ASCIIToUTF16("Address line2"))->second);
+            field_candidates_map.find(ASCIIToUTF16("Address line2"))
+                ->second.BestHeuristicType());
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index 9485e35..c92b4ab 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -24,6 +24,7 @@
 #include "base/time/time.h"
 #include "components/autofill/core/browser/autofill_metrics.h"
 #include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/field_candidates.h"
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/form_field.h"
 #include "components/autofill/core/common/autofill_constants.h"
@@ -350,12 +351,12 @@
   // prediction routines.
   if (active_field_count() >= kRequiredFieldsForPredictionRoutines &&
       (is_form_tag_ || is_formless_checkout_)) {
-    const ServerFieldTypeMap field_type_map =
+    const FieldCandidatesMap field_type_map =
         FormField::ParseFormFields(fields_.get(), is_form_tag_);
     for (AutofillField* field : fields_) {
       const auto iter = field_type_map.find(field->unique_name());
       if (iter != field_type_map.end())
-        field->set_heuristic_type(iter->second);
+        field->set_heuristic_type(iter->second.BestHeuristicType());
     }
   }
 
@@ -1106,6 +1107,8 @@
 
       AutofillUploadContents::Field* added_field = upload->add_field();
       added_field->set_autofill_type(field_type);
+      if (field->generation_type())
+        added_field->set_generation_type(field->generation_type());
 
       unsigned sig = 0;
       // The signature is a required field. If it can't be parsed, the proto
diff --git a/components/autofill/core/browser/form_structure_unittest.cc b/components/autofill/core/browser/form_structure_unittest.cc
index 045f28b..b9b9a49 100644
--- a/components/autofill/core/browser/form_structure_unittest.cc
+++ b/components/autofill/core/browser/form_structure_unittest.cc
@@ -2144,8 +2144,13 @@
   form_structure.reset(new FormStructure(form));
 
   ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
-  for (size_t i = 0; i < form_structure->field_count(); ++i)
+  for (size_t i = 0; i < form_structure->field_count(); ++i) {
     form_structure->field(i)->set_possible_types(possible_field_types[i]);
+    if (form_structure->field(i)->name == ASCIIToUTF16("password"))
+      form_structure->field(i)->set_generation_type(
+          autofill::AutofillUploadContents::Field::
+              MANUALLY_TRIGGERED_GENERATION_ON_SIGN_UP_FORM);
+  }
 
   ServerFieldTypeSet available_field_types;
   available_field_types.insert(NAME_FIRST);
@@ -2172,8 +2177,12 @@
                         "Email", "email", 9U);
   test::FillUploadField(upload.add_field(), 239111655U, "username", "text",
                         "username", "email", 86U);
-  test::FillUploadField(upload.add_field(), 2051817934U, "password", "password",
-                        "password", "email", 76U);
+  auto* upload_password_field = upload.add_field();
+  test::FillUploadField(upload_password_field, 2051817934U, "password",
+                        "password", "password", "email", 76U);
+  upload_password_field->set_generation_type(
+      autofill::AutofillUploadContents::Field::
+          MANUALLY_TRIGGERED_GENERATION_ON_SIGN_UP_FORM);
 
   std::string expected_upload_string;
   ASSERT_TRUE(upload.SerializeToString(&expected_upload_string));
diff --git a/components/autofill/core/browser/name_field.cc b/components/autofill/core/browser/name_field.cc
index 9e5a09e..3028812 100644
--- a/components/autofill/core/browser/name_field.cc
+++ b/components/autofill/core/browser/name_field.cc
@@ -23,8 +23,7 @@
   static scoped_ptr<FullNameField> Parse(AutofillScanner* scanner);
 
  protected:
-  // FormField:
-  bool ClassifyField(ServerFieldTypeMap* map) const override;
+  void AddClassifications(FieldCandidatesMap* field_candidates) const override;
 
  private:
   explicit FullNameField(AutofillField* field);
@@ -44,8 +43,7 @@
   static scoped_ptr<FirstLastNameField> Parse(AutofillScanner* scanner);
 
  protected:
-  // FormField:
-  bool ClassifyField(ServerFieldTypeMap* map) const override;
+  void AddClassifications(FieldCandidatesMap* field_candidates) const override;
 
  private:
   FirstLastNameField();
@@ -73,8 +71,7 @@
 }
 
 // This is overriden in concrete subclasses.
-bool NameField::ClassifyField(ServerFieldTypeMap* map) const {
-  return false;
+void NameField::AddClassifications(FieldCandidatesMap* field_candidates) const {
 }
 
 // static
@@ -96,8 +93,9 @@
   return NULL;
 }
 
-bool FullNameField::ClassifyField(ServerFieldTypeMap* map) const {
-  return AddClassification(field_, NAME_FULL, map);
+void FullNameField::AddClassifications(
+    FieldCandidatesMap* field_candidates) const {
+  AddClassification(field_, NAME_FULL, kBaseNameParserScore, field_candidates);
 }
 
 FullNameField::FullNameField(AutofillField* field) : field_(field) {
@@ -207,12 +205,15 @@
       middle_initial_(false) {
 }
 
-bool FirstLastNameField::ClassifyField(ServerFieldTypeMap* map) const {
-  bool ok = AddClassification(first_name_, NAME_FIRST, map);
-  ok = ok && AddClassification(last_name_, NAME_LAST, map);
-  ServerFieldType type = middle_initial_ ? NAME_MIDDLE_INITIAL : NAME_MIDDLE;
-  ok = ok && AddClassification(middle_name_, type, map);
-  return ok;
+void FirstLastNameField::AddClassifications(
+    FieldCandidatesMap* field_candidates) const {
+  AddClassification(first_name_, NAME_FIRST, kBaseNameParserScore,
+                    field_candidates);
+  AddClassification(last_name_, NAME_LAST, kBaseNameParserScore,
+                    field_candidates);
+  const ServerFieldType type =
+      middle_initial_ ? NAME_MIDDLE_INITIAL : NAME_MIDDLE;
+  AddClassification(middle_name_, type, kBaseNameParserScore, field_candidates);
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/name_field.h b/components/autofill/core/browser/name_field.h
index 7fddca6b..e0356b4 100644
--- a/components/autofill/core/browser/name_field.h
+++ b/components/autofill/core/browser/name_field.h
@@ -26,8 +26,7 @@
  protected:
   NameField() {}
 
-  // FormField:
-  bool ClassifyField(ServerFieldTypeMap* map) const override;
+  void AddClassifications(FieldCandidatesMap* field_candidates) const override;
 
  private:
   FRIEND_TEST_ALL_PREFIXES(NameFieldTest, FirstMiddleLast);
diff --git a/components/autofill/core/browser/name_field_unittest.cc b/components/autofill/core/browser/name_field_unittest.cc
index f16add0..2221da1 100644
--- a/components/autofill/core/browser/name_field_unittest.cc
+++ b/components/autofill/core/browser/name_field_unittest.cc
@@ -23,7 +23,7 @@
  protected:
   ScopedVector<AutofillField> list_;
   scoped_ptr<NameField> field_;
-  ServerFieldTypeMap field_type_map_;
+  FieldCandidatesMap field_candidates_map_;
 
   // Downcast for tests.
   static scoped_ptr<NameField> Parse(AutofillScanner* scanner) {
@@ -54,16 +54,19 @@
   AutofillScanner scanner(list_.get());
   field_ = Parse(&scanner);
   ASSERT_NE(nullptr, field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
-  EXPECT_EQ(NAME_FIRST, field_type_map_[ASCIIToUTF16("name1")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name2")) != field_type_map_.end());
-  EXPECT_EQ(NAME_MIDDLE, field_type_map_[ASCIIToUTF16("name2")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name3")) != field_type_map_.end());
-  EXPECT_EQ(NAME_LAST, field_type_map_[ASCIIToUTF16("name3")]);
+  field_->AddClassifications(&field_candidates_map_);
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(NAME_FIRST,
+            field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name2")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(NAME_MIDDLE,
+            field_candidates_map_[ASCIIToUTF16("name2")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name3")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(NAME_LAST,
+            field_candidates_map_[ASCIIToUTF16("name3")].BestHeuristicType());
 }
 
 TEST_F(NameFieldTest, FirstMiddleLast2) {
@@ -85,16 +88,19 @@
   AutofillScanner scanner(list_.get());
   field_ = Parse(&scanner);
   ASSERT_NE(nullptr, field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
-  EXPECT_EQ(NAME_FIRST, field_type_map_[ASCIIToUTF16("name1")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name2")) != field_type_map_.end());
-  EXPECT_EQ(NAME_MIDDLE, field_type_map_[ASCIIToUTF16("name2")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name3")) != field_type_map_.end());
-  EXPECT_EQ(NAME_LAST, field_type_map_[ASCIIToUTF16("name3")]);
+  field_->AddClassifications(&field_candidates_map_);
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(NAME_FIRST,
+            field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name2")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(NAME_MIDDLE,
+            field_candidates_map_[ASCIIToUTF16("name2")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name3")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(NAME_LAST,
+            field_candidates_map_[ASCIIToUTF16("name3")].BestHeuristicType());
 }
 
 TEST_F(NameFieldTest, FirstLast) {
@@ -112,13 +118,15 @@
   AutofillScanner scanner(list_.get());
   field_ = Parse(&scanner);
   ASSERT_NE(nullptr, field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
-  EXPECT_EQ(NAME_FIRST, field_type_map_[ASCIIToUTF16("name1")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name2")) != field_type_map_.end());
-  EXPECT_EQ(NAME_LAST, field_type_map_[ASCIIToUTF16("name2")]);
+  field_->AddClassifications(&field_candidates_map_);
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(NAME_FIRST,
+            field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name2")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(NAME_LAST,
+            field_candidates_map_[ASCIIToUTF16("name2")].BestHeuristicType());
 }
 
 TEST_F(NameFieldTest, FirstLast2) {
@@ -136,13 +144,15 @@
   AutofillScanner scanner(list_.get());
   field_ = Parse(&scanner);
   ASSERT_NE(nullptr, field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
-  EXPECT_EQ(NAME_FIRST, field_type_map_[ASCIIToUTF16("name1")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name2")) != field_type_map_.end());
-  EXPECT_EQ(NAME_LAST, field_type_map_[ASCIIToUTF16("name2")]);
+  field_->AddClassifications(&field_candidates_map_);
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(NAME_FIRST,
+            field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name2")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(NAME_LAST,
+            field_candidates_map_[ASCIIToUTF16("name2")].BestHeuristicType());
 }
 
 TEST_F(NameFieldTest, FirstLastMiddleWithSpaces) {
@@ -164,16 +174,19 @@
   AutofillScanner scanner(list_.get());
   field_ = Parse(&scanner);
   ASSERT_NE(nullptr, field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
-  EXPECT_EQ(NAME_FIRST, field_type_map_[ASCIIToUTF16("name1")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name2")) != field_type_map_.end());
-  EXPECT_EQ(NAME_MIDDLE, field_type_map_[ASCIIToUTF16("name2")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name3")) != field_type_map_.end());
-  EXPECT_EQ(NAME_LAST, field_type_map_[ASCIIToUTF16("name3")]);
+  field_->AddClassifications(&field_candidates_map_);
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(NAME_FIRST,
+            field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name2")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(NAME_MIDDLE,
+            field_candidates_map_[ASCIIToUTF16("name2")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name3")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(NAME_LAST,
+            field_candidates_map_[ASCIIToUTF16("name3")].BestHeuristicType());
 }
 
 TEST_F(NameFieldTest, FirstLastEmpty) {
@@ -191,13 +204,15 @@
   AutofillScanner scanner(list_.get());
   field_ = Parse(&scanner);
   ASSERT_NE(nullptr, field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
-  EXPECT_EQ(NAME_FIRST, field_type_map_[ASCIIToUTF16("name1")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name2")) != field_type_map_.end());
-  EXPECT_EQ(NAME_LAST, field_type_map_[ASCIIToUTF16("name2")]);
+  field_->AddClassifications(&field_candidates_map_);
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(NAME_FIRST,
+            field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name2")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(NAME_LAST,
+            field_candidates_map_[ASCIIToUTF16("name2")].BestHeuristicType());
 }
 
 TEST_F(NameFieldTest, FirstMiddleLastEmpty) {
@@ -219,16 +234,19 @@
   AutofillScanner scanner(list_.get());
   field_ = Parse(&scanner);
   ASSERT_NE(nullptr, field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
-  EXPECT_EQ(NAME_FIRST, field_type_map_[ASCIIToUTF16("name1")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name2")) != field_type_map_.end());
-  EXPECT_EQ(NAME_MIDDLE_INITIAL, field_type_map_[ASCIIToUTF16("name2")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name3")) != field_type_map_.end());
-  EXPECT_EQ(NAME_LAST, field_type_map_[ASCIIToUTF16("name3")]);
+  field_->AddClassifications(&field_candidates_map_);
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(NAME_FIRST,
+            field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name2")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(NAME_MIDDLE_INITIAL,
+            field_candidates_map_[ASCIIToUTF16("name2")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name3")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(NAME_LAST,
+            field_candidates_map_[ASCIIToUTF16("name3")].BestHeuristicType());
 }
 
 TEST_F(NameFieldTest, MiddleInitial) {
@@ -250,16 +268,19 @@
   AutofillScanner scanner(list_.get());
   field_ = Parse(&scanner);
   ASSERT_NE(nullptr, field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
-  EXPECT_EQ(NAME_FIRST, field_type_map_[ASCIIToUTF16("name1")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name2")) != field_type_map_.end());
-  EXPECT_EQ(NAME_MIDDLE_INITIAL, field_type_map_[ASCIIToUTF16("name2")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name3")) != field_type_map_.end());
-  EXPECT_EQ(NAME_LAST, field_type_map_[ASCIIToUTF16("name3")]);
+  field_->AddClassifications(&field_candidates_map_);
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(NAME_FIRST,
+            field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name2")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(NAME_MIDDLE_INITIAL,
+            field_candidates_map_[ASCIIToUTF16("name2")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name3")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(NAME_LAST,
+            field_candidates_map_[ASCIIToUTF16("name3")].BestHeuristicType());
 }
 
 TEST_F(NameFieldTest, MiddleInitialNoLastName) {
@@ -300,16 +321,19 @@
   AutofillScanner scanner(list_.get());
   field_ = Parse(&scanner);
   ASSERT_NE(nullptr, field_.get());
-  ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name1")) != field_type_map_.end());
-  EXPECT_EQ(NAME_FIRST, field_type_map_[ASCIIToUTF16("name1")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name2")) != field_type_map_.end());
-  EXPECT_EQ(NAME_MIDDLE_INITIAL, field_type_map_[ASCIIToUTF16("name2")]);
-  ASSERT_TRUE(
-      field_type_map_.find(ASCIIToUTF16("name3")) != field_type_map_.end());
-  EXPECT_EQ(NAME_LAST, field_type_map_[ASCIIToUTF16("name3")]);
+  field_->AddClassifications(&field_candidates_map_);
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name1")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(NAME_FIRST,
+            field_candidates_map_[ASCIIToUTF16("name1")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name2")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(NAME_MIDDLE_INITIAL,
+            field_candidates_map_[ASCIIToUTF16("name2")].BestHeuristicType());
+  ASSERT_TRUE(field_candidates_map_.find(ASCIIToUTF16("name3")) !=
+              field_candidates_map_.end());
+  EXPECT_EQ(NAME_LAST,
+            field_candidates_map_[ASCIIToUTF16("name3")].BestHeuristicType());
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/phone_field.cc b/components/autofill/core/browser/phone_field.cc
index a8810ec4..77ba9ac 100644
--- a/components/autofill/core/browser/phone_field.cc
+++ b/components/autofill/core/browser/phone_field.cc
@@ -207,25 +207,24 @@
   return std::move(phone_field);
 }
 
-bool PhoneField::ClassifyField(ServerFieldTypeMap* map) const {
-  bool ok = true;
-
+void PhoneField::AddClassifications(
+    FieldCandidatesMap* field_candidates) const {
   DCHECK(parsed_phone_fields_[FIELD_PHONE]);  // Phone was correctly parsed.
 
   if ((parsed_phone_fields_[FIELD_COUNTRY_CODE]) ||
       (parsed_phone_fields_[FIELD_AREA_CODE]) ||
       (parsed_phone_fields_[FIELD_SUFFIX])) {
     if (parsed_phone_fields_[FIELD_COUNTRY_CODE]) {
-      ok = ok && AddClassification(parsed_phone_fields_[FIELD_COUNTRY_CODE],
-                                   PHONE_HOME_COUNTRY_CODE,
-                                   map);
+      AddClassification(parsed_phone_fields_[FIELD_COUNTRY_CODE],
+                        PHONE_HOME_COUNTRY_CODE, kBasePhoneParserScore,
+                        field_candidates);
     }
 
     ServerFieldType field_number_type = PHONE_HOME_NUMBER;
     if (parsed_phone_fields_[FIELD_AREA_CODE]) {
-      ok = ok && AddClassification(parsed_phone_fields_[FIELD_AREA_CODE],
-                                   PHONE_HOME_CITY_CODE,
-                                   map);
+      AddClassification(parsed_phone_fields_[FIELD_AREA_CODE],
+                        PHONE_HOME_CITY_CODE, kBasePhoneParserScore,
+                        field_candidates);
     } else if (parsed_phone_fields_[FIELD_COUNTRY_CODE]) {
       // Only if we can find country code without city code, it means the phone
       // number include city code.
@@ -233,23 +232,19 @@
     }
     // We tag the prefix as PHONE_HOME_NUMBER, then when filling the form
     // we fill only the prefix depending on the size of the input field.
-    ok = ok && AddClassification(parsed_phone_fields_[FIELD_PHONE],
-                                 field_number_type,
-                                 map);
+    AddClassification(parsed_phone_fields_[FIELD_PHONE], field_number_type,
+                      kBasePhoneParserScore, field_candidates);
     // We tag the suffix as PHONE_HOME_NUMBER, then when filling the form
     // we fill only the suffix depending on the size of the input field.
     if (parsed_phone_fields_[FIELD_SUFFIX]) {
-      ok = ok && AddClassification(parsed_phone_fields_[FIELD_SUFFIX],
-                                   PHONE_HOME_NUMBER,
-                                   map);
+      AddClassification(parsed_phone_fields_[FIELD_SUFFIX], PHONE_HOME_NUMBER,
+                        kBasePhoneParserScore, field_candidates);
     }
   } else {
-    ok = AddClassification(parsed_phone_fields_[FIELD_PHONE],
-                           PHONE_HOME_WHOLE_NUMBER,
-                           map);
+    AddClassification(parsed_phone_fields_[FIELD_PHONE],
+                      PHONE_HOME_WHOLE_NUMBER, kBasePhoneParserScore,
+                      field_candidates);
   }
-
-  return ok;
 }
 
 PhoneField::PhoneField() {
diff --git a/components/autofill/core/browser/phone_field.h b/components/autofill/core/browser/phone_field.h
index 03dc4a9..9134ad9 100644
--- a/components/autofill/core/browser/phone_field.h
+++ b/components/autofill/core/browser/phone_field.h
@@ -33,8 +33,7 @@
   static scoped_ptr<FormField> Parse(AutofillScanner* scanner);
 
  protected:
-  // FormField:
-  bool ClassifyField(ServerFieldTypeMap* map) const override;
+  void AddClassifications(FieldCandidatesMap* field_candidates) const override;
 
  private:
   FRIEND_TEST_ALL_PREFIXES(PhoneFieldTest, ParseOneLinePhone);
diff --git a/components/autofill/core/browser/phone_field_unittest.cc b/components/autofill/core/browser/phone_field_unittest.cc
index 200d381..72903fc 100644
--- a/components/autofill/core/browser/phone_field_unittest.cc
+++ b/components/autofill/core/browser/phone_field_unittest.cc
@@ -42,19 +42,19 @@
   void Clear() {
     list_.clear();
     field_.reset();
-    field_type_map_.clear();
+    field_candidates_map_.clear();
   }
 
   void CheckField(const std::string& name,
                   ServerFieldType expected_type) const {
-    auto it = field_type_map_.find(ASCIIToUTF16(name));
-    ASSERT_TRUE(it != field_type_map_.end()) << name;
-    EXPECT_EQ(expected_type, it->second) << name;
+    auto it = field_candidates_map_.find(ASCIIToUTF16(name));
+    ASSERT_TRUE(it != field_candidates_map_.end()) << name;
+    EXPECT_EQ(expected_type, it->second.BestHeuristicType()) << name;
   }
 
   ScopedVector<AutofillField> list_;
   scoped_ptr<PhoneField> field_;
-  ServerFieldTypeMap field_type_map_;
+  FieldCandidatesMap field_candidates_map_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(PhoneFieldTest);
@@ -87,7 +87,7 @@
     AutofillScanner scanner(list_.get());
     field_ = Parse(&scanner);
     ASSERT_NE(nullptr, field_.get());
-    ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
+    field_->AddClassifications(&field_candidates_map_);
     CheckField("phone1", PHONE_HOME_WHOLE_NUMBER);
   }
 }
@@ -110,7 +110,7 @@
     AutofillScanner scanner(list_.get());
     field_ = Parse(&scanner);
     ASSERT_NE(nullptr, field_.get());
-    ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
+    field_->AddClassifications(&field_candidates_map_);
     CheckField("areacode1", PHONE_HOME_CITY_CODE);
     CheckField("phone2", PHONE_HOME_NUMBER);
   }
@@ -151,11 +151,11 @@
     AutofillScanner scanner(list_.get());
     field_ = Parse(&scanner);
     ASSERT_NE(nullptr, field_.get());
-    ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
+    field_->AddClassifications(&field_candidates_map_);
     CheckField("areacode1", PHONE_HOME_CITY_CODE);
     CheckField("prefix2", PHONE_HOME_NUMBER);
     CheckField("suffix3", PHONE_HOME_NUMBER);
-    EXPECT_FALSE(ContainsKey(field_type_map_, ASCIIToUTF16("ext4")));
+    EXPECT_FALSE(ContainsKey(field_candidates_map_, ASCIIToUTF16("ext4")));
   }
 }
 
@@ -184,7 +184,7 @@
     AutofillScanner scanner(list_.get());
     field_ = Parse(&scanner);
     ASSERT_NE(nullptr, field_.get());
-    ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
+    field_->AddClassifications(&field_candidates_map_);
     CheckField("areacode1", PHONE_HOME_CITY_CODE);
     CheckField("prefix2", PHONE_HOME_NUMBER);
     CheckField("suffix3", PHONE_HOME_NUMBER);
@@ -216,7 +216,7 @@
     AutofillScanner scanner(list_.get());
     field_ = Parse(&scanner);
     ASSERT_NE(nullptr, field_.get());
-    ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
+    field_->AddClassifications(&field_candidates_map_);
     CheckField("phone1", PHONE_HOME_CITY_CODE);
     CheckField("phone2", PHONE_HOME_NUMBER);
     CheckField("phone3", PHONE_HOME_NUMBER);
@@ -245,7 +245,7 @@
     AutofillScanner scanner(list_.get());
     field_ = Parse(&scanner);
     ASSERT_NE(nullptr, field_.get());
-    ASSERT_TRUE(field_->ClassifyField(&field_type_map_));
+    field_->AddClassifications(&field_candidates_map_);
     CheckField("country", PHONE_HOME_COUNTRY_CODE);
     CheckField("phone", PHONE_HOME_CITY_AND_NUMBER);
   }
diff --git a/components/autofill/core/browser/proto/server.proto b/components/autofill/core/browser/proto/server.proto
index 08ac272..0d8f4867 100644
--- a/components/autofill/core/browser/proto/server.proto
+++ b/components/autofill/core/browser/proto/server.proto
@@ -34,7 +34,7 @@
 
 // This message contains information about the field types in a single form.
 // It is sent by the toolbar to contribute to the field type statistics.
-// Next available id: 17
+// Next available id: 18
 message AutofillUploadContents {
   required string client_version = 1;
   required fixed64 form_signature = 2;
@@ -72,6 +72,16 @@
     // The label that is used alongside the field. Its value is truncated at
     // 200 characters.
     optional string label = 11;
+
+    enum PasswordGenerationType {
+      NO_GENERATION = 0;
+      AUTOMATICALLY_TRIGGERED_GENERATION_ON_SIGN_UP_FORM = 1;
+      AUTOMATICALLY_TRIGGERED_GENERATION_ON_CHANGE_PASSWORD_FORM = 2;
+      MANUALLY_TRIGGERED_GENERATION_ON_SIGN_UP_FORM = 3;
+      MANUALLY_TRIGGERED_GENERATION_ON_CHANGE_PASSWORD_FORM = 4;
+    }
+    // The type of password generation, if it happened.
+    optional PasswordGenerationType generation_type = 17;
   }
   // Signature of the form action host (e.g. Hash64Bit("example.com")).
   optional fixed64 action_signature = 13;
@@ -86,4 +96,4 @@
 
   // The form name.
   optional string form_name = 16;
-}
\ No newline at end of file
+}
diff --git a/components/bitmap_uploader/bitmap_uploader.cc b/components/bitmap_uploader/bitmap_uploader.cc
index 8a3a80fc..2b1a1f8 100644
--- a/components/bitmap_uploader/bitmap_uploader.cc
+++ b/components/bitmap_uploader/bitmap_uploader.cc
@@ -54,9 +54,8 @@
   mus::mojom::CommandBufferPtr gles2_client;
   gpu_service_->CreateOffscreenGLES2Context(GetProxy(&gles2_client));
   gles2_context_ = MojoGLES2CreateContext(
-      gles2_client.PassInterface().PassHandle().release().value(),
-      nullptr,
-      &LostContext, nullptr, mojo::Environment::GetDefaultAsyncWaiter());
+      gles2_client.PassInterface().PassHandle().release().value(), nullptr,
+      &LostContext, nullptr);
   MojoGLES2MakeCurrent(gles2_context_);
 }
 
diff --git a/components/browser_sync.gypi b/components/browser_sync.gypi
index 5c464060..b5bb383 100644
--- a/components/browser_sync.gypi
+++ b/components/browser_sync.gypi
@@ -31,7 +31,6 @@
         'syncable_prefs',
         'sync_bookmarks',
         'sync_driver',
-        'sync_driver_features',
         'sync_sessions',
         'variations',
         'version_info',
diff --git a/components/browser_sync/browser/BUILD.gn b/components/browser_sync/browser/BUILD.gn
index ea42016..76b8065 100644
--- a/components/browser_sync/browser/BUILD.gn
+++ b/components/browser_sync/browser/BUILD.gn
@@ -49,6 +49,7 @@
 
   sources = [
     "profile_sync_service_autofill_unittest.cc",
+    "profile_sync_service_bookmark_unittest.cc",
     "profile_sync_service_startup_unittest.cc",
     "profile_sync_service_typed_url_unittest.cc",
     "profile_sync_service_unittest.cc",
@@ -61,6 +62,9 @@
     "//base/test:test_support",
     "//components/autofill/core/browser:test_support",
     "//components/autofill/core/common:common",
+    "//components/bookmarks/browser:browser",
+    "//components/bookmarks/managed:managed",
+    "//components/bookmarks/test:test",
     "//components/browser_sync/common",
     "//components/dom_distiller/core",
     "//components/history/core/browser:browser",
@@ -71,6 +75,7 @@
     "//components/signin/core/browser:test_support",
     "//components/signin/core/common:common",
     "//components/strings",
+    "//components/sync_bookmarks:sync_bookmarks",
     "//components/sync_driver",
     "//components/sync_driver:test_support",
     "//components/sync_sessions",
@@ -82,6 +87,7 @@
     "//components/webdata_services:test_support",
     "//google_apis",
     "//net",
+    "//sync:test_support_sync_internal_api",
     "//testing/gmock",
     "//testing/gtest",
     "//ui/base",
diff --git a/components/browser_sync/browser/DEPS b/components/browser_sync/browser/DEPS
index b75d3a9..7b3e9c3 100644
--- a/components/browser_sync/browser/DEPS
+++ b/components/browser_sync/browser/DEPS
@@ -1,6 +1,8 @@
 include_rules = [
   "+components/autofill/core",
   "+components/bookmarks/browser",
+  "+components/bookmarks/managed",
+  "+components/bookmarks/test",
   "+components/dom_distiller/core",
   "+components/history/core/browser",
   "+components/invalidation",
diff --git a/components/browser_sync/browser/profile_sync_components_factory_impl.cc b/components/browser_sync/browser/profile_sync_components_factory_impl.cc
index 9ce6b74..370c93e 100644
--- a/components/browser_sync/browser/profile_sync_components_factory_impl.cc
+++ b/components/browser_sync/browser/profile_sync_components_factory_impl.cc
@@ -331,7 +331,7 @@
   scoped_ptr<syncer::AttachmentDownloader> attachment_downloader;
   // Only construct an AttachmentUploader and AttachmentDownload if we have sync
   // credentials. We may not have sync credentials because there may not be a
-  // signed in sync user (e.g. sync is running in "backup" mode).
+  // signed in sync user.
   if (!user_share.sync_credentials.account_id.empty() &&
       !user_share.sync_credentials.scope_set.empty()) {
     scoped_refptr<OAuth2TokenServiceRequest::TokenServiceProvider>
diff --git a/components/browser_sync/browser/profile_sync_service.cc b/components/browser_sync/browser/profile_sync_service.cc
index 34bf3043..67987b2 100644
--- a/components/browser_sync/browser/profile_sync_service.cc
+++ b/components/browser_sync/browser/profile_sync_service.cc
@@ -51,7 +51,6 @@
 #include "components/sync_driver/signin_manager_wrapper.h"
 #include "components/sync_driver/sync_api_component_factory.h"
 #include "components/sync_driver/sync_client.h"
-#include "components/sync_driver/sync_driver_features.h"
 #include "components/sync_driver/sync_driver_switches.h"
 #include "components/sync_driver/sync_error_controller.h"
 #include "components/sync_driver/sync_stopped_reporter.h"
@@ -72,6 +71,7 @@
 #include "sync/internal_api/public/configure_reason.h"
 #include "sync/internal_api/public/http_bridge_network_resources.h"
 #include "sync/internal_api/public/network_resources.h"
+#include "sync/internal_api/public/sessions/model_neutral_state.h"
 #include "sync/internal_api/public/sessions/type_debug_info_observer.h"
 #include "sync/internal_api/public/shutdown_reason.h"
 #include "sync/internal_api/public/sync_encryption_handler.h"
@@ -144,9 +144,6 @@
 static const base::FilePath::CharType kSyncDataFolderName[] =
     FILE_PATH_LITERAL("Sync Data");
 
-static const base::FilePath::CharType kSyncBackupDataFolderName[] =
-    FILE_PATH_LITERAL("Sync Data Backup");
-
 namespace {
 
 // Perform the actual sync data folder deletion.
@@ -165,8 +162,6 @@
   return (error.action != syncer::UNKNOWN_ACTION &&
           error.action != syncer::DISABLE_SYNC_ON_CLIENT &&
           error.action != syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT &&
-          error.action != syncer::DISABLE_SYNC_AND_ROLLBACK &&
-          error.action != syncer::ROLLBACK_DONE &&
           error.action != syncer::RESET_LOCAL_SYNC_DATA);
 }
 
@@ -223,9 +218,6 @@
       last_get_token_error_(GoogleServiceAuthError::AuthErrorNone()),
       network_resources_(new syncer::HttpBridgeNetworkResources),
       start_behavior_(init_params.start_behavior),
-      backend_mode_(IDLE),
-      need_backup_(false),
-      backup_finished_(false),
       catch_up_configure_in_progress_(false),
       passphrase_prompt_triggered_by_version_(false),
       weak_factory_(this),
@@ -260,13 +252,7 @@
   startup_controller_.reset(new browser_sync::StartupController(
       start_behavior_, oauth2_token_service_, &sync_prefs_, signin_.get(),
       base::Bind(&ProfileSyncService::StartUpSlowBackendComponents,
-                 startup_controller_weak_factory_.GetWeakPtr(), SYNC)));
-  backup_rollback_controller_.reset(new sync_driver::BackupRollbackController(
-      &sync_prefs_, signin_.get(),
-      base::Bind(&ProfileSyncService::StartUpSlowBackendComponents,
-                 startup_controller_weak_factory_.GetWeakPtr(), BACKUP),
-      base::Bind(&ProfileSyncService::StartUpSlowBackendComponents,
-                 startup_controller_weak_factory_.GetWeakPtr(), ROLLBACK)));
+                 startup_controller_weak_factory_.GetWeakPtr())));
   scoped_ptr<browser_sync::LocalSessionEventRouter> router(
       sync_client_->GetSyncSessionsClient()->GetLocalSessionEventRouter());
   local_device_ = sync_client_->GetSyncApiComponentFactory()
@@ -351,26 +337,6 @@
   AddObserver(sync_error_controller_.get());
 #endif
 
-  bool running_rollback = false;
-  if (sync_driver::BackupRollbackController::IsBackupEnabled()) {
-    // Backup is needed if user's not signed in or signed in but previous
-    // backup didn't finish, i.e. backend didn't switch from backup to sync.
-    need_backup_ = !IsSignedIn() || sync_prefs_.GetFirstSyncTime().is_null();
-
-    // Try to resume rollback if it didn't finish in last session.
-    running_rollback = backup_rollback_controller_->StartRollback();
-  } else {
-    need_backup_ = false;
-  }
-
-#if BUILDFLAG(ENABLE_PRE_SYNC_BACKUP)
-  if (!running_rollback && !IsSignedIn()) {
-    CleanUpBackup();
-  }
-#else
-  DCHECK(!running_rollback);
-#endif
-
   memory_pressure_listener_.reset(new base::MemoryPressureListener(base::Bind(
       &ProfileSyncService::OnMemoryPressure, weak_factory_.GetWeakPtr())));
   startup_controller_->Reset(GetRegisteredDataTypes());
@@ -413,7 +379,6 @@
 
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kSyncEnableClearDataOnPassphraseEncryption) &&
-      backend_mode_ == SYNC &&
       sync_prefs_.GetPassphraseEncryptionTransitionInProgress()) {
     BeginConfigureCatchUpBeforeClear();
     return;
@@ -493,34 +458,21 @@
 
 SyncCredentials ProfileSyncService::GetCredentials() {
   SyncCredentials credentials;
-  if (backend_mode_ == SYNC) {
-    credentials.account_id = signin_->GetAccountIdToUse();
-    DCHECK(!credentials.account_id.empty());
-    credentials.email = signin_->GetEffectiveUsername();
-    credentials.sync_token = access_token_;
+  credentials.account_id = signin_->GetAccountIdToUse();
+  DCHECK(!credentials.account_id.empty());
+  credentials.email = signin_->GetEffectiveUsername();
+  credentials.sync_token = access_token_;
 
-    if (credentials.sync_token.empty())
-      credentials.sync_token = "credentials_lost";
+  if (credentials.sync_token.empty())
+    credentials.sync_token = "credentials_lost";
 
-    credentials.scope_set.insert(signin_->GetSyncScopeToUse());
-  }
+  credentials.scope_set.insert(signin_->GetSyncScopeToUse());
 
   return credentials;
 }
 
 bool ProfileSyncService::ShouldDeleteSyncFolder() {
-  switch (backend_mode_) {
-    case SYNC:
-      return !IsFirstSetupComplete();
-    case BACKUP:
-      return true;
-    case ROLLBACK:
-      return false;
-    case IDLE:
-      NOTREACHED();
-      return true;
-  }
-  return true;
+  return !IsFirstSetupComplete();
 }
 
 void ProfileSyncService::InitializeBackend(bool delete_stale_data) {
@@ -531,7 +483,7 @@
 
   SyncCredentials credentials = GetCredentials();
 
-  if (backend_mode_ == SYNC && delete_stale_data)
+  if (delete_stale_data)
     ClearStaleErrors();
 
   SyncBackendHost::HttpPostProviderFactoryGetter
@@ -546,7 +498,7 @@
       GetJsEventHandler(), sync_service_url_, local_device_->GetSyncUserAgent(),
       credentials, delete_stale_data,
       scoped_ptr<syncer::SyncManagerFactory>(
-          new syncer::SyncManagerFactory(GetManagerType())),
+          new syncer::SyncManagerFactory()),
       MakeWeakHandle(weak_factory_.GetWeakPtr()),
       base::Bind(browser_sync::ChromeReportUnrecoverableError, channel_),
       http_post_provider_factory_getter, std::move(saved_nigori_state_));
@@ -623,71 +575,11 @@
   startup_controller_->OnDataTypeRequestsSyncStartup(type);
 }
 
-void ProfileSyncService::StartUpSlowBackendComponents(
-    ProfileSyncService::BackendMode mode) {
-  DCHECK_NE(IDLE, mode);
-  if (backend_mode_ == mode) {
-    return;
-  }
-
-  // Backend mode transition rules:
-  // * can transit from IDLE to any other non-IDLE mode.
-  // * forbidden to transit from SYNC to any other mode, i.e. SYNC backend must
-  //   be explicitly shut down before backup/rollback starts.
-  // * can not transit out of ROLLBACK mode until rollback is finished
-  //   (successfully or unsuccessfully).
-  // * can not transit out of BACKUP mode until backup is finished
-  //   (successfully or unsuccessfully).
-  // * if backup is needed, can only transit to SYNC if backup is finished,
-
-  if (backend_mode_ == SYNC) {
-    LOG(DFATAL) << "Shouldn't switch from mode SYNC to mode " << mode;
-    return;
-  }
-
-  if (backend_mode_ == ROLLBACK ||
-      (backend_mode_ == BACKUP && !backup_finished_)) {
-    // Wait for rollback/backup to finish before start new backend.
-    return;
-  }
-
-  if (mode == SYNC && NeedBackup() && !backup_finished_) {
-    if (backend_mode_ != BACKUP)
-      backup_rollback_controller_->StartBackup();
-    return;
-  }
-
-  DVLOG(1) << "Start backend mode: " << mode;
-
-  if (backend_) {
-    if (mode == SYNC)
-      ShutdownImpl(syncer::SWITCH_MODE_SYNC);
-    else
-      ShutdownImpl(syncer::STOP_SYNC);
-  }
-
-  backend_mode_ = mode;
-
-  if (backend_mode_ == BACKUP)
-    backup_start_time_ = base::Time::Now();
-
-  if (backend_mode_ == SYNC && !backup_start_time_.is_null()) {
-    UMA_HISTOGRAM_MEDIUM_TIMES("Sync.FirstSyncDelayByBackup",
-                               base::Time::Now() - backup_start_time_);
-    backup_start_time_ = base::Time();
-  }
-
-  if (backend_mode_ == ROLLBACK)
-    ClearBrowsingDataSinceFirstSync();
-  else if (backend_mode_ == SYNC)
-    CheckSyncBackupIfNeeded();
-
-  base::FilePath sync_folder = backend_mode_ == SYNC ?
-      base::FilePath(kSyncDataFolderName) :
-      base::FilePath(kSyncBackupDataFolderName);
+void ProfileSyncService::StartUpSlowBackendComponents() {
+  base::FilePath sync_folder = base::FilePath(kSyncDataFolderName);
 
   invalidation::InvalidationService* invalidator =
-      backend_mode_ == SYNC ? sync_client_->GetInvalidationService() : nullptr;
+      sync_client_->GetInvalidationService();
 
   directory_path_ = base_directory_.Append(sync_folder);
 
@@ -873,25 +765,9 @@
 
   weak_factory_.InvalidateWeakPtrs();
 
-  if (backend_mode_ == SYNC)
-    startup_controller_->Reset(GetRegisteredDataTypes());
-
-  // Don't let backup block sync regardless backup succeeded or not.
-  if (backend_mode_ == BACKUP)
-    backup_finished_ = true;
-
-  // Sync could be blocked by rollback/backup. Post task to check whether sync
-  // should start after shutting down rollback/backup backend.
-  if ((backend_mode_ == ROLLBACK || backend_mode_ == BACKUP) &&
-      reason != syncer::SWITCH_MODE_SYNC &&
-      reason != syncer::BROWSER_SHUTDOWN) {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(&ProfileSyncService::TryStartSyncAfterBackup,
-                              startup_controller_weak_factory_.GetWeakPtr()));
-  }
+  startup_controller_->Reset(GetRegisteredDataTypes());
 
   // Clear various flags.
-  backend_mode_ = IDLE;
   expect_sync_configuration_aborted_ = false;
   is_auth_in_progress_ = false;
   backend_initialized_ = false;
@@ -1017,9 +893,6 @@
 }
 
 void ProfileSyncService::UpdateBackendInitUMA(bool success) {
-  if (backend_mode_ != SYNC)
-    return;
-
   is_first_time_sync_configure_ = !IsFirstSetupComplete();
 
   if (is_first_time_sync_configure_) {
@@ -1039,14 +912,6 @@
 }
 
 void ProfileSyncService::PostBackendInitialization() {
-  // Never get here for backup / restore.
-  DCHECK_EQ(backend_mode_, SYNC);
-
-  if (last_backup_time_) {
-    DCHECK(device_info_sync_service_);
-    device_info_sync_service_->UpdateLocalDeviceBackupTime(*last_backup_time_);
-  }
-
   if (protocol_event_observers_.might_have_observers()) {
     backend_->RequestBufferedProtocolEventsAndEnableForwarding();
   }
@@ -1128,15 +993,17 @@
   local_device_->Initialize(cache_guid, signin_scoped_device_id,
                             blocking_pool_);
 
-  if (backend_mode_ == BACKUP || backend_mode_ == ROLLBACK)
-    ConfigureDataTypeManager();
-  else
-    PostBackendInitialization();
+  PostBackendInitialization();
 }
 
 void ProfileSyncService::OnSyncCycleCompleted() {
   UpdateLastSyncedTime();
-  if (IsDataTypeControllerRunning(syncer::SESSIONS)) {
+  const syncer::sessions::SyncSessionSnapshot snapshot =
+      GetLastSessionSnapshot();
+  if (IsDataTypeControllerRunning(syncer::SESSIONS) &&
+      snapshot.model_neutral_state().get_updates_request_types.Has(
+          syncer::SESSIONS) &&
+      !syncer::sessions::HasSyncerError(snapshot.model_neutral_state())) {
     // Trigger garbage collection of old sessions now that we've downloaded
     // any new session data.
     base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -1364,9 +1231,6 @@
                                    true,
                                    ERROR_REASON_ACTIONABLE_ERROR);
       break;
-    case syncer::DISABLE_SYNC_AND_ROLLBACK:
-      backup_rollback_controller_->OnRollbackReceived();
-      // Fall through to shutdown backend and sign user out.
     case syncer::DISABLE_SYNC_ON_CLIENT:
       if (error.error_type == syncer::NOT_MY_BIRTHDAY) {
         UMA_HISTOGRAM_ENUMERATION("Sync.StopSource", syncer::BIRTHDAY_ERROR,
@@ -1384,9 +1248,6 @@
       }
 #endif
       break;
-    case syncer::ROLLBACK_DONE:
-      backup_rollback_controller_->OnRollbackDone();
-      break;
     case syncer::STOP_SYNC_FOR_DISABLED_ACCOUNT:
       // Sync disabled by domain admin. we should stop syncing until next
       // restart.
@@ -1401,17 +1262,6 @@
       NOTREACHED();
   }
   NotifyObservers();
-
-  if (error.action == syncer::DISABLE_SYNC_ON_CLIENT ||
-      (error.action == syncer::DISABLE_SYNC_AND_ROLLBACK &&
-          !backup_rollback_controller_->StartRollback())) {
-    // Clean up backup data for sign-out only or when rollback is disabled.
-    CleanUpBackup();
-  } else if (error.action == syncer::ROLLBACK_DONE) {
-    // Shut down ROLLBACK backend and delete backup DB.
-    ShutdownImpl(syncer::DISABLE_SYNC);
-    sync_prefs_.ClearFirstSyncTime();
-  }
 }
 
 void ProfileSyncService::OnLocalSetPassphraseEncryption(
@@ -1431,7 +1281,6 @@
 }
 
 void ProfileSyncService::BeginConfigureCatchUpBeforeClear() {
-  DCHECK_EQ(backend_mode_, SYNC);
   DCHECK(data_type_manager_);
   DCHECK(!saved_nigori_state_);
   saved_nigori_state_ =
@@ -1466,26 +1315,6 @@
   configure_status_ = result.status;
   data_type_status_table_ = result.data_type_status_table;
 
-  if (backend_mode_ != SYNC) {
-    if (configure_status_ == DataTypeManager::OK) {
-      StartSyncingWithServer();
-
-      // Backup is done after models are associated.
-      if (backend_mode_ == BACKUP)
-        backup_finished_ = true;
-
-      // Asynchronously check whether sync needs to start.
-      base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE, base::Bind(&ProfileSyncService::TryStartSyncAfterBackup,
-                                startup_controller_weak_factory_.GetWeakPtr()));
-    } else if (!expect_sync_configuration_aborted_) {
-      DVLOG(1) << "Backup/rollback backend failed to configure.";
-      ShutdownImpl(syncer::STOP_SYNC);
-    }
-
-    return;
-  }
-
   // We should have cleared our cached passphrase before we get here (in
   // OnBackendInitialized()).
   DCHECK(cached_passphrase_.empty());
@@ -1588,10 +1417,6 @@
     return UNRECOVERABLE_ERROR;
   } else if (!backend_) {
     return NOT_ENABLED;
-  } else if (backend_mode_ == BACKUP) {
-    return BACKUP_USER_DATA;
-  } else if (backend_mode_ == ROLLBACK) {
-    return ROLLBACK_USER_DATA;
   } else if (backend_.get() && !IsFirstSetupComplete()) {
     return SETUP_INCOMPLETE;
   } else if (backend_ && IsFirstSetupComplete() && data_type_manager_ &&
@@ -1621,10 +1446,6 @@
       return "Datatypes not fully initialized";
     case INITIALIZED:
       return "Sync service initialized";
-    case BACKUP_USER_DATA:
-      return "Backing-up user data. Status: " + config_status_str;
-    case ROLLBACK_USER_DATA:
-      return "Restoring user data. Status: " + config_status_str;
     default:
       return "Status unknown: Internal error?";
   }
@@ -1679,7 +1500,7 @@
 }
 
 bool ProfileSyncService::IsSyncActive() const {
-  return backend_initialized_ && backend_mode_ == SYNC && data_type_manager_ &&
+  return backend_initialized_ && data_type_manager_ &&
          data_type_manager_->state() != DataTypeManager::STOPPED;
 }
 
@@ -1697,10 +1518,6 @@
   return backend_initialized_;
 }
 
-ProfileSyncService::BackendMode ProfileSyncService::backend_mode() const {
-  return backend_mode_;
-}
-
 bool ProfileSyncService::ConfigurationDone() const {
   return data_type_manager_ &&
          data_type_manager_->state() == DataTypeManager::CONFIGURED;
@@ -1921,7 +1738,7 @@
   // start syncing data until the user is done configuring encryption options,
   // etc. ReconfigureDatatypeManager() will get called again once the UI calls
   // SetSetupInProgress(false).
-  if (backend_mode_ == SYNC && startup_controller_->IsSetupInProgress())
+  if (startup_controller_->IsSetupInProgress())
     return;
 
   bool restart = false;
@@ -1941,24 +1758,19 @@
 
   syncer::ModelTypeSet types;
   syncer::ConfigureReason reason = syncer::CONFIGURE_REASON_UNKNOWN;
-  if (backend_mode_ == BACKUP || backend_mode_ == ROLLBACK) {
-    types = syncer::BackupTypes();
-    reason = syncer::CONFIGURE_REASON_BACKUP_ROLLBACK;
+  types = GetPreferredDataTypes();
+  if (!IsFirstSetupComplete()) {
+    reason = syncer::CONFIGURE_REASON_NEW_CLIENT;
+  } else if (restart) {
+    // Datatype downloads on restart are generally due to newly supported
+    // datatypes (although it's also possible we're picking up where a failed
+    // previous configuration left off).
+    // TODO(sync): consider detecting configuration recovery and setting
+    // the reason here appropriately.
+    reason = syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE;
   } else {
-    types = GetPreferredDataTypes();
-    if (!IsFirstSetupComplete()) {
-      reason = syncer::CONFIGURE_REASON_NEW_CLIENT;
-    } else if (restart) {
-      // Datatype downloads on restart are generally due to newly supported
-      // datatypes (although it's also possible we're picking up where a failed
-      // previous configuration left off).
-      // TODO(sync): consider detecting configuration recovery and setting
-      // the reason here appropriately.
-      reason = syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE;
-    } else {
-      // The user initiated a reconfiguration (either to add or remove types).
-      reason = syncer::CONFIGURE_REASON_RECONFIGURATION;
-    }
+    // The user initiated a reconfiguration (either to add or remove types).
+    reason = syncer::CONFIGURE_REASON_RECONFIGURATION;
   }
 
   data_type_manager_->Configure(types, reason);
@@ -2260,11 +2072,6 @@
   UMA_HISTOGRAM_ENUMERATION("Sync.StopSource", syncer::SIGN_OUT,
                             syncer::STOP_SOURCE_LIMIT);
   RequestStop(CLEAR_DATA);
-
-  if (sync_driver::BackupRollbackController::IsBackupEnabled()) {
-    need_backup_ = true;
-    backup_finished_ = false;
-  }
 }
 
 void ProfileSyncService::AddObserver(
@@ -2528,21 +2335,6 @@
   OnUnrecoverableErrorImpl(from_here, message, delete_sync_database);
 }
 
-syncer::SyncManagerFactory::MANAGER_TYPE
-ProfileSyncService::GetManagerType() const {
-  switch (backend_mode_) {
-    case SYNC:
-      return syncer::SyncManagerFactory::NORMAL;
-    case BACKUP:
-      return syncer::SyncManagerFactory::BACKUP;
-    case ROLLBACK:
-      return syncer::SyncManagerFactory::ROLLBACK;
-    case IDLE:
-      NOTREACHED();
-  }
-  return syncer::SyncManagerFactory::NORMAL;
-}
-
 bool ProfileSyncService::IsRetryingAccessTokenFetchForTest() const {
   return request_access_token_retry_timer_.IsRunning();
 }
@@ -2582,97 +2374,18 @@
 }
 
 bool ProfileSyncService::HasSyncingBackend() const {
-  return backend_mode_ != SYNC ? false : backend_ != NULL;
+  return backend_ != NULL;
 }
 
 void ProfileSyncService::UpdateFirstSyncTimePref() {
   if (!IsSignedIn()) {
-    // Clear if user's not signed in and rollback is done.
-    if (backend_mode_ != ROLLBACK)
-      sync_prefs_.ClearFirstSyncTime();
-  } else if (sync_prefs_.GetFirstSyncTime().is_null() &&
-      backend_mode_ == SYNC) {
+    sync_prefs_.ClearFirstSyncTime();
+  } else if (sync_prefs_.GetFirstSyncTime().is_null()) {
     // Set if not set before and it's syncing now.
     sync_prefs_.SetFirstSyncTime(base::Time::Now());
   }
 }
 
-void ProfileSyncService::ClearBrowsingDataSinceFirstSync() {
-  base::Time first_sync_time = sync_prefs_.GetFirstSyncTime();
-  if (first_sync_time.is_null())
-    return;
-
-  sync_client_->GetClearBrowsingDataCallback().Run(first_sync_time,
-                                                   base::Time::Now());
-}
-
-void ProfileSyncService::CheckSyncBackupIfNeeded() {
-  DCHECK_EQ(backend_mode_, SYNC);
-
-#if BUILDFLAG(ENABLE_PRE_SYNC_BACKUP)
-  const base::Time last_synced_time = sync_prefs_.GetLastSyncedTime();
-  // Check backup once a day.
-  if (!last_backup_time_ &&
-      (last_synced_time.is_null() ||
-          base::Time::Now() - last_synced_time >=
-              base::TimeDelta::FromDays(1))) {
-    // If sync thread is set, need to serialize check on sync thread after
-    // closing backup DB.
-    if (sync_thread_) {
-      sync_thread_->task_runner()->PostTask(
-          FROM_HERE,
-          base::Bind(syncer::CheckSyncDbLastModifiedTime,
-                     base_directory_.Append(kSyncBackupDataFolderName),
-                     base::ThreadTaskRunnerHandle::Get(),
-                     base::Bind(&ProfileSyncService::CheckSyncBackupCallback,
-                                weak_factory_.GetWeakPtr())));
-    } else {
-      file_thread_->PostTask(
-          FROM_HERE,
-          base::Bind(syncer::CheckSyncDbLastModifiedTime,
-                     base_directory_.Append(kSyncBackupDataFolderName),
-                     base::ThreadTaskRunnerHandle::Get(),
-                     base::Bind(&ProfileSyncService::CheckSyncBackupCallback,
-                                weak_factory_.GetWeakPtr())));
-    }
-  }
-#endif
-}
-
-void ProfileSyncService::CheckSyncBackupCallback(base::Time backup_time) {
-  last_backup_time_.reset(new base::Time(backup_time));
-
-  DCHECK(device_info_sync_service_);
-  device_info_sync_service_->UpdateLocalDeviceBackupTime(*last_backup_time_);
-}
-
-void ProfileSyncService::TryStartSyncAfterBackup() {
-  startup_controller_->Reset(GetRegisteredDataTypes());
-  startup_controller_->TryStart();
-}
-
-void ProfileSyncService::CleanUpBackup() {
-  sync_prefs_.ClearFirstSyncTime();
-
-  // Use the client's base directory to get the blocking task runner to use in
-  // order to ensure ordering between the tasks posted by different invocations
-  // of this method.
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner =
-      JsonPrefStore::GetTaskRunnerForFile(base_directory_, blocking_pool_);
-  blocking_task_runner->PostTask(
-      FROM_HERE,
-      base::Bind(base::IgnoreResult(base::DeleteFile),
-                 base_directory_.Append(kSyncBackupDataFolderName), true));
-}
-
-bool ProfileSyncService::NeedBackup() const {
-  return need_backup_;
-}
-
-base::Time ProfileSyncService::GetDeviceBackupTimeForTesting() const {
-  return device_info_sync_service_->GetLocalDeviceBackupTime();
-}
-
 void ProfileSyncService::FlushDirectory() const {
   // backend_initialized_ implies backend_ isn't NULL and the manager exists.
   // If sync is not initialized yet, we fail silently.
diff --git a/components/browser_sync/browser/profile_sync_service.h b/components/browser_sync/browser/profile_sync_service.h
index ada1731..df981bc3 100644
--- a/components/browser_sync/browser/profile_sync_service.h
+++ b/components/browser_sync/browser/profile_sync_service.h
@@ -25,7 +25,6 @@
 #include "build/build_config.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/signin/core/browser/signin_manager_base.h"
-#include "components/sync_driver/backup_rollback_controller.h"
 #include "components/sync_driver/data_type_controller.h"
 #include "components/sync_driver/data_type_manager.h"
 #include "components/sync_driver/data_type_manager_observer.h"
@@ -219,18 +218,9 @@
     SETUP_INCOMPLETE,
     DATATYPES_NOT_INITIALIZED,
     INITIALIZED,
-    BACKUP_USER_DATA,
-    ROLLBACK_USER_DATA,
     UNKNOWN_ERROR,
   };
 
-  enum BackendMode {
-    IDLE,       // No backend.
-    SYNC,       // Backend for syncing.
-    BACKUP,     // Backend for backup.
-    ROLLBACK    // Backend for rollback.
-  };
-
   // Bundles the arguments for ProfileSyncService construction. This is a
   // movable struct. Because of the non-POD data members, it needs out-of-line
   // constructors, so in particular the move constructor needs to be
@@ -567,11 +557,6 @@
 
   virtual bool IsDataTypeControllerRunning(syncer::ModelType type) const;
 
-  // Returns the current mode the backend is in.
-  BackendMode backend_mode() const;
-
-  base::Time GetDeviceBackupTimeForTesting() const;
-
   // This triggers a Directory::SaveChanges() call on the sync thread.
   // It should be used to persist data to disk when the process might be
   // killed in the near future.
@@ -623,8 +608,6 @@
       const std::string& message,
       bool delete_sync_database);
 
-  virtual bool NeedBackup() const;
-
   // This is a cache of the last authentication response we received from the
   // sync server. The UI queries this to display appropriate messaging to the
   // user.
@@ -733,9 +716,8 @@
 
   void ClearUnrecoverableError();
 
-  // Starts up the backend sync components. |mode| specifies the kind of
-  // backend to start, one of SYNC, BACKUP or ROLLBACK.
-  virtual void StartUpSlowBackendComponents(BackendMode mode);
+  // Starts up the backend sync components.
+  virtual void StartUpSlowBackendComponents();
 
   // Collects preferred sync data types from |preference_providers_|.
   syncer::ModelTypeSet GetDataTypesFromPreferenceProviders() const;
@@ -759,9 +741,6 @@
                                     bool delete_sync_database,
                                     UnrecoverableErrorReason reason);
 
-  // Returns the type of manager to use according to |backend_mode_|.
-  syncer::SyncManagerFactory::MANAGER_TYPE GetManagerType() const;
-
   // Update UMA for syncing backend.
   void UpdateBackendInitUMA(bool success);
 
@@ -777,22 +756,6 @@
   // Update first sync time stored in preferences
   void UpdateFirstSyncTimePref();
 
-  // Clear browsing data since first sync during rollback.
-  void ClearBrowsingDataSinceFirstSync();
-
-  // Post background task to check sync backup DB state if needed.
-  void CheckSyncBackupIfNeeded();
-
-  // Callback to receive backup DB check result.
-  void CheckSyncBackupCallback(base::Time backup_time);
-
-  // Callback function to call |startup_controller_|.TryStart() after
-  // backup/rollback finishes;
-  void TryStartSyncAfterBackup();
-
-  // Clean up prefs and backup DB when rollback is not needed.
-  void CleanUpBackup();
-
   // Tell the sync server that this client has disabled sync.
   void RemoveClientFromServer() const;
 
@@ -987,23 +950,6 @@
   browser_sync::ProfileSyncServiceStartBehavior start_behavior_;
   scoped_ptr<browser_sync::StartupController> startup_controller_;
 
-  scoped_ptr<sync_driver::BackupRollbackController> backup_rollback_controller_;
-
-  // Mode of current backend.
-  BackendMode backend_mode_;
-
-  // Whether backup is needed before sync starts.
-  bool need_backup_;
-
-  // Whether backup is finished.
-  bool backup_finished_;
-
-  base::Time backup_start_time_;
-
-  // Last time when pre-sync data was saved. NULL pointer means backup data
-  // state is unknown. If time value is null, backup data doesn't exist.
-  scoped_ptr<base::Time> last_backup_time_;
-
   // The full path to the sync data directory.
   base::FilePath directory_path_;
 
diff --git a/chrome/browser/sync/profile_sync_service_bookmark_unittest.cc b/components/browser_sync/browser/profile_sync_service_bookmark_unittest.cc
similarity index 95%
rename from chrome/browser/sync/profile_sync_service_bookmark_unittest.cc
rename to components/browser_sync/browser/profile_sync_service_bookmark_unittest.cc
index 1236cf64..8bde545 100644
--- a/chrome/browser/sync/profile_sync_service_bookmark_unittest.cc
+++ b/components/browser_sync/browser/profile_sync_service_bookmark_unittest.cc
@@ -101,8 +101,7 @@
 // since FakeServerChange will send the edits in the order specified.
 class FakeServerChange {
  public:
-  explicit FakeServerChange(syncer::WriteTransaction* trans) : trans_(trans) {
-  }
+  explicit FakeServerChange(syncer::WriteTransaction* trans) : trans_(trans) {}
 
   // Pretend that the server told the syncer to add a bookmark object.
   int64_t AddWithMetaInfo(const std::string& title,
@@ -268,9 +267,7 @@
         trans_, 0, syncer::ImmutableChangeRecordList(&changes_));
   }
 
-  const syncer::ChangeRecordList& changes() {
-    return changes_;
-  }
+  const syncer::ChangeRecordList& changes() { return changes_; }
 
  private:
   // Helper function to push an ACTION_UPDATE record onto the back
@@ -278,8 +275,7 @@
   void SetModified(int64_t id) {
     // Coalesce multi-property edits.
     if (!changes_.empty() && changes_.back().id == id &&
-        changes_.back().action ==
-        syncer::ChangeRecord::ACTION_UPDATE)
+        changes_.back().action == syncer::ChangeRecord::ACTION_UPDATE)
       return;
     syncer::ChangeRecord record;
     record.action = syncer::ChangeRecord::ACTION_UPDATE;
@@ -305,7 +301,7 @@
   }
 
   // The transaction on which everything happens.
-  syncer::WriteTransaction *trans_;
+  syncer::WriteTransaction* trans_;
 
   // The change list we construct.
   syncer::ChangeRecordList changes_;
@@ -331,17 +327,13 @@
 
   void BookmarkModelChanged() override {}
 
-  int get_started() const {
-    return started_count_;
-  }
+  int get_started() const { return started_count_; }
 
   int get_completed_count_at_started() const {
     return completed_count_at_started_;
   }
 
-  int get_completed() const {
-    return completed_count_;
-  }
+  int get_completed() const { return completed_count_; }
 
  private:
   int started_count_;
@@ -491,8 +483,7 @@
     bool root_exists = false;
     syncer::ModelType type = syncer::BOOKMARKS;
     {
-      syncer::WriteTransaction trans(FROM_HERE,
-                                     test_user_share_.user_share());
+      syncer::WriteTransaction trans(FROM_HERE, test_user_share_.user_share());
       syncer::ReadNode uber_root(&trans);
       uber_root.InitByRootLookup();
 
@@ -561,8 +552,7 @@
     int syncer_count_before = GetSyncBookmarkCount();
 
     syncer::SyncError error = model_associator_->AssociateModels(
-        &local_merge_result_,
-        &syncer_merge_result_);
+        &local_merge_result_, &syncer_merge_result_);
     if (error.IsSet())
       return false;
 
@@ -616,8 +606,7 @@
 
   bool InitSyncNodeFromChromeNode(const BookmarkNode* bnode,
                                   BaseNode* sync_node) {
-    return model_associator_->InitSyncNodeFromChromeId(bnode->id(),
-                                                       sync_node);
+    return model_associator_->InitSyncNodeFromChromeId(bnode->id(), sync_node);
   }
 
   void ExpectSyncerNodeMatching(syncer::BaseTransaction* trans,
@@ -632,9 +621,8 @@
     // Non-root node titles and parents must match.
     if (!model_->is_permanent_node(bnode)) {
       EXPECT_EQ(truncated_title, gnode.GetTitle());
-      EXPECT_EQ(
-          model_associator_->GetChromeNodeFromSyncId(gnode.GetParentId()),
-          bnode->parent());
+      EXPECT_EQ(model_associator_->GetChromeNodeFromSyncId(gnode.GetParentId()),
+                bnode->parent());
     }
     EXPECT_EQ(bnode->is_folder(), gnode.GetIsFolder());
     if (bnode->is_url())
@@ -661,8 +649,7 @@
     if (browser_index == 0) {
       EXPECT_EQ(gnode.GetPredecessorId(), 0);
     } else {
-      const BookmarkNode* bprev =
-          bnode->parent()->GetChild(browser_index - 1);
+      const BookmarkNode* bprev = bnode->parent()->GetChild(browser_index - 1);
       syncer::ReadNode gprev(trans);
       ASSERT_TRUE(InitSyncNodeFromChromeNode(bprev, &gprev));
       EXPECT_EQ(gnode.GetPredecessorId(), gprev.GetId());
@@ -672,7 +659,7 @@
     // synced; if CanSyncNode() is false then there is no next node to sync.
     const BookmarkNode* bnext = NULL;
     if (browser_index + 1 < bnode->parent()->child_count())
-        bnext = bnode->parent()->GetChild(browser_index + 1);
+      bnext = bnode->parent()->GetChild(browser_index + 1);
     if (!bnext || !CanSyncNode(bnext)) {
       EXPECT_EQ(gnode.GetSuccessorId(), 0);
     } else {
@@ -756,7 +743,8 @@
     while (!stack.empty()) {
       int64_t id = stack.top();
       stack.pop();
-      if (!id) continue;
+      if (!id)
+        continue;
 
       ExpectBrowserNodeMatching(trans, id);
 
@@ -774,13 +762,12 @@
   }
 
   int64_t mobile_bookmarks_id() {
-    return
-        model_associator_->GetSyncIdFromChromeId(model_->mobile_node()->id());
+    return model_associator_->GetSyncIdFromChromeId(
+        model_->mobile_node()->id());
   }
 
   int64_t other_bookmarks_id() {
-    return
-        model_associator_->GetSyncIdFromChromeId(model_->other_node()->id());
+    return model_associator_->GetSyncIdFromChromeId(model_->other_node()->id());
   }
 
   int64_t bookmark_bar_id() {
@@ -1190,9 +1177,9 @@
               bookmark_bar_id(), u1);
   // u5 tests an empty-string title.
   std::string javascript_url(
-      "javascript:(function(){var w=window.open(" \
-      "'about:blank','gnotesWin','location=0,menubar=0," \
-      "scrollbars=0,status=0,toolbar=0,width=300," \
+      "javascript:(function(){var w=window.open("
+      "'about:blank','gnotesWin','location=0,menubar=0,"
+      "scrollbars=0,status=0,toolbar=0,width=300,"
       "height=300,resizable');});");
   adds.AddURL(std::string(), javascript_url, other_bookmarks_id(), 0);
   int64_t u6 = adds.AddURL("Sync1", "http://www.syncable.edu/",
@@ -1379,7 +1366,6 @@
   ExpectModelMatch();
 }
 
-
 // Test strings that might pose a problem if the titles ever became used as
 // file names in the sync backend.
 TEST_F(ProfileSyncServiceBookmarkTest, CornerCaseNames) {
@@ -1391,9 +1377,9 @@
       // The empty string.
       "",
       // Illegal Windows filenames.
-      "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4",
-      "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3",
-      "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
+      "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5",
+      "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5",
+      "LPT6", "LPT7", "LPT8", "LPT9",
       // Current/parent directory markers.
       ".", "..", "...",
       // Files created automatically by the Windows shell.
@@ -1407,8 +1393,7 @@
       "234567890123456789012345678901234567890123456789012345678901234567890123"
       "456789012345678901234567890123456789012345678901234567890123456789012345"
       "678901234567890123456789012345678901234567890123456789012345678901234567"
-      "890123456789"
-  };
+      "890123456789"};
   // Create both folders and bookmarks using each name.
   GURL url("http://www.doublemint.com");
   for (size_t i = 0; i < arraysize(names); ++i) {
@@ -1703,72 +1688,68 @@
 //     +-- u5, http://www.u5.com/
 
 static TestData kBookmarkBarChildren[] = {
-  { "u2", "http://www.u2.com/" },
-  { "f1", NULL },
-  { "u1", "http://www.u1.com/" },
-  { "f2", NULL },
+    {"u2", "http://www.u2.com/"},
+    {"f1", NULL},
+    {"u1", "http://www.u1.com/"},
+    {"f2", NULL},
 };
 static TestData kF1Children[] = {
-  { "f1u4", "http://www.f1u4.com/" },
-  { "f1u2", "http://www.f1u2.com/" },
-  { "f1u3", "http://www.f1u3.com/" },
-  { "f1u1", "http://www.f1u1.com/" },
+    {"f1u4", "http://www.f1u4.com/"},
+    {"f1u2", "http://www.f1u2.com/"},
+    {"f1u3", "http://www.f1u3.com/"},
+    {"f1u1", "http://www.f1u1.com/"},
 };
 static TestData kF2Children[] = {
-  { "f2u2", "http://www.f2u2.com/" },
-  { "f2u4", "http://www.f2u4.com/" },
-  { "f2u3", "http://www.f2u3.com/" },
-  { "f2u1", "http://www.f2u1.com/" },
+    {"f2u2", "http://www.f2u2.com/"},
+    {"f2u4", "http://www.f2u4.com/"},
+    {"f2u3", "http://www.f2u3.com/"},
+    {"f2u1", "http://www.f2u1.com/"},
 };
 
-static TestData kOtherBookmarkChildren[] = {
-  { "f3", NULL },
-  { "u4", "http://www.u4.com/" },
-  { "u3", "http://www.u3.com/" },
-  { "f4", NULL },
-  { "dup", NULL },
-  { "dup", NULL },
-  { "  ls  ", "http://www.ls.com/" }
-};
+static TestData kOtherBookmarkChildren[] = {{"f3", NULL},
+                                            {"u4", "http://www.u4.com/"},
+                                            {"u3", "http://www.u3.com/"},
+                                            {"f4", NULL},
+                                            {"dup", NULL},
+                                            {"dup", NULL},
+                                            {"  ls  ", "http://www.ls.com/"}};
 static TestData kF3Children[] = {
-  { "f3u4", "http://www.f3u4.com/" },
-  { "f3u2", "http://www.f3u2.com/" },
-  { "f3u3", "http://www.f3u3.com/" },
-  { "f3u1", "http://www.f3u1.com/" },
+    {"f3u4", "http://www.f3u4.com/"},
+    {"f3u2", "http://www.f3u2.com/"},
+    {"f3u3", "http://www.f3u3.com/"},
+    {"f3u1", "http://www.f3u1.com/"},
 };
 static TestData kF4Children[] = {
-  { "f4u1", "http://www.f4u1.com/" },
-  { "f4u2", "http://www.f4u2.com/" },
-  { "f4u3", "http://www.f4u3.com/" },
-  { "f4u4", "http://www.f4u4.com/" },
+    {"f4u1", "http://www.f4u1.com/"},
+    {"f4u2", "http://www.f4u2.com/"},
+    {"f4u3", "http://www.f4u3.com/"},
+    {"f4u4", "http://www.f4u4.com/"},
 };
 static TestData kDup1Children[] = {
-  { "dupu1", "http://www.dupu1.com/" },
+    {"dupu1", "http://www.dupu1.com/"},
 };
 static TestData kDup2Children[] = {
-  { "dupu2", "http://www.dupu2.com/" },
+    {"dupu2", "http://www.dupu2.com/"},
 };
 
 static TestData kMobileBookmarkChildren[] = {
-  { "f5", NULL },
-  { "f6", NULL },
-  { "u5", "http://www.u5.com/" },
+    {"f5", NULL},
+    {"f6", NULL},
+    {"u5", "http://www.u5.com/"},
 };
 static TestData kF5Children[] = {
-  { "f5u1", "http://www.f5u1.com/" },
-  { "f5u2", "http://www.f5u2.com/" },
+    {"f5u1", "http://www.f5u1.com/"},
+    {"f5u2", "http://www.f5u2.com/"},
 };
 static TestData kF6Children[] = {
-  { "f6u1", "http://www.f6u1.com/" },
-  { "f6u2", "http://www.f6u2.com/" },
+    {"f6u1", "http://www.f6u1.com/"},
+    {"f6u2", "http://www.f6u2.com/"},
 };
 
 }  // anonymous namespace.
 
-ProfileSyncServiceBookmarkTestWithData::
-ProfileSyncServiceBookmarkTestWithData()
-    : start_time_(base::Time::Now()) {
-}
+ProfileSyncServiceBookmarkTestWithData::ProfileSyncServiceBookmarkTestWithData()
+    : start_time_(base::Time::Now()) {}
 
 void ProfileSyncServiceBookmarkTestWithData::PopulateFromTestData(
     const BookmarkNode* node,
@@ -1830,10 +1811,8 @@
 void ProfileSyncServiceBookmarkTestWithData::WriteTestDataToBookmarkModel() {
   const BookmarkNode* bookmarks_bar_node = model()->bookmark_bar_node();
   int count = 0;
-  PopulateFromTestData(bookmarks_bar_node,
-                       kBookmarkBarChildren,
-                       arraysize(kBookmarkBarChildren),
-                       &count);
+  PopulateFromTestData(bookmarks_bar_node, kBookmarkBarChildren,
+                       arraysize(kBookmarkBarChildren), &count);
 
   ASSERT_GE(bookmarks_bar_node->child_count(), 4);
   const BookmarkNode* f1_node = bookmarks_bar_node->GetChild(1);
@@ -1842,10 +1821,8 @@
   PopulateFromTestData(f2_node, kF2Children, arraysize(kF2Children), &count);
 
   const BookmarkNode* other_bookmarks_node = model()->other_node();
-  PopulateFromTestData(other_bookmarks_node,
-                       kOtherBookmarkChildren,
-                       arraysize(kOtherBookmarkChildren),
-                       &count);
+  PopulateFromTestData(other_bookmarks_node, kOtherBookmarkChildren,
+                       arraysize(kOtherBookmarkChildren), &count);
 
   ASSERT_GE(other_bookmarks_node->child_count(), 6);
   const BookmarkNode* f3_node = other_bookmarks_node->GetChild(0);
@@ -1860,10 +1837,8 @@
                        &count);
 
   const BookmarkNode* mobile_bookmarks_node = model()->mobile_node();
-  PopulateFromTestData(mobile_bookmarks_node,
-                       kMobileBookmarkChildren,
-                       arraysize(kMobileBookmarkChildren),
-                       &count);
+  PopulateFromTestData(mobile_bookmarks_node, kMobileBookmarkChildren,
+                       arraysize(kMobileBookmarkChildren), &count);
 
   ASSERT_GE(mobile_bookmarks_node->child_count(), 3);
   const BookmarkNode* f5_node = mobile_bookmarks_node->GetChild(0);
@@ -1878,10 +1853,8 @@
     ExpectBookmarkModelMatchesTestData() {
   const BookmarkNode* bookmark_bar_node = model()->bookmark_bar_node();
   int count = 0;
-  CompareWithTestData(bookmark_bar_node,
-                      kBookmarkBarChildren,
-                      arraysize(kBookmarkBarChildren),
-                      &count);
+  CompareWithTestData(bookmark_bar_node, kBookmarkBarChildren,
+                      arraysize(kBookmarkBarChildren), &count);
 
   ASSERT_GE(bookmark_bar_node->child_count(), 4);
   const BookmarkNode* f1_node = bookmark_bar_node->GetChild(1);
@@ -1890,10 +1863,8 @@
   CompareWithTestData(f2_node, kF2Children, arraysize(kF2Children), &count);
 
   const BookmarkNode* other_bookmarks_node = model()->other_node();
-  CompareWithTestData(other_bookmarks_node,
-                      kOtherBookmarkChildren,
-                      arraysize(kOtherBookmarkChildren),
-                      &count);
+  CompareWithTestData(other_bookmarks_node, kOtherBookmarkChildren,
+                      arraysize(kOtherBookmarkChildren), &count);
 
   ASSERT_GE(other_bookmarks_node->child_count(), 6);
   const BookmarkNode* f3_node = other_bookmarks_node->GetChild(0);
@@ -1908,10 +1879,8 @@
                       &count);
 
   const BookmarkNode* mobile_bookmarks_node = model()->mobile_node();
-  CompareWithTestData(mobile_bookmarks_node,
-                      kMobileBookmarkChildren,
-                      arraysize(kMobileBookmarkChildren),
-                      &count);
+  CompareWithTestData(mobile_bookmarks_node, kMobileBookmarkChildren,
+                      arraysize(kMobileBookmarkChildren), &count);
 
   ASSERT_GE(mobile_bookmarks_node->child_count(), 3);
   const BookmarkNode* f5_node = mobile_bookmarks_node->GetChild(0);
diff --git a/components/browser_sync/browser/profile_sync_service_mock.h b/components/browser_sync/browser/profile_sync_service_mock.h
index 41df3eae2..255aa2fb 100644
--- a/components/browser_sync/browser/profile_sync_service_mock.h
+++ b/components/browser_sync/browser/profile_sync_service_mock.h
@@ -96,8 +96,6 @@
   MOCK_METHOD1(SetDecryptionPassphrase, bool(const std::string& passphrase));
   MOCK_METHOD2(SetEncryptionPassphrase, void(const std::string& passphrase,
                                              PassphraseType type));
-
-  MOCK_METHOD1(StartUpSlowBackendComponents, void(BackendMode));
 };
 
 #endif  // COMPONENTS_BROWSER_SYNC_BROWSER_PROFILE_SYNC_SERVICE_MOCK_H_
diff --git a/components/browser_sync/browser/profile_sync_service_startup_unittest.cc b/components/browser_sync/browser/profile_sync_service_startup_unittest.cc
index 122fb32..206ce89 100644
--- a/components/browser_sync/browser/profile_sync_service_startup_unittest.cc
+++ b/components/browser_sync/browser/profile_sync_service_startup_unittest.cc
@@ -74,16 +74,6 @@
   sync_service->OnConfigureDone(configure_result);
 }
 
-class TestProfileSyncServiceNoBackup : public ProfileSyncService {
- public:
-  explicit TestProfileSyncServiceNoBackup(
-      ProfileSyncService::InitParams init_params)
-      : ProfileSyncService(std::move(init_params)) {}
-
- protected:
-  bool NeedBackup() const override { return false; }
-};
-
 class ProfileSyncServiceStartupTest : public testing::Test {
  public:
   ProfileSyncServiceStartupTest() {
@@ -105,8 +95,7 @@
         profile_sync_service_bundle_.CreateBasicInitParams(start_behavior,
                                                            builder.Build());
 
-    sync_service_.reset(
-        new TestProfileSyncServiceNoBackup(std::move(init_params)));
+    sync_service_.reset(new ProfileSyncService(std::move(init_params)));
     sync_service_->RegisterDataTypeController(
         new sync_driver::FakeDataTypeController(syncer::BOOKMARKS));
     sync_service_->AddObserver(&observer_);
diff --git a/components/browser_sync/browser/profile_sync_service_unittest.cc b/components/browser_sync/browser/profile_sync_service_unittest.cc
index 69df1030..b348ffa 100644
--- a/components/browser_sync/browser/profile_sync_service_unittest.cc
+++ b/components/browser_sync/browser/profile_sync_service_unittest.cc
@@ -32,7 +32,6 @@
 #include "components/sync_driver/glue/sync_backend_host_mock.h"
 #include "components/sync_driver/pref_names.h"
 #include "components/sync_driver/sync_api_component_factory_mock.h"
-#include "components/sync_driver/sync_driver_features.h"
 #include "components/sync_driver/sync_driver_switches.h"
 #include "components/sync_driver/sync_prefs.h"
 #include "components/sync_driver/sync_service_observer.h"
@@ -240,9 +239,6 @@
     component_factory_ = profile_sync_service_bundle_.component_factory();
     ProfileSyncServiceBundle::SyncClientBuilder builder(
         &profile_sync_service_bundle_);
-    builder.SetClearBrowsingDataCallback(
-        base::Bind(&ProfileSyncServiceTest::ClearBrowsingDataCallback,
-                   base::Unretained(this)));
     ProfileSyncService::InitParams init_params =
         profile_sync_service_bundle_.CreateBasicInitParams(behavior,
                                                            builder.Build());
@@ -268,8 +264,7 @@
   }
 
   void InitializeForNthSync() {
-    // Set first sync time before initialize to disable backup and simulate
-    // a complete sync setup.
+    // Set first sync time before initialize to simulate a complete sync setup.
     sync_driver::SyncPrefs sync_prefs(
         service_->GetSyncClient()->GetPrefService());
     sync_prefs.SetFirstSyncTime(base::Time::Now());
@@ -378,10 +373,6 @@
     return component_factory_;
   }
 
-  void ClearBrowsingDataCallback(base::Time start, base::Time end) {
-    clear_browsing_date_start_ = start;
-  }
-
  protected:
   void PumpLoop() {
     base::RunLoop run_loop;
@@ -390,9 +381,6 @@
     run_loop.Run();
   }
 
-  // The requested start time when ClearBrowsingDataCallback is called.
-  base::Time clear_browsing_date_start_;
-
  private:
   base::MessageLoop message_loop_;
   browser_sync::ProfileSyncServiceBundle profile_sync_service_bundle_;
@@ -423,7 +411,6 @@
   InitializeForNthSync();
   EXPECT_FALSE(service()->IsManaged());
   EXPECT_TRUE(service()->IsSyncActive());
-  EXPECT_EQ(ProfileSyncService::SYNC, service()->backend_mode());
 }
 
 // Verify that the SetSetupInProgress function call updates state
@@ -639,107 +626,6 @@
 }
 #endif
 
-#if BUILDFLAG(ENABLE_PRE_SYNC_BACKUP)
-TEST_F(ProfileSyncServiceTest, DontStartBackupOnBrowserStart) {
-  CreateServiceWithoutSignIn();
-  InitializeForFirstSync();
-  PumpLoop();
-  EXPECT_EQ(ProfileSyncService::IDLE, service()->backend_mode());
-}
-
-TEST_F(ProfileSyncServiceTest, BackupBeforeFirstSync) {
-  CreateServiceWithoutSignIn();
-  ExpectDataTypeManagerCreation(2, GetDefaultConfigureCalledCallback());
-  std::vector<bool> delete_dir_param;
-  ExpectSyncBackendHostCreationCollectDeleteDir(2, &delete_dir_param);
-  InitializeForFirstSync();
-
-  signin_manager()->SetAuthenticatedAccountInfo(kGaiaId, kEmail);
-  IssueTestTokens();
-  PumpLoop();
-
-  // At this time, backup is finished. Task is posted to start sync again.
-  EXPECT_EQ(ProfileSyncService::BACKUP, service()->backend_mode());
-  EXPECT_FALSE(service()->IsSyncActive());
-  EXPECT_EQ(1u, delete_dir_param.size());
-  EXPECT_TRUE(delete_dir_param[0]);
-
-  // Pump loop to start sync.
-  PumpLoop();
-  EXPECT_EQ(ProfileSyncService::SYNC, service()->backend_mode());
-  EXPECT_TRUE(service()->IsSyncActive());
-  EXPECT_EQ(2u, delete_dir_param.size());
-  EXPECT_TRUE(delete_dir_param[0]);
-}
-
-// Test backup is done again on browser start if user signed in last session
-// but backup didn't finish when last session was closed.
-TEST_F(ProfileSyncServiceTest, ResumeBackupIfAborted) {
-  IssueTestTokens();
-  CreateService(AUTO_START);
-  ExpectDataTypeManagerCreation(2, GetDefaultConfigureCalledCallback());
-  std::vector<bool> delete_dir_param;
-  ExpectSyncBackendHostCreationCollectDeleteDir(2, &delete_dir_param);
-  InitializeForFirstSync();
-  PumpLoop();
-
-  // At this time, backup is finished. Task is posted to start sync again.
-  EXPECT_EQ(ProfileSyncService::BACKUP, service()->backend_mode());
-  EXPECT_FALSE(service()->IsSyncActive());
-  EXPECT_EQ(1u, delete_dir_param.size());
-  EXPECT_TRUE(delete_dir_param[0]);
-
-  // Pump loop to start sync.
-  PumpLoop();
-  EXPECT_EQ(ProfileSyncService::SYNC, service()->backend_mode());
-  EXPECT_TRUE(service()->IsSyncActive());
-  EXPECT_EQ(2u, delete_dir_param.size());
-  EXPECT_TRUE(delete_dir_param[0]);
-}
-
-TEST_F(ProfileSyncServiceTest, Rollback) {
-  CreateService(browser_sync::MANUAL_START);
-  service()->SetFirstSetupComplete();
-  ExpectDataTypeManagerCreation(2, GetDefaultConfigureCalledCallback());
-  std::vector<bool> delete_dir_param;
-  ExpectSyncBackendHostCreationCollectDeleteDir(2, &delete_dir_param);
-  IssueTestTokens();
-  InitializeForNthSync();
-  EXPECT_TRUE(service()->IsSyncActive());
-  EXPECT_EQ(ProfileSyncService::SYNC, service()->backend_mode());
-
-  // First sync time should be recorded.
-  sync_driver::SyncPrefs sync_prefs(
-      service()->GetSyncClient()->GetPrefService());
-  base::Time first_sync_time = sync_prefs.GetFirstSyncTime();
-  EXPECT_FALSE(first_sync_time.is_null());
-
-  syncer::SyncProtocolError client_cmd;
-  client_cmd.action = syncer::DISABLE_SYNC_AND_ROLLBACK;
-  service()->OnActionableError(client_cmd);
-  EXPECT_EQ(ProfileSyncService::IDLE, service()->backend_mode());
-
-  // Pump loop to run rollback.
-  PumpLoop();
-  EXPECT_EQ(ProfileSyncService::ROLLBACK, service()->backend_mode());
-
-  // Browser data should be cleared during rollback.
-  EXPECT_EQ(first_sync_time, clear_browsing_date_start_);
-
-  client_cmd.action = syncer::ROLLBACK_DONE;
-  service()->OnActionableError(client_cmd);
-  EXPECT_EQ(ProfileSyncService::IDLE, service()->backend_mode());
-
-  // First sync time is erased after rollback is done.
-  EXPECT_TRUE(sync_prefs.GetFirstSyncTime().is_null());
-
-  EXPECT_EQ(2u, delete_dir_param.size());
-  EXPECT_FALSE(delete_dir_param[0]);
-  EXPECT_FALSE(delete_dir_param[1]);
-}
-
-#endif  // ENABLE_PRE_SYNC_BACKUP
-
 // Verify that LastSyncedTime is cleared when the user signs out.
 TEST_F(ProfileSyncServiceTest, ClearLastSyncedTimeOnSignOut) {
   IssueTestTokens();
@@ -834,7 +720,6 @@
       1, GetRecordingConfigureCalledCallback(&configure_reason));
   InitializeForNthSync();
   EXPECT_TRUE(service()->IsSyncActive());
-  EXPECT_EQ(ProfileSyncService::SYNC, service()->backend_mode());
   testing::Mock::VerifyAndClearExpectations(component_factory());
   EXPECT_EQ(syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE, configure_reason);
   sync_driver::DataTypeManager::ConfigureResult result;
@@ -878,7 +763,6 @@
   ExpectDataTypeManagerCreation(
       1, GetRecordingConfigureCalledCallback(&configure_reason));
   InitializeForNthSync();
-  EXPECT_EQ(ProfileSyncService::SYNC, service()->backend_mode());
   testing::Mock::VerifyAndClearExpectations(component_factory());
   EXPECT_EQ(syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE, configure_reason);
   sync_driver::DataTypeManager::ConfigureResult result;
@@ -933,7 +817,6 @@
   ExpectSyncBackendHostCreationCaptureClearServerData(&captured_callback);
   ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
   InitializeForNthSync();
-  EXPECT_EQ(ProfileSyncService::SYNC, service()->backend_mode());
   testing::Mock::VerifyAndClearExpectations(component_factory());
 
   // Simulate user entering encryption passphrase.
@@ -1018,7 +901,6 @@
   syncer::SyncProtocolError client_cmd;
   client_cmd.action = syncer::RESET_LOCAL_SYNC_DATA;
   service()->OnActionableError(client_cmd);
-  EXPECT_EQ(ProfileSyncService::SYNC, service()->backend_mode());
 }
 
 // Regression test for crbug/555434. The issue is that check for sessions DTC in
diff --git a/components/browser_sync/browser/profile_sync_test_util.cc b/components/browser_sync/browser/profile_sync_test_util.cc
index c0c678f..1f1ecd8 100644
--- a/components/browser_sync/browser/profile_sync_test_util.cc
+++ b/components/browser_sync/browser/profile_sync_test_util.cc
@@ -15,8 +15,6 @@
 #include "net/url_request/url_request_test_util.h"
 #include "sync/internal_api/public/engine/passive_model_worker.h"
 
-using sync_driver::ClearBrowsingDataCallback;
-
 namespace browser_sync {
 
 namespace {
@@ -26,7 +24,6 @@
   BundleSyncClient(
       sync_driver::SyncApiComponentFactory* factory,
       PrefService* pref_service,
-      const ClearBrowsingDataCallback& clear_browsing_data_callback,
       sync_sessions::SyncSessionsClient* sync_sessions_client,
       autofill::PersonalDataManager* personal_data_manager,
       const base::Callback<base::WeakPtr<syncer::SyncableService>(
@@ -42,7 +39,6 @@
   ~BundleSyncClient() override;
 
   PrefService* GetPrefService() override;
-  ClearBrowsingDataCallback GetClearBrowsingDataCallback() override;
   sync_sessions::SyncSessionsClient* GetSyncSessionsClient() override;
   autofill::PersonalDataManager* GetPersonalDataManager() override;
   base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType(
@@ -56,7 +52,6 @@
 
  private:
   PrefService* const pref_service_;
-  const ClearBrowsingDataCallback clear_browsing_data_callback_;
   sync_sessions::SyncSessionsClient* const sync_sessions_client_;
   autofill::PersonalDataManager* const personal_data_manager_;
   const base::Callback<base::WeakPtr<syncer::SyncableService>(
@@ -75,7 +70,6 @@
 BundleSyncClient::BundleSyncClient(
     sync_driver::SyncApiComponentFactory* factory,
     PrefService* pref_service,
-    const ClearBrowsingDataCallback& clear_browsing_data_callback,
     sync_sessions::SyncSessionsClient* sync_sessions_client,
     autofill::PersonalDataManager* personal_data_manager,
     const base::Callback<base::WeakPtr<syncer::SyncableService>(
@@ -89,7 +83,6 @@
     history::HistoryService* history_service)
     : sync_driver::FakeSyncClient(factory),
       pref_service_(pref_service),
-      clear_browsing_data_callback_(clear_browsing_data_callback),
       sync_sessions_client_(sync_sessions_client),
       personal_data_manager_(personal_data_manager),
       get_syncable_service_callback_(get_syncable_service_callback),
@@ -107,10 +100,6 @@
   return pref_service_;
 }
 
-ClearBrowsingDataCallback BundleSyncClient::GetClearBrowsingDataCallback() {
-  return clear_browsing_data_callback_;
-}
-
 sync_sessions::SyncSessionsClient* BundleSyncClient::GetSyncSessionsClient() {
   return sync_sessions_client_;
 }
@@ -195,11 +184,6 @@
     ProfileSyncServiceBundle* bundle)
     : bundle_(bundle) {}
 
-void ProfileSyncServiceBundle::SyncClientBuilder::SetClearBrowsingDataCallback(
-    ClearBrowsingDataCallback clear_browsing_data_callback) {
-  clear_browsing_data_callback_ = clear_browsing_data_callback;
-}
-
 void ProfileSyncServiceBundle::SyncClientBuilder::SetPersonalDataManager(
     autofill::PersonalDataManager* personal_data_manager) {
   personal_data_manager_ = personal_data_manager;
@@ -234,9 +218,9 @@
 ProfileSyncServiceBundle::SyncClientBuilder::Build() {
   return make_scoped_ptr(new BundleSyncClient(
       bundle_->component_factory(), bundle_->pref_service(),
-      clear_browsing_data_callback_, bundle_->sync_sessions_client(),
-      personal_data_manager_, get_syncable_service_callback_,
-      get_sync_service_callback_, get_bookmark_model_callback_,
+      bundle_->sync_sessions_client(), personal_data_manager_,
+      get_syncable_service_callback_, get_sync_service_callback_,
+      get_bookmark_model_callback_,
       activate_model_creation_ ? bundle_->db_thread() : nullptr,
       activate_model_creation_ ? base::ThreadTaskRunnerHandle::Get() : nullptr,
       history_service_));
diff --git a/components/browser_sync/browser/profile_sync_test_util.h b/components/browser_sync/browser/profile_sync_test_util.h
index b5bea3a..0953ffb 100644
--- a/components/browser_sync/browser/profile_sync_test_util.h
+++ b/components/browser_sync/browser/profile_sync_test_util.h
@@ -79,10 +79,6 @@
 
     ~SyncClientBuilder();
 
-    // Setters for the various additional data for the client to return.
-    void SetClearBrowsingDataCallback(
-        sync_driver::ClearBrowsingDataCallback clear_browsing_data_callback);
-
     void SetPersonalDataManager(
         autofill::PersonalDataManager* personal_data_manager);
 
@@ -111,7 +107,6 @@
     // Associated bundle to source objects from.
     ProfileSyncServiceBundle* const bundle_;
 
-    sync_driver::ClearBrowsingDataCallback clear_browsing_data_callback_;
     autofill::PersonalDataManager* personal_data_manager_;
     base::Callback<base::WeakPtr<syncer::SyncableService>(
         syncer::ModelType type)>
diff --git a/components/browser_sync/browser/test_profile_sync_service.cc b/components/browser_sync/browser/test_profile_sync_service.cc
index 092fdfe..48ede52 100644
--- a/components/browser_sync/browser/test_profile_sync_service.cc
+++ b/components/browser_sync/browser/test_profile_sync_service.cc
@@ -30,7 +30,3 @@
 syncer::UserShare* TestProfileSyncService::GetUserShare() const {
   return backend_->GetUserShare();
 }
-
-bool TestProfileSyncService::NeedBackup() const {
-  return false;
-}
diff --git a/components/browser_sync/browser/test_profile_sync_service.h b/components/browser_sync/browser/test_profile_sync_service.h
index 54b0c37a..abd82aa 100644
--- a/components/browser_sync/browser/test_profile_sync_service.h
+++ b/components/browser_sync/browser/test_profile_sync_service.h
@@ -41,8 +41,6 @@
   // and cause memory leak in test.
   syncer::WeakHandle<syncer::JsEventHandler> GetJsEventHandler() override;
 
-  bool NeedBackup() const override;
-
  private:
   syncer::TestIdFactory id_factory_;
 
diff --git a/components/bubble/bubble_controller.cc b/components/bubble/bubble_controller.cc
index 86001d2..1648848 100644
--- a/components/bubble/bubble_controller.cc
+++ b/components/bubble/bubble_controller.cc
@@ -66,9 +66,9 @@
   return delegate_->OwningFrame() == frame;
 }
 
-void BubbleController::DoClose() {
+void BubbleController::DoClose(BubbleCloseReason reason) {
   DCHECK(bubble_ui_);
   bubble_ui_->Close();
   bubble_ui_.reset();
-  delegate_->DidClose();
+  delegate_->DidClose(reason);
 }
diff --git a/components/bubble/bubble_controller.h b/components/bubble/bubble_controller.h
index 78889be3..f242309 100644
--- a/components/bubble/bubble_controller.h
+++ b/components/bubble/bubble_controller.h
@@ -56,7 +56,7 @@
   bool OwningFrameIs(const content::RenderFrameHost* frame) const;
 
   // Cleans up the delegate and its UI.
-  void DoClose();
+  void DoClose(BubbleCloseReason reason);
 
   BubbleManager* manager_;
   scoped_ptr<BubbleDelegate> delegate_;
diff --git a/components/bubble/bubble_delegate.cc b/components/bubble/bubble_delegate.cc
index 3e5ff58..6c66996 100644
--- a/components/bubble/bubble_delegate.cc
+++ b/components/bubble/bubble_delegate.cc
@@ -12,7 +12,7 @@
   return true;
 }
 
-void BubbleDelegate::DidClose() {}
+void BubbleDelegate::DidClose(BubbleCloseReason reason) {}
 
 bool BubbleDelegate::UpdateBubbleUi(BubbleUi* bubble_ui) {
   return false;
diff --git a/components/bubble/bubble_delegate.h b/components/bubble/bubble_delegate.h
index d3914c30..a1c47fb 100644
--- a/components/bubble/bubble_delegate.h
+++ b/components/bubble/bubble_delegate.h
@@ -31,7 +31,7 @@
   virtual bool ShouldClose(BubbleCloseReason reason) const;
 
   // Called by BubbleController to notify a bubble that it has closed.
-  virtual void DidClose();
+  virtual void DidClose(BubbleCloseReason reason);
 
   // Called by BubbleController to build the UI that will represent this bubble.
   // BubbleDelegate should not keep a reference to this newly created UI.
diff --git a/components/bubble/bubble_manager.cc b/components/bubble/bubble_manager.cc
index ad2e9c0..dc3af6d 100644
--- a/components/bubble/bubble_manager.cc
+++ b/components/bubble/bubble_manager.cc
@@ -122,7 +122,7 @@
   manager_state_ = original_state;
 
   for (auto controller : close_queue) {
-    controller->DoClose();
+    controller->DoClose(reason);
 
     FOR_EACH_OBSERVER(BubbleManagerObserver, observers_,
                       OnBubbleClosed(controller->AsWeakPtr(), reason));
diff --git a/components/bubble/bubble_manager_mocks.cc b/components/bubble/bubble_manager_mocks.cc
index 7bec6792..724a54d 100644
--- a/components/bubble/bubble_manager_mocks.cc
+++ b/components/bubble/bubble_manager_mocks.cc
@@ -18,7 +18,7 @@
   EXPECT_CALL(*delegate, ShouldClose(testing::_))
       .Times(testing::AtMost(1))
       .WillRepeatedly(testing::Return(true));
-  EXPECT_CALL(*delegate, DidClose());
+  EXPECT_CALL(*delegate, DidClose(testing::_));
   EXPECT_CALL(*delegate, Destroyed());
   return make_scoped_ptr(delegate);
 }
@@ -28,7 +28,7 @@
   MockBubbleDelegate* delegate = new MockBubbleDelegate;
   EXPECT_CALL(*delegate, ShouldClose(testing::_))
       .WillRepeatedly(testing::Return(false));
-  EXPECT_CALL(*delegate, DidClose());
+  EXPECT_CALL(*delegate, DidClose(testing::_));
   EXPECT_CALL(*delegate, Destroyed());
   return make_scoped_ptr(delegate);
 }
diff --git a/components/bubble/bubble_manager_mocks.h b/components/bubble/bubble_manager_mocks.h
index f350325..99e24931 100644
--- a/components/bubble/bubble_manager_mocks.h
+++ b/components/bubble/bubble_manager_mocks.h
@@ -41,7 +41,7 @@
   static scoped_ptr<MockBubbleDelegate> Stubborn();
 
   MOCK_CONST_METHOD1(ShouldClose, bool(BubbleCloseReason reason));
-  MOCK_METHOD0(DidClose, void());
+  MOCK_METHOD1(DidClose, void(BubbleCloseReason reason));
 
   // A scoped_ptr can't be returned in MOCK_METHOD.
   scoped_ptr<BubbleUi> BuildBubbleUi() override {
diff --git a/components/bubble/bubble_manager_unittest.cc b/components/bubble/bubble_manager_unittest.cc
index d6cbde1..625fe94 100644
--- a/components/bubble/bubble_manager_unittest.cc
+++ b/components/bubble/bubble_manager_unittest.cc
@@ -32,8 +32,8 @@
 
   ~ChainShowBubbleDelegate() override { EXPECT_TRUE(closed_); }
 
-  void DidClose() override {
-    MockBubbleDelegate::DidClose();
+  void DidClose(BubbleCloseReason reason) override {
+    MockBubbleDelegate::DidClose(reason);
     BubbleReference ref = manager_->ShowBubble(std::move(delegate_));
     if (chained_bubble_)
       *chained_bubble_ = ref;
@@ -60,7 +60,7 @@
 
   ~ChainCloseBubbleDelegate() override {}
 
-  void DidClose() override {
+  void DidClose(BubbleCloseReason reason) override {
     manager_->CloseAllBubbles(BUBBLE_CLOSE_FOCUS_LOST);
   }
 
@@ -353,7 +353,7 @@
   scoped_ptr<MockBubbleDelegate> chained_delegate(new MockBubbleDelegate);
   EXPECT_CALL(*chained_delegate->bubble_ui(), Show(testing::_)).Times(0);
   EXPECT_CALL(*chained_delegate, ShouldClose(testing::_)).Times(0);
-  EXPECT_CALL(*chained_delegate, DidClose()).Times(0);
+  EXPECT_CALL(*chained_delegate, DidClose(testing::_)).Times(0);
 
   manager_->ShowBubble(make_scoped_ptr(new ChainShowBubbleDelegate(
       manager_.get(), std::move(chained_delegate), nullptr)));
diff --git a/components/components_chromium_strings.grd b/components/components_chromium_strings.grd
index ac55266a..d19a9db 100644
--- a/components/components_chromium_strings.grd
+++ b/components/components_chromium_strings.grd
@@ -140,7 +140,7 @@
           <ph name="SETTINGS_TITLE">&lt;span jscontent="settingsTitle"&gt;&lt;/span&gt;<ex>Settings</ex></ph>
           &gt;
           <ph name="ADVANCED_TITLE">&lt;span jscontent="advancedTitle"&gt;&lt;/span&gt;<ex>Under the Hood</ex></ph>
-          and deselect &quot;<ph name="NO_PREFETCH_DESCRIPTION">&lt;span jscontent="noNetworkPredictionTitle"&gt;&lt;/span&gt;<ex>Prefetch resources to load pages more quickly</ex></ph>.&quot;
+          and deselect &quot;<ph name="NO_PREFETCH_DESCRIPTION">&lt;span jscontent="noNetworkPredictionTitle"&gt;&lt;/span&gt;<ex>Use a prediction service to load pages more quickly</ex></ph>.&quot;
           If this does not resolve the issue, we recommend selecting this option
           again for improved performance.
         </message>
diff --git a/components/components_google_chrome_strings.grd b/components/components_google_chrome_strings.grd
index 688b461f..d3744a7 100644
--- a/components/components_google_chrome_strings.grd
+++ b/components/components_google_chrome_strings.grd
@@ -140,7 +140,7 @@
           <ph name="SETTINGS_TITLE">&lt;span jscontent="settingsTitle"&gt;&lt;/span&gt;<ex>Settings</ex></ph>
           &gt;
           <ph name="ADVANCED_TITLE">&lt;span jscontent="advancedTitle"&gt;&lt;/span&gt;<ex>Under the Hood</ex></ph>
-          and deselect &quot;<ph name="NO_PREFETCH_DESCRIPTION">&lt;span jscontent="noNetworkPredictionTitle"&gt;&lt;/span&gt;<ex>Prefetch resources to load pages more quickly</ex></ph>.&quot;
+          and deselect &quot;<ph name="NO_PREFETCH_DESCRIPTION">&lt;span jscontent="noNetworkPredictionTitle"&gt;&lt;/span&gt;<ex>Use a prediction service to load pages more quickly</ex></ph>.&quot;
           If this does not resolve the issue, we recommend selecting this option
           again for improved performance.
         </message>
diff --git a/components/components_settings_strings.grdp b/components/components_settings_strings.grdp
index eb9fe3a..59d3fec 100644
--- a/components/components_settings_strings.grdp
+++ b/components/components_settings_strings.grdp
@@ -9,8 +9,8 @@
   <message name="IDS_SETTINGS_SHOW_ADVANCED_SETTINGS" desc="Title for the link to show advanced settings.">
     Show advanced settings...
   </message>
-  <message name="IDS_NETWORK_PREDICTION_ENABLED_DESCRIPTION" desc="In the advanced options tab, the text next to the checkbox that enables prediction of network actions.  Actions include DNS prefetching, TCP and SSL preconnection, and prerendering of webpages.">
-    Prefetch resources to load pages more quickly
+  <message name="IDS_NETWORK_PREDICTION_ENABLED_DESCRIPTION" desc="In the advanced options tab, the text next to the checkbox that enables prediction of network actions.  Actions include browser-initiated DNS prefetching, TCP and SSL preconnection, and prerendering of webpages.">
+    Use a prediction service to load pages more quickly
   </message>
   <message name="IDS_OPTIONS_PROXIES_CONFIGURE_BUTTON" desc="The label of the 'Configure proxy settings' button">
     Change proxy settings...
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index 9b7db382..46f7e818 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -42,6 +42,7 @@
       'autofill/core/browser/country_names_unittest.cc',
       'autofill/core/browser/credit_card_field_unittest.cc',
       'autofill/core/browser/credit_card_unittest.cc',
+      'autofill/core/browser/field_candidates_unittest.cc',
       'autofill/core/browser/form_field_unittest.cc',
       'autofill/core/browser/form_structure_unittest.cc',
       'autofill/core/browser/legal_message_line_unittest.cc',
@@ -77,6 +78,7 @@
     ],
     'browser_sync_unittest_sources': [
       'browser_sync/browser/profile_sync_service_autofill_unittest.cc',
+      'browser_sync/browser/profile_sync_service_bookmark_unittest.cc',
       'browser_sync/browser/profile_sync_service_startup_unittest.cc',
       'browser_sync/browser/profile_sync_service_unittest.cc',
       'browser_sync/browser/profile_sync_service_typed_url_unittest.cc',
@@ -740,7 +742,6 @@
     'sync_driver_unittest_sources': [
       'sync_driver/about_sync_util_unittest.cc',
       'sync_driver/backend_migrator_unittest.cc',
-      'sync_driver/backup_rollback_controller_unittest.cc',
       'sync_driver/data_type_manager_impl_unittest.cc',
       'sync_driver/device_info_data_type_controller_unittest.cc',
       'sync_driver/device_info_service_unittest.cc',
@@ -832,6 +833,9 @@
       'url_matcher/url_matcher_factory_unittest.cc',
       'url_matcher/url_matcher_unittest.cc',
     ],
+    'user_manager_unittest_sources': [
+      'user_manager/user_unittest.cc',
+    ],
     'variations_unittest_sources': [
       'variations/active_field_trials_unittest.cc',
       'variations/caching_permuted_entropy_provider_unittest.cc',
@@ -1110,7 +1114,6 @@
         'components.gyp:suggestions',
         'components.gyp:sync_bookmarks',
         'components.gyp:sync_driver',
-        'components.gyp:sync_driver_features',
         'components.gyp:sync_driver_test_support',
         'components.gyp:sync_sessions',
         'components.gyp:sync_sessions_test_support',
@@ -1454,6 +1457,7 @@
             'wifi_sync/wifi_security_class_unittest.cc',
             '<@(metrics_leak_detector_unittest_sources)',
             '<@(ownership_unittest_sources)',
+            '<@(user_manager_unittest_sources)',
           ],
           'sources!': [
             'signin/core/browser/signin_status_metrics_provider_unittest.cc',
diff --git a/components/content_settings/core/common/content_settings.cc b/components/content_settings/core/common/content_settings.cc
index 65298708..250599d 100644
--- a/components/content_settings/core/common/content_settings.cc
+++ b/components/content_settings/core/common/content_settings.cc
@@ -34,6 +34,7 @@
     CONTENT_SETTINGS_TYPE_FULLSCREEN,
     CONTENT_SETTINGS_TYPE_MOUSELOCK,
     CONTENT_SETTINGS_TYPE_MIXEDSCRIPT,
+    CONTENT_SETTINGS_TYPE_DEFAULT,  // MEDIASTREAM (removed).
     CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
     CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
     CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS,
diff --git a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
index a249839..b92afc3 100644
--- a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
+++ b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
@@ -258,10 +258,12 @@
          * Constructs default QUIC User Agent Id string including application name
          * and Cronet version. Returns empty string if QUIC is not enabled.
          *
+         * @param context Android {@link Context} to get package name from.
          * @return QUIC User Agent ID string.
          */
-        String getDefaultQuicUserAgentId() {
-            return mQuicEnabled ? UserAgent.getQuicUserAgentIdFrom(mContext) : "";
+        // TODO(mef): remove |context| parameter when legacy ChromiumUrlRequestContext is removed.
+        String getDefaultQuicUserAgentId(Context context) {
+            return mQuicEnabled ? UserAgent.getQuicUserAgentIdFrom(context) : "";
         }
 
         /**
diff --git a/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequestContext.java b/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequestContext.java
index 9b252fca..fdf9daf 100644
--- a/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequestContext.java
+++ b/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequestContext.java
@@ -36,9 +36,9 @@
     protected ChromiumUrlRequestContext(
             final Context context, String userAgent, CronetEngine.Builder config) {
         CronetLibraryLoader.ensureInitialized(context, config);
-        mChromiumUrlRequestContextAdapter =
-                nativeCreateRequestContextAdapter(userAgent, getLoggingLevel(),
-                        CronetUrlRequestContext.createNativeUrlRequestContextConfig(config));
+        mChromiumUrlRequestContextAdapter = nativeCreateRequestContextAdapter(userAgent,
+                getLoggingLevel(),
+                CronetUrlRequestContext.createNativeUrlRequestContextConfig(context, config));
         if (mChromiumUrlRequestContextAdapter == 0) {
             throw new NullPointerException("Context Adapter creation failed");
         }
diff --git a/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java b/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java
index ae28ecb..5d5dc481 100644
--- a/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java
+++ b/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java
@@ -4,6 +4,7 @@
 
 package org.chromium.net;
 
+import android.content.Context;
 import android.os.Build;
 import android.os.ConditionVariable;
 import android.os.Handler;
@@ -78,8 +79,8 @@
     public CronetUrlRequestContext(CronetEngine.Builder builder) {
         CronetLibraryLoader.ensureInitialized(builder.getContext(), builder);
         nativeSetMinLogLevel(getLoggingLevel());
-        mUrlRequestContextAdapter =
-                nativeCreateRequestContextAdapter(createNativeUrlRequestContextConfig(builder));
+        mUrlRequestContextAdapter = nativeCreateRequestContextAdapter(
+                createNativeUrlRequestContextConfig(builder.getContext(), builder));
         if (mUrlRequestContextAdapter == 0) {
             throw new NullPointerException("Context Adapter creation failed.");
         }
@@ -104,12 +105,13 @@
         }
     }
 
-    static long createNativeUrlRequestContextConfig(CronetEngine.Builder builder) {
+    static long createNativeUrlRequestContextConfig(
+            final Context context, CronetEngine.Builder builder) {
         final long urlRequestContextConfig = nativeCreateRequestContextConfig(
                 builder.getUserAgent(), builder.storagePath(), builder.quicEnabled(),
-                builder.getDefaultQuicUserAgentId(), builder.http2Enabled(), builder.sdchEnabled(),
-                builder.dataReductionProxyKey(), builder.dataReductionProxyPrimaryProxy(),
-                builder.dataReductionProxyFallbackProxy(),
+                builder.getDefaultQuicUserAgentId(context), builder.http2Enabled(),
+                builder.sdchEnabled(), builder.dataReductionProxyKey(),
+                builder.dataReductionProxyPrimaryProxy(), builder.dataReductionProxyFallbackProxy(),
                 builder.dataReductionProxySecureProxyCheckUrl(), builder.cacheDisabled(),
                 builder.httpCacheMode(), builder.httpCacheMaxSize(), builder.experimentalOptions(),
                 builder.mockCertVerifier());
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
index 28d02f35..0b4956c 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
@@ -953,7 +953,7 @@
         builder.setDataReductionProxyOptions("mnop", "qrst", "uvwx");
         builder.setStoragePath(CronetTestFramework.getTestStorage(getContext()));
         nativeVerifyUrlRequestContextConfig(
-                CronetUrlRequestContext.createNativeUrlRequestContextConfig(builder),
+                CronetUrlRequestContext.createNativeUrlRequestContextConfig(getContext(), builder),
                 CronetTestFramework.getTestStorage(getContext()));
     }
 
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/HttpUrlRequestFactoryTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/HttpUrlRequestFactoryTest.java
index 6b455e9..ffc725f1 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/HttpUrlRequestFactoryTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/HttpUrlRequestFactoryTest.java
@@ -25,16 +25,12 @@
     @SmallTest
     @Feature({"Cronet"})
     public void testCreateFactory() throws Throwable {
-        CronetEngine.Builder builder = new CronetEngine.Builder(getContext());
-        builder.enableQUIC(true);
-        builder.addQuicHint("www.google.com", 443, 443);
-        builder.addQuicHint("www.youtube.com", 443, 443);
-        builder.setLibraryName("cronet_tests");
-        String[] commandLineArgs = {
-                CronetTestFramework.LIBRARY_INIT_KEY, CronetTestFramework.LibraryInitType.LEGACY};
-        CronetTestFramework testFramework =
-                new CronetTestFramework(URL, commandLineArgs, getContext(), builder);
-        HttpUrlRequestFactory factory = testFramework.mRequestFactory;
+        HttpUrlRequestFactoryConfig config = new HttpUrlRequestFactoryConfig();
+        config.enableQUIC(true);
+        config.addQuicHint("www.google.com", 443, 443);
+        config.addQuicHint("www.youtube.com", 443, 443);
+        config.setLibraryName("cronet_tests");
+        HttpUrlRequestFactory factory = HttpUrlRequestFactory.createFactory(getContext(), config);
         assertNotNull("Factory should be created", factory);
         assertTrue("Factory should be Chromium/n.n.n.n@r but is "
                            + factory.getName(),
diff --git a/components/cronet/android/test/quic_test_server.cc b/components/cronet/android/test/quic_test_server.cc
index 13c4b65..8f21eae7 100644
--- a/components/cronet/android/test/quic_test_server.cc
+++ b/components/cronet/android/test/quic_test_server.cc
@@ -14,7 +14,6 @@
 #include "components/cronet/android/test/cronet_test_util.h"
 #include "jni/QuicTestServer_jni.h"
 #include "net/base/ip_endpoint.h"
-#include "net/base/net_util.h"
 #include "net/base/test_data_directory.h"
 #include "net/quic/crypto/proof_source_chromium.h"
 #include "net/tools/quic/quic_in_memory_cache.h"
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc
index 548f773..fee0df86 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc
@@ -9,7 +9,6 @@
 
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h"
-#include "net/base/net_util.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_request_test_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
index 4ab77a83..15356ab 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
@@ -15,7 +15,7 @@
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
 #include "net/base/host_port_pair.h"
-#include "net/base/net_util.h"
+#include "net/base/url_util.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_response_headers.h"
 #include "net/proxy/proxy_server.h"
diff --git a/components/domain_reliability/monitor.cc b/components/domain_reliability/monitor.cc
index 4a89e830..593cade6 100644
--- a/components/domain_reliability/monitor.cc
+++ b/components/domain_reliability/monitor.cc
@@ -18,7 +18,6 @@
 #include "net/base/ip_endpoint.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/http/http_response_headers.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_context.h"
diff --git a/components/exo/buffer.cc b/components/exo/buffer.cc
index cf25844fb..de74136 100644
--- a/components/exo/buffer.cc
+++ b/components/exo/buffer.cc
@@ -11,8 +11,12 @@
 #include <algorithm>
 #include <utility>
 
+#include "base/callback_helpers.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
 #include "cc/output/context_provider.h"
@@ -27,6 +31,10 @@
 namespace exo {
 namespace {
 
+// The amount of time before we wait for release queries using
+// GetQueryObjectuivEXT(GL_QUERY_RESULT_EXT).
+const int kWaitForReleaseDelayMs = 500;
+
 GLenum GLInternalFormat(gfx::BufferFormat format) {
   const GLenum kGLInternalFormats[] = {
       GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD,  // ATC
@@ -119,6 +127,11 @@
   gpu::Mailbox mailbox() const { return mailbox_; }
 
  private:
+  void ReleaseWhenQueryResultIsAvailable(const base::Closure& callback);
+  void Released();
+  void ScheduleWaitForRelease(base::TimeDelta delay);
+  void WaitForRelease();
+
   scoped_refptr<cc::ContextProvider> context_provider_;
   const unsigned texture_target_;
   const unsigned query_type_;
@@ -127,6 +140,10 @@
   unsigned query_id_;
   unsigned texture_id_;
   gpu::Mailbox mailbox_;
+  base::Closure release_callback_;
+  base::TimeTicks wait_for_release_time_;
+  bool wait_for_release_pending_;
+  base::WeakPtrFactory<Texture> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(Texture);
 };
@@ -138,7 +155,9 @@
       internalformat_(GL_RGBA),
       image_id_(0),
       query_id_(0),
-      texture_id_(0) {
+      texture_id_(0),
+      wait_for_release_pending_(false),
+      weak_ptr_factory_(this) {
   gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
   texture_id_ = CreateGLTexture(gles2, texture_target_);
   // Generate a crypto-secure random mailbox name.
@@ -155,7 +174,9 @@
       internalformat_(GLInternalFormat(gpu_memory_buffer->GetFormat())),
       image_id_(0),
       query_id_(0),
-      texture_id_(0) {
+      texture_id_(0),
+      wait_for_release_pending_(false),
+      weak_ptr_factory_(this) {
   gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
   gfx::Size size = gpu_memory_buffer->GetSize();
   image_id_ =
@@ -222,11 +243,11 @@
   gles2->BeginQueryEXT(query_type_, query_id_);
   gles2->ReleaseTexImage2DCHROMIUM(texture_target_, image_id_);
   gles2->EndQueryEXT(query_type_);
-  // Run callback when query has signaled and ReleaseTexImage has been handled
-  // if sync token has data and buffer has been used. If buffer was never used
-  // then run the callback immediately.
+  // Run callback when query result is available and ReleaseTexImage has been
+  // handled if sync token has data and buffer has been used. If buffer was
+  // never used then run the callback immediately.
   if (sync_token.HasData()) {
-    context_provider_->ContextSupport()->SignalQuery(query_id_, callback);
+    ReleaseWhenQueryResultIsAvailable(callback);
   } else {
     callback.Run();
   }
@@ -246,8 +267,9 @@
   gles2->BeginQueryEXT(query_type_, query_id_);
   gles2->ReleaseTexImage2DCHROMIUM(texture_target_, image_id_);
   gles2->EndQueryEXT(query_type_);
-  // Run callback when query has signaled and ReleaseTexImage has been handled.
-  context_provider_->ContextSupport()->SignalQuery(query_id_, callback);
+  // Run callback when query result is available and ReleaseTexImage has been
+  // handled.
+  ReleaseWhenQueryResultIsAvailable(callback);
   // Create and return a sync token that can be used to ensure that the
   // CopyTextureCHROMIUM call is processed before issuing any commands
   // that will read from the target texture on a different context.
@@ -258,6 +280,64 @@
   return sync_token;
 }
 
+void Buffer::Texture::ReleaseWhenQueryResultIsAvailable(
+    const base::Closure& callback) {
+  DCHECK(release_callback_.is_null());
+  release_callback_ = callback;
+  base::TimeDelta wait_for_release_delay =
+      base::TimeDelta::FromMilliseconds(kWaitForReleaseDelayMs);
+  wait_for_release_time_ = base::TimeTicks::Now() + wait_for_release_delay;
+  ScheduleWaitForRelease(wait_for_release_delay);
+  context_provider_->ContextSupport()->SignalQuery(
+      query_id_,
+      base::Bind(&Buffer::Texture::Released, weak_ptr_factory_.GetWeakPtr()));
+}
+
+void Buffer::Texture::Released() {
+  if (!release_callback_.is_null())
+    base::ResetAndReturn(&release_callback_).Run();
+}
+
+void Buffer::Texture::ScheduleWaitForRelease(base::TimeDelta delay) {
+  if (wait_for_release_pending_)
+    return;
+
+  wait_for_release_pending_ = true;
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::Bind(&Buffer::Texture::WaitForRelease,
+                            weak_ptr_factory_.GetWeakPtr()),
+      delay);
+}
+
+void Buffer::Texture::WaitForRelease() {
+  DCHECK(wait_for_release_pending_);
+  wait_for_release_pending_ = false;
+
+  if (release_callback_.is_null())
+    return;
+
+  base::TimeTicks current_time = base::TimeTicks::Now();
+  if (current_time < wait_for_release_time_) {
+    ScheduleWaitForRelease(wait_for_release_time_ - current_time);
+    return;
+  }
+
+  base::Closure callback = base::ResetAndReturn(&release_callback_);
+
+  {
+    TRACE_EVENT0("exo", "Buffer::Texture::WaitForQueryResult");
+
+    // We need to wait for the result to be available. Getting the result of
+    // the query implies waiting for it to become available. The actual result
+    // is unimportant and also not well defined.
+    unsigned result = 0;
+    gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
+    gles2->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &result);
+  }
+
+  callback.Run();
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Buffer, public:
 
diff --git a/components/filesystem/directory_impl.cc b/components/filesystem/directory_impl.cc
index 58480a1..e8fab2a 100644
--- a/components/filesystem/directory_impl.cc
+++ b/components/filesystem/directory_impl.cc
@@ -68,25 +68,7 @@
     return;
   }
 
-#if defined(OS_WIN)
-  // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
-  if (base::DirectoryExists(path))
-    open_flags |= base::File::FLAG_BACKUP_SEMANTICS;
-#endif  // OS_WIN
-
-  base::File base_file(path, open_flags);
-  if (!base_file.IsValid()) {
-    callback.Run(GetError(base_file));
-    return;
-  }
-
-  base::File::Info info;
-  if (!base_file.GetInfo(&info)) {
-    callback.Run(FileError::FAILED);
-    return;
-  }
-
-  if (info.is_directory) {
+  if (base::DirectoryExists(path)) {
     // We must not return directories as files. In the file abstraction, we can
     // fetch raw file descriptors over mojo pipes, and passing a file
     // descriptor to a directory is a sandbox escape on Windows.
@@ -94,6 +76,12 @@
     return;
   }
 
+  base::File base_file(path, open_flags);
+  if (!base_file.IsValid()) {
+    callback.Run(GetError(base_file));
+    return;
+  }
+
   if (file.is_pending()) {
     new FileImpl(std::move(file), path, std::move(base_file), lock_table_);
   }
@@ -110,25 +98,7 @@
     return;
   }
 
-#if defined(OS_WIN)
-  // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
-  if (base::DirectoryExists(path))
-    open_flags |= base::File::FLAG_BACKUP_SEMANTICS;
-#endif  // OS_WIN
-
-  base::File base_file(path, open_flags);
-  if (!base_file.IsValid()) {
-    callback.Run(GetError(base_file), ScopedHandle());
-    return;
-  }
-
-  base::File::Info info;
-  if (!base_file.GetInfo(&info)) {
-    callback.Run(FileError::FAILED, ScopedHandle());
-    return;
-  }
-
-  if (info.is_directory) {
+  if (base::DirectoryExists(path)) {
     // We must not return directories as files. In the file abstraction, we can
     // fetch raw file descriptors over mojo pipes, and passing a file
     // descriptor to a directory is a sandbox escape on Windows.
@@ -136,6 +106,12 @@
     return;
   }
 
+  base::File base_file(path, open_flags);
+  if (!base_file.IsValid()) {
+    callback.Run(GetError(base_file), ScopedHandle());
+    return;
+  }
+
   MojoHandle mojo_handle;
   MojoResult create_result = MojoCreatePlatformHandleWrapper(
       base_file.TakePlatformFile(), &mojo_handle);
diff --git a/components/filesystem/file_system_app.cc b/components/filesystem/file_system_app.cc
index d5d577a..0de2211 100644
--- a/components/filesystem/file_system_app.cc
+++ b/components/filesystem/file_system_app.cc
@@ -4,18 +4,42 @@
 
 #include "components/filesystem/file_system_app.h"
 
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
 #include "mojo/shell/public/cpp/connection.h"
 #include "mojo/shell/public/cpp/shell.h"
 
+#if defined(OS_WIN)
+#include "base/base_paths_win.h"
+#include "base/path_service.h"
+#include "base/strings/utf_string_conversions.h"
+#elif defined(OS_ANDROID)
+#include "base/base_paths_android.h"
+#include "base/path_service.h"
+#elif defined(OS_LINUX)
+#include "base/environment.h"
+#include "base/nix/xdg_util.h"
+#elif defined(OS_MACOSX)
+#include "base/base_paths_mac.h"
+#include "base/path_service.h"
+#endif
+
 namespace filesystem {
 
+namespace {
+
+const char kUserDataDir[] = "user-data-dir";
+
+}  // namespace filesystem
+
 FileSystemApp::FileSystemApp()
     : shell_(nullptr), lock_table_(new LockTable) {}
 
 FileSystemApp::~FileSystemApp() {}
 
 void FileSystemApp::Initialize(mojo::Shell* shell, const std::string& url,
-                               uint32_t id) {
+                               uint32_t id, uint32_t user_id) {
   shell_ = shell;
   tracing_.Initialize(shell, url);
 }
@@ -28,7 +52,43 @@
 // |InterfaceFactory<Files>| implementation:
 void FileSystemApp::Create(mojo::Connection* connection,
                            mojo::InterfaceRequest<FileSystem> request) {
-  new FileSystemImpl(connection, std::move(request), lock_table_.get());
+  new FileSystemImpl(connection, std::move(request), GetUserDataDir(),
+                     lock_table_.get());
+}
+
+//static
+base::FilePath FileSystemApp::GetUserDataDir() {
+  base::FilePath path;
+
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(kUserDataDir)) {
+    path = command_line->GetSwitchValuePath(kUserDataDir);
+  } else {
+#if defined(OS_WIN)
+    CHECK(PathService::Get(base::DIR_LOCAL_APP_DATA, &path));
+    path = path.Append(FILE_PATH_LITERAL("mandoline"));
+#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("mandoline");
+#elif defined(OS_MACOSX)
+    CHECK(PathService::Get(base::DIR_APP_DATA, &path));
+    path = path.Append("Mandoline Shell");
+#elif defined(OS_ANDROID)
+    CHECK(PathService::Get(base::DIR_ANDROID_APP_DATA, &path));
+    path = path.Append(FILE_PATH_LITERAL("mandoline"));
+#else
+    NOTIMPLEMENTED();
+#endif
+  }
+
+  if (!base::PathExists(path))
+    base::CreateDirectory(path);
+
+  return path;
 }
 
 }  // namespace filesystem
diff --git a/components/filesystem/file_system_app.h b/components/filesystem/file_system_app.h
index ae62469..3279415 100644
--- a/components/filesystem/file_system_app.h
+++ b/components/filesystem/file_system_app.h
@@ -27,9 +27,12 @@
   ~FileSystemApp() override;
 
  private:
+  // Gets the system specific toplevel profile directory.
+  static base::FilePath GetUserDataDir();
+
   // |mojo::ShellClient| override:
   void Initialize(mojo::Shell* shell, const std::string& url,
-                  uint32_t id) override;
+                  uint32_t id, uint32_t user_id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
   // |InterfaceFactory<Files>| implementation:
diff --git a/components/filesystem/file_system_impl.cc b/components/filesystem/file_system_impl.cc
index cf444b3..414bab14 100644
--- a/components/filesystem/file_system_impl.cc
+++ b/components/filesystem/file_system_impl.cc
@@ -7,7 +7,6 @@
 #include <stddef.h>
 #include <utility>
 
-#include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_file.h"
@@ -19,142 +18,44 @@
 #include "mojo/shell/public/cpp/connection.h"
 #include "url/gurl.h"
 
-#if defined(OS_WIN)
-#include "base/base_paths_win.h"
-#include "base/path_service.h"
-#include "base/strings/utf_string_conversions.h"
-#elif defined(OS_ANDROID)
-#include "base/base_paths_android.h"
-#include "base/path_service.h"
-#elif defined(OS_LINUX)
-#include "base/environment.h"
-#include "base/nix/xdg_util.h"
-#elif defined(OS_MACOSX)
-#include "base/base_paths_mac.h"
-#include "base/path_service.h"
-#endif
-
 namespace filesystem {
 
-namespace {
-
-const char kEscapeChar = ',';
-
-const char kUserDataDir[] = "user-data-dir";
-
-}  // namespace filesystem
-
 FileSystemImpl::FileSystemImpl(mojo::Connection* connection,
                                mojo::InterfaceRequest<FileSystem> request,
+                               base::FilePath persistent_dir,
                                LockTable* lock_table)
     : remote_application_url_(connection->GetRemoteApplicationURL()),
       binding_(this, std::move(request)),
-      lock_table_(lock_table) {}
+      lock_table_(lock_table),
+      persistent_dir_(persistent_dir) {}
 
 FileSystemImpl::~FileSystemImpl() {
 }
 
-void FileSystemImpl::OpenFileSystem(const mojo::String& file_system,
-                                    mojo::InterfaceRequest<Directory> directory,
-                                    FileSystemClientPtr client,
-                                    const OpenFileSystemCallback& callback) {
+void FileSystemImpl::OpenTempDirectory(
+    mojo::InterfaceRequest<Directory> directory,
+    const OpenTempDirectoryCallback& callback) {
   // Set only if the |DirectoryImpl| will own a temporary directory.
-  scoped_ptr<base::ScopedTempDir> temp_dir;
-  base::FilePath path;
-  if (file_system.get() == std::string("temp")) {
-    temp_dir.reset(new base::ScopedTempDir);
-    CHECK(temp_dir->CreateUniqueTempDir());
-    path = temp_dir->path();
-  } else if (file_system.get() == std::string("origin")) {
-    base::FilePath base_profile_dir = GetSystemProfileDir();
+  scoped_ptr<base::ScopedTempDir> temp_dir(new base::ScopedTempDir);
+  CHECK(temp_dir->CreateUniqueTempDir());
 
-    // Sanitize the url for disk access.
-    //
-    // TODO(erg): While it's currently impossible, we need to deal with http://
-    // URLs that have a path. (Or make the decision that these file systems are
-    // path bound, not origin bound.)
-    std::string sanitized_origin;
-    BuildSanitizedOrigin(remote_application_url_, &sanitized_origin);
-
-#if defined(OS_WIN)
-    path = base_profile_dir.Append(base::UTF8ToWide(sanitized_origin));
-#else
-    path = base_profile_dir.Append(sanitized_origin);
-#endif
-    if (!base::PathExists(path))
-      base::CreateDirectory(path);
-  }
-
-  if (!path.empty()) {
-    new DirectoryImpl(
-        std::move(directory), path, std::move(temp_dir), lock_table_);
-    callback.Run(FileError::OK);
-  } else {
-    callback.Run(FileError::FAILED);
-  }
+  base::FilePath path = temp_dir->path();
+  new DirectoryImpl(
+      std::move(directory), path, std::move(temp_dir), lock_table_);
+  callback.Run(FileError::OK);
 }
 
-base::FilePath FileSystemImpl::GetSystemProfileDir() const {
-  base::FilePath path;
-
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(kUserDataDir)) {
-    path = command_line->GetSwitchValuePath(kUserDataDir);
-  } else {
-#if defined(OS_WIN)
-    CHECK(PathService::Get(base::DIR_LOCAL_APP_DATA, &path));
-    path = path.Append(FILE_PATH_LITERAL("mandoline"));
-#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("mandoline");
-#elif defined(OS_MACOSX)
-    CHECK(PathService::Get(base::DIR_APP_DATA, &path));
-    path = path.Append("Mandoline Shell");
-#elif defined(OS_ANDROID)
-    CHECK(PathService::Get(base::DIR_ANDROID_APP_DATA, &path));
-    path = path.Append(FILE_PATH_LITERAL("mandoline"));
-#else
-    NOTIMPLEMENTED();
-#endif
-  }
-
+void FileSystemImpl::OpenPersistentFileSystem(
+    mojo::InterfaceRequest<Directory> directory,
+    const OpenPersistentFileSystemCallback& callback) {
+  scoped_ptr<base::ScopedTempDir> temp_dir;
+  base::FilePath path = persistent_dir_;
   if (!base::PathExists(path))
     base::CreateDirectory(path);
 
-  return path;
-}
-
-void FileSystemImpl::BuildSanitizedOrigin(
-    const std::string& origin,
-    std::string* sanitized_origin) {
-  // We take the origin string, and encode it in a way safe for filesystem
-  // access. This is vaguely based on //net/tools/dump_cache/
-  // url_to_filename_encoder.h; that file strips out schemes, and does weird
-  // things with subdirectories. We do follow the basic algorithm used there,
-  // including using ',' as our escape character.
-  for (size_t i = 0; i < origin.length(); ++i) {
-    unsigned char ch = origin[i];
-    char encoded[3];
-    int encoded_len;
-    if ((ch == '_') || (ch == '.') || (ch == '=') || (ch == '+') ||
-        (ch == '-') || (('0' <= ch) && (ch <= '9')) ||
-        (('A' <= ch) && (ch <= 'Z')) || (('a' <= ch) && (ch <= 'z'))) {
-      encoded[0] = ch;
-      encoded_len = 1;
-    } else {
-      encoded[0] = kEscapeChar;
-      encoded[1] = ch / 16;
-      encoded[1] += (encoded[1] >= 10) ? 'A' - 10 : '0';
-      encoded[2] = ch % 16;
-      encoded[2] += (encoded[2] >= 10) ? 'A' - 10 : '0';
-      encoded_len = 3;
-    }
-    sanitized_origin->append(encoded, encoded_len);
-  }
+  new DirectoryImpl(
+      std::move(directory), path, std::move(temp_dir), lock_table_);
+  callback.Run(FileError::OK);
 }
 
 }  // namespace filesystem
diff --git a/components/filesystem/file_system_impl.h b/components/filesystem/file_system_impl.h
index 4c18dd5..f7a1366 100644
--- a/components/filesystem/file_system_impl.h
+++ b/components/filesystem/file_system_impl.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_FILESYSTEM_FILE_SYSTEM_IMPL_H_
 #define COMPONENTS_FILESYSTEM_FILE_SYSTEM_IMPL_H_
 
+#include "base/files/file_path.h"
 #include "base/macros.h"
 #include "components/filesystem/public/interfaces/file_system.mojom.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
@@ -23,38 +24,32 @@
 
 class LockTable;
 
+// The base implementation of FileSystemImpl.
 class FileSystemImpl : public FileSystem {
  public:
+  // |persistent_dir| is the directory served to callers of
+  // |OpenPersistentFileSystem().
   FileSystemImpl(mojo::Connection* connection,
                  mojo::InterfaceRequest<FileSystem> request,
+                 base::FilePath persistent_dir,
                  LockTable* lock_table);
   ~FileSystemImpl() override;
 
   // |Files| implementation:
-
-  // Current valid values for |file_system| are "temp" for a temporary
-  // filesystem and "origin" for a persistent filesystem bound to the origin of
-  // the URL of the caller.
-  void OpenFileSystem(const mojo::String& file_system,
-                      mojo::InterfaceRequest<Directory> directory,
-                      FileSystemClientPtr client,
-                      const OpenFileSystemCallback& callback) override;
+  void OpenTempDirectory(
+      mojo::InterfaceRequest<Directory> directory,
+      const OpenTempDirectoryCallback& callback) override;
+  void OpenPersistentFileSystem(
+      mojo::InterfaceRequest<Directory> directory,
+      const OpenPersistentFileSystemCallback& callback) override;
 
  private:
-  // Gets the system specific toplevel profile directory.
-  base::FilePath GetSystemProfileDir() const;
-
-  // Takes the origin string from |remote_application_url_|.
-  std::string GetOriginFromRemoteApplicationURL() const;
-
-  // Sanitizes |origin| so it is an acceptable filesystem name.
-  void BuildSanitizedOrigin(const std::string& origin,
-                            std::string* sanitized_origin);
-
   const std::string remote_application_url_;
   mojo::StrongBinding<FileSystem> binding_;
   LockTable* lock_table_;
 
+  base::FilePath persistent_dir_;
+
   DISALLOW_COPY_AND_ASSIGN(FileSystemImpl);
 };
 
diff --git a/components/filesystem/files_test_base.cc b/components/filesystem/files_test_base.cc
index afc39a8..d47be02 100644
--- a/components/filesystem/files_test_base.cc
+++ b/components/filesystem/files_test_base.cc
@@ -13,7 +13,7 @@
 
 namespace filesystem {
 
-FilesTestBase::FilesTestBase() : binding_(this) {
+FilesTestBase::FilesTestBase() {
 }
 
 FilesTestBase::~FilesTestBase() {
@@ -24,14 +24,9 @@
   shell()->ConnectToInterface("mojo:filesystem", &files_);
 }
 
-void FilesTestBase::OnFileSystemShutdown() {
-}
-
 void FilesTestBase::GetTemporaryRoot(DirectoryPtr* directory) {
   FileError error = FileError::FAILED;
-  files()->OpenFileSystem("temp", GetProxy(directory),
-                          binding_.CreateInterfacePtrAndBind(),
-                          mojo::Capture(&error));
+  files()->OpenTempDirectory(GetProxy(directory), mojo::Capture(&error));
   ASSERT_TRUE(files().WaitForIncomingResponse());
   ASSERT_EQ(FileError::OK, error);
 }
diff --git a/components/filesystem/files_test_base.h b/components/filesystem/files_test_base.h
index 04499496..8ce96c07 100644
--- a/components/filesystem/files_test_base.h
+++ b/components/filesystem/files_test_base.h
@@ -12,8 +12,7 @@
 
 namespace filesystem {
 
-class FilesTestBase : public mojo::test::ApplicationTestBase,
-                      public filesystem::FileSystemClient {
+class FilesTestBase : public mojo::test::ApplicationTestBase {
  public:
   FilesTestBase();
   ~FilesTestBase() override;
@@ -21,9 +20,6 @@
   // Overridden from mojo::test::ApplicationTestBase:
   void SetUp() override;
 
-  // Overridden from FileSystemClient:
-  void OnFileSystemShutdown() override;
-
  protected:
   // Note: This has an out parameter rather than returning the |DirectoryPtr|,
   // since |ASSERT_...()| doesn't work with return values.
@@ -32,7 +28,6 @@
   FileSystemPtr& files() { return files_; }
 
  private:
-  mojo::Binding<filesystem::FileSystemClient> binding_;
   FileSystemPtr files_;
 
   DISALLOW_COPY_AND_ASSIGN(FilesTestBase);
diff --git a/components/filesystem/lock_table.cc b/components/filesystem/lock_table.cc
index 63ab1185..4f43672 100644
--- a/components/filesystem/lock_table.cc
+++ b/components/filesystem/lock_table.cc
@@ -14,6 +14,7 @@
 
 base::File::Error LockTable::LockFile(FileImpl* file) {
   DCHECK(file->IsValid());
+  DCHECK(file->path().IsAbsolute());
 
   auto it = locked_files_.find(file->path());
   if (it != locked_files_.end()) {
@@ -34,14 +35,14 @@
 base::File::Error LockTable::UnlockFile(FileImpl* file) {
   auto it = locked_files_.find(file->path());
   if (it != locked_files_.end()) {
-    locked_files_.erase(it);
-
     base::File::Error lock_err = file->RawUnlockFile();
     if (lock_err != base::File::FILE_OK) {
       // TODO(erg): When can we fail to release a lock?
       NOTREACHED();
       return lock_err;
     }
+
+    locked_files_.erase(it);
   }
 
   return base::File::FILE_OK;
diff --git a/components/filesystem/public/interfaces/file_system.mojom b/components/filesystem/public/interfaces/file_system.mojom
index 72785636..db72679 100644
--- a/components/filesystem/public/interfaces/file_system.mojom
+++ b/components/filesystem/public/interfaces/file_system.mojom
@@ -7,21 +7,11 @@
 import "components/filesystem/public/interfaces/directory.mojom";
 import "components/filesystem/public/interfaces/types.mojom";
 
-// Callback interface for FileSystem. When we call OpenFileSystem, we supply a
-// client to receive and handle the shutdown signal. Just because the shell has
-// closed the application connection to the FileSystem doesn't mean that we
-// should immediately kill all connections to our clients. We notify them that
-// we are shutting down so that they can flush any data and cleanly shutdown.
-//
-// Actual connection lifetime is controlled by the lifetime of the |directory|
-// object.
-interface FileSystemClient {
-  OnFileSystemShutdown();
-};
-
 interface FileSystem {
-  // Opens the root directory for the file system with the given name; null
-  // yields the default file system, if any.
-  OpenFileSystem(string? file_system, Directory& directory,
-                 FileSystemClient client) => (FileError error);
+  // Opens a temporary filesystem. Will return a different directory each time
+  // it is called.
+  OpenTempDirectory(Directory& directory) => (FileError error);
+
+  // Returns a directory which will persist to disk.
+  OpenPersistentFileSystem(Directory& directory) => (FileError error);
 };
diff --git a/components/font_service/font_service_app.cc b/components/font_service/font_service_app.cc
index 1be9054..83cbb37b3 100644
--- a/components/font_service/font_service_app.cc
+++ b/components/font_service/font_service_app.cc
@@ -59,7 +59,7 @@
 FontServiceApp::~FontServiceApp() {}
 
 void FontServiceApp::Initialize(mojo::Shell* shell, const std::string& url,
-                                uint32_t id) {
+                                uint32_t id, uint32_t user_id) {
   tracing_.Initialize(shell, url);
 }
 
diff --git a/components/font_service/font_service_app.h b/components/font_service/font_service_app.h
index c9926076..35fb0356 100644
--- a/components/font_service/font_service_app.h
+++ b/components/font_service/font_service_app.h
@@ -28,7 +28,7 @@
  private:
   // mojo::ShellClient:
   void Initialize(mojo::Shell* shell, const std::string& url,
-                  uint32_t id) override;
+                  uint32_t id, uint32_t user_id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
   // mojo::InterfaceFactory<FontService>:
diff --git a/components/history/core/browser/typed_url_syncable_service.cc b/components/history/core/browser/typed_url_syncable_service.cc
index d5a99420..ec128e1 100644
--- a/components/history/core/browser/typed_url_syncable_service.cc
+++ b/components/history/core/browser/typed_url_syncable_service.cc
@@ -12,7 +12,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/history/core/browser/history_backend.h"
-#include "net/base/net_util.h"
+#include "net/base/url_util.h"
 #include "sync/protocol/sync.pb.h"
 #include "sync/protocol/typed_url_specifics.pb.h"
 
diff --git a/components/infobars/core/infobar_delegate.h b/components/infobars/core/infobar_delegate.h
index 326b316..e0a17e60 100644
--- a/components/infobars/core/infobar_delegate.h
+++ b/components/infobars/core/infobar_delegate.h
@@ -130,6 +130,7 @@
     CHROME_WINDOW_ERROR = 60,
     CONFIRM_DANGEROUS_DOWNLOAD = 61,
     DESKTOP_SEARCH_REDIRECTION_INFOBAR_DELEGATE = 62,
+    UPDATE_PASSWORD_INFOBAR_DELEGATE = 63,
   };
 
   // Describes navigation events, used to decide whether infobars should be
diff --git a/components/leveldb/env_mojo.cc b/components/leveldb/env_mojo.cc
index fd8acf3..6553722f 100644
--- a/components/leveldb/env_mojo.cc
+++ b/components/leveldb/env_mojo.cc
@@ -4,6 +4,8 @@
 
 #include "components/leveldb/env_mojo.h"
 
+#include <errno.h>
+
 #include "base/trace_event/trace_event.h"
 #include "third_party/leveldatabase/chromium_logger.h"
 #include "third_party/leveldatabase/src/include/leveldb/status.h"
@@ -43,7 +45,7 @@
       : fname_(name), lock_(lock) {}
   ~MojoFileLock() override { DCHECK(!lock_); }
 
-  const std::string& name() { return fname_; }
+  const std::string& name() const { return fname_; }
 
   LevelDBFileThread::OpaqueLock* TakeLock() {
     LevelDBFileThread::OpaqueLock* to_return = lock_;
@@ -176,9 +178,6 @@
                          leveldb_env::kWritableFileSync, error);
     }
 
-    // TODO(erg): In the leveldb_env::ChromiumEnv, there is a whole system
-    // which makes backups of the data here. crbug.com/587185
-
     // leveldb's implicit contract for Sync() is that if this instance is for a
     // manifest file then the directory is also sync'ed. See leveldb's
     // env_posix.cc.
diff --git a/components/leveldb/leveldb_app.cc b/components/leveldb/leveldb_app.cc
index 1e9d1682..01fd2ff 100644
--- a/components/leveldb/leveldb_app.cc
+++ b/components/leveldb/leveldb_app.cc
@@ -15,7 +15,8 @@
 
 void LevelDBApp::Initialize(mojo::Shell* shell,
                             const std::string& url,
-                            uint32_t id) {
+                            uint32_t id,
+                            uint32_t user_id) {
   tracing_.Initialize(shell, url);
   service_.reset(new LevelDBServiceImpl);
 }
diff --git a/components/leveldb/leveldb_app.h b/components/leveldb/leveldb_app.h
index 7f5157a..4de6486b 100644
--- a/components/leveldb/leveldb_app.h
+++ b/components/leveldb/leveldb_app.h
@@ -23,7 +23,8 @@
   // |ShellClient| override:
   void Initialize(mojo::Shell* shell,
                   const std::string& url,
-                  uint32_t id) override;
+                  uint32_t id,
+                  uint32_t user_id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
   // TODO(erg): What do we have to do on shell error?
diff --git a/components/leveldb/leveldb_apptest.cc b/components/leveldb/leveldb_apptest.cc
index 9e170a2..d9e443c 100644
--- a/components/leveldb/leveldb_apptest.cc
+++ b/components/leveldb/leveldb_apptest.cc
@@ -19,8 +19,7 @@
 namespace leveldb {
 namespace {
 
-class LevelDBApptest : public mojo::test::ApplicationTestBase,
-                       public filesystem::FileSystemClient {
+class LevelDBApptest : public mojo::test::ApplicationTestBase {
  public:
   LevelDBApptest() {}
   ~LevelDBApptest() override {}
@@ -33,16 +32,12 @@
     shell()->ConnectToInterface("mojo:leveldb", &leveldb_);
   }
 
-  // Overridden from FileSystemClient:
-  void OnFileSystemShutdown() override {}
-
   // Note: This has an out parameter rather than returning the |DirectoryPtr|,
   // since |ASSERT_...()| doesn't work with return values.
-  void GetOriginRoot(filesystem::DirectoryPtr* directory) {
+  void GetUserDataDir(filesystem::DirectoryPtr* directory) {
     FileError error = FileError::FAILED;
-    files()->OpenFileSystem("origin", GetProxy(directory),
-                            bindings_.CreateInterfacePtrAndBind(this),
-                            mojo::Capture(&error));
+    files()->OpenPersistentFileSystem(GetProxy(directory),
+                                      mojo::Capture(&error));
     ASSERT_TRUE(files().WaitForIncomingResponse());
     ASSERT_EQ(FileError::OK, error);
   }
@@ -51,8 +46,6 @@
   LevelDBServicePtr& leveldb() { return leveldb_; }
 
  private:
-  mojo::WeakBindingSet<filesystem::FileSystemClient> bindings_;
-
   filesystem::FileSystemPtr files_;
   LevelDBServicePtr leveldb_;
 
@@ -61,7 +54,7 @@
 
 TEST_F(LevelDBApptest, Basic) {
   filesystem::DirectoryPtr directory;
-  GetOriginRoot(&directory);
+  GetUserDataDir(&directory);
 
   DatabaseError error;
   LevelDBDatabasePtr database;
@@ -106,7 +99,7 @@
 
 TEST_F(LevelDBApptest, WriteBatch) {
   filesystem::DirectoryPtr directory;
-  GetOriginRoot(&directory);
+  GetUserDataDir(&directory);
 
   DatabaseError error;
   LevelDBDatabasePtr database;
@@ -162,7 +155,7 @@
 
   {
     filesystem::DirectoryPtr directory;
-    GetOriginRoot(&directory);
+    GetUserDataDir(&directory);
 
     LevelDBDatabasePtr database;
     leveldb()->Open(std::move(directory), "test", GetProxy(&database),
@@ -183,7 +176,7 @@
 
   {
     filesystem::DirectoryPtr directory;
-    GetOriginRoot(&directory);
+    GetUserDataDir(&directory);
 
     // Reconnect to the database.
     LevelDBDatabasePtr database;
@@ -207,7 +200,7 @@
   DatabaseError error;
 
   filesystem::DirectoryPtr directory;
-  GetOriginRoot(&directory);
+  GetUserDataDir(&directory);
 
   LevelDBDatabasePtr database;
   leveldb()->Open(std::move(directory), "test", GetProxy(&database),
@@ -225,7 +218,7 @@
   DatabaseError error;
 
   filesystem::DirectoryPtr directory;
-  GetOriginRoot(&directory);
+  GetUserDataDir(&directory);
 
   LevelDBDatabasePtr database;
   leveldb()->Open(std::move(directory), "test", GetProxy(&database),
@@ -277,7 +270,7 @@
 
 TEST_F(LevelDBApptest, InvalidArgumentOnInvalidSnapshot) {
   filesystem::DirectoryPtr directory;
-  GetOriginRoot(&directory);
+  GetUserDataDir(&directory);
 
   LevelDBDatabasePtr database;
   DatabaseError error = DatabaseError::INVALID_ARGUMENT;
diff --git a/components/message_port.gypi b/components/message_port.gypi
index 232782c..4acee9c8 100644
--- a/components/message_port.gypi
+++ b/components/message_port.gypi
@@ -9,7 +9,7 @@
       'type': 'static_library',
       'dependencies': [
         '../base/base.gyp:base',
-        '../mojo/mojo_base.gyp:mojo_message_pump_lib',
+        '../mojo/mojo_public.gyp:mojo_message_pump_lib',
         '../mojo/mojo_public.gyp:mojo_system_cpp_headers',
         '../third_party/WebKit/public/blink.gyp:blink',
       ],
diff --git a/components/mus/BUILD.gn b/components/mus/BUILD.gn
index 3211f8fb8..b29f28e6 100644
--- a/components/mus/BUILD.gn
+++ b/components/mus/BUILD.gn
@@ -6,6 +6,7 @@
 import("//testing/test.gni")
 import("//mojo/public/mojo_application.gni")
 import("//mojo/public/mojo_application_manifest.gni")
+import("//tools/grit/repack.gni")
 
 if (is_android) {
   import("//build/config/android/config.gni")
@@ -35,6 +36,7 @@
     deps = [
       ":lib",
       ":manifest",
+      "//mojo/platform_handle:for_shared_library",
       "//mojo/shell/public/cpp:sources",
     ]
 
@@ -74,6 +76,9 @@
   ]
 
   deps = [
+    ":resources_100",
+    ":resources_200",
+    ":resources_strings",
     "//base",
     "//cc",
     "//cc/surfaces",
@@ -82,6 +87,7 @@
     "//components/mus/public/interfaces",
     "//components/mus/surfaces",
     "//components/mus/ws:lib",
+    "//components/resource_provider/public/cpp",
     "//mojo/common:common_base",
     "//mojo/services/tracing/public/cpp",
     "//mojo/shell/public/cpp",
@@ -91,6 +97,10 @@
     "//ui/platform_window:platform_window",
   ]
 
+  data_deps = [
+    "//components/resource_provider",
+  ]
+
   if (use_x11) {
     public_configs = [ "//build/config/linux:x11" ]
     public_deps = [
@@ -102,3 +112,33 @@
     deps += [ "//ui/ozone:ozone" ]
   }
 }
+
+repack("resources_strings") {
+  sources = [
+    "$root_gen_dir/ui/strings/app_locale_settings_en-US.pak",
+  ]
+  output = "$root_out_dir/mus/resources/mus_app_resources_strings.pak"
+  deps = [
+    "//ui/strings",
+  ]
+}
+
+repack("resources_100") {
+  sources = [
+    "$root_gen_dir/ui/resources/ui_resources_100_percent.pak",
+  ]
+  output = "$root_out_dir/mus/resources/mus_app_resources_100.pak"
+  deps = [
+    "//ui/resources",
+  ]
+}
+
+repack("resources_200") {
+  sources = [
+    "$root_gen_dir/ui/resources/ui_resources_200_percent.pak",
+  ]
+  output = "$root_out_dir/mus/resources/mus_app_resources_200.pak"
+  deps = [
+    "//ui/resources",
+  ]
+}
diff --git a/components/mus/DEPS b/components/mus/DEPS
index 13a109e..05f5c20 100644
--- a/components/mus/DEPS
+++ b/components/mus/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "+cc",
+  "+components/resource_provider",
   "+components/gpu",
   "+mojo/shell",
   "+mojo/common",
diff --git a/components/mus/gles2/BUILD.gn b/components/mus/gles2/BUILD.gn
index b2fd297..8299e82 100644
--- a/components/mus/gles2/BUILD.gn
+++ b/components/mus/gles2/BUILD.gn
@@ -53,7 +53,7 @@
   if (is_android) {
     deps += [ "//mojo/platform_handle:platform_handle_impl" ]
   } else {
-    deps += [ "//mojo/platform_handle:for_shared_library" ]
+    deps += [ "//mojo/platform_handle" ]
   }
 
   if (use_ozone) {
diff --git a/components/mus/mus_app.cc b/components/mus/mus_app.cc
index d93122e3..ea2410b 100644
--- a/components/mus/mus_app.cc
+++ b/components/mus/mus_app.cc
@@ -4,6 +4,8 @@
 
 #include "components/mus/mus_app.h"
 
+#include <set>
+
 #include "base/stl_util.h"
 #include "build/build_config.h"
 #include "base/threading/platform_thread.h"
@@ -15,10 +17,13 @@
 #include "components/mus/ws/window_tree_host_connection.h"
 #include "components/mus/ws/window_tree_host_impl.h"
 #include "components/mus/ws/window_tree_impl.h"
+#include "components/resource_provider/public/cpp/resource_loader.h"
 #include "mojo/public/c/system/main.h"
 #include "mojo/services/tracing/public/cpp/tracing_impl.h"
 #include "mojo/shell/public/cpp/connection.h"
 #include "mojo/shell/public/cpp/shell.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/base/ui_base_paths.h"
 #include "ui/events/event_switches.h"
 #include "ui/events/platform/platform_event_source.h"
 #include "ui/gl/gl_surface.h"
@@ -38,6 +43,14 @@
 
 namespace mus {
 
+namespace {
+
+const char kResourceFileStrings[] = "mus_app_resources_strings.pak";
+const char kResourceFile100[] = "mus_app_resources_100.pak";
+const char kResourceFile200[] = "mus_app_resources_200.pak";
+
+}  // namespace
+
 // TODO(sky): this is a pretty typical pattern, make it easier to do.
 struct MandolineUIServicesApp::PendingRequest {
   scoped_ptr<mojo::InterfaceRequest<mojom::DisplayManager>> dm_request;
@@ -54,9 +67,35 @@
   connection_manager_.reset();
 }
 
+void MandolineUIServicesApp::InitializeResources(mojo::Shell* shell) {
+  if (ui::ResourceBundle::HasSharedInstance())
+    return;
+
+  std::set<std::string> resource_paths;
+  resource_paths.insert(kResourceFileStrings);
+  resource_paths.insert(kResourceFile100);
+  resource_paths.insert(kResourceFile200);
+
+  resource_provider::ResourceLoader resource_loader(shell, resource_paths);
+  if (!resource_loader.BlockUntilLoaded())
+    return;
+  CHECK(resource_loader.loaded());
+  ui::RegisterPathProvider();
+
+  // Initialize resource bundle with 1x and 2x cursor bitmaps.
+  ui::ResourceBundle::InitSharedInstanceWithPakFileRegion(
+      resource_loader.ReleaseFile(kResourceFileStrings),
+      base::MemoryMappedFile::Region::kWholeFile);
+  ui::ResourceBundle::GetSharedInstance().AddDataPackFromFile(
+      resource_loader.ReleaseFile(kResourceFile100), ui::SCALE_FACTOR_100P);
+  ui::ResourceBundle::GetSharedInstance().AddDataPackFromFile(
+      resource_loader.ReleaseFile(kResourceFile200), ui::SCALE_FACTOR_200P);
+}
+
 void MandolineUIServicesApp::Initialize(mojo::Shell* shell,
                                         const std::string& url,
-                                        uint32_t id) {
+                                        uint32_t id,
+                                        uint32_t user_id) {
   shell_ = shell;
   surfaces_state_ = new SurfacesState;
 
@@ -70,6 +109,8 @@
   }
 #endif
 
+  InitializeResources(shell);
+
 #if defined(USE_OZONE)
   // The ozone platform can provide its own event source. So initialize the
   // platform before creating the default event source.
diff --git a/components/mus/mus_app.h b/components/mus/mus_app.h
index 956205f..c058c5f 100644
--- a/components/mus/mus_app.h
+++ b/components/mus/mus_app.h
@@ -7,6 +7,7 @@
 
 #include <stdint.h>
 
+#include <string>
 #include <vector>
 
 #include "base/macros.h"
@@ -59,9 +60,11 @@
   // has been established.
   struct PendingRequest;
 
+  void InitializeResources(mojo::Shell* shell);
+
   // mojo::ShellClient:
   void Initialize(mojo::Shell* shell, const std::string& url,
-                  uint32_t id) override;
+                  uint32_t id, uint32_t user_id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
   // ConnectionManagerDelegate:
diff --git a/components/mus/public/cpp/lib/context_provider.cc b/components/mus/public/cpp/lib/context_provider.cc
index d2d6ce01..0b0b470 100644
--- a/components/mus/public/cpp/lib/context_provider.cc
+++ b/components/mus/public/cpp/lib/context_provider.cc
@@ -9,7 +9,6 @@
 #include "base/logging.h"
 #include "mojo/gles2/gles2_context.h"
 #include "mojo/gpu/mojo_gles2_impl_autogen.h"
-#include "mojo/public/cpp/environment/environment.h"
 
 namespace mus {
 
@@ -25,8 +24,7 @@
 bool ContextProvider::BindToCurrentThread() {
   DCHECK(command_buffer_handle_.is_valid());
   context_ = MojoGLES2CreateContext(command_buffer_handle_.release().value(),
-                                    nullptr, &ContextLostThunk, this,
-                                    mojo::Environment::GetDefaultAsyncWaiter());
+                                    nullptr, &ContextLostThunk, this);
   context_gl_.reset(new mojo::MojoGLES2Impl(context_));
   return !!context_;
 }
diff --git a/components/mus/ws/BUILD.gn b/components/mus/ws/BUILD.gn
index 53eb3b4..d3fa108 100644
--- a/components/mus/ws/BUILD.gn
+++ b/components/mus/ws/BUILD.gn
@@ -158,7 +158,7 @@
     "//mojo/edk/test:run_all_unittests",
     "//mojo/environment:chromium",
     "//mojo/gles2",
-    "//mojo/platform_handle",
+    "//mojo/platform_handle:for_shared_library",
     "//mojo/public/cpp/bindings:bindings",
     "//mojo/shell/public/interfaces",
     "//testing/gtest",
diff --git a/components/mus/ws/display_manager.cc b/components/mus/ws/display_manager.cc
index 5aa8cb9..a35e08b 100644
--- a/components/mus/ws/display_manager.cc
+++ b/components/mus/ws/display_manager.cc
@@ -359,7 +359,13 @@
 }
 
 void DefaultDisplayManager::DispatchEvent(ui::Event* event) {
-  delegate_->OnEvent(*event);
+  if (event->IsMouseEvent()) {
+    delegate_->OnEvent(ui::PointerEvent(*event->AsMouseEvent()));
+  } else if (event->IsTouchEvent()) {
+    delegate_->OnEvent(ui::PointerEvent(*event->AsTouchEvent()));
+  } else {
+    delegate_->OnEvent(*event);
+  }
 
 #if defined(USE_X11) || defined(USE_OZONE)
   // We want to emulate the WM_CHAR generation behaviour of Windows.
diff --git a/components/mus/ws/event_dispatcher_unittest.cc b/components/mus/ws/event_dispatcher_unittest.cc
index 4fdda98..9167848 100644
--- a/components/mus/ws/event_dispatcher_unittest.cc
+++ b/components/mus/ws/event_dispatcher_unittest.cc
@@ -1062,5 +1062,58 @@
   EXPECT_TRUE(details->in_nonclient_area);
 }
 
+TEST_F(EventDispatcherTest, ProcessPointerEvents) {
+  scoped_ptr<ServerWindow> child(CreateChildWindow(WindowId(1, 3)));
+
+  root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
+  child->SetBounds(gfx::Rect(10, 10, 20, 20));
+
+  {
+    const ui::PointerEvent pointer_event(ui::MouseEvent(
+        ui::ET_MOUSE_PRESSED, gfx::Point(20, 25), gfx::Point(20, 25),
+        base::TimeDelta(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON));
+    event_dispatcher()->ProcessEvent(
+        mojom::Event::From(static_cast<const ui::Event&>(pointer_event)));
+
+    scoped_ptr<DispatchedEventDetails> details =
+        test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails();
+    ASSERT_TRUE(details);
+    ASSERT_EQ(child.get(), details->window);
+
+    scoped_ptr<ui::Event> dispatched_event(
+        details->event.To<scoped_ptr<ui::Event>>());
+    ASSERT_TRUE(dispatched_event);
+    ASSERT_TRUE(dispatched_event->IsMouseEvent());
+
+    ui::MouseEvent* dispatched_mouse_event = dispatched_event->AsMouseEvent();
+    EXPECT_EQ(gfx::Point(20, 25), dispatched_mouse_event->root_location());
+    EXPECT_EQ(gfx::Point(10, 15), dispatched_mouse_event->location());
+  }
+
+  {
+    const int touch_id = 3;
+    const ui::PointerEvent pointer_event(
+        ui::TouchEvent(ui::ET_TOUCH_RELEASED, gfx::Point(25, 20), touch_id,
+                       base::TimeDelta()));
+    event_dispatcher()->ProcessEvent(
+        mojom::Event::From(static_cast<const ui::Event&>(pointer_event)));
+
+    scoped_ptr<DispatchedEventDetails> details =
+        test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails();
+    ASSERT_TRUE(details);
+    ASSERT_EQ(child.get(), details->window);
+
+    scoped_ptr<ui::Event> dispatched_event(
+        details->event.To<scoped_ptr<ui::Event>>());
+    ASSERT_TRUE(dispatched_event);
+    ASSERT_TRUE(dispatched_event->IsTouchEvent());
+
+    ui::TouchEvent* dispatched_touch_event = dispatched_event->AsTouchEvent();
+    EXPECT_EQ(gfx::Point(25, 20), dispatched_touch_event->root_location());
+    EXPECT_EQ(gfx::Point(15, 10), dispatched_touch_event->location());
+    EXPECT_EQ(touch_id, dispatched_touch_event->touch_id());
+  }
+}
+
 }  // namespace ws
 }  // namespace mus
diff --git a/components/nacl/common/nacl_switches.cc b/components/nacl/common/nacl_switches.cc
index 331e2a5..749d6fdd 100644
--- a/components/nacl/common/nacl_switches.cc
+++ b/components/nacl/common/nacl_switches.cc
@@ -16,8 +16,8 @@
 // sandbox.
 const char kEnableNaClNonSfiMode[]          = "enable-nacl-nonsfi-mode";
 
-// Enable use of the Subzero as the PNaCl translator instead of LLC.
-const char kEnablePNaClSubzero[] = "enable-pnacl-subzero";
+// Force use of the Subzero as the PNaCl translator instead of LLC.
+const char kForcePNaClSubzero[] = "force-pnacl-subzero";
 
 // Value for --type that causes the process to run as a NativeClient broker
 // (used for launching NaCl loader processes on 64-bit Windows).
diff --git a/components/nacl/common/nacl_switches.h b/components/nacl/common/nacl_switches.h
index 8738946..9139960 100644
--- a/components/nacl/common/nacl_switches.h
+++ b/components/nacl/common/nacl_switches.h
@@ -14,7 +14,7 @@
 extern const char kDisablePnaclCrashThrottling[];
 extern const char kEnableNaClDebug[];
 extern const char kEnableNaClNonSfiMode[];
-extern const char kEnablePNaClSubzero[];
+extern const char kForcePNaClSubzero[];
 extern const char kNaClBrokerProcess[];
 extern const char kNaClDangerousNoSandboxNonSfi[];
 extern const char kNaClDebugMask[];
diff --git a/components/nacl/renderer/ppb_nacl_private_impl.cc b/components/nacl/renderer/ppb_nacl_private_impl.cc
index 840cdfa..cb033d39 100644
--- a/components/nacl/renderer/ppb_nacl_private_impl.cc
+++ b/components/nacl/renderer/ppb_nacl_private_impl.cc
@@ -1086,6 +1086,28 @@
   return false;
 }
 
+bool ShouldUseSubzero(const PP_PNaClOptions* pnacl_options) {
+  // Always use Subzero if explicitly overridden on the command line.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kForcePNaClSubzero))
+    return true;
+  // Otherwise, don't use Subzero for a debug pexe file since Subzero's parser
+  // is likely to reject an unfinalized pexe.
+  if (pnacl_options->is_debug)
+    return false;
+  // Only use Subzero for optlevel=0.
+  if (pnacl_options->opt_level != 0)
+    return false;
+  // Check a whitelist of architectures.
+  const char* arch = GetSandboxArch();
+  if (strcmp(arch, "x86-32") == 0)
+    return true;
+  if (strcmp(arch, "x86-64") == 0)
+    return true;
+
+  return false;
+}
+
 PP_Bool ManifestGetProgramURL(PP_Instance instance,
                               PP_Var* pp_full_url,
                               PP_PNaClOptions* pnacl_options,
@@ -1103,21 +1125,10 @@
                               &error_info)) {
     *pp_full_url = ppapi::StringVar::StringToPPVar(full_url);
     *pp_uses_nonsfi_mode = PP_FromBool(uses_nonsfi_mode);
-    // Check if we should use Subzero (x86-32 / non-debugging case for now).
-    // TODO(stichnot): When phasing in Subzero for a new target architecture,
-    // add it behind the --enable-pnacl-subzero flag, and add a clause here:
-    //   && base::CommandLine::ForCurrentProcess()->HasSwitch(
-    //         switches::kEnablePNaClSubzero)
-    // Also modify the ValidationCacheOfTranslatorNexes test to match.  When
-    // Subzero is finally fully released for all sandbox architectures, the
-    // --enable-pnacl-subzero flag can be removed.
-    if (pnacl_options->opt_level == 0 && !pnacl_options->is_debug) {
-      const char* arch = GetSandboxArch();
-      if (strcmp(arch, "x86-32") == 0 || strcmp(arch, "x86-64") == 0) {
-        pnacl_options->use_subzero = PP_TRUE;
-        // Subzero -O2 is closer to LLC -O0, so indicate -O2.
-        pnacl_options->opt_level = 2;
-      }
+    if (ShouldUseSubzero(pnacl_options)) {
+      pnacl_options->use_subzero = PP_TRUE;
+      // Subzero -O2 is closer to LLC -O0, so indicate -O2.
+      pnacl_options->opt_level = 2;
     }
     return PP_TRUE;
   }
diff --git a/components/ntp_snippets.gypi b/components/ntp_snippets.gypi
index e3267dc..551d3e6 100644
--- a/components/ntp_snippets.gypi
+++ b/components/ntp_snippets.gypi
@@ -20,6 +20,8 @@
         'ntp_snippets/inner_iterator.h',
         'ntp_snippets/ntp_snippet.cc',
         'ntp_snippets/ntp_snippet.h',
+        'ntp_snippets/ntp_snippets_fetcher.cc',
+        'ntp_snippets/ntp_snippets_fetcher.h',
         'ntp_snippets/ntp_snippets_service.cc',
         'ntp_snippets/ntp_snippets_service.h',
       ],
diff --git a/components/ntp_snippets/BUILD.gn b/components/ntp_snippets/BUILD.gn
index 89e0ccd..222ad184 100644
--- a/components/ntp_snippets/BUILD.gn
+++ b/components/ntp_snippets/BUILD.gn
@@ -8,6 +8,8 @@
     "inner_iterator.h",
     "ntp_snippet.cc",
     "ntp_snippet.h",
+    "ntp_snippets_fetcher.cc",
+    "ntp_snippets_fetcher.h",
     "ntp_snippets_service.cc",
     "ntp_snippets_service.h",
   ]
@@ -15,6 +17,9 @@
   public_deps = [
     "//base",
     "//components/keyed_service/core",
+    "//components/signin/core/browser",
+    "//google_apis",
+    "//net",
     "//url",
   ]
 }
@@ -28,6 +33,9 @@
 
   deps = [
     ":ntp_snippets",
+    "//base",
+    "//components/signin/core/browser:test_support",
+    "//net:test_support",
     "//testing/gtest",
   ]
 }
diff --git a/components/ntp_snippets/DEPS b/components/ntp_snippets/DEPS
index f0bf3d9..830c20f 100644
--- a/components/ntp_snippets/DEPS
+++ b/components/ntp_snippets/DEPS
@@ -1,3 +1,8 @@
 include_rules = [
   "+components/keyed_service/core",
+  "+components/signin",
+  "+net/base",
+  "+net/http",
+  "+net/url_request",
+  "+google_apis/gaia",
 ]
diff --git a/components/ntp_snippets/ntp_snippet.cc b/components/ntp_snippets/ntp_snippet.cc
index ef59e1b..9ee20290 100644
--- a/components/ntp_snippets/ntp_snippet.cc
+++ b/components/ntp_snippets/ntp_snippet.cc
@@ -14,14 +14,14 @@
 NTPSnippet::~NTPSnippet() {}
 
 // static
-std::unique_ptr<NTPSnippet> NTPSnippet::NTPSnippetFromDictionary(
+scoped_ptr<NTPSnippet> NTPSnippet::NTPSnippetFromDictionary(
     const base::DictionaryValue& dict) {
   // Need at least the url.
   std::string url;
   if (!dict.GetString("url", &url))
     return nullptr;
 
-  std::unique_ptr<NTPSnippet> snippet(new NTPSnippet(GURL(url)));
+  scoped_ptr<NTPSnippet> snippet(new NTPSnippet(GURL(url)));
 
   std::string site_title;
   if (dict.GetString("site_title", &site_title))
diff --git a/components/ntp_snippets/ntp_snippet.h b/components/ntp_snippets/ntp_snippet.h
index 6ea126ab..6dd2ad04 100644
--- a/components/ntp_snippets/ntp_snippet.h
+++ b/components/ntp_snippets/ntp_snippet.h
@@ -4,7 +4,6 @@
 #ifndef COMPONENTS_NTP_SNIPPETS_NTP_SNIPPET_H_
 #define COMPONENTS_NTP_SNIPPETS_NTP_SNIPPET_H_
 
-#include <memory>
 #include <string>
 
 #include "base/macros.h"
@@ -30,7 +29,7 @@
   // dictionary doesn't contain at least a url. The keys in the dictionary are
   // expected to be the same as the property name, with exceptions documented in
   // the property comment.
-  static std::unique_ptr<NTPSnippet> NTPSnippetFromDictionary(
+  static scoped_ptr<NTPSnippet> NTPSnippetFromDictionary(
       const base::DictionaryValue& dict);
 
   // URL of the page described by this snippet.
diff --git a/components/ntp_snippets/ntp_snippets_fetcher.cc b/components/ntp_snippets/ntp_snippets_fetcher.cc
new file mode 100644
index 0000000..7c74fcf
--- /dev/null
+++ b/components/ntp_snippets/ntp_snippets_fetcher.cc
@@ -0,0 +1,191 @@
+// Copyright 2016 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 "components/ntp_snippets/ntp_snippets_fetcher.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/strings/stringprintf.h"
+#include "base/task_runner_util.h"
+#include "components/signin/core/browser/profile_oauth2_token_service.h"
+#include "components/signin/core/browser/signin_manager.h"
+#include "components/signin/core/browser/signin_tracker.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_request_headers.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_status_code.h"
+#include "net/url_request/url_fetcher.h"
+
+using net::URLFetcher;
+using net::URLRequestContextGetter;
+using net::HttpRequestHeaders;
+using net::URLRequestStatus;
+
+namespace ntp_snippets {
+
+const char kSnippetSuggestionsFilename[] = "ntp_snippets.json";
+const char kApiScope[] = "https://www.googleapis.com/auth/webhistory";
+const char kContentSnippetsServer[] =
+    "https://chromereader-pa.googleapis.com/v1/fetch";
+const char kAuthorizationRequestHeaderFormat[] = "Bearer %s";
+
+const char kUnpersonalizedRequestParameters[] =
+    "{ \"response_detail_level\": \"FULL_DEBUG\", \"advanced_options\": { "
+    "\"local_scoring_params\": {\"content_params\" : { "
+    "\"only_return_personalized_results\": false } }, "
+    "\"global_scoring_params\": { \"num_to_return\": 10 } } }";
+
+base::FilePath GetSnippetsSuggestionsPath(const base::FilePath& base_dir) {
+  return base_dir.AppendASCII(kSnippetSuggestionsFilename);
+}
+
+NTPSnippetsFetcher::NTPSnippetsFetcher(
+    scoped_refptr<base::SequencedTaskRunner> file_task_runner,
+    SigninManagerBase* signin_manager,
+    OAuth2TokenService* token_service,
+    scoped_refptr<URLRequestContextGetter> url_request_context_getter,
+    const base::FilePath& base_download_path)
+    : OAuth2TokenService::Consumer("NTP_snippets"),
+      file_task_runner_(file_task_runner),
+      url_request_context_getter_(url_request_context_getter),
+      signin_manager_(signin_manager),
+      token_service_(token_service),
+      download_path_(GetSnippetsSuggestionsPath(base_download_path)),
+      waiting_for_refresh_token_(false),
+      weak_ptr_factory_(this) {}
+
+NTPSnippetsFetcher::~NTPSnippetsFetcher() {
+  if (waiting_for_refresh_token_)
+    token_service_->RemoveObserver(this);
+}
+
+scoped_ptr<NTPSnippetsFetcher::SnippetsAvailableCallbackList::Subscription>
+NTPSnippetsFetcher::AddCallback(const SnippetsAvailableCallback& callback) {
+  return callback_list_.Add(callback);
+}
+
+void NTPSnippetsFetcher::FetchSnippets(bool overwrite) {
+  if (overwrite) {
+    StartFetch();
+  } else {
+    base::PostTaskAndReplyWithResult(
+        file_task_runner_.get(), FROM_HERE,
+        base::Bind(&base::PathExists, download_path_),
+        base::Bind(&NTPSnippetsFetcher::OnFileExistsCheckDone,
+                   weak_ptr_factory_.GetWeakPtr()));
+  }
+}
+
+void NTPSnippetsFetcher::OnFileExistsCheckDone(bool exists) {
+  if (exists) {
+    NotifyObservers();
+  } else {
+    StartFetch();
+  }
+}
+
+void NTPSnippetsFetcher::StartFetch() {
+  if (signin_manager_->IsAuthenticated()) {
+    StartTokenRequest();
+  } else {
+    if (!waiting_for_refresh_token_) {
+      // Wait until we get a refresh token.
+      waiting_for_refresh_token_ = true;
+      token_service_->AddObserver(this);
+    }
+  }
+}
+
+void NTPSnippetsFetcher::StartTokenRequest() {
+  OAuth2TokenService::ScopeSet scopes;
+  scopes.insert(kApiScope);
+  oauth_request_ = token_service_->StartRequest(
+      signin_manager_->GetAuthenticatedAccountId(), scopes, this);
+}
+
+void NTPSnippetsFetcher::NotifyObservers() {
+  callback_list_.Notify(download_path_);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// OAuth2TokenService::Consumer overrides
+void NTPSnippetsFetcher::OnGetTokenSuccess(
+    const OAuth2TokenService::Request* request,
+    const std::string& access_token,
+    const base::Time& expiration_time) {
+  oauth_request_.reset();
+  url_fetcher_ =
+      URLFetcher::Create(GURL(kContentSnippetsServer), URLFetcher::POST, this);
+  url_fetcher_->SetRequestContext(url_request_context_getter_.get());
+  url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
+                             net::LOAD_DO_NOT_SAVE_COOKIES);
+  HttpRequestHeaders headers;
+  headers.SetHeader("Authorization",
+                    base::StringPrintf(kAuthorizationRequestHeaderFormat,
+                                       access_token.c_str()));
+  headers.SetHeader("Content-Type", "application/json; charset=UTF-8");
+  url_fetcher_->SetExtraRequestHeaders(headers.ToString());
+  url_fetcher_->SetUploadData("application/json",
+                              kUnpersonalizedRequestParameters);
+  url_fetcher_->SaveResponseToTemporaryFile(file_task_runner_.get());
+  url_fetcher_->Start();
+}
+
+void NTPSnippetsFetcher::OnGetTokenFailure(
+    const OAuth2TokenService::Request* request,
+    const GoogleServiceAuthError& error) {
+  oauth_request_.reset();
+  DLOG(ERROR) << "Unable to get token: " << error.ToString();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// OAuth2TokenService::Observer overrides
+void NTPSnippetsFetcher::OnRefreshTokenAvailable(
+    const std::string& account_id) {
+  token_service_->RemoveObserver(this);
+  waiting_for_refresh_token_ = false;
+  StartTokenRequest();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// URLFetcherDelegate overrides
+void NTPSnippetsFetcher::OnURLFetchComplete(const URLFetcher* source) {
+  DCHECK_EQ(url_fetcher_.get(), source);
+
+  const URLRequestStatus& status = source->GetStatus();
+  if (!status.is_success()) {
+    DLOG(WARNING) << "URLRequestStatus error " << status.error()
+                  << " while trying to download " << source->GetURL().spec();
+    return;
+  }
+
+  int response_code = source->GetResponseCode();
+  if (response_code != net::HTTP_OK) {
+    DLOG(WARNING) << "HTTP error " << response_code
+                  << " while trying to download " << source->GetURL().spec();
+    return;
+  }
+
+  base::FilePath response_path;
+  source->GetResponseAsFilePath(false, &response_path);
+
+  base::PostTaskAndReplyWithResult(
+      file_task_runner_.get(), FROM_HERE,
+      base::Bind(&base::Move, response_path, download_path_),
+      base::Bind(&NTPSnippetsFetcher::OnFileMoveDone,
+                 weak_ptr_factory_.GetWeakPtr()));
+}
+
+void NTPSnippetsFetcher::OnFileMoveDone(bool success) {
+  if (!success) {
+    DLOG(WARNING) << "Could not move file to "
+                  << download_path_.LossyDisplayName();
+    return;
+  }
+
+  NotifyObservers();
+}
+
+}  // namespace ntp_snippets
diff --git a/components/ntp_snippets/ntp_snippets_fetcher.h b/components/ntp_snippets/ntp_snippets_fetcher.h
new file mode 100644
index 0000000..2ae47ad
--- /dev/null
+++ b/components/ntp_snippets/ntp_snippets_fetcher.h
@@ -0,0 +1,94 @@
+// Copyright 2016 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 COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_FETCHER_H_
+#define COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_FETCHER_H_
+
+#include "base/callback.h"
+#include "base/callback_list.h"
+#include "base/files/file_path.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/sequenced_task_runner.h"
+#include "google_apis/gaia/oauth2_token_service.h"
+#include "net/url_request/url_request_context_getter.h"
+
+namespace net {
+class URLFetcher;
+class URLFetcherDelegate;
+}  // namespace net
+
+class SigninManagerBase;
+
+namespace ntp_snippets {
+
+// Fetches snippet data for the NTP from the server
+class NTPSnippetsFetcher : public OAuth2TokenService::Consumer,
+                           public OAuth2TokenService::Observer,
+                           public net::URLFetcherDelegate {
+ public:
+  using SnippetsAvailableCallback = base::Callback<void(const base::FilePath&)>;
+  using SnippetsAvailableCallbackList =
+      base::CallbackList<void(const base::FilePath&)>;
+
+  NTPSnippetsFetcher(scoped_refptr<base::SequencedTaskRunner> file_task_runner,
+                     SigninManagerBase* signin_manager,
+                     OAuth2TokenService* oauth2_token_service,
+                     scoped_refptr<net::URLRequestContextGetter>
+                        url_request_context_getter,
+                     const base::FilePath& base_download_path);
+  ~NTPSnippetsFetcher() override;
+
+  // Fetches snippets from the server. |overwrite| is true if existing snippets
+  // should be overwritten.
+  void FetchSnippets(bool overwrite);
+
+  // Adds a callback that is called when a new set of snippets are downloaded
+  scoped_ptr<SnippetsAvailableCallbackList::Subscription> AddCallback(
+      const SnippetsAvailableCallback& callback) WARN_UNUSED_RESULT;
+
+ private:
+  void StartTokenRequest();
+  void NotifyObservers();
+  void OnDownloadSnippetsDone(bool success);
+  void OnFileExistsCheckDone(bool exists);
+  void OnFileMoveDone(bool success);
+  void StartFetch();
+
+  // OAuth2TokenService::Consumer overrides:
+  void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
+                         const std::string& access_token,
+                         const base::Time& expiration_time) override;
+  void OnGetTokenFailure(const OAuth2TokenService::Request* request,
+                         const GoogleServiceAuthError& error) override;
+
+  // OAuth2TokenService::Observer overrides:
+  void OnRefreshTokenAvailable(const std::string& account_id) override;
+
+  // URLFetcherDelegate implementation.
+  void OnURLFetchComplete(const net::URLFetcher* source) override;
+
+  // The SequencedTaskRunner on which file system operations will be run.
+  scoped_refptr<base::SequencedTaskRunner> file_task_runner_;
+
+  // Holds the URL request context.
+  scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
+
+  scoped_ptr<net::URLFetcher> url_fetcher_;
+  scoped_ptr<SigninManagerBase> signin_manager_;
+  scoped_ptr<OAuth2TokenService> token_service_;
+  scoped_ptr<OAuth2TokenService::Request> oauth_request_;
+
+  base::FilePath download_path_;
+  bool waiting_for_refresh_token_;
+
+  SnippetsAvailableCallbackList callback_list_;
+
+  base::WeakPtrFactory<NTPSnippetsFetcher> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(NTPSnippetsFetcher);
+};
+}  // namespace ntp_snippets
+
+#endif  // COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_FETCHER_H_
diff --git a/components/ntp_snippets/ntp_snippets_service.cc b/components/ntp_snippets/ntp_snippets_service.cc
index f3c0670f..149ab4a 100644
--- a/components/ntp_snippets/ntp_snippets_service.cc
+++ b/components/ntp_snippets/ntp_snippets_service.cc
@@ -4,14 +4,36 @@
 
 #include "components/ntp_snippets/ntp_snippets_service.h"
 
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
 #include "base/json/json_string_value_serializer.h"
+#include "base/location.h"
+#include "base/path_service.h"
+#include "base/task_runner_util.h"
 #include "base/values.h"
 
 namespace ntp_snippets {
 
+bool ReadFileToString(const base::FilePath& path, std::string* data) {
+  DCHECK(data);
+  bool success = base::ReadFileToString(path, data);
+  DLOG_IF(ERROR, !success) << "Error reading file " << path.LossyDisplayName();
+  return success;
+}
+
 NTPSnippetsService::NTPSnippetsService(
-    const std::string& application_language_code)
-    : loaded_(false), application_language_code_(application_language_code) {}
+    scoped_refptr<base::SequencedTaskRunner> file_task_runner,
+    const std::string& application_language_code,
+    scoped_ptr<NTPSnippetsFetcher> snippets_fetcher)
+    : loaded_(false),
+      file_task_runner_(file_task_runner),
+      application_language_code_(application_language_code),
+      snippets_fetcher_(std::move(snippets_fetcher)),
+      weak_ptr_factory_(this) {
+  snippets_fetcher_callback_ = snippets_fetcher_->AddCallback(
+      base::Bind(&NTPSnippetsService::OnSnippetsDownloaded,
+                 weak_ptr_factory_.GetWeakPtr()));
+}
 
 NTPSnippetsService::~NTPSnippetsService() {}
 
@@ -21,6 +43,10 @@
   loaded_ = false;
 }
 
+void NTPSnippetsService::FetchSnippets(bool overwrite) {
+  snippets_fetcher_->FetchSnippets(overwrite);
+}
+
 void NTPSnippetsService::AddObserver(NTPSnippetsServiceObserver* observer) {
   observers_.AddObserver(observer);
   if (loaded_)
@@ -31,6 +57,14 @@
   observers_.RemoveObserver(observer);
 }
 
+void NTPSnippetsService::OnFileReadDone(const std::string* json, bool success) {
+  if (!success)
+    return;
+
+  DCHECK(json);
+  LoadFromJSONString(*json);
+}
+
 bool NTPSnippetsService::LoadFromJSONString(const std::string& str) {
   JSONStringValueDeserializer deserializer(str);
   int error_code;
@@ -57,16 +91,27 @@
     const base::DictionaryValue* content = NULL;
     if (!dict->GetDictionary("contentInfo", &content))
       return false;
-    std::unique_ptr<NTPSnippet> snippet =
+    scoped_ptr<NTPSnippet> snippet =
         NTPSnippet::NTPSnippetFromDictionary(*content);
     if (!snippet)
       return false;
     snippets_.push_back(std::move(snippet));
   }
   loaded_ = true;
+
   FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
                     NTPSnippetsServiceLoaded(this));
   return true;
 }
 
+void NTPSnippetsService::OnSnippetsDownloaded(
+    const base::FilePath& download_path) {
+  std::string* downloaded_data = new std::string;
+  base::PostTaskAndReplyWithResult(
+      file_task_runner_.get(), FROM_HERE,
+      base::Bind(&ReadFileToString, download_path, downloaded_data),
+      base::Bind(&NTPSnippetsService::OnFileReadDone,
+                 weak_ptr_factory_.GetWeakPtr(), base::Owned(downloaded_data)));
+}
+
 }  // namespace ntp_snippets
diff --git a/components/ntp_snippets/ntp_snippets_service.h b/components/ntp_snippets/ntp_snippets_service.h
index 76cb3d3..f9d2a40a 100644
--- a/components/ntp_snippets/ntp_snippets_service.h
+++ b/components/ntp_snippets/ntp_snippets_service.h
@@ -11,19 +11,22 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
+#include "base/sequenced_task_runner.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/ntp_snippets/inner_iterator.h"
 #include "components/ntp_snippets/ntp_snippet.h"
+#include "components/ntp_snippets/ntp_snippets_fetcher.h"
 
 namespace ntp_snippets {
 
 class NTPSnippetsServiceObserver;
 
 // Stores and vend fresh content data for the NTP.
-class NTPSnippetsService : public KeyedService {
+class NTPSnippetsService : public KeyedService, NTPSnippetsFetcher::Observer {
  public:
-  using NTPSnippetStorage = std::vector<std::unique_ptr<NTPSnippet>>;
+  using NTPSnippetStorage = std::vector<scoped_ptr<NTPSnippet>>;
   using const_iterator =
       InnerIterator<NTPSnippetStorage::const_iterator, const NTPSnippet>;
 
@@ -31,9 +34,15 @@
   // 'en' or 'en-US'. Note that this code should only specify the language, not
   // the locale, so 'en_US' (english language with US locale) and 'en-GB_US'
   // (British english person in the US) are not language code.
-  explicit NTPSnippetsService(const std::string& application_language_code);
+  NTPSnippetsService(scoped_refptr<base::SequencedTaskRunner> file_task_runner,
+                     const std::string& application_language_code,
+                     scoped_ptr<NTPSnippetsFetcher> snippets_fetcher);
   ~NTPSnippetsService() override;
 
+  // Fetches snippets from the server. |overwrite| is true if existing snippets
+  // should be overwritten.
+  void FetchSnippets(bool overwrite);
+
   // Inherited from KeyedService.
   void Shutdown() override;
 
@@ -44,11 +53,6 @@
   void AddObserver(NTPSnippetsServiceObserver* observer);
   void RemoveObserver(NTPSnippetsServiceObserver* observer);
 
-  // Expects the JSON to be a list of dictionaries with keys matching the
-  // properties of a snippet (url, title, site_title, etc...). The url is the
-  // only mandatory value.
-  bool LoadFromJSONString(const std::string& str);
-
   // Number of snippets available. Can only be called when is_loaded() is true.
   NTPSnippetStorage::size_type size() {
     DCHECK(loaded_);
@@ -72,15 +76,44 @@
   }
 
  private:
+  void OnFileReadDone(const std::string* json, bool success);
+  void OnSnippetsDownloaded(const base::FilePath& download_path);
+
+  // Expects the JSON to be a list of dictionaries with keys matching the
+  // properties of a snippet (url, title, site_title, etc...). The url is the
+  // only mandatory value.
+  bool LoadFromJSONString(const std::string& str);
+
   // True if the suggestions are loaded.
   bool loaded_;
+
+  // The SequencedTaskRunner on which file system operations will be run.
+  scoped_refptr<base::SequencedTaskRunner> file_task_runner_;
+
   // All the suggestions.
   NTPSnippetStorage snippets_;
+
   // The ISO 639-1 code of the language used by the application.
   const std::string application_language_code_;
+
   // The observers.
   base::ObserverList<NTPSnippetsServiceObserver> observers_;
 
+  // The snippets fetcher
+  scoped_ptr<NTPSnippetsFetcher> snippets_fetcher_;
+
+  // The callback from the snippets fetcher
+  scoped_ptr<NTPSnippetsFetcher::SnippetsAvailableCallbackList::Subscription>
+      snippets_fetcher_callback_;
+
+  base::WeakPtrFactory<NTPSnippetsService> weak_ptr_factory_;
+
+  friend class NTPSnippetsServiceTest;
+  FRIEND_TEST_ALL_PREFIXES(NTPSnippetsServiceTest, Loop);
+  FRIEND_TEST_ALL_PREFIXES(NTPSnippetsServiceTest, Full);
+  FRIEND_TEST_ALL_PREFIXES(NTPSnippetsServiceTest, ObserverLoaded);
+  FRIEND_TEST_ALL_PREFIXES(NTPSnippetsServiceTest, ObserverNotLoaded);
+
   DISALLOW_COPY_AND_ASSIGN(NTPSnippetsService);
 };
 
diff --git a/components/ntp_snippets/ntp_snippets_service_unittest.cc b/components/ntp_snippets/ntp_snippets_service_unittest.cc
index df1cf7b..f801e94 100644
--- a/components/ntp_snippets/ntp_snippets_service_unittest.cc
+++ b/components/ntp_snippets/ntp_snippets_service_unittest.cc
@@ -3,25 +3,31 @@
 // found in the LICENSE file.
 
 #include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "components/ntp_snippets/ntp_snippet.h"
+#include "components/ntp_snippets/ntp_snippets_fetcher.h"
 #include "components/ntp_snippets/ntp_snippets_service.h"
+#include "components/signin/core/browser/account_tracker_service.h"
+#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
+#include "components/signin/core/browser/fake_signin_manager.h"
+#include "components/signin/core/browser/test_signin_client.h"
+#include "net/url_request/url_request_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace {
+namespace ntp_snippets {
 
-class SnippetObserver : public ntp_snippets::NTPSnippetsServiceObserver {
+class SnippetObserver : public NTPSnippetsServiceObserver {
  public:
   SnippetObserver() : loaded_(false), shutdown_(false) {}
   ~SnippetObserver() override {}
 
-  void NTPSnippetsServiceLoaded(
-      ntp_snippets::NTPSnippetsService* service) override {
+  void NTPSnippetsServiceLoaded(NTPSnippetsService* service) override {
     loaded_ = true;
   }
 
-  void NTPSnippetsServiceShutdown(
-      ntp_snippets::NTPSnippetsService* service) override {
+  void NTPSnippetsServiceShutdown(NTPSnippetsService* service) override {
     shutdown_ = true;
     loaded_ = false;
   }
@@ -38,22 +44,45 @@
   NTPSnippetsServiceTest() {}
   ~NTPSnippetsServiceTest() override {}
 
+  void SetUp() override {
+    signin_client_.reset(new TestSigninClient(nullptr));
+    account_tracker_.reset(new AccountTrackerService());
+  }
+
+ protected:
+  scoped_ptr<NTPSnippetsService> CreateSnippetService() {
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner(
+        base::ThreadTaskRunnerHandle::Get());
+    scoped_refptr<net::TestURLRequestContextGetter> request_context_getter =
+        new net::TestURLRequestContextGetter(task_runner.get());
+    FakeProfileOAuth2TokenService* token_service =
+        new FakeProfileOAuth2TokenService();
+    FakeSigninManagerBase* signin_manager =  new FakeSigninManagerBase(
+        signin_client_.get(), account_tracker_.get());
+
+    scoped_ptr<NTPSnippetsService> service(
+        new NTPSnippetsService(task_runner.get(), std::string("fr"),
+          make_scoped_ptr(new NTPSnippetsFetcher(task_runner.get(),
+            signin_manager, token_service, request_context_getter,
+            base::FilePath()))));
+    return service;
+  }
+
  private:
+  scoped_ptr<AccountTrackerService> account_tracker_;
+  scoped_ptr<TestSigninClient> signin_client_;
+  base::MessageLoop message_loop_;
   DISALLOW_COPY_AND_ASSIGN(NTPSnippetsServiceTest);
 };
 
-TEST_F(NTPSnippetsServiceTest, Create) {
-  std::string language_code("fr");
-  scoped_ptr<ntp_snippets::NTPSnippetsService> service(
-      new ntp_snippets::NTPSnippetsService(language_code));
 
+TEST_F(NTPSnippetsServiceTest, Create) {
+  scoped_ptr<NTPSnippetsService> service(CreateSnippetService());
   EXPECT_FALSE(service->is_loaded());
 }
 
 TEST_F(NTPSnippetsServiceTest, Loop) {
-  std::string language_code("fr");
-  scoped_ptr<ntp_snippets::NTPSnippetsService> service(
-      new ntp_snippets::NTPSnippetsService(language_code));
+  scoped_ptr<NTPSnippetsService> service(CreateSnippetService());
 
   EXPECT_FALSE(service->is_loaded());
 
@@ -71,15 +100,13 @@
     EXPECT_EQ(snippet.url(), GURL("http://localhost/foobar"));
   }
   // Without the const, this should not compile.
-  for (const ntp_snippets::NTPSnippet& snippet : *service) {
+  for (const NTPSnippet& snippet : *service) {
     EXPECT_EQ(snippet.url(), GURL("http://localhost/foobar"));
   }
 }
 
 TEST_F(NTPSnippetsServiceTest, Full) {
-  std::string language_code("fr");
-  scoped_ptr<ntp_snippets::NTPSnippetsService> service(
-      new ntp_snippets::NTPSnippetsService(language_code));
+  scoped_ptr<NTPSnippetsService> service(CreateSnippetService());
 
   std::string json_str(
       "{ \"recos\": [ "
@@ -112,9 +139,7 @@
 }
 
 TEST_F(NTPSnippetsServiceTest, ObserverNotLoaded) {
-  std::string language_code("fr");
-  scoped_ptr<ntp_snippets::NTPSnippetsService> service(
-      new ntp_snippets::NTPSnippetsService(language_code));
+  scoped_ptr<NTPSnippetsService> service(CreateSnippetService());
 
   SnippetObserver observer;
   service->AddObserver(&observer);
@@ -131,9 +156,7 @@
 }
 
 TEST_F(NTPSnippetsServiceTest, ObserverLoaded) {
-  std::string language_code("fr");
-  scoped_ptr<ntp_snippets::NTPSnippetsService> service(
-      new ntp_snippets::NTPSnippetsService(language_code));
+  scoped_ptr<NTPSnippetsService> service(CreateSnippetService());
 
   std::string json_str(
       "{ \"recos\": [ "
@@ -148,4 +171,4 @@
 
   service->RemoveObserver(&observer);
 }
-}  // namespace
+}  // namespace ntp_snippets
diff --git a/components/omnibox/browser/autocomplete_provider.cc b/components/omnibox/browser/autocomplete_provider.cc
index a592ea3..b5963c7 100644
--- a/components/omnibox/browser/autocomplete_provider.cc
+++ b/components/omnibox/browser/autocomplete_provider.cc
@@ -9,7 +9,6 @@
 #include "components/omnibox/browser/autocomplete_input.h"
 #include "components/omnibox/browser/autocomplete_match.h"
 #include "components/url_formatter/url_fixer.h"
-#include "net/base/net_util.h"
 #include "url/gurl.h"
 
 // static
diff --git a/components/omnibox/browser/history_quick_provider.cc b/components/omnibox/browser/history_quick_provider.cc
index 438efb93..ef223266 100644
--- a/components/omnibox/browser/history_quick_provider.cc
+++ b/components/omnibox/browser/history_quick_provider.cc
@@ -27,8 +27,6 @@
 #include "components/omnibox/browser/omnibox_field_trial.h"
 #include "components/omnibox/browser/url_prefix.h"
 #include "components/prefs/pref_service.h"
-#include "components/search_engines/template_url.h"
-#include "components/search_engines/template_url_service.h"
 #include "components/url_formatter/url_formatter.h"
 #include "net/base/escape.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
@@ -171,10 +169,6 @@
   // they're visited.)  The strength of this reduction depends on the
   // likely score for the URL-what-you-typed result.
 
-  // |template_url_service| or |template_url| can be NULL in unit tests.
-  TemplateURLService* template_url_service = client()->GetTemplateURLService();
-  TemplateURL* template_url = template_url_service ?
-      template_url_service->GetDefaultSearchProvider() : NULL;
   int max_match_score = matches.begin()->raw_score;
   if (will_have_url_what_you_typed_match_first) {
     max_match_score = std::min(max_match_score,
@@ -183,18 +177,11 @@
   for (ScoredHistoryMatches::const_iterator match_iter = matches.begin();
        match_iter != matches.end(); ++match_iter) {
     const ScoredHistoryMatch& history_match(*match_iter);
-    // Culls results corresponding to queries from the default search engine.
-    // These are low-quality, difficult-to-understand matches for users, and the
-    // SearchProvider should surface past queries in a better way anyway.
-    if (!template_url ||
-        !template_url->IsSearchURL(history_match.url_info.url(),
-                                   template_url_service->search_terms_data())) {
-      // Set max_match_score to the score we'll assign this result:
-      max_match_score = std::min(max_match_score, history_match.raw_score);
-      matches_.push_back(QuickMatchToACMatch(history_match, max_match_score));
-      // Mark this max_match_score as being used:
-      max_match_score--;
-    }
+    // Set max_match_score to the score we'll assign this result.
+    max_match_score = std::min(max_match_score, history_match.raw_score);
+    matches_.push_back(QuickMatchToACMatch(history_match, max_match_score));
+    // Mark this max_match_score as being used.
+    max_match_score--;
   }
 }
 
diff --git a/components/omnibox/browser/history_quick_provider_unittest.cc b/components/omnibox/browser/history_quick_provider_unittest.cc
index 666138c..da6abd4 100644
--- a/components/omnibox/browser/history_quick_provider_unittest.cc
+++ b/components/omnibox/browser/history_quick_provider_unittest.cc
@@ -40,8 +40,6 @@
 #include "components/omnibox/browser/url_index_private_data.h"
 #include "components/prefs/pref_service.h"
 #include "components/search_engines/search_terms_data.h"
-#include "components/search_engines/template_url.h"
-#include "components/search_engines/template_url_service.h"
 #include "sql/transaction.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -182,16 +180,15 @@
  public:
   FakeAutocompleteProviderClient() : pool_owner_(3, "Background Pool") {
     bookmark_model_ = bookmarks::TestBookmarkClient::CreateModel();
-    set_template_url_service(
-        make_scoped_ptr(new TemplateURLService(nullptr, 0)));
     if (history_dir_.CreateUniqueTempDir()) {
       history_service_ = history::CreateHistoryService(
           history_dir_.path(), GetAcceptLanguages(), true);
     }
 
     in_memory_url_index_.reset(new InMemoryURLIndex(
-        bookmark_model_.get(), history_service_.get(), pool_owner_.pool().get(),
-        history_dir_.path(), GetAcceptLanguages(), SchemeSet()));
+        bookmark_model_.get(), history_service_.get(), nullptr,
+        pool_owner_.pool().get(), history_dir_.path(), GetAcceptLanguages(),
+        SchemeSet()));
     in_memory_url_index_->Init();
   }
 
@@ -823,31 +820,6 @@
           ASCIIToUTF16("popularsitewithroot.com"), base::string16());
 }
 
-TEST_F(HistoryQuickProviderTest, CullSearchResults) {
-  // Set up a default search engine.
-  TemplateURLData data;
-  data.SetShortName(ASCIIToUTF16("TestEngine"));
-  data.SetKeyword(ASCIIToUTF16("TestEngine"));
-  data.SetURL("http://testsearch.com/?q={searchTerms}");
-  TemplateURLService* template_url_service = client_->GetTemplateURLService();
-  TemplateURL* template_url = new TemplateURL(data);
-  template_url_service->Add(template_url);
-  template_url_service->SetUserSelectedDefaultSearchProvider(template_url);
-  template_url_service->Load();
-
-  // A search results page should not be returned when typing a query.
-  std::vector<std::string> expected_urls;
-  RunTest(ASCIIToUTF16("thequery"), false, expected_urls, false,
-          ASCIIToUTF16("anotherengine.com/?q=thequery"), base::string16());
-
-  // A search results page should not be returned when typing the engine URL.
-  expected_urls.clear();
-  expected_urls.push_back("http://testsearch.com/");
-  RunTest(ASCIIToUTF16("testsearch"), false, expected_urls, true,
-          ASCIIToUTF16("testsearch.com"),
-                    ASCIIToUTF16(".com"));
-}
-
 TEST_F(HistoryQuickProviderTest, DoesNotProvideMatchesOnFocus) {
   AutocompleteInput input(ASCIIToUTF16("popularsite"), base::string16::npos,
                           std::string(), GURL(),
diff --git a/components/omnibox/browser/in_memory_url_index.cc b/components/omnibox/browser/in_memory_url_index.cc
index 9920013..c027301 100644
--- a/components/omnibox/browser/in_memory_url_index.cc
+++ b/components/omnibox/browser/in_memory_url_index.cc
@@ -78,12 +78,14 @@
 InMemoryURLIndex::InMemoryURLIndex(
     bookmarks::BookmarkModel* bookmark_model,
     history::HistoryService* history_service,
+    TemplateURLService* template_url_service,
     base::SequencedWorkerPool* worker_pool,
     const base::FilePath& history_dir,
     const std::string& languages,
     const SchemeSet& client_schemes_to_whitelist)
     : bookmark_model_(bookmark_model),
       history_service_(history_service),
+      template_url_service_(template_url_service),
       history_dir_(history_dir),
       languages_(languages),
       private_data_(new URLIndexPrivateData),
@@ -131,7 +133,8 @@
     size_t cursor_position,
     size_t max_matches) {
   return private_data_->HistoryItemsForTerms(
-      term_string, cursor_position, max_matches, languages_, bookmark_model_);
+      term_string, cursor_position, max_matches, languages_, bookmark_model_,
+      template_url_service_);
 }
 
 // Updating --------------------------------------------------------------------
diff --git a/components/omnibox/browser/in_memory_url_index.h b/components/omnibox/browser/in_memory_url_index.h
index da8639c..1f098cbfe 100644
--- a/components/omnibox/browser/in_memory_url_index.h
+++ b/components/omnibox/browser/in_memory_url_index.h
@@ -27,6 +27,7 @@
 #include "components/history/core/browser/history_types.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/omnibox/browser/scored_history_match.h"
+#include "components/search_engines/template_url_service.h"
 
 class HistoryQuickProviderTest;
 
@@ -107,6 +108,7 @@
   // characters.
   InMemoryURLIndex(bookmarks::BookmarkModel* bookmark_model,
                    history::HistoryService* history_service,
+                   TemplateURLService* template_url_service,
                    base::SequencedWorkerPool* worker_pool,
                    const base::FilePath& history_dir,
                    const std::string& languages,
@@ -278,6 +280,10 @@
   // The HistoryService; may be null when testing.
   history::HistoryService* history_service_;
 
+  // The TemplateURLService; may be null when testing.  Used to identify URLs
+  // that are from the default search provider.
+  TemplateURLService* template_url_service_;
+
   // Directory where cache file resides. This is, except when unit testing,
   // the same directory in which the history database is found. It should never
   // be empty.
diff --git a/components/omnibox/browser/in_memory_url_index_types.cc b/components/omnibox/browser/in_memory_url_index_types.cc
index 6215e41e..710513c 100644
--- a/components/omnibox/browser/in_memory_url_index_types.cc
+++ b/components/omnibox/browser/in_memory_url_index_types.cc
@@ -14,7 +14,6 @@
 #include "base/i18n/case_conversion.h"
 #include "base/strings/string_util.h"
 #include "net/base/escape.h"
-#include "net/base/net_util.h"
 
 namespace {
 // The maximum number of characters to consider from an URL and page title
diff --git a/components/omnibox/browser/in_memory_url_index_unittest.cc b/components/omnibox/browser/in_memory_url_index_unittest.cc
index dd868d1..5c566a80 100644
--- a/components/omnibox/browser/in_memory_url_index_unittest.cc
+++ b/components/omnibox/browser/in_memory_url_index_unittest.cc
@@ -329,7 +329,7 @@
   SchemeSet client_schemes_to_whitelist;
   client_schemes_to_whitelist.insert(kClientWhitelistedScheme);
   url_index_.reset(new InMemoryURLIndex(
-      nullptr, history_service_.get(), pool_owner_.pool().get(),
+      nullptr, history_service_.get(), nullptr, pool_owner_.pool().get(),
       base::FilePath(), kTestLanguages, client_schemes_to_whitelist));
   url_index_->Init();
   url_index_->RebuildFromHistory(history_database_);
@@ -1243,7 +1243,8 @@
     String16Vector lower_terms;
     StringToTerms(test_cases[i].search_string, test_cases[i].cursor_position,
                   &lower_string, &lower_terms);
-    URLIndexPrivateData::AddHistoryMatch match(nullptr, *GetPrivateData(),
+    URLIndexPrivateData::AddHistoryMatch match(nullptr, nullptr,
+                                               *GetPrivateData(),
                                                kTestLanguages, lower_string,
                                                lower_terms, base::Time::Now());
 
@@ -1282,7 +1283,7 @@
 void InMemoryURLIndexCacheTest::SetUp() {
   ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
   base::FilePath path(temp_dir_.path());
-  url_index_.reset(new InMemoryURLIndex(nullptr, nullptr,
+  url_index_.reset(new InMemoryURLIndex(nullptr, nullptr, nullptr,
                                         pool_owner_.pool().get(), path,
                                         kTestLanguages, SchemeSet()));
 }
diff --git a/components/omnibox/browser/keyword_provider.cc b/components/omnibox/browser/keyword_provider.cc
index a0b5cc8..e4e21b3d 100644
--- a/components/omnibox/browser/keyword_provider.cc
+++ b/components/omnibox/browser/keyword_provider.cc
@@ -22,7 +22,6 @@
 #include "components/search_engines/template_url_service.h"
 #include "grit/components_strings.h"
 #include "net/base/escape.h"
-#include "net/base/net_util.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace {
diff --git a/components/omnibox/browser/omnibox_view.cc b/components/omnibox/browser/omnibox_view.cc
index 6101def..50accb2 100644
--- a/components/omnibox/browser/omnibox_view.cc
+++ b/components/omnibox/browser/omnibox_view.cc
@@ -66,9 +66,11 @@
   // Invalid URLs such as chrome://history can end up here.
   if (!match.destination_url.is_valid() || !model_)
     return;
+  const AutocompleteMatch::Type match_type = match.type;
   model_->OpenMatch(
       match, disposition, alternate_nav_url, pasted_text, selected_line);
-  OnMatchOpened(match);
+  // WARNING: |match| may refer to a deleted object at this point!
+  OnMatchOpened(match_type);
 }
 
 bool OmniboxView::IsEditingOrEmpty() const {
@@ -170,7 +172,7 @@
   return false;
 }
 
-void OmniboxView::OnMatchOpened(const AutocompleteMatch& match) {
+void OmniboxView::OnMatchOpened(AutocompleteMatch::Type match_type) {
 }
 
 OmniboxView::OmniboxView(OmniboxEditController* controller,
diff --git a/components/omnibox/browser/omnibox_view.h b/components/omnibox/browser/omnibox_view.h
index 2524bf9e..f092f52 100644
--- a/components/omnibox/browser/omnibox_view.h
+++ b/components/omnibox/browser/omnibox_view.h
@@ -226,8 +226,8 @@
   // only ever return true on mobile ports.
   virtual bool IsIndicatingQueryRefinement() const;
 
-  // Called after a |match| has been opened.
-  virtual void OnMatchOpened(const AutocompleteMatch& match);
+  // Called after a match has been opened.
+  virtual void OnMatchOpened(AutocompleteMatch::Type match_type);
 
   // Returns |text| with any leading javascript schemas stripped.
   static base::string16 StripJavascriptSchemas(const base::string16& text);
diff --git a/components/omnibox/browser/scored_history_match.cc b/components/omnibox/browser/scored_history_match.cc
index 05c88dc..cca9028 100644
--- a/components/omnibox/browser/scored_history_match.cc
+++ b/components/omnibox/browser/scored_history_match.cc
@@ -20,6 +20,7 @@
 #include "components/omnibox/browser/history_url_provider.h"
 #include "components/omnibox/browser/omnibox_field_trial.h"
 #include "components/omnibox/browser/url_prefix.h"
+#include "components/search_engines/template_url_service.h"
 
 namespace {
 
@@ -130,6 +131,7 @@
                          WordStarts(),
                          RowWordStarts(),
                          false,
+                         nullptr,
                          base::Time::Max()) {
 }
 
@@ -142,6 +144,7 @@
     const WordStarts& terms_to_word_starts_offsets,
     const RowWordStarts& word_starts,
     bool is_url_bookmarked,
+    TemplateURLService* template_url_service,
     base::Time now)
     : HistoryMatch(row, 0, false, false), raw_score(0) {
   // NOTE: Call Init() before doing any validity checking to ensure that the
@@ -154,6 +157,16 @@
   if (!gurl.is_valid())
     return;
 
+  // Skip results corresponding to queries from the default search engine.
+  // These are low-quality, difficult-to-understand matches for users.
+  // SearchProvider should surface past queries in a better way.
+  TemplateURL* template_url = template_url_service ?
+      template_url_service->GetDefaultSearchProvider() : nullptr;
+  if (template_url &&
+      template_url->IsSearchURL(gurl,
+                                template_url_service->search_terms_data()))
+    return;
+
   // Figure out where each search term appears in the URL and/or page title
   // so that we can score as well as provide autocomplete highlighting.
   base::OffsetAdjuster::Adjustments adjustments;
diff --git a/components/omnibox/browser/scored_history_match.h b/components/omnibox/browser/scored_history_match.h
index dfc5ccbd7..0b2e1a0 100644
--- a/components/omnibox/browser/scored_history_match.h
+++ b/components/omnibox/browser/scored_history_match.h
@@ -18,6 +18,7 @@
 #include "components/omnibox/browser/in_memory_url_index_types.h"
 
 class ScoredHistoryMatchTest;
+class TemplateURLService;
 
 // An HistoryMatch that has a score as well as metrics defining where in the
 // history item's URL and/or page title matches have occurred.
@@ -34,12 +35,14 @@
   // Initializes the ScoredHistoryMatch with a raw score calculated for the
   // history item given in |row| with recent visits as indicated in |visits|. It
   // first determines if the row qualifies by seeing if all of the terms in
-  // |terms_vector| occur in |row|.  If so, calculates a raw score.  This raw
-  // score is in part determined by whether the matches occur at word
-  // boundaries, the locations of which are stored in |word_starts|.  For some
-  // terms, it's appropriate to look for the word boundary within the term. For
-  // instance, the term ".net" should look for a word boundary at the "n". These
-  // offsets (".net" should have an offset of 1) come from
+  // |terms_vector| occur in |row| and checking if the URL does not come from
+  // the default search provider (obtained from |template_url_service|).  If
+  // both those constraints are true, calculates a raw score.  This raw score
+  // is in part determined by whether the matches occur at word boundaries, the
+  // locations of which are stored in |word_starts|.  For some terms, it's
+  // appropriate to look for the word boundary within the term. For instance,
+  // the term ".net" should look for a word boundary at the "n". These offsets
+  // (".net" should have an offset of 1) come from
   // |terms_to_word_starts_offsets|. |is_url_bookmarked| indicates whether the
   // match's URL is referenced by any bookmarks, which can also affect the raw
   // score.  The raw score allows the matches to be ordered and can be used to
@@ -54,6 +57,7 @@
                      const WordStarts& terms_to_word_starts_offsets,
                      const RowWordStarts& word_starts,
                      bool is_url_bookmarked,
+                     TemplateURLService* template_url_service,
                      base::Time now);
 
   ~ScoredHistoryMatch();
diff --git a/components/omnibox/browser/scored_history_match_unittest.cc b/components/omnibox/browser/scored_history_match_unittest.cc
index 9f78bc8f..ecab0a3 100644
--- a/components/omnibox/browser/scored_history_match_unittest.cc
+++ b/components/omnibox/browser/scored_history_match_unittest.cc
@@ -11,6 +11,10 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
+#include "components/search_engines/search_terms_data.h"
+#include "components/search_engines/template_url.h"
+#include "components/search_engines/template_url_service.h"
+#include "components/search_engines/template_url_service_client.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -133,7 +137,8 @@
   visits_a[0].second = ui::PAGE_TRANSITION_TYPED;
   ScoredHistoryMatch scored_a(row_a, visits_a, std::string(),
                               ASCIIToUTF16("abc"), Make1Term("abc"),
-                              one_word_no_offset, word_starts_a, false, now);
+                              one_word_no_offset, word_starts_a, false, nullptr,
+                              now);
 
   // Test scores based on visit_count.
   history::URLRow row_b(MakeURLRow("http://abcdef", "abcd bcd", 10, 30, 1));
@@ -143,7 +148,8 @@
   visits_b[0].second = ui::PAGE_TRANSITION_TYPED;
   ScoredHistoryMatch scored_b(row_b, visits_b, std::string(),
                               ASCIIToUTF16("abc"), Make1Term("abc"),
-                              one_word_no_offset, word_starts_b, false, now);
+                              one_word_no_offset, word_starts_b, false, nullptr,
+                              now);
   EXPECT_GT(scored_b.raw_score, scored_a.raw_score);
 
   // Test scores based on last_visit.
@@ -154,7 +160,8 @@
   visits_c[0].second = ui::PAGE_TRANSITION_TYPED;
   ScoredHistoryMatch scored_c(row_c, visits_c, std::string(),
                               ASCIIToUTF16("abc"), Make1Term("abc"),
-                              one_word_no_offset, word_starts_c, false, now);
+                              one_word_no_offset, word_starts_c, false, nullptr,
+                              now);
   EXPECT_GT(scored_c.raw_score, scored_a.raw_score);
 
   // Test scores based on typed_count.
@@ -167,7 +174,8 @@
   visits_d[2].second = ui::PAGE_TRANSITION_TYPED;
   ScoredHistoryMatch scored_d(row_d, visits_d, std::string(),
                               ASCIIToUTF16("abc"), Make1Term("abc"),
-                              one_word_no_offset, word_starts_d, false, now);
+                              one_word_no_offset, word_starts_d, false, nullptr,
+                              now);
   EXPECT_GT(scored_d.raw_score, scored_a.raw_score);
 
   // Test scores based on a terms appearing multiple times.
@@ -179,14 +187,16 @@
   const VisitInfoVector visits_e = visits_d;
   ScoredHistoryMatch scored_e(row_e, visits_e, std::string(),
                               ASCIIToUTF16("csi"), Make1Term("csi"),
-                              one_word_no_offset, word_starts_e, false, now);
+                              one_word_no_offset, word_starts_e, false, nullptr,
+                              now);
   EXPECT_LT(scored_e.raw_score, 1400);
 
   // Test that a result with only a mid-term match (i.e., not at a word
   // boundary) scores 0.
   ScoredHistoryMatch scored_f(row_a, visits_a, std::string(),
                               ASCIIToUTF16("cd"), Make1Term("cd"),
-                              one_word_no_offset, word_starts_a, false, now);
+                              one_word_no_offset, word_starts_a, false, nullptr,
+                              now);
   EXPECT_EQ(scored_f.raw_score, 0);
 }
 
@@ -204,12 +214,12 @@
   VisitInfoVector visits = CreateVisitInfoVector(8, 3, now);
   ScoredHistoryMatch scored(row, visits, std::string(), ASCIIToUTF16("abc"),
                             Make1Term("abc"), one_word_no_offset, word_starts,
-                            false, now);
+                            false, nullptr, now);
   // Now check that if URL is bookmarked then its score increases.
   base::AutoReset<int> reset(&ScoredHistoryMatch::bookmark_value_, 5);
   ScoredHistoryMatch scored_with_bookmark(
       row, visits, std::string(), ASCIIToUTF16("abc"), Make1Term("abc"),
-      one_word_no_offset, word_starts, true, now);
+      one_word_no_offset, word_starts, true, nullptr, now);
   EXPECT_GT(scored_with_bookmark.raw_score, scored.raw_score);
 }
 
@@ -228,14 +238,15 @@
   VisitInfoVector visits = CreateVisitInfoVector(8, 3, now);
   ScoredHistoryMatch scored(row, visits, std::string(), ASCIIToUTF16("fed com"),
                             Make2Terms("fed", "com"), two_words_no_offsets,
-                            word_starts, false, now);
+                            word_starts, false, nullptr, now);
   EXPECT_EQ(0, scored.raw_score);
 
   // Now allow credit for the match in the TLD.
   base::AutoReset<bool> reset(&ScoredHistoryMatch::allow_tld_matches_, true);
   ScoredHistoryMatch scored_with_tld(
       row, visits, std::string(), ASCIIToUTF16("fed com"),
-      Make2Terms("fed", "com"), two_words_no_offsets, word_starts, false, now);
+      Make2Terms("fed", "com"), two_words_no_offsets, word_starts, false,
+      nullptr, now);
   EXPECT_GT(scored_with_tld.raw_score, 0);
 }
 
@@ -254,17 +265,83 @@
   VisitInfoVector visits = CreateVisitInfoVector(8, 3, now);
   ScoredHistoryMatch scored(row, visits, std::string(),
                             ASCIIToUTF16("fed http"), Make2Terms("fed", "http"),
-                            two_words_no_offsets, word_starts, false, now);
+                            two_words_no_offsets, word_starts, false, nullptr,
+                            now);
   EXPECT_EQ(0, scored.raw_score);
 
   // Now allow credit for the match in the scheme.
   base::AutoReset<bool> reset(&ScoredHistoryMatch::allow_scheme_matches_, true);
   ScoredHistoryMatch scored_with_scheme(
       row, visits, std::string(), ASCIIToUTF16("fed http"),
-      Make2Terms("fed", "http"), two_words_no_offsets, word_starts, false, now);
+      Make2Terms("fed", "http"), two_words_no_offsets, word_starts, false,
+      nullptr, now);
   EXPECT_GT(scored_with_scheme.raw_score, 0);
 }
 
+TEST_F(ScoredHistoryMatchTest, CullSearchResults) {
+  scoped_ptr<TemplateURLService> template_url_service =
+      make_scoped_ptr(new TemplateURLService(
+          nullptr, make_scoped_ptr(new SearchTermsData), nullptr,
+          scoped_ptr<TemplateURLServiceClient>(), nullptr, nullptr,
+          base::Closure()));
+
+  // We use NowFromSystemTime() because MakeURLRow uses the same function
+  // to calculate last visit time when building a row.
+  base::Time now = base::Time::NowFromSystemTime();
+
+  // Pretend we've visited a search engine query URL, but that it's not
+  // associated with the default search engine.
+  history::URLRow row(MakeURLRow(
+      "http://testsearch.com/thequery", "Test Search Engine", 3, 30, 1));
+  RowWordStarts word_starts;
+  PopulateWordStarts(row, &word_starts);
+  WordStarts one_word_no_offset(1, 0u);
+  VisitInfoVector visits = CreateVisitInfoVector(3, 30, now);
+  // Mark one visit as typed.
+  visits[0].second = ui::PAGE_TRANSITION_TYPED;
+
+  // This page should be returned if it's associated with the default search
+  // engine.
+  ScoredHistoryMatch scored_a(row, visits, std::string(),
+                              ASCIIToUTF16("thequery"), Make1Term("thequery"),
+                              one_word_no_offset, word_starts, false,
+                              template_url_service.get(), now);
+  EXPECT_GT(scored_a.raw_score, 0);
+
+  // Likewise, it should be returned when typing the engine URL.
+  ScoredHistoryMatch scored_b(row, visits, std::string(),
+                              ASCIIToUTF16("testsearch"),
+                              Make1Term("testsearch"), one_word_no_offset,
+                              word_starts, false, template_url_service.get(),
+                              now);
+  EXPECT_GT(scored_b.raw_score, 0);
+
+  // Set up a default search engine associated with this URL.
+  TemplateURLData data;
+  data.SetShortName(ASCIIToUTF16("TestEngine"));
+  data.SetKeyword(ASCIIToUTF16("TestEngine"));
+  data.SetURL("http://testsearch.com/{searchTerms}");
+  TemplateURL* template_url = new TemplateURL(data);
+  template_url_service->Add(template_url);
+  template_url_service->SetUserSelectedDefaultSearchProvider(template_url);
+  template_url_service->Load();
+
+  // The search results page should not be returned when typing a query.
+  ScoredHistoryMatch scored_c(row, visits, std::string(),
+                              ASCIIToUTF16("thequery"), Make1Term("thequery"),
+                              one_word_no_offset, word_starts, false,
+                              template_url_service.get(), now);
+  EXPECT_EQ(0, scored_c.raw_score);
+
+  // Likewise, it shouldn't be returned when typing the engine URL.
+  ScoredHistoryMatch scored_d(row, visits, std::string(),
+                              ASCIIToUTF16("testsearch"),
+                              Make1Term("testsearch"), one_word_no_offset,
+                              word_starts, false, template_url_service.get(),
+                              now);
+  EXPECT_EQ(0, scored_d.raw_score);
+}
+
 TEST_F(ScoredHistoryMatchTest, Inlining) {
   // We use NowFromSystemTime() because MakeURLRow uses the same function
   // to calculate last visit time when building a row.
@@ -279,19 +356,19 @@
     PopulateWordStarts(row, &word_starts);
     ScoredHistoryMatch scored_a(row, visits, std::string(), ASCIIToUTF16("g"),
                                 Make1Term("g"), one_word_no_offset, word_starts,
-                                false, now);
+                                false, nullptr, now);
     EXPECT_FALSE(scored_a.match_in_scheme);
     ScoredHistoryMatch scored_b(row, visits, std::string(), ASCIIToUTF16("w"),
                                 Make1Term("w"), one_word_no_offset, word_starts,
-                                false, now);
+                                false, nullptr, now);
     EXPECT_FALSE(scored_b.match_in_scheme);
     ScoredHistoryMatch scored_c(row, visits, std::string(), ASCIIToUTF16("h"),
                                 Make1Term("h"), one_word_no_offset, word_starts,
-                                false, now);
+                                false, nullptr, now);
     EXPECT_TRUE(scored_c.match_in_scheme);
     ScoredHistoryMatch scored_d(row, visits, std::string(), ASCIIToUTF16("o"),
                                 Make1Term("o"), one_word_no_offset, word_starts,
-                                false, now);
+                                false, nullptr, now);
     EXPECT_FALSE(scored_d.match_in_scheme);
   }
 
@@ -300,15 +377,15 @@
     PopulateWordStarts(row, &word_starts);
     ScoredHistoryMatch scored_a(row, visits, std::string(), ASCIIToUTF16("t"),
                                 Make1Term("t"), one_word_no_offset, word_starts,
-                                false, now);
+                                false, nullptr, now);
     EXPECT_FALSE(scored_a.match_in_scheme);
     ScoredHistoryMatch scored_b(row, visits, std::string(), ASCIIToUTF16("f"),
                                 Make1Term("f"), one_word_no_offset, word_starts,
-                                false, now);
+                                false, nullptr, now);
     EXPECT_FALSE(scored_b.match_in_scheme);
     ScoredHistoryMatch scored_c(row, visits, std::string(), ASCIIToUTF16("o"),
                                 Make1Term("o"), one_word_no_offset, word_starts,
-                                false, now);
+                                false, nullptr, now);
     EXPECT_FALSE(scored_c.match_in_scheme);
   }
 
@@ -318,15 +395,15 @@
     PopulateWordStarts(row, &word_starts);
     ScoredHistoryMatch scored_a(row, visits, std::string(), ASCIIToUTF16("t"),
                                 Make1Term("t"), one_word_no_offset, word_starts,
-                                false, now);
+                                false, nullptr, now);
     EXPECT_FALSE(scored_a.match_in_scheme);
     ScoredHistoryMatch scored_b(row, visits, std::string(), ASCIIToUTF16("h"),
                                 Make1Term("h"), one_word_no_offset, word_starts,
-                                false, now);
+                                false, nullptr, now);
     EXPECT_TRUE(scored_b.match_in_scheme);
     ScoredHistoryMatch scored_c(row, visits, std::string(), ASCIIToUTF16("w"),
                                 Make1Term("w"), one_word_no_offset, word_starts,
-                                false, now);
+                                false, nullptr, now);
     EXPECT_FALSE(scored_c.match_in_scheme);
   }
 
@@ -336,15 +413,15 @@
     PopulateWordStarts(row, &word_starts);
     ScoredHistoryMatch scored_a(row, visits, "zh-CN", ASCIIToUTF16("x"),
                                 Make1Term("x"), one_word_no_offset, word_starts,
-                                false, now);
+                                false, nullptr, now);
     EXPECT_FALSE(scored_a.match_in_scheme);
     ScoredHistoryMatch scored_b(row, visits, "zh-CN", ASCIIToUTF16("xn"),
                                 Make1Term("xn"), one_word_no_offset,
-                                word_starts, false, now);
+                                word_starts, false, nullptr, now);
     EXPECT_FALSE(scored_b.match_in_scheme);
     ScoredHistoryMatch scored_c(row, visits, "zh-CN", ASCIIToUTF16("w"),
                                 Make1Term("w"), one_word_no_offset,
-                                word_starts, false, now);
+                                word_starts, false, nullptr, now);
     EXPECT_FALSE(scored_c.match_in_scheme);
   }
 }
diff --git a/components/omnibox/browser/url_index_private_data.cc b/components/omnibox/browser/url_index_private_data.cc
index 4657273b..0409ea6 100644
--- a/components/omnibox/browser/url_index_private_data.cc
+++ b/components/omnibox/browser/url_index_private_data.cc
@@ -28,6 +28,7 @@
 #include "components/history/core/browser/history_db_task.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/omnibox/browser/in_memory_url_index.h"
+#include "components/search_engines/template_url_service.h"
 #include "components/url_formatter/url_formatter.h"
 
 #if defined(USE_SYSTEM_PROTOBUF)
@@ -156,7 +157,8 @@
     size_t cursor_position,
     size_t max_matches,
     const std::string& languages,
-    bookmarks::BookmarkModel* bookmark_model) {
+    bookmarks::BookmarkModel* bookmark_model,
+    TemplateURLService* template_url_service) {
   // If cursor position is set and useful (not at either end of the
   // string), allow the search string to be broken at cursor position.
   // We do this by pretending there's a space where the cursor is.
@@ -251,8 +253,9 @@
   scored_items =
       std::for_each(
           history_id_set.begin(), history_id_set.end(),
-          AddHistoryMatch(bookmark_model, *this, languages, lower_raw_string,
-                          lower_raw_terms, base::Time::Now())).ScoredMatches();
+          AddHistoryMatch(bookmark_model, template_url_service, *this,
+                          languages, lower_raw_string, lower_raw_terms,
+                          base::Time::Now())).ScoredMatches();
 
   // Select and sort only the top |max_matches| results.
   if (scored_items.size() > max_matches) {
@@ -1274,12 +1277,14 @@
 
 URLIndexPrivateData::AddHistoryMatch::AddHistoryMatch(
     bookmarks::BookmarkModel* bookmark_model,
+    TemplateURLService* template_url_service,
     const URLIndexPrivateData& private_data,
     const std::string& languages,
     const base::string16& lower_string,
     const String16Vector& lower_terms,
     const base::Time now)
     : bookmark_model_(bookmark_model),
+      template_url_service_(template_url_service),
       private_data_(private_data),
       languages_(languages),
       lower_string_(lower_string),
@@ -1321,7 +1326,7 @@
         hist_item, visits, languages_, lower_string_, lower_terms_,
         lower_terms_to_word_starts_offsets_, starts_pos->second,
         bookmark_model_ && bookmark_model_->IsBookmarked(hist_item.url()),
-        now_);
+        template_url_service_, now_);
     if (match.raw_score > 0)
       scored_matches_.push_back(match);
   }
diff --git a/components/omnibox/browser/url_index_private_data.h b/components/omnibox/browser/url_index_private_data.h
index 90ab171..9253ee1 100644
--- a/components/omnibox/browser/url_index_private_data.h
+++ b/components/omnibox/browser/url_index_private_data.h
@@ -19,6 +19,7 @@
 #include "components/omnibox/browser/scored_history_match.h"
 
 class HistoryQuickProviderTest;
+class TemplateURLService;
 
 namespace bookmarks {
 class BookmarkModel;
@@ -73,7 +74,8 @@
       size_t cursor_position,
       size_t max_matches,
       const std::string& languages,
-      bookmarks::BookmarkModel* bookmark_model);
+      bookmarks::BookmarkModel* bookmark_model,
+      TemplateURLService* template_url_service);
 
   // Adds the history item in |row| to the index if it does not already already
   // exist and it meets the minimum 'quick' criteria. If the row already exists
@@ -198,6 +200,7 @@
   class AddHistoryMatch : public std::unary_function<HistoryID, void> {
    public:
     AddHistoryMatch(bookmarks::BookmarkModel* bookmark_model,
+                    TemplateURLService* template_url_service,
                     const URLIndexPrivateData& private_data,
                     const std::string& languages,
                     const base::string16& lower_string,
@@ -213,6 +216,7 @@
     friend class InMemoryURLIndexTest;
     FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest, AddHistoryMatch);
     bookmarks::BookmarkModel* bookmark_model_;
+    TemplateURLService* template_url_service_;
     const URLIndexPrivateData& private_data_;
     const std::string& languages_;
     ScoredHistoryMatches scored_matches_;
diff --git a/components/password_manager/content/browser/content_password_manager_driver.cc b/components/password_manager/content/browser/content_password_manager_driver.cc
index 054aa1d..08bb4d9 100644
--- a/components/password_manager/content/browser/content_password_manager_driver.cc
+++ b/components/password_manager/content/browser/content_password_manager_driver.cc
@@ -117,7 +117,8 @@
 
 void ContentPasswordManagerDriver::GeneratePassword() {
   content::RenderFrameHost* host = render_frame_host_;
-  host->Send(new AutofillMsg_GeneratePassword(host->GetRoutingID()));
+  host->Send(
+      new AutofillMsg_UserTriggeredGeneratePassword(host->GetRoutingID()));
 }
 
 void ContentPasswordManagerDriver::SendLoggingAvailability() {
diff --git a/components/password_manager/content/renderer/credential_manager_client.cc b/components/password_manager/content/renderer/credential_manager_client.cc
index 7fe3ab54..749b429e 100644
--- a/components/password_manager/content/renderer/credential_manager_client.cc
+++ b/components/password_manager/content/renderer/credential_manager_client.cc
@@ -40,7 +40,6 @@
 }
 
 CredentialManagerClient::~CredentialManagerClient() {
-  ClearCallbacksMapWithErrors(&failed_sign_in_callbacks_);
   ClearCallbacksMapWithErrors(&store_callbacks_);
   ClearCallbacksMapWithErrors(&require_user_mediation_callbacks_);
   ClearCallbacksMapWithErrors(&get_callbacks_);
diff --git a/components/password_manager/content/renderer/credential_manager_client.h b/components/password_manager/content/renderer/credential_manager_client.h
index 7696857..d87e4601 100644
--- a/components/password_manager/content/renderer/credential_manager_client.h
+++ b/components/password_manager/content/renderer/credential_manager_client.h
@@ -32,18 +32,13 @@
 // calls to 'navigator.credential.*' and the password manager internals which
 // live in the browser process.
 //
-// One instance of CredentialManagerClient is created per RenderThread,
-// held in a scoped_ptr on ChromeContentRendererClient. The client holds
-// a raw pointer to the RenderThread on which it lives, and uses that pointer
-// to send messages to the browser process, and to route responses to itself.
-//
-// When the render thread is shut down (or the client is destructed), the
-// routing is removed, the pointer is cleared, and any pending responses are
-// rejected.
+// One instance of CredentialManagerClient is created per RenderView,
+// acts as RenderViewObserver so it can send messages to the browser process,
+// and route responses to itself.
+// Once RenderView is gone away, the instance will be deleted.
 //
 // Note that each RenderView's WebView holds a pointer to the
-// CredentialManagerClient (set in 'OnRenderViewCreated()'). The client is
-// guaranteed to outlive the views that point to it.
+// CredentialManagerClient (set in 'OnRenderViewCreated()') but does not own it.
 class CredentialManagerClient : public blink::WebCredentialManagerClient,
                                 public content::RenderViewObserver {
  public:
@@ -83,7 +78,6 @@
 
   // Track the various blink::WebCredentialManagerClient::*Callbacks objects
   // generated from Blink. This class takes ownership of these objects.
-  NotificationCallbacksMap failed_sign_in_callbacks_;
   NotificationCallbacksMap store_callbacks_;
   NotificationCallbacksMap require_user_mediation_callbacks_;
   RequestCallbacksMap get_callbacks_;
diff --git a/components/password_manager/core/browser/BUILD.gn b/components/password_manager/core/browser/BUILD.gn
index fea92bc..c672db0 100644
--- a/components/password_manager/core/browser/BUILD.gn
+++ b/components/password_manager/core/browser/BUILD.gn
@@ -116,6 +116,7 @@
     "//base",
     "//base:i18n",
     "//components/autofill/core/browser",
+    "//components/autofill/core/browser/proto",
     "//components/autofill/core/common",
     "//components/keyed_service/core",
     "//components/os_crypt",
@@ -226,6 +227,7 @@
     ":test_support",
     "//base/test:test_support",
     "//components/autofill/core/browser:test_support",
+    "//components/autofill/core/browser/proto",
     "//components/autofill/core/common",
     "//components/os_crypt",
     "//components/password_manager/core/browser:proto",
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc
index 1a64f72..6035f328 100644
--- a/components/password_manager/core/browser/password_form_manager.cc
+++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -17,6 +17,7 @@
 #include "build/build_config.h"
 #include "components/autofill/core/browser/autofill_manager.h"
 #include "components/autofill/core/browser/form_structure.h"
+#include "components/autofill/core/browser/proto/server.pb.h"
 #include "components/autofill/core/browser/validation.h"
 #include "components/autofill/core/common/password_form.h"
 #include "components/password_manager/core/browser/affiliation_utils.h"
@@ -108,6 +109,7 @@
               : std::vector<std::string>()),
       is_new_login_(true),
       has_generated_password_(false),
+      is_manual_generation_(false),
       password_overridden_(false),
       retry_password_form_password_update_(false),
       generation_available_(false),
@@ -590,7 +592,9 @@
   // by password generation to help determine account creation sites.
   // Credentials that have been previously used (e.g. PSL matches) are checked
   // to see if they are valid account creation forms.
-  if (pending_credentials_.times_used == 0) {
+  if (has_generated_password_) {
+    UploadGeneratedVote();
+  } else if (pending_credentials_.times_used == 0) {
     if (!observed_form_.IsPossibleChangePasswordFormWithoutUsername())
       UploadPasswordForm(pending_credentials_.form_data, base::string16(),
                          autofill::PASSWORD, std::string());
@@ -661,7 +665,9 @@
   // Check to see if this form is a candidate for password generation.
   // Do not send votes on change password forms, since they were already sent in
   // Update() method.
-  if (!observed_form_.IsPossibleChangePasswordForm())
+  if (has_generated_password_) {
+    UploadGeneratedVote();
+  } else if (!observed_form_.IsPossibleChangePasswordForm())
     SendAutofillVotes(observed_form_, &pending_credentials_);
 
   UpdatePreferredLoginState(password_store);
@@ -792,6 +798,7 @@
   DCHECK(password_type == autofill::PASSWORD ||
          password_type == autofill::ACCOUNT_CREATION_PASSWORD ||
          autofill::NOT_ACCOUNT_CREATION_PASSWORD);
+  DCHECK(!has_generated_password_);
   autofill::AutofillManager* autofill_manager =
       client_->GetAutofillManagerForMainFrame();
   if (!autofill_manager || !autofill_manager->download_manager())
@@ -847,6 +854,7 @@
 bool PasswordFormManager::UploadChangePasswordForm(
     const autofill::ServerFieldType& password_type,
     const std::string& login_form_signature) {
+  DCHECK(!has_generated_password_);
   DCHECK(password_type == autofill::NEW_PASSWORD ||
          password_type == autofill::PROBABLY_NEW_PASSWORD ||
          autofill::NOT_NEW_PASSWORD);
@@ -919,6 +927,60 @@
       login_form_signature, true /* observed_submission */);
 }
 
+bool PasswordFormManager::UploadGeneratedVote() {
+  DCHECK(has_generated_password_);
+  if (generation_element_.empty())
+    return false;
+  // Create FormStructure with field type information for uploading a vote.
+  FormStructure form_structure(observed_form_.form_data);
+
+  autofill::AutofillManager* autofill_manager =
+      client_->GetAutofillManagerForMainFrame();
+  if (!autofill_manager->ShouldUploadForm(form_structure) ||
+      !form_structure.ShouldBeCrowdsourced())
+    return false;
+
+  autofill::ServerFieldTypeSet available_field_types;
+  available_field_types.insert(autofill::UNKNOWN_TYPE);
+  available_field_types.insert(autofill::PASSWORD);
+
+  autofill::AutofillUploadContents::Field::PasswordGenerationType type =
+      autofill::AutofillUploadContents::Field::NO_GENERATION;
+  if (is_manual_generation_) {
+    type = observed_form_.IsPossibleChangePasswordForm()
+               ? autofill::AutofillUploadContents::Field::
+                     MANUALLY_TRIGGERED_GENERATION_ON_CHANGE_PASSWORD_FORM
+               : autofill::AutofillUploadContents::Field::
+                     MANUALLY_TRIGGERED_GENERATION_ON_SIGN_UP_FORM;
+  } else {
+    type = observed_form_.IsPossibleChangePasswordForm()
+               ? autofill::AutofillUploadContents::Field::
+                     AUTOMATICALLY_TRIGGERED_GENERATION_ON_CHANGE_PASSWORD_FORM
+               : autofill::AutofillUploadContents::Field::
+                     AUTOMATICALLY_TRIGGERED_GENERATION_ON_SIGN_UP_FORM;
+  }
+
+  bool generation_field_found = false;
+  for (size_t i = 0; i < form_structure.field_count(); ++i) {
+    autofill::AutofillField* field = form_structure.field(i);
+    if (field->name == generation_element_) {
+      field->set_generation_type(type);
+      autofill::ServerFieldTypeSet types;
+      types.insert(autofill::PASSWORD);
+      field->set_possible_types(types);
+      generation_field_found = true;
+      break;
+    }
+  }
+
+  if (!generation_field_found)
+    return false;
+
+  return autofill_manager->download_manager()->StartUploadRequest(
+      form_structure, false /* was_autofilled */, available_field_types,
+      std::string(), true /* observed_submission */);
+}
+
 void PasswordFormManager::CreatePendingCredentials() {
   DCHECK(provisionally_saved_form_);
   base::string16 password_to_save(PasswordToSave(*provisionally_saved_form_));
@@ -1189,10 +1251,12 @@
 
 PasswordForm* PasswordFormManager::FindBestSavedMatch(
     const PasswordForm* form) const {
-  PasswordFormMap::const_iterator it =
-      best_matches_.find(provisionally_saved_form_->username_value);
+  PasswordFormMap::const_iterator it = best_matches_.find(form->username_value);
   if (it != best_matches_.end())
     return it->second.get();
+  if (form->type == autofill::PasswordForm::TYPE_API)
+    // Match Credential API forms only by username.
+    return nullptr;
   if (!form->username_element.empty() || !form->new_password_element.empty())
     return nullptr;
   for (const auto& stored_match : best_matches_) {
diff --git a/components/password_manager/core/browser/password_form_manager.h b/components/password_manager/core/browser/password_form_manager.h
index aa2a792..6eee71a 100644
--- a/components/password_manager/core/browser/password_form_manager.h
+++ b/components/password_manager/core/browser/password_form_manager.h
@@ -181,6 +181,16 @@
     has_generated_password_ = generated_password;
   }
 
+  bool is_manual_generation() { return is_manual_generation_; }
+  void set_is_manual_generation(bool is_manual_generation) {
+    is_manual_generation_ = is_manual_generation;
+  }
+
+  const base::string16& generation_element() { return generation_element_; }
+  void set_generation_element(const base::string16& generation_element) {
+    generation_element_ = generation_element;
+  }
+
   bool password_overridden() const { return password_overridden_; }
 
   bool retry_password_form_password_update() const {
@@ -399,6 +409,12 @@
   bool UploadChangePasswordForm(const autofill::ServerFieldType& password_type,
                                 const std::string& login_form_signature);
 
+  // Try to label a password field that was used for generation with information
+  // that the password was generated and upload |form_data|. For labelling
+  // |generation_element_| and |is_manual_generation_| fields are used. Returns
+  // true on success.
+  bool UploadGeneratedVote();
+
   // Create pending credentials from provisionally saved form and forms received
   // from password store.
   void CreatePendingCredentials();
@@ -423,9 +439,12 @@
   // Try to find best matched to |form| from |best_matches_| by the rules:
   // 1. If there is an element in |best_matches_| with the same username then
   // return it;
-  // 2. If |form| has no username and there is an element from |best_matches_|
-  // with the same password as in |form| then return it;
-  // 3. Otherwise return nullptr.
+  // 2. If |form| is created with Credential API return nullptr, i.e. we match
+  // Credentials API forms only by username;
+  // 3. If |form| has no |username_element| and no |new_password_element| (i.e.
+  // a form contains only one field which is a password) and there is an element
+  // from |best_matches_| with the same password as in |form| then return it;
+  // 4. Otherwise return nullptr.
   autofill::PasswordForm* FindBestSavedMatch(
       const autofill::PasswordForm* form) const;
 
@@ -472,14 +491,20 @@
   // Whether this form has an auto generated password.
   bool has_generated_password_;
 
+  // Whether password generation was manually triggered.
+  bool is_manual_generation_;
+
+  // A password field name that is used for generation.
+  base::string16 generation_element_;
+
   // Whether the saved password was overridden.
   bool password_overridden_;
 
   // A form is considered to be "retry" password if it has only one field which
   // is a current password field.
   // This variable is true if the password passed through ProvisionallySave() is
-  // a password that is not equal to any password from stored for this origin
-  // credentials and it was entered on a retry password form.
+  // a password that is not part of any password form stored for this origin
+  // and it was entered on a retry password form.
   bool retry_password_form_password_update_;
 
   // Whether the user can choose to generate a password for this form.
diff --git a/components/password_manager/core/browser/password_form_manager_unittest.cc b/components/password_manager/core/browser/password_form_manager_unittest.cc
index e3df6b1..b3a19e2 100644
--- a/components/password_manager/core/browser/password_form_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_form_manager_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/test/histogram_tester.h"
 #include "build/build_config.h"
 #include "components/autofill/core/browser/autofill_manager.h"
+#include "components/autofill/core/browser/proto/server.pb.h"
 #include "components/autofill/core/browser/test_autofill_client.h"
 #include "components/autofill/core/browser/test_autofill_driver.h"
 #include "components/autofill/core/browser/test_personal_data_manager.h"
@@ -65,9 +66,10 @@
   return arg.username_value == username_value;
 }
 
-MATCHER_P2(CheckUploadFormStructure,
+MATCHER_P3(CheckUploadFormStructure,
            form_signature,
            expected_types,
+           expected_generation_types,
            "Upload form structure is incorrect") {
   if (form_signature != arg.FormSignature()) {
     // An unexpected form is uploaded.
@@ -80,16 +82,36 @@
         return false;
       }
     } else {
-      if (field->possible_types().size() != 1) {
-        // Currently we expect only one type per field.
+      if (field->possible_types().size() > 1) {
+        // Currently we expect not more than 1 type per field.
         return false;
       }
-      if (expected_types.find(field->name)->second !=
-          *field->possible_types().begin()) {
-        // An unexpected field type is found.
-        return false;
+
+      if (field->possible_types().empty()) {
+        if (expected_types.find(field->name) != expected_types.end())
+          // A vote is expected but not found.
+          return false;
+      } else {
+        if (expected_types.find(field->name)->second !=
+            *field->possible_types().begin()) {
+          // An unexpected field type is found.
+          return false;
+        }
       }
     }
+
+    if (expected_generation_types.find(field->name) ==
+        expected_generation_types.end()) {
+      if (field->generation_type() !=
+          autofill::AutofillUploadContents::Field::NO_GENERATION)
+        // Unexpected generation event is found.
+        return false;
+    } else {
+      if (expected_generation_types.find(field->name)->second !=
+          field->generation_type())
+        // Unexpected generation event is found.
+        return false;
+    }
   }
   return true;
 }
@@ -395,13 +417,19 @@
       expected_types[saved_match()->password_element] =
           autofill::NOT_ACCOUNT_CREATION_PASSWORD;
     }
+
+    std::map<base::string16,
+             autofill::AutofillUploadContents::Field::PasswordGenerationType>
+        expected_generation_types;
+
     if (field_type) {
-      EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
-                  StartUploadRequest(
-                      CheckUploadFormStructure(
-                          pending_structure.FormSignature(), expected_types),
-                      false, expected_available_field_types,
-                      expected_login_signature, true));
+      EXPECT_CALL(
+          *client()->mock_driver()->mock_autofill_download_manager(),
+          StartUploadRequest(CheckUploadFormStructure(
+                                 pending_structure.FormSignature(),
+                                 expected_types, expected_generation_types),
+                             false, expected_available_field_types,
+                             expected_login_signature, true));
     } else {
       EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
                   StartUploadRequest(_, _, _, _, _))
@@ -469,6 +497,10 @@
     std::string observed_form_signature =
         autofill::FormStructure(observed_form()->form_data).FormSignature();
 
+    std::map<base::string16,
+             autofill::AutofillUploadContents::Field::PasswordGenerationType>
+        expected_generation_types;
+
     std::string expected_login_signature;
     if (field_type == autofill::NEW_PASSWORD) {
       autofill::FormStructure pending_structure(saved_match()->form_data);
@@ -476,7 +508,8 @@
     }
     EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
                 StartUploadRequest(CheckUploadFormStructure(
-                                       observed_form_signature, expected_types),
+                                       observed_form_signature, expected_types,
+                                       expected_generation_types),
                                    false, expected_available_field_types,
                                    expected_login_signature, true));
 
@@ -495,6 +528,94 @@
     }
   }
 
+  // The user types username and generates password on SignUp or change password
+  // form. The password generation might be triggered automatically or manually.
+  // This function checks that correct vote is uploaded on server.
+  void GeneratedVoteUploadTest(bool is_manual_generation,
+                               bool is_change_password_form) {
+    SCOPED_TRACE(testing::Message()
+                 << "is_manual_generation=" << is_manual_generation
+                 << " is_change_password_form=" << is_change_password_form);
+    PasswordForm form(*observed_form());
+    form.form_data = saved_match()->form_data;
+
+    if (is_change_password_form) {
+      // Turn |form| to a change password form.
+      form.new_password_element = ASCIIToUTF16("NewPasswd");
+
+      autofill::FormFieldData field;
+      field.label = ASCIIToUTF16("password");
+      field.name = ASCIIToUTF16("NewPasswd");
+      field.form_control_type = "password";
+      form.form_data.fields.push_back(field);
+    }
+
+    // Create submitted form.
+    PasswordForm submitted_form(form);
+    submitted_form.preferred = true;
+    submitted_form.username_value = saved_match()->username_value;
+    submitted_form.password_value = saved_match()->password_value;
+
+    if (is_change_password_form) {
+      submitted_form.new_password_value =
+          saved_match()->password_value + ASCIIToUTF16("1");
+    }
+
+    PasswordFormManager form_manager(password_manager(), client(),
+                                     client()->driver(), form, false);
+
+    ScopedVector<PasswordForm> result;
+    form_manager.SimulateFetchMatchingLoginsFromPasswordStore();
+    form_manager.OnGetPasswordStoreResults(std::move(result));
+
+    autofill::ServerFieldTypeSet expected_available_field_types;
+    expected_available_field_types.insert(autofill::UNKNOWN_TYPE);
+    expected_available_field_types.insert(autofill::PASSWORD);
+
+    form_manager.set_is_manual_generation(is_manual_generation);
+    base::string16 generation_element = is_change_password_form
+                                            ? form.new_password_element
+                                            : form.password_element;
+    form_manager.set_generation_element(generation_element);
+    form_manager.set_has_generated_password(true);
+
+    std::map<base::string16, autofill::ServerFieldType> expected_types;
+    expected_types[generation_element] = autofill::PASSWORD;
+
+    // Figure out expected generation event type.
+    autofill::AutofillUploadContents::Field::PasswordGenerationType
+      expected_generation_type =
+        is_manual_generation
+            ? (is_change_password_form
+                ? autofill::AutofillUploadContents::Field::
+                    MANUALLY_TRIGGERED_GENERATION_ON_CHANGE_PASSWORD_FORM
+                : autofill::AutofillUploadContents::Field::
+                    MANUALLY_TRIGGERED_GENERATION_ON_SIGN_UP_FORM)
+            : (is_change_password_form
+                ? autofill::AutofillUploadContents::Field::
+                    AUTOMATICALLY_TRIGGERED_GENERATION_ON_CHANGE_PASSWORD_FORM
+                : autofill::AutofillUploadContents::Field::
+                    AUTOMATICALLY_TRIGGERED_GENERATION_ON_SIGN_UP_FORM);
+
+    std::map<base::string16,
+             autofill::AutofillUploadContents::Field::PasswordGenerationType>
+        expected_generation_types;
+    expected_generation_types[generation_element] = expected_generation_type;
+
+    autofill::FormStructure form_structure(submitted_form.form_data);
+
+    EXPECT_CALL(
+        *client()->mock_driver()->mock_autofill_download_manager(),
+        StartUploadRequest(
+            CheckUploadFormStructure(form_structure.FormSignature(),
+                                     expected_types, expected_generation_types),
+            false, expected_available_field_types, std::string(), true));
+
+    form_manager.ProvisionallySave(
+        submitted_form, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+    form_manager.Save();
+  }
+
   PasswordForm* observed_form() { return &observed_form_; }
   PasswordForm* saved_match() { return &saved_match_; }
   PasswordForm* psl_saved_match() { return &psl_saved_match_; }
@@ -2779,13 +2900,67 @@
   std::string expected_login_signature =
       autofill::FormStructure(saved_match()->form_data).FormSignature();
 
+  std::map<base::string16,
+           autofill::AutofillUploadContents::Field::PasswordGenerationType>
+      expected_generation_types;
+
   EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
               StartUploadRequest(CheckUploadFormStructure(
-                                     observed_form_signature, expected_types),
+                                     observed_form_signature, expected_types,
+                                     expected_generation_types),
                                  false, expected_available_field_types,
                                  expected_login_signature, true));
 
   form_manager.Update(*saved_match());
 }
 
+TEST_F(PasswordFormManagerTest, GeneratedVoteUpload) {
+  // Automatic generation, sign-up form.
+  GeneratedVoteUploadTest(false, false);
+  // Automatic generation, change password form.
+  GeneratedVoteUploadTest(false, true);
+  // Manual generation, sign-up form.
+  GeneratedVoteUploadTest(true, false);
+  // Manual generation, change password form.
+  GeneratedVoteUploadTest(true, true);
+}
+
+TEST_F(PasswordFormManagerTest, TestSavingAPIFormsWithSamePassword) {
+  // Turn |observed_form| and |saved_match| to API created forms.
+  observed_form()->username_element.clear();
+  observed_form()->type = autofill::PasswordForm::TYPE_API;
+  saved_match()->username_element.clear();
+  saved_match()->type = autofill::PasswordForm::TYPE_API;
+
+  PasswordFormManager form_manager(password_manager(), client(),
+                                   client()->driver(), *observed_form(), false);
+  SimulateMatchingPhase(&form_manager, RESULT_SAVED_MATCH);
+
+  // User submits new credentials with the same password as in already saved
+  // one.
+  PasswordForm credentials(*observed_form());
+  credentials.username_value =
+      saved_match()->username_value + ASCIIToUTF16("1");
+  credentials.password_value = saved_match()->password_value;
+  credentials.preferred = true;
+
+  form_manager.ProvisionallySave(
+      credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+
+  EXPECT_TRUE(form_manager.IsNewLogin());
+
+  PasswordForm new_credentials;
+  EXPECT_CALL(*mock_store(), AddLogin(_))
+      .WillOnce(SaveArg<0>(&new_credentials));
+
+  form_manager.Save();
+  Mock::VerifyAndClearExpectations(mock_store());
+
+  EXPECT_EQ(saved_match()->username_value + ASCIIToUTF16("1"),
+            new_credentials.username_value);
+  EXPECT_EQ(saved_match()->password_value, new_credentials.password_value);
+  EXPECT_EQ(base::string16(), new_credentials.username_element);
+  EXPECT_EQ(autofill::PasswordForm::TYPE_API, new_credentials.type);
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc
index ad3e723..02164e35 100644
--- a/components/password_manager/core/browser/password_manager.cc
+++ b/components/password_manager/core/browser/password_manager.cc
@@ -211,9 +211,21 @@
 
   UMA_HISTOGRAM_BOOLEAN("PasswordManager.GeneratedFormHasNoFormManager",
                         password_is_generated);
+}
 
-  if (!password_is_generated)
+void PasswordManager::SetGenerationElementAndReasonForForm(
+    password_manager::PasswordManagerDriver* driver,
+    const autofill::PasswordForm& form,
+    const base::string16& generation_element,
+    bool is_manually_triggered) {
+  DCHECK(client_->IsSavingAndFillingEnabledForCurrentPage());
+
+  PasswordFormManager* form_manager = GetMatchingPendingManager(form);
+  if (form_manager) {
+    form_manager->set_generation_element(generation_element);
+    form_manager->set_is_manual_generation(is_manually_triggered);
     return;
+  }
 
   // If there is no corresponding PasswordFormManager, we create one. This is
   // not the common case, and should only happen when there is a bug in our
diff --git a/components/password_manager/core/browser/password_manager.h b/components/password_manager/core/browser/password_manager.h
index b24a87c0..745251a8 100644
--- a/components/password_manager/core/browser/password_manager.h
+++ b/components/password_manager/core/browser/password_manager.h
@@ -88,6 +88,14 @@
       const autofill::PasswordForm& form,
       bool password_is_generated);
 
+  // Update the generation element and whether generation was triggered
+  // manually.
+  void SetGenerationElementAndReasonForForm(
+      password_manager::PasswordManagerDriver* driver,
+      const autofill::PasswordForm& form,
+      const base::string16& generation_element,
+      bool is_manually_triggered);
+
   // TODO(isherman): This should not be public, but is currently being used by
   // the LoginPrompt code.
   // When a form is submitted, we prepare to save the password but wait
diff --git a/components/password_manager/core/browser/password_manager_constants.cc b/components/password_manager/core/browser/password_manager_constants.cc
index ecfb8e7..cf38361e 100644
--- a/components/password_manager/core/browser/password_manager_constants.cc
+++ b/components/password_manager/core/browser/password_manager_constants.cc
@@ -14,4 +14,7 @@
 const char kPasswordManagerAccountDashboardURL[] =
     "https://passwords.google.com";
 
+const char kPasswordManagerHelpCenterSmartLock[] =
+    "https://support.google.com/accounts?p=smart_lock_chrome";
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/password_manager_constants.h b/components/password_manager/core/browser/password_manager_constants.h
index 1631c915..4a54e807 100644
--- a/components/password_manager/core/browser/password_manager_constants.h
+++ b/components/password_manager/core/browser/password_manager_constants.h
@@ -15,6 +15,9 @@
 // URL to the password manager account dashboard.
 extern const char kPasswordManagerAccountDashboardURL[];
 
+// URL to the help center article about Smart Lock;
+extern const char kPasswordManagerHelpCenterSmartLock[];
+
 }  // namespace password_manager
 
 #endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_MANAGER_CONSTANTS_H_
diff --git a/components/policy/core/common/cloud/user_cloud_policy_store.cc b/components/policy/core/common/cloud/user_cloud_policy_store.cc
index 9240d06e..6df3619 100644
--- a/components/policy/core/common/cloud/user_cloud_policy_store.cc
+++ b/components/policy/core/common/cloud/user_cloud_policy_store.cc
@@ -86,7 +86,8 @@
   }
   std::string data;
 
-  if (!base::ReadFileToString(policy_path, &data, kPolicySizeLimit) ||
+  if (!base::ReadFileToStringWithMaxSize(policy_path, &data,
+                                         kPolicySizeLimit) ||
       !result.policy.ParseFromString(data)) {
     LOG(WARNING) << "Failed to read or parse policy data from "
                  << policy_path.value();
@@ -94,7 +95,7 @@
     return result;
   }
 
-  if (!base::ReadFileToString(key_path, &data, kKeySizeLimit) ||
+  if (!base::ReadFileToStringWithMaxSize(key_path, &data, kKeySizeLimit) ||
       !result.key.ParseFromString(data)) {
     // Log an error on missing key data, but do not trigger a load failure
     // for now since there are still old unsigned cached policy blobs in the
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 7573cc2..b626efa 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -7836,18 +7836,12 @@
       'schema': {
         'type': 'string',
         'enum': [
-          'tls1',
           'tls1.1',
           'tls1.2',
         ],
       },
       'items': [
         {
-          'name': 'TLSv1',
-          'value': 'tls1',
-          'caption': 'TLS 1.0',
-        },
-        {
           'name': 'TLSv1.1',
           'value': 'tls1.1',
           'caption': 'TLS 1.1',
@@ -7859,10 +7853,10 @@
         },
       ],
       'supported_on': [
-        'chrome.*:45-47',
-        'chrome_os:45-47',
-        'android:45-47',
-        'ios:45-47',
+        'chrome.*:50-52',
+        'chrome_os:50-52',
+        'android:50-52',
+        'ios:50-52',
       ],
       'features': {
         'dynamic_refresh': True,
@@ -7871,16 +7865,14 @@
       'example_value': 'tls1.1',
       'id': 280,
       'caption': '''Minimum TLS version to fallback to''',
-      'tags': [],
-      'desc': '''Warning: The TLS 1.0 version fallback will be removed from <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> after version 47 (around January 2016) and the "tls1" option will stop working then.
+      'tags': ['system-security'],
+      'desc': '''Warning: The TLS version fallback will be removed from <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> after version 52 (around September 2016) and this policy will stop working then.
 
-      When a TLS handshake fails, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will retry the connection with a lesser version of TLS in order to work around bugs in HTTPS servers. This setting configures the version at which this fallback process will stop. If a server performs version negotiation correctly (i.e. without breaking the connection) then this setting doesn't apply. Regardless, the resulting connection must still comply with SSLVersionMin.
+      When a TLS handshake fails, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> would previously retry the connection with a lesser version of TLS in order to work around bugs in HTTPS servers. This setting configures the version at which this fallback process will stop. If a server performs version negotiation correctly (i.e. without breaking the connection) then this setting doesn't apply. Regardless, the resulting connection must still comply with SSLVersionMin.
 
-      If this policy is not configured then <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> uses a default minimum version which is TLS 1.0 in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> 44 and TLS 1.1 in later versions. Note this does not disable support for TLS 1.0, only whether <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will work around buggy servers which cannot negotiate versions correctly.
+      If this policy is not configured or if it is set to "tls1.2" then <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> no longer performs this fallback. Note this does not disable support for older TLS versions, only whether <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will work around buggy servers which cannot negotiate versions correctly.
 
-      Otherwise it may be set to one of the following values: "tls1", "tls1.1" or "tls1.2". If compatibility with a buggy server must be maintained, this may be set to "tls1". This is a stopgap measure and the server should be rapidly fixed.
-
-      A setting of "tls1.2" disables all fallback but this may have a significant compatibility impact.''',
+      Otherwise, if compatibility with a buggy server must be maintained, this policy may be set to "tls1.1". This is a stopgap measure and the server should be rapidly fixed.''',
     },
     {
       'name': 'RC4Enabled',
diff --git a/components/rappor/rappor_utils.cc b/components/rappor/rappor_utils.cc
index 9b253c2..89e4576 100644
--- a/components/rappor/rappor_utils.cc
+++ b/components/rappor/rappor_utils.cc
@@ -5,8 +5,8 @@
 #include "components/rappor/rappor_utils.h"
 
 #include "components/rappor/rappor_service.h"
-#include "net/base/net_util.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "net/base/url_util.h"
 #include "url/gurl.h"
 
 namespace rappor {
diff --git a/components/resource_provider/resource_provider_app.cc b/components/resource_provider/resource_provider_app.cc
index 6d93f21..b3723ab 100644
--- a/components/resource_provider/resource_provider_app.cc
+++ b/components/resource_provider/resource_provider_app.cc
@@ -22,7 +22,7 @@
 }
 
 void ResourceProviderApp::Initialize(mojo::Shell* shell, const std::string& url,
-                                     uint32_t id) {
+                                     uint32_t id, uint32_t user_id) {
   tracing_.Initialize(shell, url);
 }
 
diff --git a/components/resource_provider/resource_provider_app.h b/components/resource_provider/resource_provider_app.h
index d5aa7386..4897d0c6 100644
--- a/components/resource_provider/resource_provider_app.h
+++ b/components/resource_provider/resource_provider_app.h
@@ -30,7 +30,7 @@
  private:
   // mojo::ShellClient:
   void Initialize(mojo::Shell* shell, const std::string& url,
-                  uint32_t id) override;
+                  uint32_t id, uint32_t user_id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
   // mojo::InterfaceFactory<ResourceProvider>:
diff --git a/components/safe_browsing_db/BUILD.gn b/components/safe_browsing_db/BUILD.gn
index 9aa781c6..f1154f7 100644
--- a/components/safe_browsing_db/BUILD.gn
+++ b/components/safe_browsing_db/BUILD.gn
@@ -52,6 +52,7 @@
     ":util",
     ":v4_get_hash_protocol_manager",
     "//base:base",
+    "//content/public/browser",
     "//content/public/common",
     "//net",
     "//url:url",
@@ -93,6 +94,7 @@
     "//base:base",
     "//components/variations",
     "//content/public/browser",
+    "//net",
     "//url:url",
   ]
 }
@@ -145,6 +147,7 @@
   deps = [
     ":database_manager",
     "//base:base",
+    "//net",
   ]
 }
 
diff --git a/components/safe_browsing_db/database_manager.cc b/components/safe_browsing_db/database_manager.cc
index be1fcf87..ba9ea16 100644
--- a/components/safe_browsing_db/database_manager.cc
+++ b/components/safe_browsing_db/database_manager.cc
@@ -5,26 +5,43 @@
 #include "components/safe_browsing_db/database_manager.h"
 
 #include "components/safe_browsing_db/v4_get_hash_protocol_manager.h"
+#include "content/public/browser/browser_thread.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "url/gurl.h"
 
+using content::BrowserThread;
+
 namespace safe_browsing {
 
 SafeBrowsingDatabaseManager::SafeBrowsingDatabaseManager()
-    : SafeBrowsingDatabaseManager(NULL, V4ProtocolConfig()) {
-}
-
-SafeBrowsingDatabaseManager::SafeBrowsingDatabaseManager(
-    net::URLRequestContextGetter* request_context_getter,
-    const V4ProtocolConfig& config) {
-  // Instantiate a V4GetHashProtocolManager.
-  if (request_context_getter) {
-    v4_get_hash_protocol_manager_.reset(V4GetHashProtocolManager::Create(
-        request_context_getter, config));
-  }
+    : v4_get_hash_protocol_manager_(NULL) {
 }
 
 SafeBrowsingDatabaseManager::~SafeBrowsingDatabaseManager() {
+  DCHECK(v4_get_hash_protocol_manager_ == NULL);
+}
+
+void SafeBrowsingDatabaseManager::StartOnIOThread(
+    net::URLRequestContextGetter* request_context_getter,
+    const V4ProtocolConfig& config) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  // Instantiate a V4GetHashProtocolManager.
+  if (request_context_getter) {
+    v4_get_hash_protocol_manager_ = V4GetHashProtocolManager::Create(
+        request_context_getter, config);
+  }
+}
+
+// |shutdown| not used. Destroys the v4 protocol manager. This may be called
+// multiple times during the life of the DatabaseManager. Must be called on IO
+// thread.
+void SafeBrowsingDatabaseManager::StopOnIOThread(bool shutdown) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  // This cancels all in-flight GetHash requests.
+  if (v4_get_hash_protocol_manager_) {
+    delete v4_get_hash_protocol_manager_;
+    v4_get_hash_protocol_manager_ = NULL;
+  }
 }
 
 void SafeBrowsingDatabaseManager::CheckApiBlacklistUrl(const GURL& url,
diff --git a/components/safe_browsing_db/database_manager.h b/components/safe_browsing_db/database_manager.h
index 19f18de6..660a6ee 100644
--- a/components/safe_browsing_db/database_manager.h
+++ b/components/safe_browsing_db/database_manager.h
@@ -158,30 +158,25 @@
   // accessing the database at all.
   virtual void CheckApiBlacklistUrl(const GURL& url, Client* client);
 
-  // Called to initialize objects that are used on the io_thread.  This may be
-  // called multiple times during the life of the DatabaseManager. Must be
-  // called on IO thread.
-  virtual void StartOnIOThread() = 0;
-
-  // Called to stop or shutdown operations on the io_thread. This may be called
-  // multiple times during the life of the DatabaseManager. Must be called
-  // on IO thread. If shutdown is true, the manager is disabled permanently.
-  virtual void StopOnIOThread(bool shutdown) = 0;
-
- protected:
-  // Use this constructor for testing only.
-  SafeBrowsingDatabaseManager();
-
-  // Constructs the database manager.
-  SafeBrowsingDatabaseManager(
+  // Called to initialize objects that are used on the io_thread, such as the
+  // v4 protocol manager.  This may be called multiple times during the life of
+  // the DatabaseManager. Must be called on IO thread.
+  virtual void StartOnIOThread(
       net::URLRequestContextGetter* request_context_getter,
       const V4ProtocolConfig& config);
 
+  // Called to stop or shutdown operations on the io_thread.
+  virtual void StopOnIOThread(bool shutdown);
+
+ protected:
+  SafeBrowsingDatabaseManager();
+
   virtual ~SafeBrowsingDatabaseManager();
 
   friend class base::RefCountedThreadSafe<SafeBrowsingDatabaseManager>;
 
-  std::unique_ptr<V4GetHashProtocolManager> v4_get_hash_protocol_manager_;
+  // Created and destroyed via StartonIOThread/StopOnIOThread.
+  V4GetHashProtocolManager* v4_get_hash_protocol_manager_;
 };  // class SafeBrowsingDatabaseManager
 
 }  // namespace safe_browsing
diff --git a/components/safe_browsing_db/remote_database_manager.cc b/components/safe_browsing_db/remote_database_manager.cc
index 9e861d41..74c6c0c 100644
--- a/components/safe_browsing_db/remote_database_manager.cc
+++ b/components/safe_browsing_db/remote_database_manager.cc
@@ -17,6 +17,10 @@
 
 using content::BrowserThread;
 
+namespace net {
+class URLRequestContextGetter;
+}  // namespace net
+
 namespace {
 
 // Android field trial for controlling types_to_check.
@@ -94,14 +98,7 @@
 
 // TODO(nparker): Add more tests for this class
 RemoteSafeBrowsingDatabaseManager::RemoteSafeBrowsingDatabaseManager()
-    : RemoteSafeBrowsingDatabaseManager(NULL, V4ProtocolConfig()) {
-}
-
-RemoteSafeBrowsingDatabaseManager::RemoteSafeBrowsingDatabaseManager(
-      net::URLRequestContextGetter* request_context_getter,
-      const V4ProtocolConfig& config)
-    : SafeBrowsingDatabaseManager(request_context_getter, config),
-      enabled_(false) {
+    : enabled_(false) {
   // Decide which resource types to check. These two are the minimum.
   resource_types_to_check_.insert(content::RESOURCE_TYPE_MAIN_FRAME);
   resource_types_to_check_.insert(content::RESOURCE_TYPE_SUB_FRAME);
@@ -283,8 +280,11 @@
   NOTREACHED();
 }
 
-void RemoteSafeBrowsingDatabaseManager::StartOnIOThread() {
+void RemoteSafeBrowsingDatabaseManager::StartOnIOThread(
+      net::URLRequestContextGetter* request_context_getter,
+      const V4ProtocolConfig& config) {
   VLOG(1) << "RemoteSafeBrowsingDatabaseManager starting";
+  SafeBrowsingDatabaseManager::StartOnIOThread(request_context_getter, config);
   enabled_ = true;
 }
 
@@ -301,6 +301,8 @@
     req->OnRequestDone(SB_THREAT_TYPE_SAFE, std::string());
   }
   enabled_ = false;
+
+  SafeBrowsingDatabaseManager::StopOnIOThread(shutdown);
 }
 
 }  // namespace safe_browsing
diff --git a/components/safe_browsing_db/remote_database_manager.h b/components/safe_browsing_db/remote_database_manager.h
index 04585da..ebf1f0cd 100644
--- a/components/safe_browsing_db/remote_database_manager.h
+++ b/components/safe_browsing_db/remote_database_manager.h
@@ -30,14 +30,9 @@
 // Does not manage a local database.
 class RemoteSafeBrowsingDatabaseManager : public SafeBrowsingDatabaseManager {
  public:
-  // Use this constructor for testing only.
-  RemoteSafeBrowsingDatabaseManager();
-
   // Construct RemoteSafeBrowsingDatabaseManager.
   // Must be initialized by calling StartOnIOThread() before using.
-  RemoteSafeBrowsingDatabaseManager(
-      net::URLRequestContextGetter* request_context_getter,
-      const V4ProtocolConfig& config);
+  RemoteSafeBrowsingDatabaseManager();
 
   //
   // SafeBrowsingDatabaseManager implementation
@@ -51,7 +46,9 @@
   bool download_protection_enabled() const override;
   bool CheckBrowseUrl(const GURL& url, Client* client) override;
   void CancelCheck(Client* client) override;
-  void StartOnIOThread() override;
+  void StartOnIOThread(
+      net::URLRequestContextGetter* request_context_getter,
+      const V4ProtocolConfig& config) override;
   void StopOnIOThread(bool shutdown) override;
 
   // These will fail with DCHECK() since their functionality isn't implemented.
diff --git a/components/safe_browsing_db/test_database_manager.cc b/components/safe_browsing_db/test_database_manager.cc
index d24cb6a..dbccf5e9 100644
--- a/components/safe_browsing_db/test_database_manager.cc
+++ b/components/safe_browsing_db/test_database_manager.cc
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/logging.h"
+#include "net/url_request/url_request_context_getter.h"
 
 namespace safe_browsing {
 
@@ -124,7 +125,9 @@
   NOTIMPLEMENTED();
 }
 
-void TestSafeBrowsingDatabaseManager::StartOnIOThread() {
+void TestSafeBrowsingDatabaseManager::StartOnIOThread(
+    net::URLRequestContextGetter* request_context_getter,
+    const V4ProtocolConfig& config) {
 }
 
 void TestSafeBrowsingDatabaseManager::StopOnIOThread(bool shutdown) {
diff --git a/components/safe_browsing_db/test_database_manager.h b/components/safe_browsing_db/test_database_manager.h
index 2b01c20..c56e683 100644
--- a/components/safe_browsing_db/test_database_manager.h
+++ b/components/safe_browsing_db/test_database_manager.h
@@ -11,8 +11,14 @@
 
 #include "components/safe_browsing_db/database_manager.h"
 
+namespace net {
+class URLRequestContextGetter;
+}
+
 namespace safe_browsing {
 
+struct V4ProtocolConfig;
+
 // This is a non-pure-virtual implementation of the SafeBrowsingDatabaseManager
 // interface.  It's used in tests by overriding only the functions that get
 // called, and it'll complain if you call one that isn't overriden.
@@ -42,7 +48,9 @@
   bool IsCsdWhitelistKillSwitchOn() override;
   void CancelCheck(Client* client) override;
   void CheckApiBlacklistUrl(const GURL& url, Client* client) override;
-  void StartOnIOThread() override;
+  void StartOnIOThread(
+      net::URLRequestContextGetter* request_context_getter,
+      const V4ProtocolConfig& config) override;
   void StopOnIOThread(bool shutdown) override;
 
  protected:
diff --git a/components/scheduler/BUILD.gn b/components/scheduler/BUILD.gn
index 97e6463c..80a9ad59 100644
--- a/components/scheduler/BUILD.gn
+++ b/components/scheduler/BUILD.gn
@@ -74,6 +74,8 @@
     "renderer/renderer_web_scheduler_impl.h",
     "renderer/task_cost_estimator.cc",
     "renderer/task_cost_estimator.h",
+    "renderer/throttled_time_domain.cc",
+    "renderer/throttled_time_domain.h",
     "renderer/throttling_helper.cc",
     "renderer/throttling_helper.h",
     "renderer/user_model.cc",
diff --git a/components/scheduler/base/real_time_domain.cc b/components/scheduler/base/real_time_domain.cc
index bafd757..e084ee4 100644
--- a/components/scheduler/base/real_time_domain.cc
+++ b/components/scheduler/base/real_time_domain.cc
@@ -30,6 +30,12 @@
   return task_queue_manager_->delegate()->NowTicks();
 }
 
+base::TimeTicks RealTimeDomain::ComputeDelayedRunTime(
+    base::TimeTicks time_domain_now,
+    base::TimeDelta delay) const {
+  return time_domain_now + delay;
+}
+
 void RealTimeDomain::RequestWakeup(base::TimeTicks now, base::TimeDelta delay) {
   // NOTE this is only called if the scheduled runtime is sooner than any
   // previously scheduled runtime, or there is no (outstanding) previously
@@ -59,5 +65,4 @@
 const char* RealTimeDomain::GetName() const {
   return "RealTimeDomain";
 }
-
 }  // namespace scheduler
diff --git a/components/scheduler/base/real_time_domain.h b/components/scheduler/base/real_time_domain.h
index 29e0f1e..d4b6640 100644
--- a/components/scheduler/base/real_time_domain.h
+++ b/components/scheduler/base/real_time_domain.h
@@ -21,6 +21,8 @@
   // TimeDomain implementation:
   LazyNow CreateLazyNow() const override;
   base::TimeTicks Now() const override;
+  base::TimeTicks ComputeDelayedRunTime(base::TimeTicks time_domain_now,
+                                        base::TimeDelta delay) const override;
   bool MaybeAdvanceTime() override;
   const char* GetName() const override;
 
diff --git a/components/scheduler/base/task_queue_impl.cc b/components/scheduler/base/task_queue_impl.cc
index 5ce23f16..c11aeca7 100644
--- a/components/scheduler/base/task_queue_impl.cc
+++ b/components/scheduler/base/task_queue_impl.cc
@@ -186,11 +186,14 @@
     EnqueueOrder sequence_number =
         main_thread_only().task_queue_manager->GetNextSequenceNumber();
 
-    base::TimeTicks now = main_thread_only().time_domain->Now();
+    base::TimeTicks time_domain_now = main_thread_only().time_domain->Now();
+    base::TimeTicks time_domain_delayed_run_time =
+        main_thread_only().time_domain->ComputeDelayedRunTime(time_domain_now,
+                                                              delay);
     PushOntoDelayedIncomingQueueFromMainThread(
-        Task(from_here, task, now + delay, sequence_number,
+        Task(from_here, task, time_domain_delayed_run_time, sequence_number,
              task_type != TaskType::NON_NESTABLE),
-        now);
+        time_domain_now);
   } else {
     // NOTE posting a delayed task from a different thread is not expected to
     // be common. This pathway is less optimal than perhaps it could be
@@ -203,9 +206,12 @@
     EnqueueOrder sequence_number =
         any_thread().task_queue_manager->GetNextSequenceNumber();
 
+    base::TimeTicks time_domain_now = any_thread().time_domain->Now();
+    base::TimeTicks time_domain_delayed_run_time =
+        any_thread().time_domain->ComputeDelayedRunTime(time_domain_now, delay);
     PushOntoDelayedIncomingQueueLocked(
-        Task(from_here, task, any_thread().time_domain->Now() + delay,
-             sequence_number, task_type != TaskType::NON_NESTABLE));
+        Task(from_here, task, time_domain_delayed_run_time, sequence_number,
+             task_type != TaskType::NON_NESTABLE));
   }
   return true;
 }
diff --git a/components/scheduler/base/time_domain.h b/components/scheduler/base/time_domain.h
index fe1788c..1b37fed 100644
--- a/components/scheduler/base/time_domain.h
+++ b/components/scheduler/base/time_domain.h
@@ -49,6 +49,13 @@
   // Evaluate this TimeDomain's Now. Can be called from any thread.
   virtual base::TimeTicks Now() const = 0;
 
+  // Computes a runtime which is >= |time_domain_now| + |delay|. This is used to
+  // allow the TimeDomain to decide if the real or virtual time should be used
+  // when computing the task run time.  This can be called from any thread.
+  virtual base::TimeTicks ComputeDelayedRunTime(
+      base::TimeTicks time_domain_now,
+      base::TimeDelta delay) const = 0;
+
   // Some TimeDomains support virtual time, this method tells us to advance time
   // if possible and return true if time was advanced.
   virtual bool MaybeAdvanceTime() = 0;
diff --git a/components/scheduler/base/time_domain_unittest.cc b/components/scheduler/base/time_domain_unittest.cc
index c29f0ed..dc8918d 100644
--- a/components/scheduler/base/time_domain_unittest.cc
+++ b/components/scheduler/base/time_domain_unittest.cc
@@ -40,6 +40,11 @@
   LazyNow CreateLazyNow() const override { return LazyNow(now_); }
   base::TimeTicks Now() const override { return now_; }
 
+  base::TimeTicks ComputeDelayedRunTime(base::TimeTicks time_domain_now,
+                                        base::TimeDelta delay) const override {
+    return time_domain_now + delay;
+  }
+
   void AsValueIntoInternal(
       base::trace_event::TracedValue* state) const override {}
 
diff --git a/components/scheduler/base/virtual_time_domain.cc b/components/scheduler/base/virtual_time_domain.cc
index db9c403..86108b20 100644
--- a/components/scheduler/base/virtual_time_domain.cc
+++ b/components/scheduler/base/virtual_time_domain.cc
@@ -33,6 +33,12 @@
   return now_;
 }
 
+base::TimeTicks VirtualTimeDomain::ComputeDelayedRunTime(
+    base::TimeTicks time_domain_now,
+    base::TimeDelta delay) const {
+  return time_domain_now + delay;
+}
+
 void VirtualTimeDomain::RequestWakeup(base::TimeTicks now,
                                       base::TimeDelta delay) {
   // We don't need to do anything here because the caller of AdvanceTo is
diff --git a/components/scheduler/base/virtual_time_domain.h b/components/scheduler/base/virtual_time_domain.h
index e522533..830958c0 100644
--- a/components/scheduler/base/virtual_time_domain.h
+++ b/components/scheduler/base/virtual_time_domain.h
@@ -21,6 +21,8 @@
   // TimeDomain implementation:
   LazyNow CreateLazyNow() const override;
   base::TimeTicks Now() const override;
+  base::TimeTicks ComputeDelayedRunTime(base::TimeTicks time_domain_now,
+                                        base::TimeDelta delay) const override;
   bool MaybeAdvanceTime() override;
   const char* GetName() const override;
 
diff --git a/components/scheduler/child/web_task_runner_impl.cc b/components/scheduler/child/web_task_runner_impl.cc
index 49b5133..d3ba455 100644
--- a/components/scheduler/child/web_task_runner_impl.cc
+++ b/components/scheduler/child/web_task_runner_impl.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "components/scheduler/base/task_queue.h"
+#include "components/scheduler/base/time_domain.h"
 #include "third_party/WebKit/public/platform/WebTraceLocation.h"
 
 namespace scheduler {
@@ -40,6 +41,24 @@
       base::TimeDelta::FromMillisecondsD(delayMs));
 }
 
+double WebTaskRunnerImpl::virtualTimeSeconds() const {
+  return (Now() - base::TimeTicks::UnixEpoch()).InSecondsF();
+}
+
+double WebTaskRunnerImpl::monotonicallyIncreasingVirtualTimeSeconds() const {
+  return Now().ToInternalValue() /
+         static_cast<double>(base::Time::kMicrosecondsPerSecond);
+}
+
+base::TimeTicks WebTaskRunnerImpl::Now() const {
+  TimeDomain* time_domain = task_queue_->GetTimeDomain();
+  // It's possible task_queue_ has been Unregistered which can lead to a null
+  // TimeDomain.  If that happens just return the current real time.
+  if (!time_domain)
+    return base::TimeTicks::Now();
+  return time_domain->Now();
+}
+
 blink::WebTaskRunner* WebTaskRunnerImpl::clone() {
   return new WebTaskRunnerImpl(task_queue_);
 }
diff --git a/components/scheduler/child/web_task_runner_impl.h b/components/scheduler/child/web_task_runner_impl.h
index ed4a3f88..a0dc118 100644
--- a/components/scheduler/child/web_task_runner_impl.h
+++ b/components/scheduler/child/web_task_runner_impl.h
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
 #include "components/scheduler/scheduler_export.h"
 #include "third_party/WebKit/public/platform/WebTaskRunner.h"
 
@@ -26,6 +27,8 @@
   void postDelayedTask(const blink::WebTraceLocation& web_location,
                        blink::WebTaskRunner::Task* task,
                        double delayMs) override;
+  double virtualTimeSeconds() const override;
+  double monotonicallyIncreasingVirtualTimeSeconds() const override;
   blink::WebTaskRunner* clone() override;
 
   // blink::WebTaskRunner::Task should be wrapped by base::Passed() when
@@ -36,6 +39,8 @@
   static void runTask(scoped_ptr<blink::WebTaskRunner::Task>);
 
  private:
+  base::TimeTicks Now() const;
+
   scoped_refptr<TaskQueue> task_queue_;
 
   DISALLOW_COPY_AND_ASSIGN(WebTaskRunnerImpl);
diff --git a/components/scheduler/renderer/renderer_scheduler.h b/components/scheduler/renderer/renderer_scheduler.h
index 9f9204f1..98635ba 100644
--- a/components/scheduler/renderer/renderer_scheduler.h
+++ b/components/scheduler/renderer/renderer_scheduler.h
@@ -151,18 +151,6 @@
   // received via OnRendererBackgrounded. Defaults to disabled.
   virtual void SetTimerQueueSuspensionWhenBackgroundedEnabled(bool enabled) = 0;
 
-  // Returns a double which is the number of seconds since epoch (Jan 1, 1970).
-  // This may represent either the real time, or a virtual time depending on
-  // whether or not the system is currently running a task associated with a
-  // virtual time domain or real time domain.
-  virtual double VirtualTimeSeconds() const = 0;
-
-  // Returns a microsecond resolution platform dependant time source.
-  // This may represent either the real time, or a virtual time depending on
-  // whether or not the system is currently running a task associated with a
-  // virtual time domain or real time domain.
-  virtual double MonotonicallyIncreasingVirtualTimeSeconds() const = 0;
-
  protected:
   RendererScheduler();
   DISALLOW_COPY_AND_ASSIGN(RendererScheduler);
diff --git a/components/scheduler/renderer/renderer_scheduler_impl.cc b/components/scheduler/renderer/renderer_scheduler_impl.cc
index 9076b2c..5b11beac 100644
--- a/components/scheduler/renderer/renderer_scheduler_impl.cc
+++ b/components/scheduler/renderer/renderer_scheduler_impl.cc
@@ -1128,27 +1128,6 @@
   UpdatePolicyLocked(UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED);
 }
 
-double RendererSchedulerImpl::VirtualTimeSeconds() const {
-  TaskQueue* current_tq = helper_.CurrentlyExecutingTaskQueue();
-  if (current_tq && current_tq->GetTimeDomain()) {
-    return (current_tq->GetTimeDomain()->Now() -
-            base::TimeTicks::UnixEpoch()).InSecondsF();
-  }
-  return (helper_.scheduler_tqm_delegate()->NowTicks() -
-          base::TimeTicks::UnixEpoch()).InSecondsF();
-}
-
-double RendererSchedulerImpl::MonotonicallyIncreasingVirtualTimeSeconds()
-    const {
-  TaskQueue* current_tq = helper_.CurrentlyExecutingTaskQueue();
-  if (current_tq && current_tq->GetTimeDomain()) {
-    return current_tq->GetTimeDomain()->Now().ToInternalValue() /
-           static_cast<double>(base::Time::kMicrosecondsPerSecond);
-  }
-  return helper_.scheduler_tqm_delegate()->NowTicks().ToInternalValue() /
-          static_cast<double>(base::Time::kMicrosecondsPerSecond);
-}
-
 void RendererSchedulerImpl::RegisterTimeDomain(TimeDomain* time_domain) {
   helper_.RegisterTimeDomain(time_domain);
 }
diff --git a/components/scheduler/renderer/renderer_scheduler_impl.h b/components/scheduler/renderer/renderer_scheduler_impl.h
index 3f3a5ca..ecca2050 100644
--- a/components/scheduler/renderer/renderer_scheduler_impl.h
+++ b/components/scheduler/renderer/renderer_scheduler_impl.h
@@ -76,8 +76,6 @@
   void SuspendTimerQueue() override;
   void ResumeTimerQueue() override;
   void SetTimerQueueSuspensionWhenBackgroundedEnabled(bool enabled) override;
-  double VirtualTimeSeconds() const override;
-  double MonotonicallyIncreasingVirtualTimeSeconds() const override;
 
   // RenderWidgetSignals::Observer implementation:
   void SetAllRenderWidgetsHidden(bool hidden) override;
diff --git a/components/scheduler/renderer/throttled_time_domain.cc b/components/scheduler/renderer/throttled_time_domain.cc
new file mode 100644
index 0000000..76a94a2
--- /dev/null
+++ b/components/scheduler/renderer/throttled_time_domain.cc
@@ -0,0 +1,31 @@
+// Copyright 2016 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 "components/scheduler/renderer/throttled_time_domain.h"
+
+#include "base/time/tick_clock.h"
+
+namespace scheduler {
+
+ThrottledTimeDomain::ThrottledTimeDomain(TimeDomain::Observer* observer,
+                                         base::TickClock* tick_clock)
+    : VirtualTimeDomain(observer, tick_clock->NowTicks()),
+      tick_clock_(tick_clock) {}
+
+ThrottledTimeDomain::~ThrottledTimeDomain() {}
+
+base::TimeTicks ThrottledTimeDomain::ComputeDelayedRunTime(
+    base::TimeTicks,
+    base::TimeDelta delay) const {
+  // We ignore the |time_domain_now| parameter since its the virtual time but we
+  // need to use the current real time when computing the delayed runtime.  If
+  // don't do that, throttled timers may fire sooner than expected.
+  return tick_clock_->NowTicks() + delay;
+}
+
+const char* ThrottledTimeDomain::GetName() const {
+  return "ThrottledTimeDomain";
+}
+
+}  // namespace scheduler
diff --git a/components/scheduler/renderer/throttled_time_domain.h b/components/scheduler/renderer/throttled_time_domain.h
new file mode 100644
index 0000000..f274e8c
--- /dev/null
+++ b/components/scheduler/renderer/throttled_time_domain.h
@@ -0,0 +1,34 @@
+// Copyright 2016 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 COMPONENTS_SCHEDULER_RENDERER_THROTTLED_TIME_DOMAIN_H_
+#define COMPONENTS_SCHEDULER_RENDERER_THROTTLED_TIME_DOMAIN_H_
+
+#include "base/macros.h"
+#include "components/scheduler/base/virtual_time_domain.h"
+
+namespace scheduler {
+
+// A time domain that's mostly a VirtualTimeDomain except that real time is used
+// when computing the delayed runtime.
+class SCHEDULER_EXPORT ThrottledTimeDomain : public VirtualTimeDomain {
+ public:
+  ThrottledTimeDomain(TimeDomain::Observer* observer,
+                      base::TickClock* tick_clock);
+  ~ThrottledTimeDomain() override;
+
+  // TimeDomain implementation:
+  base::TimeTicks ComputeDelayedRunTime(base::TimeTicks time_domain_now,
+                                        base::TimeDelta delay) const override;
+  const char* GetName() const override;
+
+ private:
+  base::TickClock* const tick_clock_;  // NOT OWNED
+
+  DISALLOW_COPY_AND_ASSIGN(ThrottledTimeDomain);
+};
+
+}  // namespace scheduler
+
+#endif  // COMPONENTS_SCHEDULER_RENDERER_THROTTLED_TIME_DOMAIN_H_
diff --git a/components/scheduler/renderer/throttling_helper.cc b/components/scheduler/renderer/throttling_helper.cc
index 54baacc..19794469e 100644
--- a/components/scheduler/renderer/throttling_helper.cc
+++ b/components/scheduler/renderer/throttling_helper.cc
@@ -6,9 +6,9 @@
 
 #include "base/logging.h"
 #include "components/scheduler/base/real_time_domain.h"
-#include "components/scheduler/base/virtual_time_domain.h"
 #include "components/scheduler/child/scheduler_tqm_delegate.h"
 #include "components/scheduler/renderer/renderer_scheduler_impl.h"
+#include "components/scheduler/renderer/throttled_time_domain.h"
 #include "components/scheduler/renderer/web_frame_scheduler_impl.h"
 #include "third_party/WebKit/public/platform/WebFrameScheduler.h"
 
@@ -20,7 +20,7 @@
       renderer_scheduler_(renderer_scheduler),
       tick_clock_(renderer_scheduler->tick_clock()),
       tracing_category_(tracing_category),
-      time_domain_(new VirtualTimeDomain(this, tick_clock_->NowTicks())),
+      time_domain_(new ThrottledTimeDomain(this, tick_clock_)),
       weak_factory_(this) {
   suspend_timers_when_backgrounded_closure_.Reset(base::Bind(
       &ThrottlingHelper::PumpThrottledTasks, weak_factory_.GetWeakPtr()));
diff --git a/components/scheduler/renderer/throttling_helper.h b/components/scheduler/renderer/throttling_helper.h
index d5eebf5..d41ab65 100644
--- a/components/scheduler/renderer/throttling_helper.h
+++ b/components/scheduler/renderer/throttling_helper.h
@@ -16,7 +16,7 @@
 namespace scheduler {
 
 class RendererSchedulerImpl;
-class VirtualTimeDomain;
+class ThrottledTimeDomain;
 class WebFrameSchedulerImpl;
 
 class SCHEDULER_EXPORT ThrottlingHelper : public TimeDomain::Observer {
@@ -42,7 +42,7 @@
   // Removes |task_queue| from |throttled_queues_|.
   void UnregisterTaskQueue(TaskQueue* task_queue);
 
-  const VirtualTimeDomain* time_domain() const { return time_domain_.get(); }
+  const ThrottledTimeDomain* time_domain() const { return time_domain_.get(); }
 
   static base::TimeTicks ThrottledRunTime(base::TimeTicks unthrottled_runtime);
 
@@ -67,7 +67,7 @@
   RendererSchedulerImpl* renderer_scheduler_;  // NOT OWNED
   base::TickClock* tick_clock_;                // NOT OWNED
   const char* tracing_category_;               // NOT OWNED
-  scoped_ptr<VirtualTimeDomain> time_domain_;
+  scoped_ptr<ThrottledTimeDomain> time_domain_;
 
   CancelableClosureHolder suspend_timers_when_backgrounded_closure_;
   base::TimeTicks pending_pump_throttled_tasks_runtime_;
diff --git a/components/scheduler/renderer/throttling_helper_unittest.cc b/components/scheduler/renderer/throttling_helper_unittest.cc
index e547c93..459db8b 100644
--- a/components/scheduler/renderer/throttling_helper_unittest.cc
+++ b/components/scheduler/renderer/throttling_helper_unittest.cc
@@ -328,4 +328,34 @@
                   base::TimeTicks() + base::TimeDelta::FromSeconds(16)));
 }
 
+TEST_F(ThrottlingHelperTest, TaskDelayIsBasedOnRealTime) {
+  std::vector<base::TimeTicks> run_times;
+
+  throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get());
+
+  // Post an initial task that should run at the first aligned time period.
+  timer_queue_->PostDelayedTask(FROM_HERE,
+                                base::Bind(&TestTask, &run_times, clock_.get()),
+                                base::TimeDelta::FromMilliseconds(900.0));
+
+  mock_task_runner_->RunUntilIdle();
+
+  // Advance realtime.
+  clock_->Advance(base::TimeDelta::FromMilliseconds(250));
+
+  // Post a task that due to real time + delay must run in the third aligned
+  // time period.
+  timer_queue_->PostDelayedTask(FROM_HERE,
+                                base::Bind(&TestTask, &run_times, clock_.get()),
+                                base::TimeDelta::FromMilliseconds(900.0));
+
+  mock_task_runner_->RunUntilIdle();
+
+  EXPECT_THAT(
+      run_times,
+      ElementsAre(
+          base::TimeTicks() + base::TimeDelta::FromMilliseconds(1000.0),
+          base::TimeTicks() + base::TimeDelta::FromMilliseconds(3000.0)));
+}
+
 }  // namespace scheduler
diff --git a/components/scheduler/renderer/web_view_scheduler_impl.h b/components/scheduler/renderer/web_view_scheduler_impl.h
index 07ebdfb..07be0593 100644
--- a/components/scheduler/renderer/web_view_scheduler_impl.h
+++ b/components/scheduler/renderer/web_view_scheduler_impl.h
@@ -40,11 +40,9 @@
   void setPageVisible(bool page_visible) override;
   blink::WebPassOwnPtr<blink::WebFrameScheduler> createFrameScheduler()
       override;
-
-  // TODO(alexclarke): Expose in blink::WebViewScheduler.
-  void enableVirtualTime();
+  void enableVirtualTime() override;
   void setAllowVirtualTimeToAdvance(
-      bool allow_virtual_time_to_advance);
+      bool allow_virtual_time_to_advance) override;
 
   // Virtual for testing.
   virtual void AddConsoleWarning(const std::string& message);
diff --git a/components/scheduler/renderer/web_view_scheduler_impl_unittest.cc b/components/scheduler/renderer/web_view_scheduler_impl_unittest.cc
index 2611332..4a482a0 100644
--- a/components/scheduler/renderer/web_view_scheduler_impl_unittest.cc
+++ b/components/scheduler/renderer/web_view_scheduler_impl_unittest.cc
@@ -158,23 +158,26 @@
 namespace {
 class VirtualTimeRecorderTask : public blink::WebTaskRunner::Task {
  public:
-  VirtualTimeRecorderTask(RendererSchedulerImpl* scheduler,
+  VirtualTimeRecorderTask(base::SimpleTestTickClock* clock,
+                          blink::WebTaskRunner* web_task_runner,
                           std::vector<base::TimeTicks>* out_real_times,
                           std::vector<size_t>* out_virtual_times_ms)
-      : scheduler_(scheduler),
+      : clock_(clock),
+        web_task_runner_(web_task_runner),
         out_real_times_(out_real_times),
         out_virtual_times_ms_(out_virtual_times_ms) {}
 
   ~VirtualTimeRecorderTask() override {}
 
   void run() override {
-    out_real_times_->push_back(scheduler_->tick_clock()->NowTicks());
+    out_real_times_->push_back(clock_->NowTicks());
     out_virtual_times_ms_->push_back(
-        scheduler_->MonotonicallyIncreasingVirtualTimeSeconds() * 1000.0);
+        web_task_runner_->monotonicallyIncreasingVirtualTimeSeconds() * 1000.0);
   }
 
  private:
-  RendererSchedulerImpl* scheduler_;              // NOT OWNED
+  base::SimpleTestTickClock* clock_;              // NOT OWNED
+  blink::WebTaskRunner* web_task_runner_;         // NOT OWNED
   std::vector<base::TimeTicks>* out_real_times_;  // NOT OWNED
   std::vector<size_t>* out_virtual_times_ms_;     // NOT OWNED
 };
@@ -185,26 +188,31 @@
   std::vector<size_t> virtual_times_ms;
   base::TimeTicks initial_real_time = scheduler_->tick_clock()->NowTicks();
   size_t initial_virtual_time_ms =
-      scheduler_->MonotonicallyIncreasingVirtualTimeSeconds() * 1000.0;
+      web_frame_scheduler_->timerTaskRunner()
+          ->monotonicallyIncreasingVirtualTimeSeconds() *
+      1000.0;
 
   web_view_scheduler_->enableVirtualTime();
 
   web_frame_scheduler_->timerTaskRunner()->postDelayedTask(
       BLINK_FROM_HERE,
-      new VirtualTimeRecorderTask(scheduler_.get(), &real_times,
-                                  &virtual_times_ms),
+      new VirtualTimeRecorderTask(clock_.get(),
+                                  web_frame_scheduler_->timerTaskRunner(),
+                                  &real_times, &virtual_times_ms),
       2.0);
 
   web_frame_scheduler_->timerTaskRunner()->postDelayedTask(
       BLINK_FROM_HERE,
-      new VirtualTimeRecorderTask(scheduler_.get(), &real_times,
-                                  &virtual_times_ms),
+      new VirtualTimeRecorderTask(clock_.get(),
+                                  web_frame_scheduler_->timerTaskRunner(),
+                                  &real_times, &virtual_times_ms),
       20.0);
 
   web_frame_scheduler_->timerTaskRunner()->postDelayedTask(
       BLINK_FROM_HERE,
-      new VirtualTimeRecorderTask(scheduler_.get(), &real_times,
-                                  &virtual_times_ms),
+      new VirtualTimeRecorderTask(clock_.get(),
+                                  web_frame_scheduler_->timerTaskRunner(),
+                                  &real_times, &virtual_times_ms),
       200.0);
 
   mock_task_runner_->RunUntilIdle();
@@ -222,26 +230,31 @@
   std::vector<size_t> virtual_times_ms;
   base::TimeTicks initial_real_time = scheduler_->tick_clock()->NowTicks();
   size_t initial_virtual_time_ms =
-      scheduler_->MonotonicallyIncreasingVirtualTimeSeconds() * 1000.0;
+      web_frame_scheduler_->timerTaskRunner()
+          ->monotonicallyIncreasingVirtualTimeSeconds() *
+      1000.0;
 
   web_view_scheduler_->enableVirtualTime();
 
   web_frame_scheduler_->loadingTaskRunner()->postDelayedTask(
       BLINK_FROM_HERE,
-      new VirtualTimeRecorderTask(scheduler_.get(), &real_times,
-                                  &virtual_times_ms),
+      new VirtualTimeRecorderTask(clock_.get(),
+                                  web_frame_scheduler_->loadingTaskRunner(),
+                                  &real_times, &virtual_times_ms),
       2.0);
 
   web_frame_scheduler_->loadingTaskRunner()->postDelayedTask(
       BLINK_FROM_HERE,
-      new VirtualTimeRecorderTask(scheduler_.get(), &real_times,
-                                  &virtual_times_ms),
+      new VirtualTimeRecorderTask(clock_.get(),
+                                  web_frame_scheduler_->loadingTaskRunner(),
+                                  &real_times, &virtual_times_ms),
       20.0);
 
   web_frame_scheduler_->loadingTaskRunner()->postDelayedTask(
       BLINK_FROM_HERE,
-      new VirtualTimeRecorderTask(scheduler_.get(), &real_times,
-                                  &virtual_times_ms),
+      new VirtualTimeRecorderTask(clock_.get(),
+                                  web_frame_scheduler_->loadingTaskRunner(),
+                                  &real_times, &virtual_times_ms),
       200.0);
 
   mock_task_runner_->RunUntilIdle();
@@ -255,7 +268,7 @@
 }
 
 TEST_F(WebViewSchedulerImplTest,
-       RepeatingTimer_PageInBackground_MeansNothingForFirtualTime) {
+       RepeatingTimer_PageInBackground_MeansNothingForVirtualTime) {
   web_view_scheduler_->enableVirtualTime();
   web_view_scheduler_->setPageVisible(false);
   base::TimeTicks initial_real_time = scheduler_->tick_clock()->NowTicks();
@@ -267,6 +280,7 @@
       1.0);
 
   mock_task_runner_->RunTasksWhile(mock_task_runner_->TaskRunCountBelow(2000));
+  // Virtual time means page visibility is ignored.
   EXPECT_EQ(1999, run_count);
 
   // The global tick clock has not moved, yet we ran a large number of "delayed"
diff --git a/components/scheduler/scheduler.gypi b/components/scheduler/scheduler.gypi
index b0f3442..d9f5e38 100644
--- a/components/scheduler/scheduler.gypi
+++ b/components/scheduler/scheduler.gypi
@@ -80,6 +80,8 @@
       'renderer/render_widget_signals.h',
       'renderer/task_cost_estimator.cc',
       'renderer/task_cost_estimator.h',
+      'renderer/throttled_time_domain.cc',
+      'renderer/throttled_time_domain.h',
       'renderer/throttling_helper.cc',
       'renderer/throttling_helper.h',
       'renderer/web_frame_scheduler_impl.cc',
diff --git a/components/signin/core/account_id/account_id.cc b/components/signin/core/account_id/account_id.cc
index 09e5cdf..45dee4d 100644
--- a/components/signin/core/account_id/account_id.cc
+++ b/components/signin/core/account_id/account_id.cc
@@ -22,7 +22,7 @@
 const char kEmailKey[] = "email";
 
 // Prefix for GetGaiaIdKey().
-const char kKeyGaiaIdPrefix[] = "g:";
+const char kKeyGaiaIdPrefix[] = "g-";
 
 struct GoogleStringSingleton {
   GoogleStringSingleton() : google(kGoogle) {}
diff --git a/components/ssl_config/ssl_config_service_manager_pref.cc b/components/ssl_config/ssl_config_service_manager_pref.cc
index 8d8cf5c..af1cd09 100644
--- a/components/ssl_config/ssl_config_service_manager_pref.cc
+++ b/components/ssl_config/ssl_config_service_manager_pref.cc
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/feature_list.h"
 #include "base/macros.h"
 #include "base/metrics/field_trial.h"
 #include "base/single_thread_task_runner.h"
@@ -88,6 +89,10 @@
   return base::StartsWith(group_name, "Enabled", base::CompareCase::SENSITIVE);
 }
 
+const base::Feature kSSLVersionFallbackTLSv11 {
+    "SSLVersionFallbackTLSv1.1", base::FEATURE_DISABLED_BY_DEFAULT,
+};
+
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -197,6 +202,15 @@
       ssl_config::prefs::kRC4Enabled,
       new base::FundamentalValue(IsRC4EnabledByDefault()));
 
+  // Restore the TLS 1.1 fallback leg if enabled via features.
+  // TODO(davidben): Remove this when the fallback removal has succeeded.
+  // https://crbug.com/536200.
+  if (base::FeatureList::IsEnabled(kSSLVersionFallbackTLSv11)) {
+    local_state->SetDefaultPrefValue(
+        ssl_config::prefs::kSSLVersionFallbackMin,
+        new base::StringValue(switches::kSSLVersionTLSv11));
+  }
+
   PrefChangeRegistrar::NamedChangeCallback local_state_callback =
       base::Bind(&SSLConfigServiceManagerPref::OnPreferenceChanged,
                  base::Unretained(this), local_state);
@@ -294,7 +308,9 @@
     uint16_t supported_version_max = config->version_max;
     config->version_max = std::min(supported_version_max, version_max);
   }
-  if (version_fallback_min) {
+  // Values below TLS 1.1 are invalid.
+  if (version_fallback_min &&
+      version_fallback_min >= net::SSL_PROTOCOL_VERSION_TLS1_1) {
     config->version_fallback_min = version_fallback_min;
   }
   config->disabled_cipher_suites = disabled_cipher_suites_;
diff --git a/components/ssl_config/ssl_config_service_manager_pref_unittest.cc b/components/ssl_config/ssl_config_service_manager_pref_unittest.cc
index 72b8818..c15e72b 100644
--- a/components/ssl_config/ssl_config_service_manager_pref_unittest.cc
+++ b/components/ssl_config/ssl_config_service_manager_pref_unittest.cc
@@ -4,7 +4,11 @@
 
 #include "components/ssl_config/ssl_config_service_manager.h"
 
+#include <utility>
+
+#include "base/feature_list.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/values.h"
@@ -173,3 +177,49 @@
   // The command-line option must not have been honored.
   EXPECT_LE(net::SSL_PROTOCOL_VERSION_TLS1, ssl_config.version_min);
 }
+
+// Tests that fallback beyond TLS 1.0 cannot be re-enabled.
+TEST_F(SSLConfigServiceManagerPrefTest, NoTLS1Fallback) {
+  scoped_refptr<TestingPrefStore> local_state_store(new TestingPrefStore());
+
+  TestingPrefServiceSimple local_state;
+  local_state.SetUserPref(ssl_config::prefs::kSSLVersionFallbackMin,
+                          new base::StringValue("tls1"));
+  SSLConfigServiceManager::RegisterPrefs(local_state.registry());
+
+  scoped_ptr<SSLConfigServiceManager> config_manager(
+      SSLConfigServiceManager::CreateDefaultManager(
+          &local_state, base::ThreadTaskRunnerHandle::Get()));
+  ASSERT_TRUE(config_manager.get());
+  scoped_refptr<SSLConfigService> config_service(config_manager->Get());
+  ASSERT_TRUE(config_service.get());
+
+  SSLConfig ssl_config;
+  config_service->GetSSLConfig(&ssl_config);
+  // The command-line option must not have been honored.
+  EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1_2, ssl_config.version_fallback_min);
+}
+
+// Tests that the TLS 1.1 fallback may be re-enabled via features.
+TEST_F(SSLConfigServiceManagerPrefTest, TLSFallbackFeature) {
+  // Toggle the feature.
+  base::FeatureList::ClearInstanceForTesting();
+  scoped_ptr<base::FeatureList> feature_list(new base::FeatureList);
+  feature_list->InitializeFromCommandLine("SSLVersionFallbackTLSv1.1",
+                                          std::string());
+  base::FeatureList::SetInstance(std::move(feature_list));
+
+  TestingPrefServiceSimple local_state;
+  SSLConfigServiceManager::RegisterPrefs(local_state.registry());
+
+  scoped_ptr<SSLConfigServiceManager> config_manager(
+      SSLConfigServiceManager::CreateDefaultManager(
+          &local_state, base::ThreadTaskRunnerHandle::Get()));
+  scoped_refptr<SSLConfigService> config_service(config_manager->Get());
+  ASSERT_TRUE(config_service.get());
+
+  // The feature should have switched the default version_fallback_min value.
+  SSLConfig ssl_config;
+  config_service->GetSSLConfig(&ssl_config);
+  EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1_1, ssl_config.version_fallback_min);
+}
diff --git a/components/ssl_config/ssl_config_switches.cc b/components/ssl_config/ssl_config_switches.cc
index 139593e5..779149d0 100644
--- a/components/ssl_config/ssl_config_switches.cc
+++ b/components/ssl_config/ssl_config_switches.cc
@@ -12,7 +12,7 @@
 // Specifies the minimum SSL/TLS version ("tls1", "tls1.1", or "tls1.2").
 const char kSSLVersionMin[] = "ssl-version-min";
 
-// Specifies the minimum SSL/TLS version ("tls1", "tls1.1", or "tls1.2") that
+// Specifies the minimum SSL/TLS version ("tls1.1" or "tls1.2") that
 // TLS fallback will accept.
 const char kSSLVersionFallbackMin[] = "ssl-version-fallback-min";
 
diff --git a/components/ssl_errors/error_classification.cc b/components/ssl_errors/error_classification.cc
index dccacbc9..7ab390b 100644
--- a/components/ssl_errors/error_classification.cc
+++ b/components/ssl_errors/error_classification.cc
@@ -18,7 +18,6 @@
 #include "build/build_config.h"
 #include "components/ssl_errors/error_info.h"
 #include "components/url_formatter/url_formatter.h"
-#include "net/base/net_util.h"
 #include "net/base/network_change_notifier.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "net/base/url_util.h"
diff --git a/components/sync_driver.gypi b/components/sync_driver.gypi
index 0a4310b9a..ab98660b 100644
--- a/components/sync_driver.gypi
+++ b/components/sync_driver.gypi
@@ -18,7 +18,6 @@
         'invalidation_public',
         'os_crypt',
         'signin_core_browser',
-        'sync_driver_features',
         'version_info',
       ],
       'export_dependent_settings': [
@@ -35,8 +34,6 @@
         'sync_driver/backend_data_type_configurer.h',
         'sync_driver/backend_migrator.cc',
         'sync_driver/backend_migrator.h',
-        'sync_driver/backup_rollback_controller.cc',
-        'sync_driver/backup_rollback_controller.h',
         'sync_driver/change_processor.cc',
         'sync_driver/change_processor.h',
         'sync_driver/data_type_controller.cc',
@@ -156,26 +153,6 @@
       ],
     },
     {
-      # GN version: //components/sync_driver:features
-      'target_name': 'sync_driver_features',
-      'includes': [ '../build/buildflag_header.gypi' ],
-      'variables': {
-        'buildflag_header_path': 'components/sync_driver/sync_driver_features.h',
-        'variables': {
-          'conditions': [
-            ['OS=="win" or OS=="mac" or (OS=="linux" and chromeos==0)', {
-              'enable_pre_sync_backup%': 1,
-            }, {
-              'enable_pre_sync_backup%': 0,
-            }],
-          ],
-        },
-        'buildflag_flags': [
-          "ENABLE_PRE_SYNC_BACKUP=<(enable_pre_sync_backup)",
-        ],
-      },
-    },
-    {
       'target_name': 'sync_driver_test_support',
       'type': 'static_library',
       'dependencies': [
diff --git a/components/sync_driver/BUILD.gn b/components/sync_driver/BUILD.gn
index b20c8bc..9ea51d50 100644
--- a/components/sync_driver/BUILD.gn
+++ b/components/sync_driver/BUILD.gn
@@ -13,8 +13,6 @@
     "backend_data_type_configurer.h",
     "backend_migrator.cc",
     "backend_migrator.h",
-    "backup_rollback_controller.cc",
-    "backup_rollback_controller.h",
     "change_processor.cc",
     "change_processor.h",
     "data_type_controller.cc",
@@ -122,7 +120,6 @@
   ]
 
   public_deps = [
-    ":features",
     "//third_party/cacheinvalidation",
   ]
   deps = [
@@ -205,7 +202,6 @@
   sources = [
     "about_sync_util_unittest.cc",
     "backend_migrator_unittest.cc",
-    "backup_rollback_controller_unittest.cc",
     "data_type_manager_impl_unittest.cc",
     "device_info_data_type_controller_unittest.cc",
     "device_info_service_unittest.cc",
@@ -257,12 +253,3 @@
     ]
   }
 }
-
-buildflag_header("features") {
-  header = "sync_driver_features.h"
-
-  # Whether to back up data before sync.
-  enable_pre_sync_backup = is_win || is_mac || (is_linux && !is_chromeos)
-
-  flags = [ "ENABLE_PRE_SYNC_BACKUP=$enable_pre_sync_backup" ]
-}
diff --git a/components/sync_driver/backup_rollback_controller.cc b/components/sync_driver/backup_rollback_controller.cc
deleted file mode 100644
index 36299731..0000000
--- a/components/sync_driver/backup_rollback_controller.cc
+++ /dev/null
@@ -1,103 +0,0 @@
-// 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 "components/sync_driver/backup_rollback_controller.h"
-
-#include <string>
-
-#include "base/command_line.h"
-#include "base/location.h"
-#include "base/metrics/field_trial.h"
-#include "base/single_thread_task_runner.h"
-#include "base/thread_task_runner_handle.h"
-#include "components/sync_driver/signin_manager_wrapper.h"
-#include "components/sync_driver/sync_driver_features.h"
-#include "components/sync_driver/sync_driver_switches.h"
-#include "components/sync_driver/sync_prefs.h"
-
-namespace sync_driver {
-
-#if BUILDFLAG(ENABLE_PRE_SYNC_BACKUP)
-// Number of rollback attempts to try before giving up.
-static const int kRollbackLimits = 3;
-
-// Finch experiment name and group.
-static char kSyncBackupFinchName[] = "SyncBackup";
-static char kSyncBackupFinchDisabled[] = "disabled";
-#endif
-
-BackupRollbackController::BackupRollbackController(
-    sync_driver::SyncPrefs* sync_prefs,
-    const SigninManagerWrapper* signin,
-    base::Closure start_backup,
-    base::Closure start_rollback)
-    : sync_prefs_(sync_prefs),
-      signin_(signin),
-      start_backup_(start_backup),
-      start_rollback_(start_rollback) {}
-
-BackupRollbackController::~BackupRollbackController() {}
-
-bool BackupRollbackController::StartBackup() {
-  if (!IsBackupEnabled())
-    return false;
-
-  // Disable rollback to previous backup DB because it will be overwritten by
-  // new backup.
-  sync_prefs_->SetRemainingRollbackTries(0);
-  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, start_backup_);
-  return true;
-}
-
-bool BackupRollbackController::StartRollback() {
-  if (!IsBackupEnabled())
-    return false;
-
-  // Don't roll back if disabled or user is signed in.
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kSyncDisableRollback) ||
-      !signin_->GetEffectiveUsername().empty()) {
-    sync_prefs_->SetRemainingRollbackTries(0);
-    return false;
-  }
-
-  int rollback_tries = sync_prefs_->GetRemainingRollbackTries();
-  if (rollback_tries <= 0)
-    return false;  // No pending rollback.
-
-  sync_prefs_->SetRemainingRollbackTries(rollback_tries - 1);
-  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, start_rollback_);
-  return true;
-}
-
-void BackupRollbackController::OnRollbackReceived() {
-#if BUILDFLAG(ENABLE_PRE_SYNC_BACKUP)
-  sync_prefs_->SetRemainingRollbackTries(kRollbackLimits);
-#endif
-}
-
-void BackupRollbackController::OnRollbackDone() {
-#if BUILDFLAG(ENABLE_PRE_SYNC_BACKUP)
-  sync_prefs_->SetRemainingRollbackTries(0);
-#endif
-}
-
-// static
-bool BackupRollbackController::IsBackupEnabled() {
-#if BUILDFLAG(ENABLE_PRE_SYNC_BACKUP)
-  const std::string group_name =
-      base::FieldTrialList::FindFullName(kSyncBackupFinchName);
-
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kSyncDisableBackup) ||
-      group_name == kSyncBackupFinchDisabled) {
-    return false;
-  }
-  return true;
-#else
-  return false;
-#endif
-}
-
-}  // namespace sync_driver
diff --git a/components/sync_driver/backup_rollback_controller.h b/components/sync_driver/backup_rollback_controller.h
deleted file mode 100644
index f8b6b26..0000000
--- a/components/sync_driver/backup_rollback_controller.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// 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 COMPONENTS_SYNC_DRIVER_BACKUP_ROLLBACK_CONTROLLER_H_
-#define COMPONENTS_SYNC_DRIVER_BACKUP_ROLLBACK_CONTROLLER_H_
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-
-class SigninManagerWrapper;
-
-namespace sync_driver {
-
-class SyncPrefs;
-
-// BackupRollbackController takes two closures for starting backup/rollback
-// process. It calls the closures according to user's signin status or
-// received rollback command. Backup is not run when user signed in, even when
-// sync is not running.
-class BackupRollbackController {
- public:
-  BackupRollbackController(sync_driver::SyncPrefs* sync_prefs,
-                           const SigninManagerWrapper* signin,
-                           base::Closure start_backup,
-                           base::Closure start_rollback);
-  ~BackupRollbackController();
-
-  // Post task to run |start_backup_| if conditions are met. Return true if
-  // task is posted, false otherwise.
-  bool StartBackup();
-
-  // Post task to run |start_rollback_| if conditions are met. Return true if
-  // task is posted, false otherwise.
-  bool StartRollback();
-
-  // Update rollback preference to indicate rollback is needed.
-  void OnRollbackReceived();
-
-  // Update rollback preference to indicate rollback is finished.
-  void OnRollbackDone();
-
-  // Return true if platform supports backup and backup is enabled.
-  static bool IsBackupEnabled();
-
- private:
-  sync_driver::SyncPrefs* sync_prefs_;
-
-  // Use SigninManagerWrapper instead of SigninManagerBase so that
-  // supervised users are treated like regular signed-in users.
-  const SigninManagerWrapper* signin_;
-
-  base::Closure start_backup_;
-  base::Closure start_rollback_;
-
-  DISALLOW_COPY_AND_ASSIGN(BackupRollbackController);
-};
-
-}  // namespace sync_driver
-
-#endif  // COMPONENTS_SYNC_DRIVER_BACKUP_ROLLBACK_CONTROLLER_H_
diff --git a/components/sync_driver/backup_rollback_controller_unittest.cc b/components/sync_driver/backup_rollback_controller_unittest.cc
deleted file mode 100644
index 7d5f9b6..0000000
--- a/components/sync_driver/backup_rollback_controller_unittest.cc
+++ /dev/null
@@ -1,148 +0,0 @@
-// 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 "components/sync_driver/backup_rollback_controller.h"
-
-#include <string>
-
-#include "base/command_line.h"
-#include "base/location.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "components/sync_driver/signin_manager_wrapper.h"
-#include "components/sync_driver/sync_driver_features.h"
-#include "components/sync_driver/sync_driver_switches.h"
-#include "components/sync_driver/sync_prefs.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using ::testing::Return;
-
-namespace {
-
-#if BUILDFLAG(ENABLE_PRE_SYNC_BACKUP)
-
-class MockSigninManagerWrapper : public SigninManagerWrapper {
- public:
-  MockSigninManagerWrapper() : SigninManagerWrapper(NULL) {}
-
-  MOCK_CONST_METHOD0(GetEffectiveUsername, std::string());
-};
-
-class FakeSyncPrefs : public sync_driver::SyncPrefs {
- public:
-  FakeSyncPrefs() : rollback_tries_left_(0) {}
-
-  int GetRemainingRollbackTries() const override {
-    return rollback_tries_left_;
-  }
-
-  void SetRemainingRollbackTries(int v) override { rollback_tries_left_ = v; }
-
- private:
-  int rollback_tries_left_;
-};
-
-class BackupRollbackControllerTest : public testing::Test {
- public:
-  void ControllerCallback(bool start_backup) {
-    if (start_backup)
-      backup_started_ = true;
-    else
-      rollback_started_ = true;
-  }
-
- protected:
-  void SetUp() override {
-    backup_started_ = false;
-    rollback_started_ = false;
-
-    EXPECT_CALL(signin_wrapper_, GetEffectiveUsername())
-        .WillRepeatedly(Return(""));
-
-    controller_.reset(new sync_driver::BackupRollbackController(
-        &fake_prefs_, &signin_wrapper_,
-        base::Bind(&BackupRollbackControllerTest::ControllerCallback,
-                   base::Unretained(this), true),
-        base::Bind(&BackupRollbackControllerTest::ControllerCallback,
-                   base::Unretained(this), false)));
-  }
-
-  void PumpLoop() {
-    base::RunLoop run_loop;
-    loop_.task_runner()->PostTask(FROM_HERE, run_loop.QuitClosure());
-    run_loop.Run();
-  }
-
-  MockSigninManagerWrapper signin_wrapper_;
-  FakeSyncPrefs fake_prefs_;
-  scoped_ptr<sync_driver::BackupRollbackController> controller_;
-  bool backup_started_;
-  bool rollback_started_;
-  base::MessageLoop loop_;
-};
-
-TEST_F(BackupRollbackControllerTest, StartBackup) {
-  EXPECT_TRUE(controller_->StartBackup());
-  PumpLoop();
-  EXPECT_TRUE(backup_started_);
-}
-
-TEST_F(BackupRollbackControllerTest, NoBackupIfDisabled) {
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kSyncDisableBackup);
-
-  base::RunLoop run_loop;
-  EXPECT_FALSE(controller_->StartBackup());
-  loop_.task_runner()->PostTask(FROM_HERE, run_loop.QuitClosure());
-  run_loop.Run();
-  EXPECT_FALSE(backup_started_);
-}
-
-TEST_F(BackupRollbackControllerTest, StartRollback) {
-  fake_prefs_.SetRemainingRollbackTries(1);
-
-  EXPECT_TRUE(controller_->StartRollback());
-  PumpLoop();
-  EXPECT_TRUE(rollback_started_);
-  EXPECT_EQ(0, fake_prefs_.GetRemainingRollbackTries());
-}
-
-TEST_F(BackupRollbackControllerTest, NoRollbackIfOutOfTries) {
-  fake_prefs_.SetRemainingRollbackTries(0);
-
-  EXPECT_FALSE(controller_->StartRollback());
-  PumpLoop();
-  EXPECT_FALSE(rollback_started_);
-}
-
-TEST_F(BackupRollbackControllerTest, NoRollbackIfUserSignedIn) {
-  fake_prefs_.SetRemainingRollbackTries(1);
-  EXPECT_CALL(signin_wrapper_, GetEffectiveUsername())
-      .Times(1)
-      .WillOnce(Return("test"));
-  EXPECT_FALSE(controller_->StartRollback());
-  EXPECT_EQ(0, fake_prefs_.GetRemainingRollbackTries());
-
-  PumpLoop();
-  EXPECT_FALSE(backup_started_);
-  EXPECT_FALSE(rollback_started_);
-}
-
-TEST_F(BackupRollbackControllerTest, NoRollbackIfDisabled) {
-  fake_prefs_.SetRemainingRollbackTries(1);
-
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kSyncDisableRollback);
-  EXPECT_FALSE(controller_->StartRollback());
-  EXPECT_EQ(0, fake_prefs_.GetRemainingRollbackTries());
-
-  PumpLoop();
-  EXPECT_FALSE(rollback_started_);
-}
-
-#endif
-
-}  // anonymous namespace
diff --git a/components/sync_driver/data_type_manager_impl.cc b/components/sync_driver/data_type_manager_impl.cc
index 4450bec..b739611 100644
--- a/components/sync_driver/data_type_manager_impl.cc
+++ b/components/sync_driver/data_type_manager_impl.cc
@@ -76,10 +76,7 @@
   if (reason == syncer::CONFIGURE_REASON_CATCH_UP)
     catch_up_in_progress_ = true;
 
-  if (reason == syncer::CONFIGURE_REASON_BACKUP_ROLLBACK)
-    desired_types.PutAll(syncer::ControlTypes());
-  else
-    desired_types.PutAll(syncer::CoreTypes());
+  desired_types.PutAll(syncer::CoreTypes());
 
   // Only allow control types and types that have controllers.
   syncer::ModelTypeSet filtered_desired_types;
diff --git a/components/sync_driver/data_type_manager_impl_unittest.cc b/components/sync_driver/data_type_manager_impl_unittest.cc
index 0374618..7f0b2d55 100644
--- a/components/sync_driver/data_type_manager_impl_unittest.cc
+++ b/components/sync_driver/data_type_manager_impl_unittest.cc
@@ -1286,21 +1286,6 @@
   EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state());
 }
 
-TEST_F(SyncDataTypeManagerImplTest, ConfigureForBackupRollback) {
-  AddController(BOOKMARKS);
-
-  SetConfigureStartExpectation();
-
-  ModelTypeSet expected_types = syncer::ControlTypes();
-  expected_types.Put(BOOKMARKS);
-  configurer_.set_expected_configure_types(
-      BackendDataTypeConfigurer::CONFIGURE_ACTIVE, expected_types);
-  dtm_->set_priority_types(expected_types);
-
-  dtm_->Configure(ModelTypeSet(BOOKMARKS),
-                  syncer::CONFIGURE_REASON_BACKUP_ROLLBACK);
-}
-
 TEST_F(SyncDataTypeManagerImplTest, ReenableAfterDataTypeError) {
   AddController(PREFERENCES);  // Will succeed.
   AddController(BOOKMARKS);    // Will be disabled due to datatype error.
diff --git a/components/sync_driver/device_info_service.cc b/components/sync_driver/device_info_service.cc
index 138a7820..46a4bcf 100644
--- a/components/sync_driver/device_info_service.cc
+++ b/components/sync_driver/device_info_service.cc
@@ -21,7 +21,7 @@
 using syncer_v2::DataBatchImpl;
 using syncer_v2::EntityChangeList;
 using syncer_v2::EntityData;
-using syncer_v2::EntityDataList;
+using syncer_v2::EntityDataMap;
 using syncer_v2::MetadataBatch;
 using syncer_v2::MetadataChangeList;
 using syncer_v2::ModelTypeStore;
@@ -62,7 +62,7 @@
 
 SyncError DeviceInfoService::MergeSyncData(
     scoped_ptr<MetadataChangeList> metadata_change_list,
-    EntityDataList entity_data_list) {
+    EntityDataMap entity_data_map) {
   // TODO(skym): crbug.com/543406: Implementation.
   return SyncError();
 }
diff --git a/components/sync_driver/device_info_service.h b/components/sync_driver/device_info_service.h
index 13542a6a..b167c6e 100644
--- a/components/sync_driver/device_info_service.h
+++ b/components/sync_driver/device_info_service.h
@@ -53,7 +53,7 @@
   scoped_ptr<syncer_v2::MetadataChangeList> CreateMetadataChangeList() override;
   syncer::SyncError MergeSyncData(
       scoped_ptr<syncer_v2::MetadataChangeList> metadata_change_list,
-      syncer_v2::EntityDataList entity_data_list) override;
+      syncer_v2::EntityDataMap entity_data_map) override;
   syncer::SyncError ApplySyncChanges(
       scoped_ptr<syncer_v2::MetadataChangeList> metadata_change_list,
       syncer_v2::EntityChangeList entity_changes) override;
diff --git a/components/sync_driver/device_info_service_unittest.cc b/components/sync_driver/device_info_service_unittest.cc
index d9c89cfe..7556519 100644
--- a/components/sync_driver/device_info_service_unittest.cc
+++ b/components/sync_driver/device_info_service_unittest.cc
@@ -55,7 +55,6 @@
   ASSERT_EQ(s1.device_type(), s2.device_type());
   ASSERT_EQ(s1.sync_user_agent(), s2.sync_user_agent());
   ASSERT_EQ(s1.chrome_version(), s2.chrome_version());
-  ASSERT_EQ(s1.backup_timestamp(), s2.backup_timestamp());
   ASSERT_EQ(s1.signin_scoped_device_id(), s2.signin_scoped_device_id());
 }
 
@@ -189,7 +188,6 @@
         base::StringPrintf("sync user agent %d", label));
     specifics.set_chrome_version(
         base::StringPrintf("chrome version %d", label));
-    specifics.set_backup_timestamp(label);
     specifics.set_signin_scoped_device_id(
         base::StringPrintf("signin scoped device id %d", label));
     return specifics;
@@ -275,7 +273,6 @@
 
   scoped_ptr<WriteBatch> batch = store()->CreateWriteBatch();
   DeviceInfoSpecifics specifics(GenerateTestSpecifics());
-  specifics.set_backup_timestamp(6);
   store()->WriteData(batch.get(), "tag", specifics.SerializeAsString());
   store()->CommitWriteBatch(std::move(batch),
                             base::Bind(&AssertResultIsSuccess));
diff --git a/components/sync_driver/device_info_sync_service.cc b/components/sync_driver/device_info_sync_service.cc
index 77eaed4..009f6aa 100644
--- a/components/sync_driver/device_info_sync_service.cc
+++ b/components/sync_driver/device_info_sync_service.cc
@@ -59,8 +59,7 @@
 
 DeviceInfoSyncService::DeviceInfoSyncService(
     LocalDeviceInfoProvider* local_device_info_provider)
-    : local_device_backup_time_(-1),
-      local_device_info_provider_(local_device_info_provider) {
+    : local_device_info_provider_(local_device_info_provider) {
   DCHECK(local_device_info_provider);
 }
 
@@ -108,19 +107,6 @@
       scoped_ptr<DeviceInfo> synced_local_device_info =
           make_scoped_ptr(CreateDeviceInfo(*iter));
 
-      // Retrieve local device backup timestamp value from the sync data.
-      bool has_synced_backup_time =
-          iter->GetSpecifics().device_info().has_backup_timestamp();
-      int64_t synced_backup_time =
-          has_synced_backup_time
-              ? iter->GetSpecifics().device_info().backup_timestamp()
-              : -1;
-
-      // Overwrite |local_device_backup_time_| with this value if it
-      // hasn't been set yet.
-      if (!has_local_device_backup_time() && has_synced_backup_time) {
-        set_local_device_backup_time(synced_backup_time);
-      }
       // TODO(pavely): Remove histogram once device_id mismatch is understood
       // (crbug/481596).
       if (synced_local_device_info->signin_scoped_device_id() !=
@@ -130,12 +116,11 @@
             local_device_info->signin_scoped_device_id());
       }
 
-      // Store the synced device info for the local device only
+      // Store the synced device info for the local device only if
       // it is the same as the local info. Otherwise store the local
       // device info and issue a change further below after finishing
       // processing the |initial_sync_data|.
-      if (synced_local_device_info->Equals(*local_device_info) &&
-          synced_backup_time == local_device_backup_time()) {
+      if (synced_local_device_info->Equals(*local_device_info)) {
         change_type = SyncChange::ACTION_INVALID;
       } else {
         num_items_updated++;
@@ -185,7 +170,6 @@
   all_data_.clear();
   sync_processor_.reset();
   error_handler_.reset();
-  clear_local_device_backup_time();
 
   if (was_syncing) {
     NotifyObservers();
@@ -284,56 +268,6 @@
   FOR_EACH_OBSERVER(Observer, observers_, OnDeviceInfoChange());
 }
 
-void DeviceInfoSyncService::UpdateLocalDeviceBackupTime(
-    base::Time backup_time) {
-  set_local_device_backup_time(syncer::TimeToProtoTime(backup_time));
-
-  if (sync_processor_.get()) {
-    // Local device info must be available in advance
-    DCHECK(local_device_info_provider_->GetLocalDeviceInfo());
-    const std::string& local_id =
-        local_device_info_provider_->GetLocalDeviceInfo()->guid();
-
-    SyncDataMap::iterator iter = all_data_.find(local_id);
-    DCHECK(iter != all_data_.end());
-
-    syncer::SyncData& data = iter->second;
-    if (UpdateBackupTime(&data)) {
-      // Local device backup time has changed.
-      // Push changes to the server via the |sync_processor_|.
-      SyncChangeList change_list;
-      change_list.push_back(SyncChange(
-          FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data));
-      sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
-    }
-  }
-}
-
-bool DeviceInfoSyncService::UpdateBackupTime(syncer::SyncData* sync_data) {
-  DCHECK(has_local_device_backup_time());
-  DCHECK(sync_data->GetSpecifics().has_device_info());
-  const sync_pb::DeviceInfoSpecifics& source_specifics =
-      sync_data->GetSpecifics().device_info();
-
-  if (!source_specifics.has_backup_timestamp() ||
-      source_specifics.backup_timestamp() != local_device_backup_time()) {
-    sync_pb::EntitySpecifics entity(sync_data->GetSpecifics());
-    entity.mutable_device_info()->set_backup_timestamp(
-        local_device_backup_time());
-    *sync_data = CreateLocalData(entity);
-
-    return true;
-  }
-
-  return false;
-}
-
-base::Time DeviceInfoSyncService::GetLocalDeviceBackupTime() const {
-  return has_local_device_backup_time()
-             ? syncer::ProtoTimeToTime(local_device_backup_time())
-             : base::Time();
-}
-
 SyncData DeviceInfoSyncService::CreateLocalData(const DeviceInfo* info) {
   sync_pb::EntitySpecifics entity;
   sync_pb::DeviceInfoSpecifics& specifics = *entity.mutable_device_info();
@@ -345,10 +279,6 @@
   specifics.set_device_type(info->device_type());
   specifics.set_signin_scoped_device_id(info->signin_scoped_device_id());
 
-  if (has_local_device_backup_time()) {
-    specifics.set_backup_timestamp(local_device_backup_time());
-  }
-
   return CreateLocalData(entity);
 }
 
diff --git a/components/sync_driver/device_info_sync_service.h b/components/sync_driver/device_info_sync_service.h
index 7d529bb..6c82a12 100644
--- a/components/sync_driver/device_info_sync_service.h
+++ b/components/sync_driver/device_info_sync_service.h
@@ -52,13 +52,8 @@
   void AddObserver(Observer* observer) override;
   void RemoveObserver(Observer* observer) override;
 
-  // Called to update local device backup time.
-  void UpdateLocalDeviceBackupTime(base::Time backup_time);
-  // Gets the most recently set local device backup time.
-  base::Time GetLocalDeviceBackupTime() const;
-
  private:
-  // Create SyncData from local DeviceInfo and |local_device_backup_time_|.
+  // Create SyncData from local DeviceInfo.
   syncer::SyncData CreateLocalData(const DeviceInfo* info);
   // Create SyncData from EntitySpecifics.
   static syncer::SyncData CreateLocalData(
@@ -74,25 +69,6 @@
   // Notify all registered observers.
   void NotifyObservers();
 
-  // Updates backup time in place in |sync_data| if it is different than
-  // the one stored in |local_device_backup_time_|.
-  // Returns true if backup time was updated.
-  bool UpdateBackupTime(syncer::SyncData* sync_data);
-
-  // |local_device_backup_time_| accessors.
-  int64_t local_device_backup_time() const { return local_device_backup_time_; }
-  bool has_local_device_backup_time() const {
-    return local_device_backup_time_ >= 0;
-  }
-  void set_local_device_backup_time(int64_t value) {
-    local_device_backup_time_ = value;
-  }
-  void clear_local_device_backup_time() { local_device_backup_time_ = -1; }
-
-  // Local device last set backup time (in proto format).
-  // -1 if the value hasn't been specified
-  int64_t local_device_backup_time_;
-
   // |local_device_info_provider_| isn't owned.
   const LocalDeviceInfoProvider* const local_device_info_provider_;
 
diff --git a/components/sync_driver/device_info_sync_service_unittest.cc b/components/sync_driver/device_info_sync_service_unittest.cc
index 9592b71..2dffcbe 100644
--- a/components/sync_driver/device_info_sync_service_unittest.cc
+++ b/components/sync_driver/device_info_sync_service_unittest.cc
@@ -124,10 +124,6 @@
     specifics.set_device_type(sync_pb::SyncEnums_DeviceType_TYPE_LINUX);
     specifics.set_signin_scoped_device_id("device_id");
 
-    if (backup_timestamp != 0) {
-      specifics.set_backup_timestamp(backup_timestamp);
-    }
-
     return SyncData::CreateRemoteData(1,
                                       entity,
                                       base::Time(),
@@ -418,152 +414,6 @@
   EXPECT_EQ(0, num_device_info_changed_callbacks_);
 }
 
-// Verifies setting backup timestamp after the initial sync.
-TEST_F(DeviceInfoSyncServiceTest, UpdateLocalDeviceBackupTime) {
-  // Shouldn't have backuptime initially.
-  base::Time backup_time = sync_service_->GetLocalDeviceBackupTime();
-  EXPECT_TRUE(backup_time.is_null());
-
-  // Perform the initial sync with empty data.
-  SyncMergeResult merge_result =
-      sync_service_->MergeDataAndStartSyncing(syncer::DEVICE_INFO,
-                                              SyncDataList(),
-                                              PassProcessor(),
-                                              CreateAndPassSyncErrorFactory());
-
-  // Should have local device after the initial sync.
-  EXPECT_EQ(1U, sync_processor_->change_list_size());
-  EXPECT_EQ(SyncChange::ACTION_ADD, sync_processor_->change_type_at(0));
-
-  // Shouldn't have backup time initially.
-  EXPECT_EQ("guid_1", sync_processor_->cache_guid_at(0));
-  EXPECT_FALSE(sync_processor_->device_info_at(0).has_backup_timestamp());
-
-  sync_service_->UpdateLocalDeviceBackupTime(base::Time::FromTimeT(1000));
-
-  // Should have local device info updated with the specified backup timestamp.
-  EXPECT_EQ(1U, sync_processor_->change_list_size());
-  EXPECT_EQ(SyncChange::ACTION_UPDATE, sync_processor_->change_type_at(0));
-  EXPECT_EQ("guid_1", sync_processor_->cache_guid_at(0));
-  EXPECT_TRUE(sync_processor_->device_info_at(0).has_backup_timestamp());
-
-  backup_time = syncer::ProtoTimeToTime(
-      sync_processor_->device_info_at(0).backup_timestamp());
-  EXPECT_EQ(1000, backup_time.ToTimeT());
-
-  // Also verify that we get the same backup time directly from the service.
-  backup_time = sync_service_->GetLocalDeviceBackupTime();
-  EXPECT_EQ(1000, backup_time.ToTimeT());
-}
-
-// Verifies setting backup timestamp prior to the initial sync.
-TEST_F(DeviceInfoSyncServiceTest, UpdateLocalDeviceBackupTimeBeforeSync) {
-  // Set the backup timestamp.
-  sync_service_->UpdateLocalDeviceBackupTime(base::Time::FromTimeT(2000));
-  // Verify that we get it back.
-  base::Time backup_time = sync_service_->GetLocalDeviceBackupTime();
-  EXPECT_EQ(2000, backup_time.ToTimeT());
-
-  // Now perform the initial sync with empty data.
-  SyncMergeResult merge_result =
-      sync_service_->MergeDataAndStartSyncing(syncer::DEVICE_INFO,
-                                              SyncDataList(),
-                                              PassProcessor(),
-                                              CreateAndPassSyncErrorFactory());
-
-  // Should have local device after the initial sync.
-  // Should have the backup timestamp set.
-  EXPECT_EQ(1U, sync_processor_->change_list_size());
-  EXPECT_EQ(SyncChange::ACTION_ADD, sync_processor_->change_type_at(0));
-  EXPECT_EQ("guid_1", sync_processor_->cache_guid_at(0));
-  EXPECT_TRUE(sync_processor_->device_info_at(0).has_backup_timestamp());
-
-  backup_time = syncer::ProtoTimeToTime(
-      sync_processor_->device_info_at(0).backup_timestamp());
-  EXPECT_EQ(2000, backup_time.ToTimeT());
-}
-
-// Verifies that the backup timestamp that comes in the intial sync data
-// gets preserved when there are no changes to the local device.
-TEST_F(DeviceInfoSyncServiceTest, PreserveBackupTimeWithMatchingLocalDevice) {
-  base::Time backup_time = base::Time::FromTimeT(3000);
-  SyncDataList sync_data;
-  sync_data.push_back(CreateRemoteData(
-      "guid_1", "client_1", syncer::TimeToProtoTime(backup_time)));
-
-  SyncMergeResult merge_result =
-      sync_service_->MergeDataAndStartSyncing(syncer::DEVICE_INFO,
-                                              sync_data,
-                                              PassProcessor(),
-                                              CreateAndPassSyncErrorFactory());
-
-  // Everything is matching so there should be no updates.
-  EXPECT_EQ(0U, sync_processor_->change_list_size());
-
-  // Verify that we get back the same time.
-  backup_time = sync_service_->GetLocalDeviceBackupTime();
-  EXPECT_EQ(3000, backup_time.ToTimeT());
-}
-
-// Verifies that the backup timestamp that comes in the intial sync data
-// gets merged with the local device data.
-TEST_F(DeviceInfoSyncServiceTest, MergeBackupTimeWithMatchingLocalDevice) {
-  base::Time backup_time = base::Time::FromTimeT(4000);
-  SyncDataList sync_data;
-  sync_data.push_back(CreateRemoteData(
-      "guid_1", "foo_1", syncer::TimeToProtoTime(backup_time)));
-
-  SyncMergeResult merge_result =
-      sync_service_->MergeDataAndStartSyncing(syncer::DEVICE_INFO,
-                                              sync_data,
-                                              PassProcessor(),
-                                              CreateAndPassSyncErrorFactory());
-
-  // Should be one change because of the client name mismatch.
-  // However the backup time passed in the initial data should be merged into
-  // the change.
-  EXPECT_EQ(1U, sync_processor_->change_list_size());
-
-  EXPECT_EQ(SyncChange::ACTION_UPDATE, sync_processor_->change_type_at(0));
-  EXPECT_EQ("guid_1", sync_processor_->cache_guid_at(0));
-  EXPECT_EQ("client_1", sync_processor_->client_name_at(0));
-
-  backup_time = syncer::ProtoTimeToTime(
-      sync_processor_->device_info_at(0).backup_timestamp());
-  EXPECT_EQ(4000, backup_time.ToTimeT());
-}
-
-// Verifies that mismatching backup timestamp generates an update even
-// when the rest of local device data is matching.
-TEST_F(DeviceInfoSyncServiceTest,
-       MergeMismatchingBackupTimeWithMatchingLocalDevice) {
-  base::Time backup_time = base::Time::FromTimeT(5000);
-  SyncDataList sync_data;
-  sync_data.push_back(CreateRemoteData(
-      "guid_1", "client_1", syncer::TimeToProtoTime(backup_time)));
-
-  // Set the backup timestamp different than the one in the sync data.
-  sync_service_->UpdateLocalDeviceBackupTime(base::Time::FromTimeT(6000));
-
-  SyncMergeResult merge_result =
-      sync_service_->MergeDataAndStartSyncing(syncer::DEVICE_INFO,
-                                              sync_data,
-                                              PassProcessor(),
-                                              CreateAndPassSyncErrorFactory());
-
-  // Should generate and update due to timestamp mismatch.
-  // The locally set timestamp wins.
-  EXPECT_EQ(1U, sync_processor_->change_list_size());
-
-  EXPECT_EQ(SyncChange::ACTION_UPDATE, sync_processor_->change_type_at(0));
-  EXPECT_EQ("guid_1", sync_processor_->cache_guid_at(0));
-  EXPECT_EQ("client_1", sync_processor_->client_name_at(0));
-
-  backup_time = syncer::ProtoTimeToTime(
-      sync_processor_->device_info_at(0).backup_timestamp());
-  EXPECT_EQ(6000, backup_time.ToTimeT());
-}
-
 }  // namespace
 
 }  // namespace sync_driver
diff --git a/components/sync_driver/fake_sync_client.cc b/components/sync_driver/fake_sync_client.cc
index 2b65860..2dce0cea 100644
--- a/components/sync_driver/fake_sync_client.cc
+++ b/components/sync_driver/fake_sync_client.cc
@@ -12,8 +12,6 @@
 
 namespace {
 
-void DummyClearBrowsingDataCallback(base::Time start, base::Time end) {}
-
 void DummyRegisterPlatformTypesCallback(SyncService* sync_service,
                                         syncer::ModelTypeSet,
                                         syncer::ModelTypeSet) {}
@@ -52,10 +50,6 @@
   return nullptr;
 }
 
-ClearBrowsingDataCallback FakeSyncClient::GetClearBrowsingDataCallback() {
-  return base::Bind(&DummyClearBrowsingDataCallback);
-}
-
 base::Closure FakeSyncClient::GetPasswordStateChangedCallback() {
   return base::Bind(&base::DoNothing);
 }
diff --git a/components/sync_driver/fake_sync_client.h b/components/sync_driver/fake_sync_client.h
index f394b6d..7aa7251f 100644
--- a/components/sync_driver/fake_sync_client.h
+++ b/components/sync_driver/fake_sync_client.h
@@ -25,7 +25,6 @@
   bookmarks::BookmarkModel* GetBookmarkModel() override;
   favicon::FaviconService* GetFaviconService() override;
   history::HistoryService* GetHistoryService() override;
-  ClearBrowsingDataCallback GetClearBrowsingDataCallback() override;
   base::Closure GetPasswordStateChangedCallback() override;
   sync_driver::SyncApiComponentFactory::RegisterDataTypesMethod
   GetRegisterPlatformTypesCallback() override;
diff --git a/components/sync_driver/glue/sync_backend_host_impl_unittest.cc b/components/sync_driver/glue/sync_backend_host_impl_unittest.cc
index 1968558..f01f7405 100644
--- a/components/sync_driver/glue/sync_backend_host_impl_unittest.cc
+++ b/components/sync_driver/glue/sync_backend_host_impl_unittest.cc
@@ -120,8 +120,7 @@
 class FakeSyncManagerFactory : public syncer::SyncManagerFactory {
  public:
   explicit FakeSyncManagerFactory(FakeSyncManager** fake_manager)
-     : SyncManagerFactory(NORMAL),
-       fake_manager_(fake_manager) {
+     : fake_manager_(fake_manager) {
     *fake_manager_ = NULL;
   }
   ~FakeSyncManagerFactory() override {}
diff --git a/components/sync_driver/non_blocking_data_type_controller_unittest.cc b/components/sync_driver/non_blocking_data_type_controller_unittest.cc
index dcf610e25..2141607 100644
--- a/components/sync_driver/non_blocking_data_type_controller_unittest.cc
+++ b/components/sync_driver/non_blocking_data_type_controller_unittest.cc
@@ -261,7 +261,9 @@
   }
 
   void LoadModels() {
-    OnMetadataLoaded();
+    if (!type_processor_->IsAllowingChanges()) {
+      OnMetadataLoaded();
+    }
     controller_->LoadModels(
         base::Bind(&NonBlockingDataTypeControllerTest::LoadModelsDone,
                    base::Unretained(this)));
diff --git a/components/sync_driver/pref_names.cc b/components/sync_driver/pref_names.cc
index 550b927..ef7ab29 100644
--- a/components/sync_driver/pref_names.cc
+++ b/components/sync_driver/pref_names.cc
@@ -91,9 +91,6 @@
 const char kSyncSpareBootstrapToken[] = "sync.spare_bootstrap_token";
 #endif  // defined(OS_CHROMEOS)
 
-// Stores how many times to try rollback before giving up.
-const char kSyncRemainingRollbackTries[] = "sync.remaining_rollback_tries";
-
 // Stores the timestamp of first sync.
 const char kSyncFirstSyncTime[] = "sync.first_sync_time";
 
diff --git a/components/sync_driver/pref_names.h b/components/sync_driver/pref_names.h
index 3209780..d3ecf97 100644
--- a/components/sync_driver/pref_names.h
+++ b/components/sync_driver/pref_names.h
@@ -64,7 +64,6 @@
 extern const char kSyncSpareBootstrapToken[];
 #endif  // defined(OS_CHROMEOS)
 
-extern const char kSyncRemainingRollbackTries[];
 extern const char kSyncFirstSyncTime[];
 
 extern const char kSyncPassphrasePrompted[];
diff --git a/components/sync_driver/startup_controller.cc b/components/sync_driver/startup_controller.cc
index f22f31f..4db2bb2 100644
--- a/components/sync_driver/startup_controller.cc
+++ b/components/sync_driver/startup_controller.cc
@@ -159,10 +159,7 @@
   // defer the heavy lifting for sync init until things have calmed down.
   if (sync_prefs_->IsFirstSetupComplete()) {
     // For first time, defer start if data type hasn't requested sync to avoid
-    // stressing browser start. If |first_start_| is false, most likely the
-    // first attempt to start is intercepted by backup. When backup finishes,
-    // TryStart() is called again and we should start immediately to avoid
-    // unnecessary delay.
+    // stressing browser start.
     if (!received_start_request_ && first_start_)
       return StartUp(STARTUP_BACKEND_DEFERRED);
     else
diff --git a/components/sync_driver/sync_client.h b/components/sync_driver/sync_client.h
index a2e0558..2982a4d 100644
--- a/components/sync_driver/sync_client.h
+++ b/components/sync_driver/sync_client.h
@@ -9,7 +9,6 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
 #include "components/sync_driver/sync_api_component_factory.h"
 #include "sync/internal_api/public/base/model_type.h"
 #include "sync/internal_api/public/engine/model_safe_worker.h"
@@ -52,8 +51,6 @@
 
 class SyncService;
 
-typedef base::Callback<void(base::Time, base::Time)> ClearBrowsingDataCallback;
-
 // Interface for clients of the Sync API to plumb through necessary dependent
 // components. This interface is purely for abstracting dependencies, and
 // should not contain any non-trivial functional logic.
@@ -79,10 +76,6 @@
   virtual favicon::FaviconService* GetFaviconService() = 0;
   virtual history::HistoryService* GetHistoryService() = 0;
 
-  // Returns a callback that will be invoked when the sync service wishes to
-  // have browsing data cleared.
-  virtual ClearBrowsingDataCallback GetClearBrowsingDataCallback() = 0;
-
   // Returns a callback that will register the types specific to the current
   // platform.
   virtual sync_driver::SyncApiComponentFactory::RegisterDataTypesMethod
diff --git a/components/sync_driver/sync_driver_switches.cc b/components/sync_driver/sync_driver_switches.cc
index 15cde97..498a82b 100644
--- a/components/sync_driver/sync_driver_switches.cc
+++ b/components/sync_driver/sync_driver_switches.cc
@@ -10,16 +10,10 @@
 const char kSyncDeferredStartupTimeoutSeconds[] =
     "sync-deferred-startup-timeout-seconds";
 
-// Disable data backup when user's not signed in.
-const char kSyncDisableBackup[] = "disable-sync-backup";
-
 // Enables deferring sync backend initialization until user initiated changes
 // occur.
 const char kSyncDisableDeferredStartup[] = "sync-disable-deferred-startup";
 
-// Disable sync rollback.
-const char kSyncDisableRollback[] = "disable-sync-rollback";
-
 // Enables clearing of sync data when a user enables passphrase encryption.
 const char kSyncEnableClearDataOnPassphraseEncryption[] =
     "enable-clear-sync-data-on-passphrase-encryption";
diff --git a/components/sync_driver/sync_driver_switches.h b/components/sync_driver/sync_driver_switches.h
index caeb038c..9528aa6 100644
--- a/components/sync_driver/sync_driver_switches.h
+++ b/components/sync_driver/sync_driver_switches.h
@@ -12,9 +12,7 @@
 // All switches in alphabetical order. The switches should be documented
 // alongside the definition of their values in the .cc file.
 extern const char kSyncDeferredStartupTimeoutSeconds[];
-extern const char kSyncDisableBackup[];
 extern const char kSyncDisableDeferredStartup[];
-extern const char kSyncDisableRollback[];
 extern const char kSyncEnableClearDataOnPassphraseEncryption[];
 extern const char kSyncEnableGetUpdateAvoidance[];
 extern const char kSyncEnableUSSDeviceInfo[];
diff --git a/components/sync_driver/sync_prefs.cc b/components/sync_driver/sync_prefs.cc
index e029142..185a122fe 100644
--- a/components/sync_driver/sync_prefs.cc
+++ b/components/sync_driver/sync_prefs.cc
@@ -79,7 +79,6 @@
 
   registry->RegisterBooleanPref(prefs::kSyncHasAuthError, false);
   registry->RegisterStringPref(prefs::kSyncSessionsGUID, std::string());
-  registry->RegisterIntegerPref(prefs::kSyncRemainingRollbackTries, 0);
   registry->RegisterBooleanPref(prefs::kSyncPassphrasePrompted, false);
   registry->RegisterIntegerPref(prefs::kSyncMemoryPressureWarningCount, -1);
   registry->RegisterBooleanPref(prefs::kSyncShutdownCleanly, false);
@@ -337,14 +336,6 @@
 }
 #endif
 
-int SyncPrefs::GetRemainingRollbackTries() const {
-  return pref_service_->GetInteger(prefs::kSyncRemainingRollbackTries);
-}
-
-void SyncPrefs::SetRemainingRollbackTries(int times) {
-  pref_service_->SetInteger(prefs::kSyncRemainingRollbackTries, times);
-}
-
 void SyncPrefs::OnSyncManagedPrefChanged() {
   DCHECK(CalledOnValidThread());
   FOR_EACH_OBSERVER(SyncPrefObserver,
diff --git a/components/sync_driver/sync_prefs.h b/components/sync_driver/sync_prefs.h
index 96f1a8e..4f2c65e 100644
--- a/components/sync_driver/sync_prefs.h
+++ b/components/sync_driver/sync_prefs.h
@@ -133,10 +133,6 @@
   void SetSpareBootstrapToken(const std::string& token);
 #endif
 
-  // Get/Set number of rollback attempts allowed.
-  virtual int GetRemainingRollbackTries() const;
-  virtual void SetRemainingRollbackTries(int times);
-
   // Get/set/clear first sync time of current user. Used to roll back browsing
   // data later when user signs out.
   base::Time GetFirstSyncTime() const;
diff --git a/components/sync_driver/sync_service.h b/components/sync_driver/sync_service.h
index e722444..76efc25 100644
--- a/components/sync_driver/sync_service.h
+++ b/components/sync_driver/sync_service.h
@@ -99,8 +99,6 @@
   // an initial configuration has successfully completed, although there may
   // be datatype specific, auth, or other transient errors. To see which
   // datetypes are actually syncing, see GetActiveTypes() below.
-  // Note that if sync is in backup or rollback mode, IsSyncActive() will be
-  // false.
   virtual bool IsSyncActive() const = 0;
 
   // Triggers a GetUpdates call for the specified |types|, pulling any new data
diff --git a/components/test_runner/BUILD.gn b/components/test_runner/BUILD.gn
index 577c04e..ebeef6a 100644
--- a/components/test_runner/BUILD.gn
+++ b/components/test_runner/BUILD.gn
@@ -64,8 +64,6 @@
     "spell_check_client.h",
     "test_common.cc",
     "test_common.h",
-    "test_info_extractor.cc",
-    "test_info_extractor.h",
     "test_interfaces.cc",
     "test_interfaces.h",
     "test_plugin.cc",
diff --git a/components/test_runner/event_sender.cc b/components/test_runner/event_sender.cc
index 6e1df4f..31867c9 100644
--- a/components/test_runner/event_sender.cc
+++ b/components/test_runner/event_sender.cc
@@ -2594,13 +2594,17 @@
 
   WebPoint client_point(e.x, e.y);
   WebPoint screen_point(e.globalX, e.globalY);
-  FinishDragAndDrop(
-      e,
-      view_->dragTargetDragOver(
-          client_point,
-          screen_point,
-          current_drag_effects_allowed_,
-          e.modifiers));
+  blink::WebDragOperation drag_effect = view_->dragTargetDragOver(
+      client_point,
+      screen_point,
+      current_drag_effects_allowed_,
+      e.modifiers);
+
+  // Bail if dragover caused cancellation.
+  if (current_drag_data_.isNull())
+    return;
+
+  FinishDragAndDrop(e, drag_effect);
 }
 
 void EventSender::DoMouseMove(const WebMouseEvent& e) {
diff --git a/components/test_runner/test_runner.gyp b/components/test_runner/test_runner.gyp
index ee4829e..4b67c3d5 100644
--- a/components/test_runner/test_runner.gyp
+++ b/components/test_runner/test_runner.gyp
@@ -91,17 +91,15 @@
         'spell_check_client.h',
         'test_common.cc',
         'test_common.h',
-        'test_info_extractor.cc',
-        'test_info_extractor.h',
         'test_interfaces.cc',
         'test_interfaces.h',
         'test_plugin.cc',
         'test_plugin.h',
+        'test_preferences.cc',
+        'test_preferences.h',
         'test_runner.cc',
         'test_runner.h',
         'test_runner_export.h',
-        'test_preferences.cc',
-        'test_preferences.h',
         'text_input_controller.cc',
         'text_input_controller.h',
         'web_ax_object_proxy.cc',
diff --git a/components/toolbar.gypi b/components/toolbar.gypi
index e15ebcae4..301edb1 100644
--- a/components/toolbar.gypi
+++ b/components/toolbar.gypi
@@ -39,6 +39,7 @@
       'target_name': 'toolbar_test_support',
       'type': 'static_library',
       'dependencies': [
+        'components_resources.gyp:components_resources',
         'toolbar',
       ],
       'include_dirs': [
diff --git a/components/tracing/trace_config_file.cc b/components/tracing/trace_config_file.cc
index 3e64724b..670bcc9c 100644
--- a/components/tracing/trace_config_file.cc
+++ b/components/tracing/trace_config_file.cc
@@ -82,9 +82,9 @@
   }
 
   std::string trace_config_file_content;
-  if (!base::ReadFileToString(trace_config_file,
-                              &trace_config_file_content,
-                              kTraceConfigFileSizeLimit)) {
+  if (!base::ReadFileToStringWithMaxSize(trace_config_file,
+                                         &trace_config_file_content,
+                                         kTraceConfigFileSizeLimit)) {
     DLOG(WARNING) << "Cannot read the trace config file correctly.";
     return;
   }
diff --git a/components/user_manager/BUILD.gn b/components/user_manager/BUILD.gn
index 32fbdc2..19bc615 100644
--- a/components/user_manager/BUILD.gn
+++ b/components/user_manager/BUILD.gn
@@ -46,9 +46,9 @@
   }
 }
 
-source_set("test_support") {
-  testonly = true
-  if (is_chromeos) {
+if (is_chromeos) {
+  source_set("test_support") {
+    testonly = true
     sources = [
       "fake_user_manager.cc",
       "fake_user_manager.h",
@@ -62,4 +62,18 @@
       "//ui/base",
     ]
   }
+
+  source_set("unit_tests") {
+    testonly = true
+    sources = [
+      "user_unittest.cc",
+    ]
+    deps = [
+      ":user_manager",
+      "//components/signin/core/account_id",
+      "//skia",
+      "//testing/gtest",
+      "//ui/gfx",
+    ]
+  }
 }
diff --git a/components/user_manager/fake_user_manager.cc b/components/user_manager/fake_user_manager.cc
index 7dca0e54..7efb1d3 100644
--- a/components/user_manager/fake_user_manager.cc
+++ b/components/user_manager/fake_user_manager.cc
@@ -47,7 +47,7 @@
     const AccountId& account_id,
     bool is_affiliated) {
   user_manager::User* user = user_manager::User::CreateRegularUser(account_id);
-  user->set_affiliation(is_affiliated);
+  user->SetAffiliation(is_affiliated);
   users_.push_back(user);
   return user;
 }
diff --git a/components/user_manager/user.cc b/components/user_manager/user.cc
index 2a09a22..a77ab8b 100644
--- a/components/user_manager/user.cc
+++ b/components/user_manager/user.cc
@@ -69,7 +69,22 @@
   DISALLOW_COPY_AND_ASSIGN(GuestUser);
 };
 
-class KioskAppUser : public User {
+class DeviceLocalAccountUserBase : public User {
+ public:
+  // User:
+  bool IsAffiliated() const override;
+
+ protected:
+  explicit DeviceLocalAccountUserBase(const AccountId& account_id);
+  ~DeviceLocalAccountUserBase() override;
+  // User:
+  void SetAffiliation(bool) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DeviceLocalAccountUserBase);
+};
+
+class KioskAppUser : public DeviceLocalAccountUserBase {
  public:
   explicit KioskAppUser(const AccountId& kiosk_app_account_id);
   ~KioskAppUser() override;
@@ -94,7 +109,7 @@
   DISALLOW_COPY_AND_ASSIGN(SupervisedUser);
 };
 
-class PublicAccountUser : public User {
+class PublicAccountUser : public DeviceLocalAccountUserBase {
  public:
   explicit PublicAccountUser(const AccountId& account_id);
   ~PublicAccountUser() override;
@@ -181,6 +196,14 @@
   return is_active_;
 }
 
+bool User::IsAffiliated() const {
+  return is_affiliated_;
+}
+
+void User::SetAffiliation(bool is_affiliated) {
+  is_affiliated_ = is_affiliated;
+}
+
 User* User::CreateRegularUser(const AccountId& account_id) {
   return new RegularUser(account_id);
 }
@@ -265,8 +288,25 @@
   return user_manager::USER_TYPE_GUEST;
 }
 
+DeviceLocalAccountUserBase::DeviceLocalAccountUserBase(
+    const AccountId& account_id) : User(account_id) {
+}
+
+DeviceLocalAccountUserBase::~DeviceLocalAccountUserBase() {
+}
+
+bool DeviceLocalAccountUserBase::IsAffiliated() const {
+  return true;
+}
+
+void DeviceLocalAccountUserBase::SetAffiliation(bool) {
+  // Device local accounts are always affiliated. No affiliation modification
+  // must happen.
+  NOTREACHED();
+}
+
 KioskAppUser::KioskAppUser(const AccountId& kiosk_app_account_id)
-    : User(kiosk_app_account_id) {
+    : DeviceLocalAccountUserBase(kiosk_app_account_id) {
   set_display_email(kiosk_app_account_id.GetUserEmail());
 }
 
@@ -293,7 +333,7 @@
 }
 
 PublicAccountUser::PublicAccountUser(const AccountId& account_id)
-    : User(account_id) {}
+    : DeviceLocalAccountUserBase(account_id) {}
 
 PublicAccountUser::~PublicAccountUser() {
 }
diff --git a/components/user_manager/user.h b/components/user_manager/user.h
index 2f5542a5..0d6431b6 100644
--- a/components/user_manager/user.h
+++ b/components/user_manager/user.h
@@ -8,6 +8,7 @@
 #include <string>
 #include <vector>
 
+#include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/strings/string16.h"
 #include "components/signin/core/account_id/account_id.h"
@@ -79,19 +80,6 @@
   // Returns true if user type has gaia account.
   static bool TypeHasGaiaAccount(UserType user_type);
 
-  // Returns the user type.
-  virtual UserType GetType() const = 0;
-
-  // The email the user used to log in.
-  // TODO(alemate): rename this to GetUserEmail() (see crbug.com/548923)
-  const std::string& email() const;
-
-  // The displayed user name.
-  base::string16 display_name() const { return display_name_; }
-
-  // If the user has to use SAML to log in.
-  bool using_saml() const { return using_saml_; }
-
   // UserInfo
   std::string GetEmail() const override;
   base::string16 GetDisplayName() const override;
@@ -99,6 +87,9 @@
   const gfx::ImageSkia& GetImage() const override;
   const AccountId& GetAccountId() const override;
 
+  // Returns the user type.
+  virtual UserType GetType() const = 0;
+
   // Allows managing child status of the user. Used for RegularUser.
   virtual void SetIsChild(bool is_child);
 
@@ -109,6 +100,25 @@
   // Returns true if user is supervised.
   virtual bool IsSupervised() const;
 
+  // True if user image can be synced.
+  virtual bool CanSyncImage() const;
+
+  // The displayed (non-canonical) user email.
+  virtual std::string display_email() const;
+
+  // True if the user is affiliated to the device.
+  virtual bool IsAffiliated() const;
+
+  // The email the user used to log in.
+  // TODO(alemate): rename this to GetUserEmail() (see crbug.com/548923)
+  const std::string& email() const;
+
+  // The displayed user name.
+  base::string16 display_name() const { return display_name_; }
+
+  // If the user has to use SAML to log in.
+  bool using_saml() const { return using_saml_; }
+
   // Returns the account name part of the email. Use the display form of the
   // email if available and use_display_name == true. Otherwise use canonical.
   std::string GetAccountName(bool use_display_email) const;
@@ -116,9 +126,6 @@
   // Whether the user has a default image.
   bool HasDefaultImage() const;
 
-  // True if user image can be synced.
-  virtual bool CanSyncImage() const;
-
   int image_index() const { return image_index_; }
   bool has_raw_image() const { return user_image_.has_raw_image(); }
   // Returns raw representation of static user image.
@@ -140,9 +147,6 @@
   // True if image is being loaded from file.
   bool image_is_loading() const { return image_is_loading_; }
 
-  // The displayed (non-canonical) user email.
-  virtual std::string display_email() const;
-
   // OAuth token status for this user.
   OAuthTokenStatus oauth_token_status() const { return oauth_token_status_; }
 
@@ -166,9 +170,6 @@
   // True if the user Profile is created.
   bool is_profile_created() const { return profile_is_created_; }
 
-  // True if the user is affiliated to the device.
-  bool is_affiliated() const { return is_affiliated_; }
-
  protected:
   friend class UserManagerBase;
   friend class chromeos::ChromeUserManagerImpl;
@@ -181,6 +182,7 @@
   friend class chromeos::FakeChromeUserManager;
   friend class chromeos::MockUserManager;
   friend class chromeos::UserAddingScreenTest;
+  FRIEND_TEST_ALL_PREFIXES(UserTest, DeviceLocalAccountAffiliation);
 
   // Do not allow anyone else to create new User instances.
   static User* CreateRegularUser(const AccountId& account_id);
@@ -247,9 +249,7 @@
   // True if user has google account (not a guest or managed user).
   bool has_gaia_account() const;
 
-  void set_affiliation(bool is_affiliated) {
-    is_affiliated_ = is_affiliated;
-  }
+  virtual void SetAffiliation(bool is_affiliated);
 
  private:
   AccountId account_id_;
diff --git a/components/user_manager/user_unittest.cc b/components/user_manager/user_unittest.cc
new file mode 100644
index 0000000..dcc4019
--- /dev/null
+++ b/components/user_manager/user_unittest.cc
@@ -0,0 +1,45 @@
+// Copyright 2016 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 "components/user_manager/user.h"
+
+#include "components/signin/core/account_id/account_id.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace user_manager {
+
+namespace {
+
+const char kEmail[] = "email@example.com";
+const char kGaiaId[] = "fake_gaia_id";
+
+}  // namespace
+
+TEST(UserTest, DeviceLocalAccountAffiliation) {
+  // This implementation of RAII for User* is to prevent memory leak.
+  // Smart pointers are not friends of User and can't call protected destructor.
+  class ScopedUser {
+   public:
+    ScopedUser(const User* const user) : user_(user) {}
+    ~ScopedUser() { delete user_; }
+
+    bool IsAffiliated() const { return user_ && user_->IsAffiliated(); }
+
+   private:
+    const User* const user_;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedUser);
+  };
+
+  const AccountId account_id = AccountId::FromUserEmailGaiaId(kEmail, kGaiaId);
+
+  ScopedUser kiosk_user(User::CreateKioskAppUser(account_id));
+  EXPECT_TRUE(kiosk_user.IsAffiliated());
+
+  ScopedUser public_session_user(User::CreatePublicAccountUser(account_id));
+  EXPECT_TRUE(public_session_user.IsAffiliated());
+
+}
+
+}  // namespace user_manager
diff --git a/components/user_prefs/tracked/pref_hash_filter.cc b/components/user_prefs/tracked/pref_hash_filter.cc
index 6d8e6285..a9b4183 100644
--- a/components/user_prefs/tracked/pref_hash_filter.cc
+++ b/components/user_prefs/tracked/pref_hash_filter.cc
@@ -36,6 +36,8 @@
       "safebrowsing.incident_report_sent",
       // TODO(mad): Remove in M48+.
       "software_reporter.prompt_reason",
+      // TODO(zea): Remove in M52+,
+      "sync.remaining_rollback_tries"
   };
 
   for (size_t i = 0; i < arraysize(kDeprecatedTrackedPreferences); ++i) {
diff --git a/content/browser/DEPS b/content/browser/DEPS
index d95f3e7c..8a7a51a9 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   # Allow inclusion of specific components that we depend on. We may only
   # depend on components which we share with the mojo html_viewer.
+  "+components/leveldb/public/interfaces",
   "+components/mime_util",
   "+components/mus/public/interfaces",
   "+components/mus/public",
@@ -15,6 +16,7 @@
   "+gin/v8_initializer.h",
   "+media/media_features.h",
   "+media/audio",  # For audio input for speech input feature.
+  "+media/capture",  # For Video Device monitoring in Mac.
   "+media/base",  # For Android JNI registration.
   "+media/capture",  # For Device Monitoring
   "+media/filters",  # For reporting GPU decoding UMA.
diff --git a/content/browser/accessibility/browser_accessibility_android.cc b/content/browser/accessibility/browser_accessibility_android.cc
index f9e3aa55..3cc4c5e 100644
--- a/content/browser/accessibility/browser_accessibility_android.cc
+++ b/content/browser/accessibility/browser_accessibility_android.cc
@@ -1333,9 +1333,8 @@
 }
 
 bool BrowserAccessibilityAndroid::IsIframe() const {
-  base::string16 html_tag = GetString16Attribute(
-      ui::AX_ATTR_HTML_TAG);
-  return html_tag == base::ASCIIToUTF16("iframe");
+  return (GetRole() == ui::AX_ROLE_IFRAME ||
+          GetRole() == ui::AX_ROLE_IFRAME_PRESENTATIONAL);
 }
 
 void BrowserAccessibilityAndroid::OnDataChanged() {
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index 3ab3d20..84415e1 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -218,39 +218,19 @@
     return [](BrowserAccessibility* start, BrowserAccessibility* current) {
       return true;
     };
-  } else if ([searchKey isEqualToString:@"AXBlockquoteSameLevelSearchKey"] ||
-             [searchKey isEqualToString:@"AXBlockquoteSearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      // TODO(dmazzoni): implement the "same level" part.
-      return current->GetRole() == ui::AX_ROLE_BLOCKQUOTE;
-    };
+  } else if ([searchKey isEqualToString:@"AXBlockquoteSameLevelSearchKey"]) {
+    // TODO(dmazzoni): implement the "same level" part.
+    return content::AccessibilityBlockquotePredicate;
+  } else if ([searchKey isEqualToString:@"AXBlockquoteSearchKey"]) {
+    return content::AccessibilityBlockquotePredicate;
   } else if ([searchKey isEqualToString:@"AXBoldFontSearchKey"]) {
-    // TODO(dmazzoni): implement this.
-    return nullptr;
+    return content::AccessibilityTextStyleBoldPredicate;
   } else if ([searchKey isEqualToString:@"AXButtonSearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      return (current->GetRole() == ui::AX_ROLE_BUTTON ||
-              current->GetRole() == ui::AX_ROLE_MENU_BUTTON ||
-              current->GetRole() == ui::AX_ROLE_POP_UP_BUTTON ||
-              current->GetRole() == ui::AX_ROLE_SWITCH ||
-              current->GetRole() == ui::AX_ROLE_TOGGLE_BUTTON);
-    };
+    return content::AccessibilityButtonPredicate;
   } else if ([searchKey isEqualToString:@"AXCheckBoxSearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      return (current->GetRole() == ui::AX_ROLE_CHECK_BOX ||
-              current->GetRole() == ui::AX_ROLE_MENU_ITEM_CHECK_BOX);
-    };
+    return content::AccessibilityCheckboxPredicate;
   } else if ([searchKey isEqualToString:@"AXControlSearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      if (current->IsControl())
-        return true;
-      if (current->HasState(ui::AX_STATE_FOCUSABLE) &&
-          current->GetRole() != ui::AX_ROLE_IMAGE_MAP_LINK &&
-          current->GetRole() != ui::AX_ROLE_LINK) {
-        return true;
-      }
-      return false;
-    };
+    return content::AccessibilityControlPredicate;
   } else if ([searchKey isEqualToString:@"AXDifferentTypeSearchKey"]) {
     return [](BrowserAccessibility* start, BrowserAccessibility* current) {
       return current->GetRole() != start->GetRole();
@@ -262,102 +242,48 @@
     // TODO(dmazzoni): implement this.
     return nullptr;
   } else if ([searchKey isEqualToString:@"AXFrameSearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      if (current->IsWebAreaForPresentationalIframe())
-        return false;
-      if (!current->GetParent())
-        return false;
-      return (current->GetRole() == ui::AX_ROLE_WEB_AREA ||
-              current->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA);
-    };
+    return content::AccessibilityFramePredicate;
   } else if ([searchKey isEqualToString:@"AXGraphicSearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      return current->GetRole() == ui::AX_ROLE_IMAGE;
-    };
+    return content::AccessibilityGraphicPredicate;
   } else if ([searchKey isEqualToString:@"AXHeadingLevel1SearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      return (current->GetRole() == ui::AX_ROLE_HEADING &&
-              current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 1);
-    };
+    return content::AccessibilityH1Predicate;
   } else if ([searchKey isEqualToString:@"AXHeadingLevel2SearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      return (current->GetRole() == ui::AX_ROLE_HEADING &&
-              current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 2);
-    };
+    return content::AccessibilityH2Predicate;
   } else if ([searchKey isEqualToString:@"AXHeadingLevel3SearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      return (current->GetRole() == ui::AX_ROLE_HEADING &&
-              current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 3);
-    };
+    return content::AccessibilityH3Predicate;
   } else if ([searchKey isEqualToString:@"AXHeadingLevel4SearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      return (current->GetRole() == ui::AX_ROLE_HEADING &&
-              current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 4);
-    };
+    return content::AccessibilityH4Predicate;
   } else if ([searchKey isEqualToString:@"AXHeadingLevel5SearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      return (current->GetRole() == ui::AX_ROLE_HEADING &&
-              current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 5);
-    };
+    return content::AccessibilityH5Predicate;
   } else if ([searchKey isEqualToString:@"AXHeadingLevel6SearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      return (current->GetRole() == ui::AX_ROLE_HEADING &&
-              current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 6);
-    };
+    return content::AccessibilityH6Predicate;
   } else if ([searchKey isEqualToString:@"AXHeadingSameLevelSearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      return (current->GetRole() == ui::AX_ROLE_HEADING &&
-              start->GetRole() == ui::AX_ROLE_HEADING &&
-              (current->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) ==
-               start->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL)));
-    };
+    return content::AccessibilityHeadingSameLevelPredicate;
   } else if ([searchKey isEqualToString:@"AXHeadingSearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      return current->GetRole() == ui::AX_ROLE_HEADING;
-    };
+    return content::AccessibilityHeadingPredicate;
   } else if ([searchKey isEqualToString:@"AXHighlightedSearchKey"]) {
     // TODO(dmazzoni): implement this.
     return nullptr;
   } else if ([searchKey isEqualToString:@"AXItalicFontSearchKey"]) {
-    // TODO(dmazzoni): implement this.
-    return nullptr;
+    return content::AccessibilityTextStyleItalicPredicate;
   } else if ([searchKey isEqualToString:@"AXLandmarkSearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      return (current->GetRole() == ui::AX_ROLE_APPLICATION ||
-              current->GetRole() == ui::AX_ROLE_BANNER ||
-              current->GetRole() == ui::AX_ROLE_COMPLEMENTARY ||
-              current->GetRole() == ui::AX_ROLE_CONTENT_INFO ||
-              current->GetRole() == ui::AX_ROLE_FORM ||
-              current->GetRole() == ui::AX_ROLE_MAIN ||
-              current->GetRole() == ui::AX_ROLE_NAVIGATION ||
-              current->GetRole() == ui::AX_ROLE_SEARCH);
-    };
+    return content::AccessibilityLandmarkPredicate;
   } else if ([searchKey isEqualToString:@"AXLinkSearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      return current->GetRole() == ui::AX_ROLE_LINK;
-    };
+    return content::AccessibilityLinkPredicate;
   } else if ([searchKey isEqualToString:@"AXListSearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      return current->GetRole() == ui::AX_ROLE_LIST;
-    };
+    return content::AccessibilityListPredicate;
   } else if ([searchKey isEqualToString:@"AXLiveRegionSearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      return current->HasStringAttribute(ui::AX_ATTR_LIVE_STATUS);
-    };
+    return content::AccessibilityLiveRegionPredicate;
   } else if ([searchKey isEqualToString:@"AXMisspelledWordSearchKey"]) {
     // TODO(dmazzoni): implement this.
     return nullptr;
   } else if ([searchKey isEqualToString:@"AXOutlineSearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      return current->GetRole() == ui::AX_ROLE_TREE;
-    };
+    return content::AccessibilityTreePredicate;
   } else if ([searchKey isEqualToString:@"AXPlainTextSearchKey"]) {
     // TODO(dmazzoni): implement this.
     return nullptr;
   } else if ([searchKey isEqualToString:@"AXRadioGroupSearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      return current->GetRole() == ui::AX_ROLE_RADIO_GROUP;
-    };
+    return content::AccessibilityRadioGroupPredicate;
   } else if ([searchKey isEqualToString:@"AXSameTypeSearchKey"]) {
     return [](BrowserAccessibility* start, BrowserAccessibility* current) {
       return current->GetRole() == start->GetRole();
@@ -370,33 +296,18 @@
     // TODO(dmazzoni): implement this.
     return nullptr;
   } else if ([searchKey isEqualToString:@"AXTableSameLevelSearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      // TODO(dmazzoni): implement the "same level" part.
-      return current->GetRole() == ui::AX_ROLE_GRID ||
-             current->GetRole() == ui::AX_ROLE_TABLE;
-    };
+    // TODO(dmazzoni): implement the "same level" part.
+    return content::AccessibilityTablePredicate;
   } else if ([searchKey isEqualToString:@"AXTableSearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      return current->GetRole() == ui::AX_ROLE_GRID ||
-             current->GetRole() == ui::AX_ROLE_TABLE;
-    };
+    return content::AccessibilityTablePredicate;
   } else if ([searchKey isEqualToString:@"AXTextFieldSearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      return current->IsSimpleTextControl() || current->IsRichTextControl();
-    };
+    return content::AccessibilityTextfieldPredicate;
   } else if ([searchKey isEqualToString:@"AXUnderlineSearchKey"]) {
-    // TODO(dmazzoni): implement this.
-    return nullptr;
+    return content::AccessibilityTextStyleUnderlinePredicate;
   } else if ([searchKey isEqualToString:@"AXUnvisitedLinkSearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      return (current->GetRole() == ui::AX_ROLE_LINK &&
-              !current->HasState(ui::AX_STATE_VISITED));
-    };
+    return content::AccessibilityUnvisitedLinkPredicate;
   } else if ([searchKey isEqualToString:@"AXVisitedLinkSearchKey"]) {
-    return [](BrowserAccessibility* start, BrowserAccessibility* current) {
-      return (current->GetRole() == ui::AX_ROLE_LINK &&
-              current->HasState(ui::AX_STATE_VISITED));
-    };
+    return content::AccessibilityVisitedLinkPredicate;
   }
 
   return nullptr;
diff --git a/content/browser/accessibility/browser_accessibility_manager.h b/content/browser/accessibility/browser_accessibility_manager.h
index 66d9d5d..da1ded8d 100644
--- a/content/browser/accessibility/browser_accessibility_manager.h
+++ b/content/browser/accessibility/browser_accessibility_manager.h
@@ -219,7 +219,7 @@
 
   // Called when the renderer process updates the location of accessibility
   // objects.
-  void OnLocationChanges(
+  virtual void OnLocationChanges(
       const std::vector<AccessibilityHostMsg_LocationChangeParams>& params);
 
   // Called when a new find in page result is received. We hold on to this
diff --git a/content/browser/accessibility/browser_accessibility_manager_android.cc b/content/browser/accessibility/browser_accessibility_manager_android.cc
index 99000dd..9c7a316 100644
--- a/content/browser/accessibility/browser_accessibility_manager_android.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_android.cc
@@ -15,6 +15,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "content/browser/accessibility/browser_accessibility_android.h"
+#include "content/browser/accessibility/one_shot_accessibility_tree_search.h"
 #include "content/common/accessibility_messages.h"
 #include "jni/BrowserAccessibilityManager_jni.h"
 #include "ui/accessibility/ax_text_utils.h"
@@ -22,32 +23,97 @@
 using base::android::AttachCurrentThread;
 using base::android::ScopedJavaLocalRef;
 
-namespace {
+namespace content {
 
-enum AndroidHtmlElementType {
-  HTML_ELEMENT_TYPE_SECTION,
-  HTML_ELEMENT_TYPE_LIST,
-  HTML_ELEMENT_TYPE_CONTROL,
-  HTML_ELEMENT_TYPE_ANY
-};
+namespace {
 
 // These are special unofficial strings sent from TalkBack/BrailleBack
 // to jump to certain categories of web elements.
-AndroidHtmlElementType HtmlElementTypeFromString(base::string16 element_type) {
-  if (element_type == base::ASCIIToUTF16("SECTION"))
-    return HTML_ELEMENT_TYPE_SECTION;
-  else if (element_type == base::ASCIIToUTF16("LIST"))
-    return HTML_ELEMENT_TYPE_LIST;
-  else if (element_type == base::ASCIIToUTF16("CONTROL"))
-    return HTML_ELEMENT_TYPE_CONTROL;
-  else
-    return HTML_ELEMENT_TYPE_ANY;
+AccessibilityMatchPredicate PredicateForSearchKey(base::string16 element_type) {
+  if (element_type == base::ASCIIToUTF16("SECTION")) {
+    return [](BrowserAccessibility* start, BrowserAccessibility* node) {
+      switch (node->GetRole()) {
+        case ui::AX_ROLE_ARTICLE:
+        case ui::AX_ROLE_APPLICATION:
+        case ui::AX_ROLE_BANNER:
+        case ui::AX_ROLE_COMPLEMENTARY:
+        case ui::AX_ROLE_CONTENT_INFO:
+        case ui::AX_ROLE_HEADING:
+        case ui::AX_ROLE_MAIN:
+        case ui::AX_ROLE_NAVIGATION:
+        case ui::AX_ROLE_SEARCH:
+        case ui::AX_ROLE_REGION:
+          return true;
+        default:
+          return false;
+      }
+    };
+  } else if (element_type == base::ASCIIToUTF16("LIST")) {
+    return AccessibilityListPredicate;
+  } else if (element_type == base::ASCIIToUTF16("CONTROL")) {
+    return AccessibilityControlPredicate;
+  } else if (element_type == base::ASCIIToUTF16("ARTICLE")) {
+    return AccessibilityArticlePredicate;
+  } else if (element_type == base::ASCIIToUTF16("BUTTON")) {
+    return AccessibilityButtonPredicate;
+  } else if (element_type == base::ASCIIToUTF16("CHECKBOX")) {
+    return AccessibilityCheckboxPredicate;
+  } else if (element_type == base::ASCIIToUTF16("COMBOBOX")) {
+    return AccessibilityComboboxPredicate;
+  } else if (element_type == base::ASCIIToUTF16("TEXT_FIELD")) {
+    return AccessibilityTextfieldPredicate;
+  } else if (element_type == base::ASCIIToUTF16("FOCUSABLE")) {
+    return AccessibilityFocusablePredicate;
+  } else if (element_type == base::ASCIIToUTF16("GRAPHIC")) {
+    return AccessibilityGraphicPredicate;
+  } else if (element_type == base::ASCIIToUTF16("HEADING")) {
+    return AccessibilityHeadingPredicate;
+  } else if (element_type == base::ASCIIToUTF16("H1")) {
+    return AccessibilityH1Predicate;
+  } else if (element_type == base::ASCIIToUTF16("H2")) {
+    return AccessibilityH2Predicate;
+  } else if (element_type == base::ASCIIToUTF16("H3")) {
+    return AccessibilityH3Predicate;
+  } else if (element_type == base::ASCIIToUTF16("H4")) {
+    return AccessibilityH4Predicate;
+  } else if (element_type == base::ASCIIToUTF16("H5")) {
+    return AccessibilityH5Predicate;
+  } else if (element_type == base::ASCIIToUTF16("H6")) {
+    return AccessibilityH6Predicate;
+  } else if (element_type == base::ASCIIToUTF16("FRAME")) {
+    return AccessibilityFramePredicate;
+  } else if (element_type == base::ASCIIToUTF16("LANDMARK")) {
+    return AccessibilityLandmarkPredicate;
+  } else if (element_type == base::ASCIIToUTF16("LINK")) {
+    return AccessibilityLinkPredicate;
+  } else if (element_type == base::ASCIIToUTF16("LIST_ITEM")) {
+    return AccessibilityListItemPredicate;
+  } else if (element_type == base::ASCIIToUTF16("MAIN")) {
+    return AccessibilityMainPredicate;
+  } else if (element_type == base::ASCIIToUTF16("MEDIA")) {
+    return AccessibilityMediaPredicate;
+  } else if (element_type == base::ASCIIToUTF16("RADIO")) {
+    return AccessibilityRadioButtonPredicate;
+  } else if (element_type == base::ASCIIToUTF16("TABLE")) {
+    return AccessibilityTablePredicate;
+  } else if (element_type == base::ASCIIToUTF16("UNVISITED_LINK")) {
+    return AccessibilityUnvisitedLinkPredicate;
+  } else if (element_type == base::ASCIIToUTF16("VISITED_LINK")) {
+    return AccessibilityVisitedLinkPredicate;
+  }
+
+  // If we don't recognize the selector, return any element that's clickable.
+  // We mark all focusable nodes and leaf nodes as clickable because it's
+  // impossible to know whether a web node has a click handler or not, so
+  // to be safe we have to allow accessibility services to click on nearly
+  // anything that could possibly respond to a click.
+  return [](BrowserAccessibility* start, BrowserAccessibility* node) {
+    return static_cast<BrowserAccessibilityAndroid*>(node)->IsClickable();
+  };
 }
 
 }  // anonymous namespace
 
-namespace content {
-
 namespace aria_strings {
   const char kAriaLivePolite[] = "polite";
   const char kAriaLiveAssertive[] = "assertive";
@@ -129,6 +195,10 @@
   if (event_type == ui::AX_EVENT_TREE_CHANGED)
     return;
 
+  // Layout changes are handled in OnLocationChanges.
+  if (event_type == ui::AX_EVENT_LAYOUT_COMPLETE)
+    return;
+
   if (event_type == ui::AX_EVENT_HOVER) {
     HandleHoverEvent(node);
     return;
@@ -198,6 +268,25 @@
   }
 }
 
+void BrowserAccessibilityManagerAndroid::OnLocationChanges(
+      const std::vector<AccessibilityHostMsg_LocationChangeParams>& params) {
+  // Android is not very efficient at handling notifications, and location
+  // changes in particular are frequent and not time-critical. If a lot of
+  // nodes changed location, just send a single notification after a short
+  // delay (to batch them), rather than lots of individual notifications.
+  if (params.size() > 3) {
+    JNIEnv* env = AttachCurrentThread();
+    ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
+    if (obj.is_null())
+      return;
+    Java_BrowserAccessibilityManager_sendDelayedWindowContentChangedEvent(
+        env, obj.obj());
+    return;
+  }
+
+  BrowserAccessibilityManager::OnLocationChanges(params);
+}
+
 jint BrowserAccessibilityManagerAndroid::GetRootId(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj) {
@@ -601,58 +690,36 @@
     jint start_id,
     const JavaParamRef<jstring>& element_type_str,
     jboolean forwards) {
-  BrowserAccessibility* node = GetFromID(start_id);
-  if (!node)
+  BrowserAccessibility* start_node = GetFromID(start_id);
+  if (!start_node)
     return 0;
 
-  AndroidHtmlElementType element_type = HtmlElementTypeFromString(
+  BrowserAccessibilityManager* root_manager = GetRootManager();
+  if (!root_manager)
+    return 0;
+
+  BrowserAccessibility* root = root_manager->GetRoot();
+  if (!root)
+    return 0;
+
+  AccessibilityMatchPredicate predicate = PredicateForSearchKey(
       base::android::ConvertJavaStringToUTF16(env, element_type_str));
 
-  node = forwards ? NextInTreeOrder(node) : PreviousInTreeOrder(node);
-  while (node) {
-    switch(element_type) {
-      case HTML_ELEMENT_TYPE_SECTION:
-        if (node->GetRole() == ui::AX_ROLE_ARTICLE ||
-            node->GetRole() == ui::AX_ROLE_APPLICATION ||
-            node->GetRole() == ui::AX_ROLE_BANNER ||
-            node->GetRole() == ui::AX_ROLE_COMPLEMENTARY ||
-            node->GetRole() == ui::AX_ROLE_CONTENT_INFO ||
-            node->GetRole() == ui::AX_ROLE_HEADING ||
-            node->GetRole() == ui::AX_ROLE_MAIN ||
-            node->GetRole() == ui::AX_ROLE_NAVIGATION ||
-            node->GetRole() == ui::AX_ROLE_SEARCH ||
-            node->GetRole() == ui::AX_ROLE_REGION) {
-          return node->GetId();
-        }
-        break;
-      case HTML_ELEMENT_TYPE_LIST:
-        if (node->GetRole() == ui::AX_ROLE_LIST ||
-            node->GetRole() == ui::AX_ROLE_GRID ||
-            node->GetRole() == ui::AX_ROLE_TABLE ||
-            node->GetRole() == ui::AX_ROLE_TREE) {
-          return node->GetId();
-        }
-        break;
-      case HTML_ELEMENT_TYPE_CONTROL:
-        if (static_cast<BrowserAccessibilityAndroid*>(node)->IsFocusable())
-          return node->GetId();
-        break;
-      case HTML_ELEMENT_TYPE_ANY:
-        // In theory, the API says that an accessibility service could
-        // jump to an element by element name, like 'H1' or 'P'. This isn't
-        // currently used by any accessibility service, and we think it's
-        // better to keep them high-level like 'SECTION' or 'CONTROL', so we
-        // just fall back on linear navigation when we don't recognize the
-        // element type.
-        if (static_cast<BrowserAccessibilityAndroid*>(node)->IsClickable())
-          return node->GetId();
-        break;
-    }
+  OneShotAccessibilityTreeSearch tree_search(root);
+  tree_search.SetStartNode(start_node);
+  tree_search.SetDirection(
+      forwards ?
+          OneShotAccessibilityTreeSearch::FORWARDS :
+          OneShotAccessibilityTreeSearch::BACKWARDS);
+  tree_search.SetResultLimit(1);
+  tree_search.SetImmediateDescendantsOnly(false);
+  tree_search.SetVisibleOnly(false);
+  tree_search.AddPredicate(predicate);
 
-    node = forwards ? NextInTreeOrder(node) : PreviousInTreeOrder(node);
-  }
+  if (tree_search.CountMatches() == 0)
+    return 0;
 
-  return 0;
+  return tree_search.GetMatchAtIndex(0)->GetId();
 }
 
 jboolean BrowserAccessibilityManagerAndroid::NextAtGranularity(
diff --git a/content/browser/accessibility/browser_accessibility_manager_android.h b/content/browser/accessibility/browser_accessibility_manager_android.h
index 404676bb..4bc42b5 100644
--- a/content/browser/accessibility/browser_accessibility_manager_android.h
+++ b/content/browser/accessibility/browser_accessibility_manager_android.h
@@ -77,6 +77,9 @@
   // Implementation of BrowserAccessibilityManager.
   void NotifyAccessibilityEvent(ui::AXEvent event_type,
                                 BrowserAccessibility* node) override;
+  void OnLocationChanges(
+      const std::vector<AccessibilityHostMsg_LocationChangeParams>& params)
+          override;
 
   // --------------------------------------------------------------------------
   // Methods called from Java via JNI
diff --git a/content/browser/accessibility/browser_accessibility_manager_win.cc b/content/browser/accessibility/browser_accessibility_manager_win.cc
index a02cc9a..a60b749 100644
--- a/content/browser/accessibility/browser_accessibility_manager_win.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_win.cc
@@ -47,6 +47,7 @@
       inside_on_window_focused_(false) {
   ui::win::CreateATLModuleIfNeeded();
   Initialize(initial_tree);
+  ui::GetIAccessible2UsageObserverList().AddObserver(this);
 }
 
 BrowserAccessibilityManagerWin::~BrowserAccessibilityManagerWin() {
@@ -59,6 +60,7 @@
     tracked_scroll_object_->Release();
     tracked_scroll_object_ = NULL;
   }
+  ui::GetIAccessible2UsageObserverList().RemoveObserver(this);
 }
 
 // static
@@ -151,6 +153,10 @@
   ::NotifyWinEvent(event, hwnd, OBJID_CLIENT, child_id);
 }
 
+void BrowserAccessibilityManagerWin::OnIAccessible2Used() {
+  BrowserAccessibilityStateImpl::GetInstance()->OnScreenReaderDetected();
+}
+
 void BrowserAccessibilityManagerWin::OnWindowFocused() {
   // Make sure we don't call this recursively.
   if (inside_on_window_focused_)
diff --git a/content/browser/accessibility/browser_accessibility_manager_win.h b/content/browser/accessibility/browser_accessibility_manager_win.h
index b9da9a1..b505a63 100644
--- a/content/browser/accessibility/browser_accessibility_manager_win.h
+++ b/content/browser/accessibility/browser_accessibility_manager_win.h
@@ -11,13 +11,15 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/win/scoped_comptr.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "ui/accessibility/platform/ax_platform_node_win.h"
 
 namespace content {
 class BrowserAccessibilityWin;
 
 // Manages a tree of BrowserAccessibilityWin objects.
 class CONTENT_EXPORT BrowserAccessibilityManagerWin
-    : public BrowserAccessibilityManager {
+    : public BrowserAccessibilityManager,
+      public ui::IAccessible2UsageObserver {
  public:
   BrowserAccessibilityManagerWin(
       const ui::AXTreeUpdate& initial_tree,
@@ -37,6 +39,9 @@
   // Calls NotifyWinEvent if the parent window's IAccessible pointer is known.
   void MaybeCallNotifyWinEvent(DWORD event, BrowserAccessibility* node);
 
+  // IAccessible2UsageObserver
+  void OnIAccessible2Used() override;
+
   // BrowserAccessibilityManager methods
   void OnWindowFocused() override;
   void UserIsReloading() override;
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index 4b68343..e43d778 100644
--- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -852,6 +852,10 @@
   RunHtmlTest(FILE_PATH_LITERAL("img.html"));
 }
 
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityImgEmptyAlt) {
+  RunHtmlTest(FILE_PATH_LITERAL("img-empty-alt.html"));
+}
+
 IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputButton) {
   RunHtmlTest(FILE_PATH_LITERAL("input-button.html"));
 }
diff --git a/content/browser/accessibility/one_shot_accessibility_tree_search.cc b/content/browser/accessibility/one_shot_accessibility_tree_search.cc
index 8b17f2d..1a0239eb 100644
--- a/content/browser/accessibility/one_shot_accessibility_tree_search.cc
+++ b/content/browser/accessibility/one_shot_accessibility_tree_search.cc
@@ -11,6 +11,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "content/browser/accessibility/browser_accessibility.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
+#include "ui/accessibility/ax_enums.h"
 
 namespace content {
 
@@ -210,4 +211,249 @@
   return true;
 }
 
+//
+// Predicates
+//
+
+bool AccessibilityArticlePredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return node->GetRole() == ui::AX_ROLE_ARTICLE;
+}
+
+bool AccessibilityButtonPredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  switch (node->GetRole()) {
+    case ui::AX_ROLE_BUTTON:
+    case ui::AX_ROLE_MENU_BUTTON:
+    case ui::AX_ROLE_POP_UP_BUTTON:
+    case ui::AX_ROLE_SWITCH:
+    case ui::AX_ROLE_TOGGLE_BUTTON:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool AccessibilityBlockquotePredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return node->GetRole() == ui::AX_ROLE_BLOCKQUOTE;
+}
+
+bool AccessibilityCheckboxPredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return (node->GetRole() == ui::AX_ROLE_CHECK_BOX ||
+          node->GetRole() == ui::AX_ROLE_MENU_ITEM_CHECK_BOX);
+}
+
+bool AccessibilityComboboxPredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return (node->GetRole() == ui::AX_ROLE_COMBO_BOX ||
+          node->GetRole() == ui::AX_ROLE_POP_UP_BUTTON);
+}
+
+bool AccessibilityControlPredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  if (node->IsControl())
+    return true;
+  if (node->HasState(ui::AX_STATE_FOCUSABLE) &&
+      node->GetRole() != ui::AX_ROLE_IFRAME &&
+      node->GetRole() != ui::AX_ROLE_IFRAME_PRESENTATIONAL &&
+      node->GetRole() != ui::AX_ROLE_IMAGE_MAP_LINK &&
+      node->GetRole() != ui::AX_ROLE_LINK &&
+      node->GetRole() != ui::AX_ROLE_WEB_AREA &&
+      node->GetRole() != ui::AX_ROLE_ROOT_WEB_AREA) {
+    return true;
+  }
+  return false;
+}
+
+bool AccessibilityFocusablePredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  bool focusable = node->HasState(ui::AX_STATE_FOCUSABLE);
+  if (node->GetRole() == ui::AX_ROLE_IFRAME ||
+      node->GetRole() == ui::AX_ROLE_IFRAME_PRESENTATIONAL ||
+      node->GetRole() == ui::AX_ROLE_WEB_AREA ||
+      node->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA) {
+    focusable = false;
+  }
+  return focusable;
+}
+
+bool AccessibilityGraphicPredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return node->GetRole() == ui::AX_ROLE_IMAGE;
+}
+
+bool AccessibilityHeadingPredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return (node->GetRole() == ui::AX_ROLE_HEADING);
+}
+
+bool AccessibilityH1Predicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return (node->GetRole() == ui::AX_ROLE_HEADING &&
+          node->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 1);
+}
+
+bool AccessibilityH2Predicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return (node->GetRole() == ui::AX_ROLE_HEADING &&
+          node->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 2);
+}
+
+bool AccessibilityH3Predicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return (node->GetRole() == ui::AX_ROLE_HEADING &&
+          node->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 3);
+}
+
+bool AccessibilityH4Predicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return (node->GetRole() == ui::AX_ROLE_HEADING &&
+          node->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 4);
+}
+
+bool AccessibilityH5Predicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return (node->GetRole() == ui::AX_ROLE_HEADING &&
+          node->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 5);
+}
+
+bool AccessibilityH6Predicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return (node->GetRole() == ui::AX_ROLE_HEADING &&
+          node->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) == 6);
+}
+
+bool AccessibilityHeadingSameLevelPredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return (node->GetRole() == ui::AX_ROLE_HEADING &&
+          start->GetRole() == ui::AX_ROLE_HEADING &&
+          (node->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL) ==
+           start->GetIntAttribute(ui::AX_ATTR_HIERARCHICAL_LEVEL)));
+}
+
+bool AccessibilityFramePredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  if (node->IsWebAreaForPresentationalIframe())
+    return false;
+  if (!node->GetParent())
+    return false;
+  return (node->GetRole() == ui::AX_ROLE_WEB_AREA ||
+          node->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA);
+}
+
+bool AccessibilityLandmarkPredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  switch (node->GetRole()) {
+    case ui::AX_ROLE_APPLICATION:
+    case ui::AX_ROLE_ARTICLE:
+    case ui::AX_ROLE_BANNER:
+    case ui::AX_ROLE_COMPLEMENTARY:
+    case ui::AX_ROLE_CONTENT_INFO:
+    case ui::AX_ROLE_MAIN:
+    case ui::AX_ROLE_NAVIGATION:
+    case ui::AX_ROLE_SEARCH:
+    case ui::AX_ROLE_REGION:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool AccessibilityLinkPredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return (node->GetRole() == ui::AX_ROLE_LINK ||
+          node->GetRole() == ui::AX_ROLE_IMAGE_MAP_LINK);
+}
+
+bool AccessibilityListPredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return (node->GetRole() == ui::AX_ROLE_LIST_BOX ||
+          node->GetRole() == ui::AX_ROLE_LIST ||
+          node->GetRole() == ui::AX_ROLE_DESCRIPTION_LIST);
+}
+
+bool AccessibilityListItemPredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return (node->GetRole() == ui::AX_ROLE_LIST_ITEM ||
+          node->GetRole() == ui::AX_ROLE_DESCRIPTION_LIST_TERM ||
+          node->GetRole() == ui::AX_ROLE_LIST_BOX_OPTION);
+}
+
+bool AccessibilityLiveRegionPredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return node->HasStringAttribute(ui::AX_ATTR_LIVE_STATUS);
+}
+
+bool AccessibilityMainPredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return (node->GetRole() == ui::AX_ROLE_MAIN);
+}
+
+bool AccessibilityMediaPredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  const std::string& tag = node->GetStringAttribute(ui::AX_ATTR_HTML_TAG);
+  return tag == "audio" || tag == "video";
+}
+
+bool AccessibilityRadioButtonPredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return (node->GetRole() == ui::AX_ROLE_RADIO_BUTTON ||
+          node->GetRole() == ui::AX_ROLE_MENU_ITEM_RADIO);
+}
+
+bool AccessibilityRadioGroupPredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return node->GetRole() == ui::AX_ROLE_RADIO_GROUP;
+}
+
+bool AccessibilityTablePredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return (node->GetRole() == ui::AX_ROLE_TABLE ||
+          node->GetRole() == ui::AX_ROLE_GRID);
+}
+
+bool AccessibilityTextfieldPredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return (node->IsSimpleTextControl() || node->IsRichTextControl());
+}
+
+bool AccessibilityTextStyleBoldPredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  int32_t style = node->GetIntAttribute(ui::AX_ATTR_TEXT_STYLE);
+  return 0 != (style & ui::AX_TEXT_STYLE_BOLD);
+}
+
+bool AccessibilityTextStyleItalicPredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  int32_t style = node->GetIntAttribute(ui::AX_ATTR_TEXT_STYLE);
+  return 0 != (style & ui::AX_TEXT_STYLE_BOLD);
+}
+
+bool AccessibilityTextStyleUnderlinePredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  int32_t style = node->GetIntAttribute(ui::AX_ATTR_TEXT_STYLE);
+  return 0 != (style & ui::AX_TEXT_STYLE_UNDERLINE);
+}
+
+bool AccessibilityTreePredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return (node->IsSimpleTextControl() || node->IsRichTextControl());
+}
+
+bool AccessibilityUnvisitedLinkPredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return ((node->GetRole() == ui::AX_ROLE_LINK ||
+           node->GetRole() == ui::AX_ROLE_IMAGE_MAP_LINK) &&
+          !node->HasState(ui::AX_STATE_VISITED));
+}
+
+bool AccessibilityVisitedLinkPredicate(
+    BrowserAccessibility* start, BrowserAccessibility* node) {
+  return ((node->GetRole() == ui::AX_ROLE_LINK ||
+           node->GetRole() == ui::AX_ROLE_IMAGE_MAP_LINK) &&
+          node->HasState(ui::AX_STATE_VISITED));
+}
+
 }  // namespace content
diff --git a/content/browser/accessibility/one_shot_accessibility_tree_search.h b/content/browser/accessibility/one_shot_accessibility_tree_search.h
index 2538bb8..df79eb94 100644
--- a/content/browser/accessibility/one_shot_accessibility_tree_search.h
+++ b/content/browser/accessibility/one_shot_accessibility_tree_search.h
@@ -24,6 +24,47 @@
     BrowserAccessibility* start_element,
     BrowserAccessibility* this_element);
 
+#define DECLARE_ACCESSIBILITY_PREDICATE(PredicateName) \
+    bool PredicateName(BrowserAccessibility* start_element, \
+                       BrowserAccessibility* this_element);
+
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityArticlePredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityBlockquotePredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityButtonPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityCheckboxPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityComboboxPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityControlPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityFocusablePredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityGraphicPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityHeadingPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityH1Predicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityH2Predicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityH3Predicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityH4Predicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityH5Predicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityH6Predicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityHeadingSameLevelPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityFramePredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityLandmarkPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityLinkPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityListPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityListItemPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityLiveRegionPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityMainPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityMediaPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityRadioButtonPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityRadioGroupPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityTablePredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityTextfieldPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityTextStyleBoldPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityTextStyleItalicPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityTextStyleUnderlinePredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityTreePredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityUnvisitedLinkPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityVisitedLinkPredicate);
+DECLARE_ACCESSIBILITY_PREDICATE(AccessibilityTextStyleBoldPredicate);
+
+
 // This class provides an interface for searching the accessibility tree from
 // a given starting node, with a few built-in options and allowing an arbitrary
 // number of predicates that can be used to restrict the search.
diff --git a/content/browser/android/download_controller_android_impl.cc b/content/browser/android/download_controller_android_impl.cc
index 76d7f85d38..1d150ba 100644
--- a/content/browser/android/download_controller_android_impl.cc
+++ b/content/browser/android/download_controller_android_impl.cc
@@ -32,6 +32,7 @@
 #include "content/public/common/content_client.h"
 #include "content/public/common/referrer.h"
 #include "jni/DownloadController_jni.h"
+#include "net/base/filename_util.h"
 #include "net/cookies/cookie_options.h"
 #include "net/cookies/cookie_store.h"
 #include "net/http/http_content_disposition.h"
@@ -211,6 +212,11 @@
       env, GetJavaObject()->Controller(env).obj(), view.obj(), callback_id);
 }
 
+void DownloadControllerAndroidImpl::SetDefaultDownloadFileName(
+    const std::string& file_name) {
+  default_file_name_ = file_name;
+}
+
 bool DownloadControllerAndroidImpl::HasFileAccessPermission(
     ScopedJavaLocalRef<jobject> j_content_view_core) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -388,11 +394,14 @@
   ScopedJavaLocalRef<jstring> jreferer =
       ConvertUTF8ToJavaString(env, info.referer);
 
-  // Try parsing the content disposition header to get a
-  // explicitly specified filename if available.
-  net::HttpContentDisposition header(info.content_disposition, "");
+  // net::GetSuggestedFilename will fallback to "download" as filename.
   ScopedJavaLocalRef<jstring> jfilename =
-      ConvertUTF8ToJavaString(env, header.filename());
+      base::android::ConvertUTF16ToJavaString(
+          env, net::GetSuggestedFilename(info.url, info.content_disposition,
+                                         std::string(),  // referrer_charset
+                                         std::string(),  // suggested_name
+                                         info.original_mime_type,
+                                         default_file_name_));
 
   Java_DownloadController_newHttpGetDownload(
       env, GetJavaObject()->Controller(env).obj(), view.obj(), jurl.obj(),
diff --git a/content/browser/android/download_controller_android_impl.h b/content/browser/android/download_controller_android_impl.h
index 386135e..9045d29 100644
--- a/content/browser/android/download_controller_android_impl.h
+++ b/content/browser/android/download_controller_android_impl.h
@@ -59,6 +59,7 @@
   void AcquireFileAccessPermission(
       WebContents* web_contents,
       const AcquireFileAccessPermissionCallback& callback) override;
+  void SetDefaultDownloadFileName(const std::string& file_name) override;
 
  private:
   // Used to store all the information about an Android download.
@@ -142,6 +143,8 @@
 
   JavaObject* java_object_;
 
+  std::string default_file_name_;
+
   ScopedVector<DeferredDownloadObserver> deferred_downloads_;
 
   DISALLOW_COPY_AND_ASSIGN(DownloadControllerAndroidImpl);
diff --git a/content/browser/android/synchronous_compositor_host.cc b/content/browser/android/synchronous_compositor_host.cc
index 3e272e45..658c818d 100644
--- a/content/browser/android/synchronous_compositor_host.cc
+++ b/content/browser/android/synchronous_compositor_host.cc
@@ -43,9 +43,9 @@
       root_scroll_offset_updated_by_browser_(false),
       renderer_param_version_(0u),
       need_animate_scroll_(false),
-      need_invalidate_(false),
+      need_invalidate_count_(0u),
       need_begin_frame_(false),
-      did_activate_pending_tree_(false),
+      did_activate_pending_tree_count_(0u),
       weak_ptr_factory_(this) {
   client_->DidInitializeCompositor(this);
 }
@@ -404,18 +404,16 @@
     need_begin_frame_ = params.need_begin_frame;
     UpdateNeedsBeginFrames();
   }
-  need_invalidate_ = need_invalidate_ || params.need_invalidate;
-  did_activate_pending_tree_ =
-      did_activate_pending_tree_ || params.did_activate_pending_tree;
   root_scroll_offset_ = params.total_scroll_offset;
 
-  if (need_invalidate_) {
-    need_invalidate_ = false;
+  if (need_invalidate_count_ != params.need_invalidate_count) {
+    need_invalidate_count_ = params.need_invalidate_count;
     client_->PostInvalidate();
   }
 
-  if (did_activate_pending_tree_) {
-    did_activate_pending_tree_ = false;
+  if (did_activate_pending_tree_count_ !=
+      params.did_activate_pending_tree_count) {
+    did_activate_pending_tree_count_ = params.did_activate_pending_tree_count;
     client_->DidUpdateContent();
   }
 
diff --git a/content/browser/android/synchronous_compositor_host.h b/content/browser/android/synchronous_compositor_host.h
index 4435a31e..1d7f58d 100644
--- a/content/browser/android/synchronous_compositor_host.h
+++ b/content/browser/android/synchronous_compositor_host.h
@@ -95,9 +95,9 @@
   // From renderer.
   uint32_t renderer_param_version_;
   bool need_animate_scroll_;
-  bool need_invalidate_;
+  uint32_t need_invalidate_count_;
   bool need_begin_frame_;
-  bool did_activate_pending_tree_;
+  uint32_t did_activate_pending_tree_count_;
 
   base::WeakPtrFactory<SynchronousCompositorHost> weak_ptr_factory_;
   DISALLOW_COPY_AND_ASSIGN(SynchronousCompositorHost);
diff --git a/content/browser/appcache/appcache_database.cc b/content/browser/appcache/appcache_database.cc
index f9e83ac9..f3053c7d 100644
--- a/content/browser/appcache/appcache_database.cc
+++ b/content/browser/appcache/appcache_database.cc
@@ -191,6 +191,8 @@
     : group_id(0) {
 }
 
+AppCacheDatabase::GroupRecord::GroupRecord(const GroupRecord& other) = default;
+
 AppCacheDatabase::GroupRecord::~GroupRecord() {
 }
 
diff --git a/content/browser/appcache/appcache_database.h b/content/browser/appcache/appcache_database.h
index a6f017e..e2b265d 100644
--- a/content/browser/appcache/appcache_database.h
+++ b/content/browser/appcache/appcache_database.h
@@ -51,6 +51,7 @@
  public:
   struct CONTENT_EXPORT GroupRecord {
     GroupRecord();
+    GroupRecord(const GroupRecord& other);
     ~GroupRecord();
 
     int64_t group_id;
diff --git a/content/browser/appcache/appcache_disk_cache.cc b/content/browser/appcache/appcache_disk_cache.cc
index 49030f0..da5475d 100644
--- a/content/browser/appcache/appcache_disk_cache.cc
+++ b/content/browser/appcache/appcache_disk_cache.cc
@@ -336,6 +336,8 @@
     const net::CompletionCallback& callback)
     : call_type(call_type), key(key), entry(entry), callback(callback) {}
 
+AppCacheDiskCache::PendingCall::PendingCall(const PendingCall& other) = default;
+
 AppCacheDiskCache::PendingCall::~PendingCall() {}
 
 int AppCacheDiskCache::Init(
diff --git a/content/browser/appcache/appcache_disk_cache.h b/content/browser/appcache/appcache_disk_cache.h
index 2b8c299..d06bcf5 100644
--- a/content/browser/appcache/appcache_disk_cache.h
+++ b/content/browser/appcache/appcache_disk_cache.h
@@ -89,6 +89,8 @@
                 Entry** entry,
                 const net::CompletionCallback& callback);
 
+    PendingCall(const PendingCall& other);
+
     ~PendingCall();
   };
   typedef std::vector<PendingCall> PendingCalls;
diff --git a/content/browser/appcache/appcache_update_job.cc b/content/browser/appcache/appcache_update_job.cc
index b7133fc..7c922f8 100644
--- a/content/browser/appcache/appcache_update_job.cc
+++ b/content/browser/appcache/appcache_update_job.cc
@@ -140,6 +140,8 @@
       existing_response_info(info) {
 }
 
+AppCacheUpdateJob::UrlToFetch::UrlToFetch(const UrlToFetch& other) = default;
+
 AppCacheUpdateJob::UrlToFetch::~UrlToFetch() {
 }
 
diff --git a/content/browser/appcache/appcache_update_job.h b/content/browser/appcache/appcache_update_job.h
index f1c7af03..4fa1588 100644
--- a/content/browser/appcache/appcache_update_job.h
+++ b/content/browser/appcache/appcache_update_job.h
@@ -101,6 +101,7 @@
 
   struct UrlToFetch {
     UrlToFetch(const GURL& url, bool checked, AppCacheResponseInfo* info);
+    UrlToFetch(const UrlToFetch& other);
     ~UrlToFetch();
 
     GURL url;
diff --git a/content/browser/background_sync/background_sync_manager.cc b/content/browser/background_sync/background_sync_manager.cc
index 25f95328..4cc3901 100644
--- a/content/browser/background_sync/background_sync_manager.cc
+++ b/content/browser/background_sync/background_sync_manager.cc
@@ -139,6 +139,9 @@
     : next_id(BackgroundSyncRegistration::kInitialId) {
 }
 
+BackgroundSyncManager::BackgroundSyncRegistrations::BackgroundSyncRegistrations(
+    const BackgroundSyncRegistrations& other) = default;
+
 BackgroundSyncManager::BackgroundSyncRegistrations::
     ~BackgroundSyncRegistrations() {
 }
diff --git a/content/browser/background_sync/background_sync_manager.h b/content/browser/background_sync/background_sync_manager.h
index 448b4700..fe3eda60 100644
--- a/content/browser/background_sync/background_sync_manager.h
+++ b/content/browser/background_sync/background_sync_manager.h
@@ -164,6 +164,7 @@
         std::map<RegistrationKey, scoped_refptr<RefCountedRegistration>>;
 
     BackgroundSyncRegistrations();
+    BackgroundSyncRegistrations(const BackgroundSyncRegistrations& other);
     ~BackgroundSyncRegistrations();
 
     RegistrationMap registration_map;
diff --git a/content/browser/bad_message.h b/content/browser/bad_message.h
index f79f9bf57..4df3837 100644
--- a/content/browser/bad_message.h
+++ b/content/browser/bad_message.h
@@ -134,6 +134,7 @@
   WSH_SEND_BLOB_DURING_BLOB_SEND = 110,
   WSH_SEND_FRAME_DURING_BLOB_SEND = 111,
   RFH_UNEXPECTED_LOAD_START = 112,
+  NMF_INVALID_ARGUMENT = 113,
 
   // Please add new elements here. The naming convention is abbreviated class
   // name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
diff --git a/content/browser/bluetooth/bluetooth_dispatcher_host.cc b/content/browser/bluetooth/bluetooth_dispatcher_host.cc
index c4fe0562..22ad2c6 100644
--- a/content/browser/bluetooth/bluetooth_dispatcher_host.cc
+++ b/content/browser/bluetooth/bluetooth_dispatcher_host.cc
@@ -792,6 +792,16 @@
   RecordWebBluetoothFunctionCall(UMAWebBluetoothFunction::GET_CHARACTERISTIC);
   RecordGetCharacteristicCharacteristic(characteristic_uuid);
 
+  // Check Blacklist for characteristic_uuid.
+  if (BluetoothBlacklist::Get().IsExcluded(
+          BluetoothUUID(characteristic_uuid))) {
+    RecordGetCharacteristicOutcome(UMAGetCharacteristicOutcome::BLACKLISTED);
+    Send(new BluetoothMsg_GetCharacteristicError(
+        thread_id, request_id,
+        WebBluetoothError::BlacklistedCharacteristicUUID));
+    return;
+  }
+
   const CacheQueryResult query_result =
       QueryCacheForService(GetOrigin(frame_routing_id), service_instance_id);
 
@@ -1266,15 +1276,24 @@
     return;
   }
 
-  VLOG(1) << "Device: " << device->GetName();
-  VLOG(1) << "UUIDs: ";
-  for (BluetoothUUID uuid : device->GetUUIDs())
-    VLOG(1) << "\t" << uuid.canonical_value();
-
   const std::string& device_id_for_origin = allowed_devices_map_.AddDevice(
       session->origin, device->GetAddress(), session->filters,
       session->optional_services);
 
+  VLOG(1) << "Device: " << device->GetName();
+  VLOG(1) << "UUIDs: ";
+
+  device::BluetoothDevice::UUIDList filtered_uuids;
+  for (BluetoothUUID uuid : device->GetUUIDs()) {
+    if (allowed_devices_map_.IsOriginAllowedToAccessService(
+            session->origin, device_id_for_origin, uuid.canonical_value())) {
+      VLOG(1) << "\t Allowed: " << uuid.canonical_value();
+      filtered_uuids.push_back(uuid);
+    } else {
+      VLOG(1) << "\t Not Allowed: " << uuid.canonical_value();
+    }
+  }
+
   content::BluetoothDevice device_ipc(
       device_id_for_origin,  // id
       device->GetName(),     // name
@@ -1288,7 +1307,7 @@
       device->GetProductID(),         // product_id
       device->GetDeviceID(),          // product_version
       content::BluetoothDevice::UUIDsFromBluetoothUUIDs(
-          device->GetUUIDs()));  // uuids
+          filtered_uuids));  // uuids
   RecordRequestDeviceOutcome(UMARequestDeviceOutcome::SUCCESS);
   Send(new BluetoothMsg_RequestDeviceSuccess(session->thread_id,
                                              session->request_id, device_ipc));
diff --git a/content/browser/bluetooth/bluetooth_metrics.h b/content/browser/bluetooth/bluetooth_metrics.h
index fbbea33..b226a8c3 100644
--- a/content/browser/bluetooth/bluetooth_metrics.h
+++ b/content/browser/bluetooth/bluetooth_metrics.h
@@ -150,6 +150,7 @@
   NO_DEVICE = 1,
   NO_SERVICE = 2,
   NOT_FOUND = 3,
+  BLACKLISTED = 4,
   // Note: Add new outcomes immediately above this line.
   // Make sure to update the enum list in
   // tools/metrisc/histogram/histograms.xml accordingly.
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 64cec9e..8f6909b7 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -147,7 +147,7 @@
 #if defined(OS_LINUX) && defined(USE_UDEV)
 #include "media/capture/device_monitor_udev.h"
 #elif defined(OS_MACOSX) && !defined(OS_IOS)
-#include "content/browser/device_monitor_mac.h"
+#include "media/capture/device_monitor_mac.h"
 #endif
 
 #if defined(OS_POSIX) && !defined(OS_MACOSX)
@@ -1260,7 +1260,7 @@
   device_monitor_linux_.reset(
       new media::DeviceMonitorLinux(io_thread_->task_runner()));
 #elif defined(OS_MACOSX)
-  device_monitor_mac_.reset(new DeviceMonitorMac());
+  device_monitor_mac_.reset(new media::DeviceMonitorMac());
 #endif
 
 #if defined(OS_WIN)
diff --git a/content/browser/browser_main_loop.h b/content/browser/browser_main_loop.h
index 5832f0e..f58fccad 100644
--- a/content/browser/browser_main_loop.h
+++ b/content/browser/browser_main_loop.h
@@ -37,6 +37,9 @@
 class DeviceMonitorLinux;
 #endif
 class UserInputMonitor;
+#if defined(OS_MACOSX)
+class DeviceMonitorMac;
+#endif
 namespace midi {
 class MidiManager;
 }  // namespace midi
@@ -66,8 +69,6 @@
 
 #if defined(OS_ANDROID)
 class ScreenOrientationDelegate;
-#elif defined(OS_MACOSX)
-class DeviceMonitorMac;
 #elif defined(OS_WIN)
 class SystemMessageWindowWin;
 #endif
@@ -131,7 +132,7 @@
   void StopStartupTracingTimer();
 
 #if defined(OS_MACOSX) && !defined(OS_IOS)
-  DeviceMonitorMac* device_monitor_mac() const {
+  media::DeviceMonitorMac* device_monitor_mac() const {
     return device_monitor_mac_.get();
   }
 #endif
@@ -253,7 +254,7 @@
 #if defined(OS_LINUX) && defined(USE_UDEV)
   scoped_ptr<media::DeviceMonitorLinux> device_monitor_linux_;
 #elif defined(OS_MACOSX) && !defined(OS_IOS)
-  scoped_ptr<DeviceMonitorMac> device_monitor_mac_;
+  scoped_ptr<media::DeviceMonitorMac> device_monitor_mac_;
 #endif
 #if defined(USE_OZONE)
   scoped_ptr<ui::ClientNativePixmapFactory> client_native_pixmap_factory_;
diff --git a/content/browser/cache_storage/cache_storage_cache.cc b/content/browser/cache_storage/cache_storage_cache.cc
index e037dbf33..0c9a85af 100644
--- a/content/browser/cache_storage/cache_storage_cache.cc
+++ b/content/browser/cache_storage/cache_storage_cache.cc
@@ -813,7 +813,7 @@
   scoped_ptr<ServiceWorkerFetchRequest> request_copy(
       new ServiceWorkerFetchRequest(*put_context->request));
 
-  DeleteImpl(std::move(request_copy),
+  DeleteImpl(std::move(request_copy), CacheStorageCacheQueryParams(),
              base::Bind(&CacheStorageCache::PutDidDelete,
                         weak_ptr_factory_.GetWeakPtr(),
                         base::Passed(std::move(put_context))));
@@ -1035,17 +1035,27 @@
                  weak_ptr_factory_.GetWeakPtr(), callback);
   scheduler_->ScheduleOperation(
       base::Bind(&CacheStorageCache::DeleteImpl, weak_ptr_factory_.GetWeakPtr(),
-                 base::Passed(std::move(request)), pending_callback));
+                 base::Passed(std::move(request)), operation.match_params,
+                 pending_callback));
 }
 
 void CacheStorageCache::DeleteImpl(
     scoped_ptr<ServiceWorkerFetchRequest> request,
+    const CacheStorageCacheQueryParams& match_params,
     const ErrorCallback& callback) {
   DCHECK_NE(BACKEND_UNINITIALIZED, backend_state_);
   if (backend_state_ != BACKEND_OPEN) {
     callback.Run(CACHE_STORAGE_ERROR_STORAGE);
     return;
   }
+
+  if (match_params.ignore_search) {
+    OpenAllEntries(base::Bind(&CacheStorageCache::DeleteDidOpenAllEntries,
+                              weak_ptr_factory_.GetWeakPtr(),
+                              base::Passed(std::move(request)), callback));
+    return;
+  }
+
   scoped_ptr<disk_cache::Entry*> entry(new disk_cache::Entry*);
 
   disk_cache::Entry** entry_ptr = entry.get();
@@ -1063,6 +1073,30 @@
     open_entry_callback.Run(rv);
 }
 
+void CacheStorageCache::DeleteDidOpenAllEntries(
+    scoped_ptr<ServiceWorkerFetchRequest> request,
+    const ErrorCallback& callback,
+    scoped_ptr<OpenAllEntriesContext> entries_context,
+    CacheStorageError error) {
+  if (error != CACHE_STORAGE_OK) {
+    callback.Run(error);
+    return;
+  }
+
+  GURL request_url_without_query = RemoveQueryParam(request->url);
+  for (Entries::iterator iter = entries_context->entries.begin();
+       iter != entries_context->entries.end(); iter++) {
+    disk_cache::Entry* entry(*iter);
+    if (request_url_without_query == RemoveQueryParam(GURL(entry->GetKey())))
+      entry->Doom();
+  }
+
+  entries_context.reset();
+
+  UpdateCacheSize();
+  callback.Run(CACHE_STORAGE_OK);
+}
+
 void CacheStorageCache::DeleteDidOpenEntry(
     const GURL& origin,
     scoped_ptr<ServiceWorkerFetchRequest> request,
diff --git a/content/browser/cache_storage/cache_storage_cache.h b/content/browser/cache_storage/cache_storage_cache.h
index 1bbd16b..72e1c9a 100644
--- a/content/browser/cache_storage/cache_storage_cache.h
+++ b/content/browser/cache_storage/cache_storage_cache.h
@@ -223,7 +223,13 @@
   void Delete(const CacheStorageBatchOperation& operation,
               const ErrorCallback& callback);
   void DeleteImpl(scoped_ptr<ServiceWorkerFetchRequest> request,
+                  const CacheStorageCacheQueryParams& match_params,
                   const ErrorCallback& callback);
+  void DeleteDidOpenAllEntries(
+      scoped_ptr<ServiceWorkerFetchRequest> request,
+      const ErrorCallback& callback,
+      scoped_ptr<OpenAllEntriesContext> entries_context,
+      CacheStorageError error);
   void DeleteDidOpenEntry(const GURL& origin,
                           scoped_ptr<ServiceWorkerFetchRequest> request,
                           const CacheStorageCache::ErrorCallback& callback,
diff --git a/content/browser/cache_storage/cache_storage_cache_unittest.cc b/content/browser/cache_storage/cache_storage_cache_unittest.cc
index d279f0c..d2ed1df 100644
--- a/content/browser/cache_storage/cache_storage_cache_unittest.cc
+++ b/content/browser/cache_storage/cache_storage_cache_unittest.cc
@@ -408,10 +408,13 @@
                     responses, body_handles);
   }
 
-  bool Delete(const ServiceWorkerFetchRequest& request) {
+  bool Delete(const ServiceWorkerFetchRequest& request,
+              const CacheStorageCacheQueryParams& match_params =
+                  CacheStorageCacheQueryParams()) {
     CacheStorageBatchOperation operation;
     operation.operation_type = CACHE_STORAGE_CACHE_OPERATION_TYPE_DELETE;
     operation.request = request;
+    operation.match_params = match_params;
 
     CacheStorageError error =
         BatchOperation(std::vector<CacheStorageBatchOperation>(1, operation));
@@ -942,6 +945,61 @@
   EXPECT_TRUE(Delete(body_request_));
 }
 
+TEST_P(CacheStorageCacheTestP, DeleteWithIgnoreSearchTrue) {
+  EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+  EXPECT_TRUE(Put(body_request_, body_response_));
+  EXPECT_TRUE(Put(body_request_with_query_, body_response_with_query_));
+
+  EXPECT_TRUE(Keys());
+  EXPECT_EQ(3u, callback_strings_.size());
+  std::vector<std::string> expected_keys;
+  expected_keys.push_back(no_body_request_.url.spec());
+  expected_keys.push_back(body_request_.url.spec());
+  expected_keys.push_back(body_request_with_query_.url.spec());
+  EXPECT_TRUE(VerifyKeys(expected_keys));
+
+  // The following delete operation will remove both of body_request_ and
+  // body_request_with_query_ from cache storage.
+  CacheStorageCacheQueryParams match_params;
+  match_params.ignore_search = true;
+  EXPECT_TRUE(Delete(body_request_with_query_, match_params));
+
+  EXPECT_TRUE(Keys());
+  EXPECT_EQ(1u, callback_strings_.size());
+  expected_keys.clear();
+  expected_keys.push_back(no_body_request_.url.spec());
+  EXPECT_TRUE(VerifyKeys(expected_keys));
+}
+
+TEST_P(CacheStorageCacheTestP, DeleteWithIgnoreSearchFalse) {
+  EXPECT_TRUE(Put(no_body_request_, no_body_response_));
+  EXPECT_TRUE(Put(body_request_, body_response_));
+  EXPECT_TRUE(Put(body_request_with_query_, body_response_with_query_));
+
+  EXPECT_TRUE(Keys());
+  EXPECT_EQ(3u, callback_strings_.size());
+  std::vector<std::string> expected_keys;
+  expected_keys.push_back(no_body_request_.url.spec());
+  expected_keys.push_back(body_request_.url.spec());
+  expected_keys.push_back(body_request_with_query_.url.spec());
+  EXPECT_TRUE(VerifyKeys(expected_keys));
+
+  // Default value of ignore_search is false.
+  CacheStorageCacheQueryParams match_params;
+  match_params.ignore_search = false;
+  EXPECT_EQ(match_params.ignore_search,
+            CacheStorageCacheQueryParams().ignore_search);
+
+  EXPECT_TRUE(Delete(body_request_with_query_, match_params));
+
+  EXPECT_TRUE(Keys());
+  EXPECT_EQ(2u, callback_strings_.size());
+  expected_keys.clear();
+  expected_keys.push_back(no_body_request_.url.spec());
+  expected_keys.push_back(body_request_.url.spec());
+  EXPECT_TRUE(VerifyKeys(expected_keys));
+}
+
 TEST_P(CacheStorageCacheTestP, QuickStressNoBody) {
   for (int i = 0; i < 100; ++i) {
     EXPECT_FALSE(Match(no_body_request_));
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index 55239b1..53c8ed3 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -672,6 +672,10 @@
 bool RenderFrameDevToolsAgentHost::OnMessageReceived(
     const IPC::Message& message,
     RenderFrameHost* render_frame_host) {
+  bool is_current = current_ && current_->host() == render_frame_host;
+  bool is_pending = pending_ && pending_->host() == render_frame_host;
+  if (!is_current && !is_pending)
+    return false;
   if (!IsAttached())
     return false;
   bool handled = true;
diff --git a/content/browser/devtools/site_per_process_devtools_browsertest.cc b/content/browser/devtools/site_per_process_devtools_browsertest.cc
index cfa2b4a1..04d244d 100644
--- a/content/browser/devtools/site_per_process_devtools_browsertest.cc
+++ b/content/browser/devtools/site_per_process_devtools_browsertest.cc
@@ -23,7 +23,7 @@
 
 class TestClient: public DevToolsAgentHostClient {
  public:
-  TestClient() : closed_(false) {}
+  TestClient() : closed_(false), waiting_for_reply_(false) {}
   ~TestClient() override {}
 
   bool closed() { return closed_; }
@@ -31,6 +31,10 @@
   void DispatchProtocolMessage(
       DevToolsAgentHost* agent_host,
       const std::string& message) override {
+    if (waiting_for_reply_) {
+      waiting_for_reply_ = false;
+      base::MessageLoop::current()->QuitNow();
+    }
   }
 
   void AgentHostClosed(
@@ -39,8 +43,14 @@
     closed_ = true;
   }
 
+  void WaitForReply() {
+    waiting_for_reply_ = true;
+    base::MessageLoop::current()->Run();
+  }
+
  private:
   bool closed_;
+  bool waiting_for_reply_;
 };
 
 // Fails on Android, http://crbug.com/464993.
@@ -90,10 +100,20 @@
   EXPECT_EQ(DevToolsAgentHost::TYPE_FRAME, list[1]->GetType());
   EXPECT_EQ(cross_site_url.spec(), list[1]->GetURL().spec());
 
-  // Attaching to child frame.
+  // Attaching to both agent hosts.
   scoped_refptr<DevToolsAgentHost> child_host = list[1];
-  TestClient client;
-  child_host->AttachClient(&client);
+  TestClient child_client;
+  child_host->AttachClient(&child_client);
+  scoped_refptr<DevToolsAgentHost> parent_host = list[0];
+  TestClient parent_client;
+  parent_host->AttachClient(&parent_client);
+
+  // Send message to parent and child frames and get result back.
+  char message[] = "{\"id\": 0, \"method\": \"incorrect.method\"}";
+  child_host->DispatchProtocolMessage(message);
+  child_client.WaitForReply();
+  parent_host->DispatchProtocolMessage(message);
+  parent_client.WaitForReply();
 
   // Load back same-site page into iframe.
   NavigateFrameToURL(root->child_at(0), http_url);
@@ -102,9 +122,12 @@
   EXPECT_EQ(1U, list.size());
   EXPECT_EQ(DevToolsAgentHost::TYPE_WEB_CONTENTS, list[0]->GetType());
   EXPECT_EQ(main_url.spec(), list[0]->GetURL().spec());
-  EXPECT_TRUE(client.closed());
+  EXPECT_TRUE(child_client.closed());
   child_host->DetachClient();
   child_host = nullptr;
+  EXPECT_FALSE(parent_client.closed());
+  parent_host->DetachClient();
+  parent_host = nullptr;
 }
 
 IN_PROC_BROWSER_TEST_F(SitePerProcessDevToolsBrowserTest, AgentHostForFrames) {
diff --git a/content/browser/dom_storage/dom_storage_browsertest.cc b/content/browser/dom_storage/dom_storage_browsertest.cc
index b0c1c63d..9fc8c417 100644
--- a/content/browser/dom_storage/dom_storage_browsertest.cc
+++ b/content/browser/dom_storage/dom_storage_browsertest.cc
@@ -9,7 +9,6 @@
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
 #include "content/shell/browser/shell.h"
-#include "net/base/net_util.h"
 
 namespace content {
 
diff --git a/content/browser/dom_storage/dom_storage_context_wrapper.cc b/content/browser/dom_storage/dom_storage_context_wrapper.cc
index db486f3..e58187f 100644
--- a/content/browser/dom_storage/dom_storage_context_wrapper.cc
+++ b/content/browser/dom_storage/dom_storage_context_wrapper.cc
@@ -17,6 +17,7 @@
 #include "content/browser/dom_storage/dom_storage_context_impl.h"
 #include "content/browser/dom_storage/dom_storage_task_runner.h"
 #include "content/browser/dom_storage/session_storage_namespace_impl.h"
+#include "content/browser/level_db_wrapper_impl.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/local_storage_usage_info.h"
 #include "content/public/browser/session_storage_usage_info.h"
@@ -166,4 +167,29 @@
       base::Bind(&DOMStorageContextImpl::Flush, context_));
 }
 
+void DOMStorageContextWrapper::OpenLocalStorage(
+    const mojo::String& origin,
+    LevelDBObserverPtr observer,
+    mojo::InterfaceRequest<LevelDBWrapper> request) {
+  if (level_db_wrappers_.find(origin) == level_db_wrappers_.end()) {
+    level_db_wrappers_[origin] = make_scoped_ptr(new LevelDBWrapperImpl(
+        origin,
+        base::Bind(&DOMStorageContextWrapper::LevelDBWrapperImplHasNoBindings,
+                   base::Unretained(this),
+                   origin.get())));
+  }
+  // TODO(jam): call LevelDB service (once per this object) to open the database
+  // for LocalStorage and keep a pointer to it in this class. Then keep a map
+  // from origins to LevelDBWrapper object. Each call here for the same origin
+  // should use the same LevelDBWrapper object.
+
+  level_db_wrappers_[origin]->Bind(std::move(request), std::move(observer));
+}
+
+void DOMStorageContextWrapper::LevelDBWrapperImplHasNoBindings(
+    const std::string& origin) {
+  DCHECK(level_db_wrappers_.find(origin) != level_db_wrappers_.end());
+  level_db_wrappers_.erase(origin);
+}
+
 }  // namespace content
diff --git a/content/browser/dom_storage/dom_storage_context_wrapper.h b/content/browser/dom_storage/dom_storage_context_wrapper.h
index 5303344..b1aaa8b4 100644
--- a/content/browser/dom_storage/dom_storage_context_wrapper.h
+++ b/content/browser/dom_storage/dom_storage_context_wrapper.h
@@ -5,11 +5,13 @@
 #ifndef CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_CONTEXT_WRAPPER_H_
 #define CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_CONTEXT_WRAPPER_H_
 
+#include <map>
 #include <string>
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "content/common/content_export.h"
+#include "content/common/storage_partition_service.mojom.h"
 #include "content/public/browser/dom_storage_context.h"
 
 namespace base {
@@ -23,9 +25,10 @@
 namespace content {
 
 class DOMStorageContextImpl;
+class LevelDBWrapperImpl;
 
-// This is owned by BrowserContext (aka Profile) and encapsulates all
-// per-profile dom storage state.
+// This is owned by Storage Partition and encapsulates all its dom storage
+// state.
 class CONTENT_EXPORT DOMStorageContextWrapper :
     NON_EXPORTED_BASE(public DOMStorageContext),
     public base::RefCountedThreadSafe<DOMStorageContextWrapper> {
@@ -58,6 +61,12 @@
 
   void Flush();
 
+  // See StoragePartitionService interface.
+  void OpenLocalStorage(
+      const mojo::String& origin,
+      LevelDBObserverPtr observer,
+      mojo::InterfaceRequest<LevelDBWrapper> request);
+
  private:
   friend class DOMStorageMessageFilter;  // for access to context()
   friend class SessionStorageNamespaceImpl;  // ditto
@@ -66,6 +75,13 @@
   ~DOMStorageContextWrapper() override;
   DOMStorageContextImpl* context() const { return context_.get(); }
 
+  void LevelDBWrapperImplHasNoBindings(const std::string& origin);
+
+  // Used for mojo-based LocalStorage implementation (behind
+  // --mojo-local-storage for now). Maps between an origin and its prefixed
+  // LevelDB view.
+  std::map<std::string, scoped_ptr<LevelDBWrapperImpl>> level_db_wrappers_;
+
   scoped_refptr<DOMStorageContextImpl> context_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(DOMStorageContextWrapper);
diff --git a/content/browser/dom_storage/dom_storage_host.cc b/content/browser/dom_storage/dom_storage_host.cc
index 14d288d8..3db7d5a1 100644
--- a/content/browser/dom_storage/dom_storage_host.cc
+++ b/content/browser/dom_storage/dom_storage_host.cc
@@ -153,6 +153,8 @@
 // NamespaceAndArea
 
 DOMStorageHost::NamespaceAndArea::NamespaceAndArea() {}
+DOMStorageHost::NamespaceAndArea::NamespaceAndArea(
+    const NamespaceAndArea& other) = default;
 DOMStorageHost::NamespaceAndArea::~NamespaceAndArea() {}
 
 }  // namespace content
diff --git a/content/browser/dom_storage/dom_storage_host.h b/content/browser/dom_storage/dom_storage_host.h
index 9b79406..d53bd15 100644
--- a/content/browser/dom_storage/dom_storage_host.h
+++ b/content/browser/dom_storage/dom_storage_host.h
@@ -57,6 +57,7 @@
     scoped_refptr<DOMStorageNamespace> namespace_;
     scoped_refptr<DOMStorageArea> area_;
     NamespaceAndArea();
+    NamespaceAndArea(const NamespaceAndArea& other);
     ~NamespaceAndArea();
   };
   typedef std::map<int, NamespaceAndArea > AreaMap;
diff --git a/content/browser/dom_storage/dom_storage_namespace.cc b/content/browser/dom_storage/dom_storage_namespace.cc
index 25e44e5..a8681b6 100644
--- a/content/browser/dom_storage/dom_storage_namespace.cc
+++ b/content/browser/dom_storage/dom_storage_namespace.cc
@@ -195,6 +195,8 @@
     : area_(area), open_count_(count) {
 }
 
+DOMStorageNamespace::AreaHolder::AreaHolder(const AreaHolder& other) = default;
+
 DOMStorageNamespace::AreaHolder::~AreaHolder() {
 }
 
diff --git a/content/browser/dom_storage/dom_storage_namespace.h b/content/browser/dom_storage/dom_storage_namespace.h
index a9f65693..238b7ca5 100644
--- a/content/browser/dom_storage/dom_storage_namespace.h
+++ b/content/browser/dom_storage/dom_storage_namespace.h
@@ -86,6 +86,7 @@
     int open_count_;
     AreaHolder();
     AreaHolder(DOMStorageArea* area, int count);
+    AreaHolder(const AreaHolder& other);
     ~AreaHolder();
   };
   typedef std::map<GURL, AreaHolder> AreaMap;
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index 18af2c4..40fa2a8 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -1576,7 +1576,7 @@
   TestFileErrorInjector::FileErrorInfo err = {
       request_handler.url().spec(),
       TestFileErrorInjector::FILE_OPERATION_RENAME_ANNOTATE, 0,
-      DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE};
+      DOWNLOAD_INTERRUPT_REASON_FILE_FAILED};
   injector->AddError(err);
   injector->InjectErrors();
 
@@ -1585,8 +1585,7 @@
       initiator_shell_for_resumption(), request_handler.url()));
   WaitForInterrupt(download);
   ASSERT_EQ(DownloadItem::INTERRUPTED, download->GetState());
-  EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE,
-            download->GetLastReason());
+  EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_FILE_FAILED, download->GetLastReason());
   EXPECT_TRUE(download->GetFullPath().empty());
   // Target path should still be intact.
   EXPECT_FALSE(download->GetTargetFilePath().empty());
diff --git a/content/browser/download/download_interrupt_reasons_impl.cc b/content/browser/download/download_interrupt_reasons_impl.cc
index 2ed8f147e..406c4e9 100644
--- a/content/browser/download/download_interrupt_reasons_impl.cc
+++ b/content/browser/download/download_interrupt_reasons_impl.cc
@@ -83,7 +83,8 @@
     case net::ERR_TIMED_OUT:
       return DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT;
 
-    // The network connection has been lost.
+    // The network connection was lost or changed.
+    case net::ERR_NETWORK_CHANGED:
     case net::ERR_INTERNET_DISCONNECTED:
       return DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED;
 
diff --git a/content/browser/download/download_item_impl.cc b/content/browser/download/download_item_impl.cc
index 35ef960..6a6dc7d7 100644
--- a/content/browser/download/download_item_impl.cc
+++ b/content/browser/download/download_item_impl.cc
@@ -50,7 +50,6 @@
 #include "content/public/browser/download_url_parameters.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/referrer.h"
-#include "net/base/net_util.h"
 
 namespace content {
 
@@ -124,20 +123,15 @@
                                    DownloadInterruptReason interrupt_reason,
                                    bool opened,
                                    const net::BoundNetLog& bound_net_log)
-    : is_save_package_download_(false),
-      download_id_(download_id),
+    : download_id_(download_id),
       current_path_(current_path),
       target_path_(target_path),
-      target_disposition_(TARGET_DISPOSITION_OVERWRITE),
       url_chain_(url_chain),
       referrer_url_(referrer_url),
-      transition_type_(ui::PAGE_TRANSITION_LINK),
-      has_user_gesture_(false),
       mime_type_(mime_type),
       original_mime_type_(original_mime_type),
       total_bytes_(total_bytes),
       received_bytes_(received_bytes),
-      bytes_per_sec_(0),
       last_modified_time_(last_modified),
       etag_(etag),
       last_reason_(interrupt_reason),
@@ -147,16 +141,8 @@
       start_time_(start_time),
       end_time_(end_time),
       delegate_(delegate),
-      is_paused_(false),
-      auto_resume_count_(0),
-      open_when_complete_(false),
-      file_externally_removed_(false),
-      auto_opened_(false),
-      is_temporary_(false),
       all_data_saved_(state == COMPLETE),
-      destination_error_(content::DOWNLOAD_INTERRUPT_REASON_NONE),
       opened_(opened),
-      delegate_delayed_complete_(false),
       bound_net_log_(bound_net_log),
       weak_ptr_factory_(this) {
   delegate_->Attach();
@@ -170,8 +156,7 @@
                                    uint32_t download_id,
                                    const DownloadCreateInfo& info,
                                    const net::BoundNetLog& bound_net_log)
-    : is_save_package_download_(false),
-      download_id_(download_id),
+    : download_id_(download_id),
       target_disposition_((info.save_info->prompt_for_save_location)
                               ? TARGET_DISPOSITION_PROMPT
                               : TARGET_DISPOSITION_OVERWRITE),
@@ -188,26 +173,14 @@
       original_mime_type_(info.original_mime_type),
       remote_address_(info.remote_address),
       total_bytes_(info.total_bytes),
-      received_bytes_(0),
-      bytes_per_sec_(0),
       last_modified_time_(info.last_modified),
       etag_(info.etag),
       last_reason_(info.result),
       start_tick_(base::TimeTicks::Now()),
       state_(INITIAL_INTERNAL),
-      danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS),
       start_time_(info.start_time),
       delegate_(delegate),
-      is_paused_(false),
-      auto_resume_count_(0),
-      open_when_complete_(false),
-      file_externally_removed_(false),
-      auto_opened_(false),
       is_temporary_(!info.save_info->file_path.empty()),
-      all_data_saved_(false),
-      destination_error_(DOWNLOAD_INTERRUPT_REASON_NONE),
-      opened_(false),
-      delegate_delayed_complete_(false),
       bound_net_log_(bound_net_log),
       weak_ptr_factory_(this) {
   delegate_->Attach();
@@ -237,32 +210,13 @@
       download_id_(download_id),
       current_path_(path),
       target_path_(path),
-      target_disposition_(TARGET_DISPOSITION_OVERWRITE),
       url_chain_(1, url),
-      referrer_url_(GURL()),
-      transition_type_(ui::PAGE_TRANSITION_LINK),
-      has_user_gesture_(false),
       mime_type_(mime_type),
       original_mime_type_(mime_type),
-      total_bytes_(0),
-      received_bytes_(0),
-      bytes_per_sec_(0),
-      last_reason_(DOWNLOAD_INTERRUPT_REASON_NONE),
       start_tick_(base::TimeTicks::Now()),
       state_(IN_PROGRESS_INTERNAL),
-      danger_type_(DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS),
       start_time_(base::Time::Now()),
       delegate_(delegate),
-      is_paused_(false),
-      auto_resume_count_(0),
-      open_when_complete_(false),
-      file_externally_removed_(false),
-      auto_opened_(false),
-      is_temporary_(false),
-      all_data_saved_(false),
-      destination_error_(content::DOWNLOAD_INTERRUPT_REASON_NONE),
-      opened_(false),
-      delegate_delayed_complete_(false),
       bound_net_log_(bound_net_log),
       weak_ptr_factory_(this) {
   delegate_->Attach();
@@ -881,35 +835,28 @@
   // We can't continue without a handle on the intermediate file.
   // We also can't continue if we don't have some verifier to make sure
   // we're getting the same file.
-  const bool force_restart =
+  bool restart_required =
       (current_path_.empty() || (etag_.empty() && last_modified_time_.empty()));
 
   // We won't auto-restart if we've used up our attempts or the
   // download has been paused by user action.
-  const bool force_user =
+  bool user_action_required =
       (auto_resume_count_ >= kMaxAutoResumeAttempts || is_paused_);
 
-  ResumeMode mode = RESUME_MODE_INVALID;
-
   switch(last_reason_) {
     case DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR:
     case DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT:
-      if (force_restart && force_user)
-        mode = RESUME_MODE_USER_RESTART;
-      else if (force_restart)
-        mode = RESUME_MODE_IMMEDIATE_RESTART;
-      else if (force_user)
-        mode = RESUME_MODE_USER_CONTINUE;
-      else
-        mode = RESUME_MODE_IMMEDIATE_CONTINUE;
       break;
 
     case DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE:
+    // The server disagreed with the file offset that we sent.
+
     case DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT:
-      if (force_user)
-        mode = RESUME_MODE_USER_RESTART;
-      else
-        mode = RESUME_MODE_IMMEDIATE_RESTART;
+      // The [possibly persisted] file offset disagreed with the file on disk.
+
+      // The intermediate stub is not usable and the server is resonding. Hence
+      // retrying the request from the beginning is likely to work.
+      restart_required = true;
       break;
 
     case DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED:
@@ -919,18 +866,28 @@
     case DOWNLOAD_INTERRUPT_REASON_SERVER_UNREACHABLE:
     case DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN:
     case DOWNLOAD_INTERRUPT_REASON_CRASH:
-      if (force_restart)
-        mode = RESUME_MODE_USER_RESTART;
-      else
-        mode = RESUME_MODE_USER_CONTINUE;
+      // It is not clear whether attempting a resumption is acceptable at this
+      // time or whether it would work at all. Hence allow the user to retry the
+      // download manually.
+      user_action_required = true;
+      break;
+
+    case DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE:
+      // There was no space. Require user interaction so that the user may, for
+      // example, choose a different location to store the file. Or they may
+      // free up some space on the targret device and retry. But try to reuse
+      // the partial stub.
+      user_action_required = true;
       break;
 
     case DOWNLOAD_INTERRUPT_REASON_FILE_FAILED:
     case DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED:
-    case DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE:
     case DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG:
     case DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE:
-      mode = RESUME_MODE_USER_RESTART;
+      // Assume the partial stub is unusable. Also it may not be possible to
+      // restart immediately.
+      user_action_required = true;
+      restart_required = true;
       break;
 
     case DOWNLOAD_INTERRUPT_REASON_NONE:
@@ -943,11 +900,20 @@
     case DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED:
     case DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM:
     case DOWNLOAD_INTERRUPT_REASON_SERVER_FORBIDDEN:
-      mode = RESUME_MODE_INVALID;
-      break;
+      // Unhandled.
+      return RESUME_MODE_INVALID;
   }
 
-  return mode;
+  if (user_action_required && restart_required)
+    return RESUME_MODE_USER_RESTART;
+
+  if (restart_required)
+    return RESUME_MODE_IMMEDIATE_RESTART;
+
+  if (user_action_required)
+    return RESUME_MODE_USER_CONTINUE;
+
+  return RESUME_MODE_IMMEDIATE_CONTINUE;
 }
 
 void DownloadItemImpl::UpdateValidatorsOnResumption(
diff --git a/content/browser/download/download_item_impl.h b/content/browser/download/download_item_impl.h
index 053d441..18ba449 100644
--- a/content/browser/download/download_item_impl.h
+++ b/content/browser/download/download_item_impl.h
@@ -474,13 +474,13 @@
 
   // Will be false for save package downloads retrieved from the history.
   // TODO(rdsmith): Replace with a generalized enum for "download source".
-  const bool is_save_package_download_;
+  const bool is_save_package_download_ = false;
 
   // The handle to the request information.  Used for operations outside the
   // download system.
   scoped_ptr<DownloadRequestHandleInterface> request_handle_;
 
-  uint32_t download_id_;
+  uint32_t download_id_ = kInvalidId;
 
   // Display name for the download. If this is empty, then the display name is
   // considered to be |target_path_.BaseName()|.
@@ -498,7 +498,7 @@
   base::FilePath target_path_;
 
   // Whether the target should be overwritten, uniquified or prompted for.
-  TargetDisposition target_disposition_;
+  TargetDisposition target_disposition_ = TARGET_DISPOSITION_OVERWRITE;
 
   // The chain of redirects that leading up to and including the final URL.
   std::vector<GURL> url_chain_;
@@ -521,11 +521,11 @@
   // the target path.
   base::FilePath forced_file_path_;
 
-  // Page transition that triggered the download.
-  ui::PageTransition transition_type_;
+  // Page transition that triggerred the download.
+  ui::PageTransition transition_type_ = ui::PAGE_TRANSITION_LINK;
 
   // Whether the download was triggered with a user gesture.
-  bool has_user_gesture_;
+  bool has_user_gesture_ = false;
 
   // Information from the request.
   // Content-disposition field from the header.
@@ -544,13 +544,13 @@
   std::string remote_address_;
 
   // Total bytes expected.
-  int64_t total_bytes_;
+  int64_t total_bytes_ = 0;
 
   // Current received bytes.
-  int64_t received_bytes_;
+  int64_t received_bytes_ = 0;
 
   // Current speed. Calculated by the DownloadFile.
-  int64_t bytes_per_sec_;
+  int64_t bytes_per_sec_ = 0;
 
   // Sha256 hash of the content.  This might be empty either because
   // the download isn't done yet or because the hash isn't needed
@@ -568,16 +568,16 @@
   std::string etag_;
 
   // Last reason.
-  DownloadInterruptReason last_reason_;
+  DownloadInterruptReason last_reason_ = DOWNLOAD_INTERRUPT_REASON_NONE;
 
   // Start time for recording statistics.
   base::TimeTicks start_tick_;
 
   // The current state of this download.
-  DownloadInternalState state_;
+  DownloadInternalState state_ = INITIAL_INTERNAL;
 
   // Current danger type for the download.
-  DownloadDangerType danger_type_;
+  DownloadDangerType danger_type_ = DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS;
 
   // The views of this item in the download shelf and download contents.
   base::ObserverList<Observer> observers_;
@@ -589,44 +589,44 @@
   base::Time end_time_;
 
   // Our delegate.
-  DownloadItemImplDelegate* delegate_;
+  DownloadItemImplDelegate* delegate_ = nullptr;
 
   // In progress downloads may be paused by the user, we note it here.
-  bool is_paused_;
+  bool is_paused_ = false;
 
   // The number of times this download has been resumed automatically.
-  int auto_resume_count_;
+  int auto_resume_count_ = 0;
 
   // A flag for indicating if the download should be opened at completion.
-  bool open_when_complete_;
+  bool open_when_complete_ = false;
 
   // A flag for indicating if the downloaded file is externally removed.
-  bool file_externally_removed_;
+  bool file_externally_removed_ = false;
 
   // True if the download was auto-opened. We set this rather than using
   // an observer as it's frequently possible for the download to be auto opened
   // before the observer is added.
-  bool auto_opened_;
+  bool auto_opened_ = false;
 
   // True if the item was downloaded temporarily.
-  bool is_temporary_;
+  bool is_temporary_ = false;
 
   // True if we've saved all the data for the download.
-  bool all_data_saved_;
+  bool all_data_saved_ = false;
 
   // Error return from DestinationError.  Stored separately from
   // last_reason_ so that we can avoid handling destination errors until
   // after file name determination has occurred.
-  DownloadInterruptReason destination_error_;
+  DownloadInterruptReason destination_error_ = DOWNLOAD_INTERRUPT_REASON_NONE;
 
   // Did the user open the item either directly or indirectly (such as by
   // setting always open files of this type)? The shelf also sets this field
   // when the user closes the shelf before the item has been opened but should
   // be treated as though the user opened it.
-  bool opened_;
+  bool opened_ = false;
 
   // Did the delegate delay calling Complete on this download?
-  bool delegate_delayed_complete_;
+  bool delegate_delayed_complete_ = false;
 
   // DownloadFile associated with this download.  Note that this
   // pointer may only be used or destroyed on the FILE thread.
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc
index 9f7029d..3fcb33ef 100644
--- a/content/browser/download/download_manager_impl.cc
+++ b/content/browser/download/download_manager_impl.cc
@@ -519,19 +519,18 @@
 
 namespace {
 
-bool RemoveDownloadBetween(base::Time remove_begin,
-                           base::Time remove_end,
-                           const DownloadItemImpl* download_item) {
-  return download_item->GetStartTime() >= remove_begin &&
-         (remove_end.is_null() || download_item->GetStartTime() < remove_end);
+bool EmptyFilter(const GURL& url) {
+  return true;
 }
 
-bool RemoveDownloadByOriginAndTime(const url::Origin& origin,
-                                   base::Time remove_begin,
-                                   base::Time remove_end,
-                                   const DownloadItemImpl* download_item) {
-  return origin.IsSameOriginWith(url::Origin(download_item->GetURL())) &&
-         RemoveDownloadBetween(remove_begin, remove_end, download_item);
+bool RemoveDownloadByURLAndTime(
+    const base::Callback<bool(const GURL&)>& url_filter,
+          base::Time remove_begin,
+          base::Time remove_end,
+          const DownloadItemImpl* download_item) {
+  return url_filter.Run(download_item->GetURL()) &&
+         download_item->GetStartTime() >= remove_begin &&
+         (remove_end.is_null() || download_item->GetStartTime() < remove_end);
 }
 
 }  // namespace
@@ -554,24 +553,21 @@
   return count;
 }
 
-int DownloadManagerImpl::RemoveDownloadsByOriginAndTime(
-    const url::Origin& origin,
+int DownloadManagerImpl::RemoveDownloadsByURLAndTime(
+    const base::Callback<bool(const GURL&)>& url_filter,
     base::Time remove_begin,
     base::Time remove_end) {
-  return RemoveDownloads(base::Bind(&RemoveDownloadByOriginAndTime,
-                                    base::ConstRef(origin), remove_begin,
-                                    remove_end));
-}
-
-int DownloadManagerImpl::RemoveDownloadsBetween(base::Time remove_begin,
-                                                base::Time remove_end) {
-  return RemoveDownloads(
-      base::Bind(&RemoveDownloadBetween, remove_begin, remove_end));
+  return RemoveDownloads(base::Bind(&RemoveDownloadByURLAndTime,
+                                    url_filter,
+                                    remove_begin, remove_end));
 }
 
 int DownloadManagerImpl::RemoveAllDownloads() {
+  const base::Callback<bool(const GURL&)> empty_filter =
+      base::Bind(&EmptyFilter);
   // The null times make the date range unbounded.
-  int num_deleted = RemoveDownloadsBetween(base::Time(), base::Time());
+  int num_deleted = RemoveDownloadsByURLAndTime(
+      empty_filter, base::Time(), base::Time());
   RecordClearAllSize(num_deleted);
   return num_deleted;
 }
diff --git a/content/browser/download/download_manager_impl.h b/content/browser/download/download_manager_impl.h
index edf604f..bbd348cd 100644
--- a/content/browser/download/download_manager_impl.h
+++ b/content/browser/download/download_manager_impl.h
@@ -73,11 +73,10 @@
       scoped_ptr<ByteStreamReader> stream,
       const DownloadUrlParameters::OnStartedCallback& on_started) override;
 
-  int RemoveDownloadsByOriginAndTime(const url::Origin& origin,
-                                     base::Time remove_begin,
-                                     base::Time remove_end) override;
-  int RemoveDownloadsBetween(base::Time remove_begin,
-                             base::Time remove_end) override;
+  int RemoveDownloadsByURLAndTime(
+      const base::Callback<bool(const GURL&)>& url_filter,
+      base::Time remove_begin,
+      base::Time remove_end) override;
   int RemoveAllDownloads() override;
   void DownloadUrl(scoped_ptr<DownloadUrlParameters> params) override;
   void AddObserver(Observer* observer) override;
diff --git a/content/browser/download/download_manager_impl_unittest.cc b/content/browser/download/download_manager_impl_unittest.cc
index 8aeb3bd..56bf593 100644
--- a/content/browser/download/download_manager_impl_unittest.cc
+++ b/content/browser/download/download_manager_impl_unittest.cc
@@ -37,7 +37,6 @@
 #include "content/public/test/mock_download_item.h"
 #include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_browser_thread.h"
-#include "net/base/net_util.h"
 #include "net/log/net_log.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gmock_mutant.h"
@@ -711,8 +710,16 @@
   // result in them being removed from the DownloadManager list.
 }
 
-// Confirm that only downloads with same origin are removed.
-TEST_F(DownloadManagerTest, RemoveSameOriginDownloads) {
+namespace {
+
+base::Callback<bool(const GURL&)> GetSingleURLFilter(const GURL& url) {
+  return base::Bind(&GURL::operator==, base::Owned(new GURL(url)));
+}
+
+}  // namespace
+
+// Confirm that only downloads with the specified URL are removed.
+TEST_F(DownloadManagerTest, RemoveDownloadsByURL) {
   base::Time now(base::Time::Now());
   for (uint32_t i = 0; i < 2; ++i) {
     MockDownloadItemImpl& item(AddItemToManager());
@@ -724,9 +731,10 @@
   EXPECT_CALL(GetMockDownloadItem(0), Remove());
   EXPECT_CALL(GetMockDownloadItem(1), Remove()).Times(0);
 
-  url::Origin origin_to_clear(download_urls_[0]);
-  int remove_count = download_manager_->RemoveDownloadsByOriginAndTime(
-      origin_to_clear, base::Time(), base::Time::Max());
+  base::Callback<bool(const GURL&)> url_filter =
+      GetSingleURLFilter(download_urls_[0]);
+  int remove_count = download_manager_->RemoveDownloadsByURLAndTime(
+      url_filter, base::Time(), base::Time::Max());
   EXPECT_EQ(remove_count, 1);
 }
 
diff --git a/content/browser/download/download_request_handle.cc b/content/browser/download/download_request_handle.cc
index 67dda4f..8a46917 100644
--- a/content/browser/download/download_request_handle.cc
+++ b/content/browser/download/download_request_handle.cc
@@ -18,6 +18,9 @@
 
 DownloadRequestHandleInterface::~DownloadRequestHandleInterface() {}
 
+DownloadRequestHandle::DownloadRequestHandle(
+    const DownloadRequestHandle& other) = default;
+
 DownloadRequestHandle::~DownloadRequestHandle() {}
 
 DownloadRequestHandle::DownloadRequestHandle()
diff --git a/content/browser/download/download_request_handle.h b/content/browser/download/download_request_handle.h
index 5d047c7..b74d9d2 100644
--- a/content/browser/download/download_request_handle.h
+++ b/content/browser/download/download_request_handle.h
@@ -45,6 +45,7 @@
 class CONTENT_EXPORT DownloadRequestHandle
     : public DownloadRequestHandleInterface {
  public:
+  DownloadRequestHandle(const DownloadRequestHandle& other);
   ~DownloadRequestHandle() override;
 
   // Create a null DownloadRequestHandle: getters will return null, and
diff --git a/content/browser/download/save_types.cc b/content/browser/download/save_types.cc
index 9c4972a88..0dd7605 100644
--- a/content/browser/download/save_types.cc
+++ b/content/browser/download/save_types.cc
@@ -45,6 +45,9 @@
       total_bytes(total_bytes),
       save_source(SaveFileCreateInfo::SAVE_FILE_FROM_NET) {}
 
+SaveFileCreateInfo::SaveFileCreateInfo(const SaveFileCreateInfo& other) =
+    default;
+
 SaveFileCreateInfo::~SaveFileCreateInfo() {}
 
 }  // namespace content
diff --git a/content/browser/download/save_types.h b/content/browser/download/save_types.h
index a9ab45c3..9d61a9a7 100644
--- a/content/browser/download/save_types.h
+++ b/content/browser/download/save_types.h
@@ -63,6 +63,8 @@
                      const std::string& content_disposition,
                      int64_t total_bytes);
 
+  SaveFileCreateInfo(const SaveFileCreateInfo& other);
+
   ~SaveFileCreateInfo();
 
   // SaveItem fields.
diff --git a/content/browser/fileapi/file_system_dir_url_request_job_unittest.cc b/content/browser/fileapi/file_system_dir_url_request_job_unittest.cc
index 15f376ce..f3576cbf 100644
--- a/content/browser/fileapi/file_system_dir_url_request_job_unittest.cc
+++ b/content/browser/fileapi/file_system_dir_url_request_job_unittest.cc
@@ -22,7 +22,6 @@
 #include "content/public/test/test_file_system_backend.h"
 #include "content/public/test/test_file_system_context.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/request_priority.h"
 #include "net/http/http_request_headers.h"
 #include "net/url_request/url_request.h"
diff --git a/content/browser/fileapi/file_system_url_request_job_unittest.cc b/content/browser/fileapi/file_system_url_request_job_unittest.cc
index 4b2715c2..58ab33b6 100644
--- a/content/browser/fileapi/file_system_url_request_job_unittest.cc
+++ b/content/browser/fileapi/file_system_url_request_job_unittest.cc
@@ -27,7 +27,6 @@
 #include "net/base/load_flags.h"
 #include "net/base/mime_util.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/request_priority.h"
 #include "net/http/http_byte_range.h"
 #include "net/http/http_request_headers.h"
diff --git a/content/browser/frame_host/frame_mojo_shell.cc b/content/browser/frame_host/frame_mojo_shell.cc
index 9541672..ce43f2d5 100644
--- a/content/browser/frame_host/frame_mojo_shell.cc
+++ b/content/browser/frame_host/frame_mojo_shell.cc
@@ -45,15 +45,26 @@
   bindings_.AddBinding(this, std::move(shell_request));
 }
 
+void FrameMojoShell::GetConnector(
+    mojo::shell::mojom::ConnectorRequest request) {
+  connectors_.AddBinding(this, std::move(request));
+}
+
+void FrameMojoShell::QuitApplication() {
+}
+
 // TODO(xhwang): Currently no callers are exposing |exposed_services|. So we
 // drop it and replace it with services we provide in the browser. In the
 // future we may need to support both.
 void FrameMojoShell::Connect(
     const mojo::String& application_url,
+    uint32_t user_id,
     mojo::shell::mojom::InterfaceProviderRequest services,
     mojo::shell::mojom::InterfaceProviderPtr /* exposed_services */,
     mojo::shell::mojom::CapabilityFilterPtr filter,
-    const ConnectCallback& callback) {
+    const mojo::shell::mojom::Connector::ConnectCallback& callback) {
+  // TODO(beng): user_id is dropped on the floor right now. Figure out what to
+  //             do with it.
   mojo::shell::mojom::InterfaceProviderPtr frame_services;
   service_provider_bindings_.AddBinding(GetServiceRegistry(),
                                         GetProxy(&frame_services));
@@ -68,7 +79,8 @@
       std::move(frame_services), capability_filter, callback);
 }
 
-void FrameMojoShell::QuitApplication() {
+void FrameMojoShell::Clone(mojo::shell::mojom::ConnectorRequest request) {
+  connectors_.AddBinding(this, std::move(request));
 }
 
 ServiceRegistryImpl* FrameMojoShell::GetServiceRegistry() {
diff --git a/content/browser/frame_host/frame_mojo_shell.h b/content/browser/frame_host/frame_mojo_shell.h
index 9c41fb2..8870906 100644
--- a/content/browser/frame_host/frame_mojo_shell.h
+++ b/content/browser/frame_host/frame_mojo_shell.h
@@ -19,7 +19,8 @@
 // This provides the |mojo::shell::mojom::Shell| service interface to each
 // frame's ServiceRegistry, giving frames the ability to connect to Mojo
 // applications.
-class FrameMojoShell : public mojo::shell::mojom::Shell {
+class FrameMojoShell : public mojo::shell::mojom::Shell,
+                       public mojo::shell::mojom::Connector {
  public:
   explicit FrameMojoShell(RenderFrameHost* frame_host);
   ~FrameMojoShell() override;
@@ -29,18 +30,24 @@
 
  private:
   // mojo::Shell:
+  void GetConnector(mojo::shell::mojom::ConnectorRequest request) override;
+  void QuitApplication() override;
+
+  // mojo::Connector:
   void Connect(
       const mojo::String& application_url,
+      uint32_t user_id,
       mojo::shell::mojom::InterfaceProviderRequest services,
       mojo::shell::mojom::InterfaceProviderPtr exposed_services,
       mojo::shell::mojom::CapabilityFilterPtr filter,
-      const ConnectCallback& callback) override;
-  void QuitApplication() override;
+      const mojo::shell::mojom::Connector::ConnectCallback& callback) override;
+  void Clone(mojo::shell::mojom::ConnectorRequest request) override;
 
   ServiceRegistryImpl* GetServiceRegistry();
 
   RenderFrameHost* frame_host_;
   mojo::WeakBindingSet<mojo::shell::mojom::Shell> bindings_;
+  mojo::WeakBindingSet<mojo::shell::mojom::Connector> connectors_;
 
   // ServiceRegistry providing browser services to connected applications.
   scoped_ptr<ServiceRegistryImpl> service_registry_;
diff --git a/content/browser/frame_host/frame_tree.cc b/content/browser/frame_host/frame_tree.cc
index 199edd49..ceb5985 100644
--- a/content/browser/frame_host/frame_tree.cc
+++ b/content/browser/frame_host/frame_tree.cc
@@ -40,6 +40,8 @@
 
 }  // namespace
 
+FrameTree::NodeIterator::NodeIterator(const NodeIterator& other) = default;
+
 FrameTree::NodeIterator::~NodeIterator() {}
 
 FrameTree::NodeIterator& FrameTree::NodeIterator::operator++() {
diff --git a/content/browser/frame_host/frame_tree.h b/content/browser/frame_host/frame_tree.h
index d9fc1b66..d6638e29 100644
--- a/content/browser/frame_host/frame_tree.h
+++ b/content/browser/frame_host/frame_tree.h
@@ -45,6 +45,7 @@
 
   class CONTENT_EXPORT NodeIterator {
    public:
+    NodeIterator(const NodeIterator& other);
     ~NodeIterator();
 
     NodeIterator& operator++();
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc
index e1c24c7..c08834bbf 100644
--- a/content/browser/frame_host/navigation_controller_impl.cc
+++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -79,7 +79,6 @@
 #include "content/public/common/content_switches.h"
 #include "media/base/mime_util.h"
 #include "net/base/escape.h"
-#include "net/base/net_util.h"
 #include "skia/ext/platform_canvas.h"
 #include "url/url_constants.h"
 
diff --git a/content/browser/frame_host/navigation_controller_impl_unittest.cc b/content/browser/frame_host/navigation_controller_impl_unittest.cc
index 6121d1f..7a7f4bf2 100644
--- a/content/browser/frame_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_unittest.cc
@@ -46,7 +46,6 @@
 #include "content/test/test_render_frame_host.h"
 #include "content/test/test_render_view_host.h"
 #include "content/test/test_web_contents.h"
-#include "net/base/net_util.h"
 #include "skia/ext/platform_canvas.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/web/WebFrameOwnerProperties.h"
diff --git a/content/browser/frame_host/render_frame_host_manager_browsertest.cc b/content/browser/frame_host/render_frame_host_manager_browsertest.cc
index 4a37ef5..644ba904 100644
--- a/content/browser/frame_host/render_frame_host_manager_browsertest.cc
+++ b/content/browser/frame_host/render_frame_host_manager_browsertest.cc
@@ -48,7 +48,6 @@
 #include "content/public/test/test_utils.h"
 #include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test_utils_internal.h"
-#include "net/base/net_util.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/request_handler_util.h"
diff --git a/content/browser/frame_host/render_frame_host_manager_unittest.cc b/content/browser/frame_host/render_frame_host_manager_unittest.cc
index 2bedae3..0cea5319 100644
--- a/content/browser/frame_host/render_frame_host_manager_unittest.cc
+++ b/content/browser/frame_host/render_frame_host_manager_unittest.cc
@@ -674,8 +674,6 @@
   base::string16 unused;
   FrameHostMsg_RunBeforeUnloadConfirm before_unload_msg(
       ntp_rfh->GetRoutingID(), kChromeURL, msg, false, &result, &unused);
-  // Enable pumping for check in BrowserMessageFilter::CheckCanDispatchOnUI.
-  before_unload_msg.EnableMessagePumping();
   EXPECT_TRUE(ntp_rfh->OnMessageReceived(before_unload_msg));
   EXPECT_TRUE(ntp_process_host->sink().GetUniqueMessageMatching(IPC_REPLY_ID));
 
diff --git a/content/browser/frame_host/render_frame_message_filter.cc b/content/browser/frame_host/render_frame_message_filter.cc
index 0c60f97..803ce426 100644
--- a/content/browser/frame_host/render_frame_message_filter.cc
+++ b/content/browser/frame_host/render_frame_message_filter.cc
@@ -21,6 +21,7 @@
 #include "content/public/common/content_constants.h"
 #include "content/public/common/content_switches.h"
 #include "gpu/GLES2/gl2extchromium.h"
+#include "net/cookies/cookie_options.h"
 #include "net/cookies/cookie_store.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
@@ -391,10 +392,13 @@
   base::debug::Alias(url_buf);
 
   net::URLRequestContext* context = GetRequestContextForURL(url);
-  context->cookie_store()->GetAllCookiesForURLAsync(
-      url, base::Bind(&RenderFrameMessageFilter::CheckPolicyForCookies, this,
-                      render_frame_id, url, first_party_for_cookies,
-                      reply_msg));
+
+  net::CookieOptions options;
+  options.set_include_same_site();
+  context->cookie_store()->GetCookieListWithOptionsAsync(
+      url, options,
+      base::Bind(&RenderFrameMessageFilter::CheckPolicyForCookies, this,
+                 render_frame_id, url, first_party_for_cookies, reply_msg));
 }
 
 void RenderFrameMessageFilter::OnCookiesEnabled(
@@ -423,11 +427,8 @@
       GetContentClient()->browser()->AllowGetCookie(
           url, first_party_for_cookies, cookie_list, resource_context_,
           render_process_id_, render_frame_id)) {
-    // Gets the cookies from cookie store if allowed.
-    context->cookie_store()->GetCookiesWithOptionsAsync(
-        url, net::CookieOptions(),
-        base::Bind(&RenderFrameMessageFilter::SendGetCookiesResponse,
-                   this, reply_msg));
+    SendGetCookiesResponse(reply_msg,
+                           net::CookieStore::BuildCookieLine(cookie_list));
   } else {
     SendGetCookiesResponse(reply_msg, std::string());
   }
diff --git a/content/browser/frame_host/render_frame_message_filter_browsertest.cc b/content/browser/frame_host/render_frame_message_filter_browsertest.cc
index 3362e96..adf9516 100644
--- a/content/browser/frame_host/render_frame_message_filter_browsertest.cc
+++ b/content/browser/frame_host/render_frame_message_filter_browsertest.cc
@@ -24,6 +24,7 @@
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 namespace content {
 
@@ -48,7 +49,8 @@
   SetupCrossSiteRedirector(embedded_test_server());
 
   net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
-  https_server.ServeFilesFromSourceDirectory("content/test/data");
+  https_server.AddDefaultHandlers(
+      base::FilePath(FILE_PATH_LITERAL("content/test/data")));
   ASSERT_TRUE(https_server.Start());
 
   // The server sends a HttpOnly cookie. The RenderFrameMessageFilter should
@@ -102,6 +104,26 @@
   EXPECT_EQ("B=2; D=4", GetCookieFromJS(web_contents_http->GetMainFrame()));
 }
 
+// SameSite cookies (that aren't marked as http-only) should be available to
+// JavaScript.
+IN_PROC_BROWSER_TEST_F(RenderFrameMessageFilterBrowserTest, SameSiteCookies) {
+  host_resolver()->AddRule("*", "127.0.0.1");
+  ASSERT_TRUE(embedded_test_server()->Start());
+  SetupCrossSiteRedirector(embedded_test_server());
+
+  // The server sends a SameSite cookie. The RenderFrameMessageFilter should
+  // allow this to be sent to the renderer.
+  GURL url = embedded_test_server()->GetURL("/set-cookie?samesite=1;SameSite");
+  NavigateToURL(shell(), url);
+
+  WebContentsImpl* web_contents =
+      static_cast<WebContentsImpl*>(shell()->web_contents());
+  EXPECT_EQ("http://127.0.0.1/",
+            web_contents->GetSiteInstance()->GetSiteURL().spec());
+
+  EXPECT_EQ("samesite=1", GetCookieFromJS(web_contents->GetMainFrame()));
+}
+
 // The RenderFrameMessageFilter will kill processes when they access the cookies
 // of sites other than the site the process is dedicated to, under site
 // isolation.
diff --git a/content/browser/gamepad/gamepad_provider.cc b/content/browser/gamepad/gamepad_provider.cc
index 682afc5..fea94e0 100644
--- a/content/browser/gamepad/gamepad_provider.cc
+++ b/content/browser/gamepad/gamepad_provider.cc
@@ -39,6 +39,9 @@
     : closure(c), task_runner(m) {
 }
 
+GamepadProvider::ClosureAndThread::ClosureAndThread(
+    const ClosureAndThread& other) = default;
+
 GamepadProvider::ClosureAndThread::~ClosureAndThread() {
 }
 
diff --git a/content/browser/gamepad/gamepad_provider.h b/content/browser/gamepad/gamepad_provider.h
index f2dcad24..fa15411 100644
--- a/content/browser/gamepad/gamepad_provider.h
+++ b/content/browser/gamepad/gamepad_provider.h
@@ -106,6 +106,7 @@
   struct ClosureAndThread {
     ClosureAndThread(const base::Closure& c,
                      const scoped_refptr<base::SingleThreadTaskRunner>& m);
+    ClosureAndThread(const ClosureAndThread& other);
     ~ClosureAndThread();
 
     base::Closure closure;
diff --git a/content/browser/geolocation/wifi_data.cc b/content/browser/geolocation/wifi_data.cc
index 2f41c33..d82e6f4 100644
--- a/content/browser/geolocation/wifi_data.cc
+++ b/content/browser/geolocation/wifi_data.cc
@@ -23,6 +23,8 @@
 
 WifiData::WifiData() {}
 
+WifiData::WifiData(const WifiData& other) = default;
+
 WifiData::~WifiData() {}
 
 bool WifiData::DiffersSignificantly(const WifiData& other) const {
diff --git a/content/browser/geolocation/wifi_data.h b/content/browser/geolocation/wifi_data.h
index d6e0b33..b3cf569 100644
--- a/content/browser/geolocation/wifi_data.h
+++ b/content/browser/geolocation/wifi_data.h
@@ -37,6 +37,7 @@
 // All data for wifi.
 struct CONTENT_EXPORT WifiData {
   WifiData();
+  WifiData(const WifiData& other);
   ~WifiData();
 
   // Determines whether a new set of WiFi data differs significantly from this.
diff --git a/content/browser/indexed_db/indexed_db_backing_store.cc b/content/browser/indexed_db/indexed_db_backing_store.cc
index dc4f336..8e356fc 100644
--- a/content/browser/indexed_db/indexed_db_backing_store.cc
+++ b/content/browser/indexed_db/indexed_db_backing_store.cc
@@ -413,11 +413,10 @@
           INTERNAL_CONSISTENCY_ERROR_UNTESTED(SET_UP_METADATA);
           return InternalInconsistencyStatus();
         }
-        std::string int_version_key = DatabaseMetaDataKey::Encode(
-            database_id, DatabaseMetaDataKey::USER_INT_VERSION);
-        PutVarInt(transaction.get(),
-                  int_version_key,
-                  IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
+        std::string version_key = DatabaseMetaDataKey::Encode(
+            database_id, DatabaseMetaDataKey::USER_VERSION);
+        PutVarInt(transaction.get(), version_key,
+                  IndexedDBDatabaseMetadata::DEFAULT_VERSION);
       }
     }
     if (s.ok() && db_schema_version < 2) {
@@ -798,6 +797,8 @@
 IndexedDBBackingStore::RecordIdentifier::~RecordIdentifier() {}
 
 IndexedDBBackingStore::Cursor::CursorOptions::CursorOptions() {}
+IndexedDBBackingStore::Cursor::CursorOptions::CursorOptions(
+    const CursorOptions& other) = default;
 IndexedDBBackingStore::Cursor::CursorOptions::~CursorOptions() {}
 
 // Values match entries in tools/metrics/histograms/histograms.xml
@@ -1218,19 +1219,18 @@
 
     // Look up version by id.
     bool found = false;
-    int64_t database_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION;
+    int64_t database_version = IndexedDBDatabaseMetadata::DEFAULT_VERSION;
     *s = GetVarInt(db_.get(),
                    DatabaseMetaDataKey::Encode(
-                       database_id, DatabaseMetaDataKey::USER_INT_VERSION),
-                   &database_version,
-                   &found);
+                       database_id, DatabaseMetaDataKey::USER_VERSION),
+                   &database_version, &found);
     if (!s->ok() || !found) {
       INTERNAL_READ_ERROR_UNTESTED(GET_DATABASE_NAMES);
       continue;
     }
 
     // Ignore stale metadata from failed initial opens.
-    if (database_version != IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION)
+    if (database_version != IndexedDBDatabaseMetadata::DEFAULT_VERSION)
       found_names.push_back(database_name_key.database_name());
   }
 
@@ -1255,11 +1255,9 @@
   if (!*found)
     return leveldb::Status::OK();
 
-  s = GetVarInt(db_.get(),
-                DatabaseMetaDataKey::Encode(
-                    metadata->id, DatabaseMetaDataKey::USER_INT_VERSION),
-                &metadata->int_version,
-                found);
+  s = GetVarInt(db_.get(), DatabaseMetaDataKey::Encode(
+                               metadata->id, DatabaseMetaDataKey::USER_VERSION),
+                &metadata->version, found);
   if (!s.ok()) {
     INTERNAL_READ_ERROR_UNTESTED(GET_IDBDATABASE_METADATA);
     return s;
@@ -1269,8 +1267,8 @@
     return InternalInconsistencyStatus();
   }
 
-  if (metadata->int_version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION)
-    metadata->int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION;
+  if (metadata->version == IndexedDBDatabaseMetadata::DEFAULT_VERSION)
+    metadata->version = IndexedDBDatabaseMetadata::NO_VERSION;
 
   s = GetMaxObjectStoreId(
       db_.get(), metadata->id, &metadata->max_object_store_id);
@@ -1329,7 +1327,7 @@
 
 leveldb::Status IndexedDBBackingStore::CreateIDBDatabaseMetaData(
     const base::string16& name,
-    int64_t int_version,
+    int64_t version,
     int64_t* row_id) {
   // TODO(jsbell): Don't persist metadata if open fails. http://crbug.com/395472
   scoped_refptr<LevelDBTransaction> transaction =
@@ -1340,16 +1338,15 @@
     return s;
   DCHECK_GE(*row_id, 0);
 
-  if (int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION)
-    int_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION;
+  if (version == IndexedDBDatabaseMetadata::NO_VERSION)
+    version = IndexedDBDatabaseMetadata::DEFAULT_VERSION;
 
   PutInt(transaction.get(),
          DatabaseNameKey::Encode(origin_identifier_, name),
          *row_id);
-  PutVarInt(transaction.get(),
-            DatabaseMetaDataKey::Encode(*row_id,
-                                        DatabaseMetaDataKey::USER_INT_VERSION),
-            int_version);
+  PutVarInt(transaction.get(), DatabaseMetaDataKey::Encode(
+                                   *row_id, DatabaseMetaDataKey::USER_VERSION),
+            version);
   PutVarInt(
       transaction.get(),
       DatabaseMetaDataKey::Encode(
@@ -1365,14 +1362,14 @@
 bool IndexedDBBackingStore::UpdateIDBDatabaseIntVersion(
     IndexedDBBackingStore::Transaction* transaction,
     int64_t row_id,
-    int64_t int_version) {
-  if (int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION)
-    int_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION;
-  DCHECK_GE(int_version, 0) << "int_version was " << int_version;
-  PutVarInt(transaction->transaction(),
-            DatabaseMetaDataKey::Encode(row_id,
-                                        DatabaseMetaDataKey::USER_INT_VERSION),
-            int_version);
+    int64_t version) {
+  if (version == IndexedDBDatabaseMetadata::NO_VERSION)
+    version = IndexedDBDatabaseMetadata::DEFAULT_VERSION;
+  DCHECK_GE(version, 0) << "version was " << version;
+  PutVarInt(
+      transaction->transaction(),
+      DatabaseMetaDataKey::Encode(row_id, DatabaseMetaDataKey::USER_VERSION),
+      version);
   return true;
 }
 
diff --git a/content/browser/indexed_db/indexed_db_backing_store.h b/content/browser/indexed_db/indexed_db_backing_store.h
index 0c61c8b..f1fecbd 100644
--- a/content/browser/indexed_db/indexed_db_backing_store.h
+++ b/content/browser/indexed_db/indexed_db_backing_store.h
@@ -287,6 +287,7 @@
 
     struct CursorOptions {
       CursorOptions();
+      CursorOptions(const CursorOptions& other);
       ~CursorOptions();
       int64_t database_id;
       int64_t object_store_id;
@@ -408,14 +409,13 @@
       const base::string16& name,
       IndexedDBDatabaseMetadata* metadata,
       bool* success) WARN_UNUSED_RESULT;
-  virtual leveldb::Status CreateIDBDatabaseMetaData(
-      const base::string16& name,
-      int64_t int_version,
-      int64_t* row_id);
+  virtual leveldb::Status CreateIDBDatabaseMetaData(const base::string16& name,
+                                                    int64_t version,
+                                                    int64_t* row_id);
   virtual bool UpdateIDBDatabaseIntVersion(
       IndexedDBBackingStore::Transaction* transaction,
       int64_t row_id,
-      int64_t int_version);
+      int64_t version);
   virtual leveldb::Status DeleteDatabase(const base::string16& name);
 
   // Assumes caller has already closed the backing store.
diff --git a/content/browser/indexed_db/indexed_db_backing_store_unittest.cc b/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
index 9f611da..55acfa0 100644
--- a/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
@@ -941,8 +941,7 @@
 TEST_F(IndexedDBBackingStoreTest, CreateDatabase) {
   const base::string16 database_name(ASCIIToUTF16("db1"));
   int64_t database_id;
-  const base::string16 version(ASCIIToUTF16("old_string_version"));
-  const int64_t int_version = 9;
+  const int64_t version = 9;
 
   const int64_t object_store_id = 99;
   const base::string16 object_store_name(ASCIIToUTF16("object_store1"));
@@ -958,7 +957,7 @@
 
   {
     leveldb::Status s = backing_store_->CreateIDBDatabaseMetaData(
-        database_name, int_version, &database_id);
+        database_name, version, &database_id);
     EXPECT_TRUE(s.ok());
     EXPECT_GT(database_id, 0);
 
@@ -1001,7 +1000,7 @@
     EXPECT_TRUE(found);
 
     // database.name is not filled in by the implementation.
-    EXPECT_EQ(int_version, database.int_version);
+    EXPECT_EQ(version, database.version);
     EXPECT_EQ(database_id, database.id);
 
     s = backing_store_->GetObjectStores(database.id, &database.object_stores);
@@ -1028,10 +1027,10 @@
   const int64_t db1_version = 1LL;
   int64_t db1_id;
 
-  // Database records with DEFAULT_INT_VERSION represent stale data,
+  // Database records with DEFAULT_VERSION represent stale data,
   // and should not be enumerated.
   const base::string16 db2_name(ASCIIToUTF16("db2"));
-  const int64_t db2_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION;
+  const int64_t db2_version = IndexedDBDatabaseMetadata::DEFAULT_VERSION;
   int64_t db2_id;
 
   leveldb::Status s =
diff --git a/content/browser/indexed_db/indexed_db_database.cc b/content/browser/indexed_db/indexed_db_database.cc
index 48187750..a877a7b 100644
--- a/content/browser/indexed_db/indexed_db_database.cc
+++ b/content/browser/indexed_db/indexed_db_database.cc
@@ -150,7 +150,7 @@
     : backing_store_(backing_store),
       metadata_(name,
                 kInvalidId,
-                IndexedDBDatabaseMetadata::NO_INT_VERSION,
+                IndexedDBDatabaseMetadata::NO_VERSION,
                 kInvalidId),
       identifier_(unique_identifier),
       factory_(factory) {
@@ -216,7 +216,7 @@
                                            &metadata_.object_stores);
 
   return backing_store_->CreateIDBDatabaseMetaData(
-      metadata_.name, metadata_.int_version, &metadata_.id);
+      metadata_.name, metadata_.version, &metadata_.id);
 }
 
 IndexedDBDatabase::~IndexedDBDatabase() {
@@ -1516,7 +1516,7 @@
     IndexedDBTransaction* transaction) {
   IDB_TRACE1(
       "IndexedDBDatabase::VersionChangeOperation", "txn.id", transaction->id());
-  int64_t old_version = metadata_.int_version;
+  int64_t old_version = metadata_.version;
   DCHECK_GT(version, old_version);
 
   if (!backing_store_->UpdateIDBDatabaseIntVersion(
@@ -1532,10 +1532,9 @@
   }
 
   transaction->ScheduleAbortTask(
-      base::Bind(&IndexedDBDatabase::VersionChangeAbortOperation,
-                 this,
-                 metadata_.int_version));
-  metadata_.int_version = version;
+      base::Bind(&IndexedDBDatabase::VersionChangeAbortOperation, this,
+                 metadata_.version));
+  metadata_.version = version;
 
   DCHECK(!pending_second_half_open_);
   pending_second_half_open_.reset(
@@ -1553,7 +1552,7 @@
   if (transaction->mode() == blink::WebIDBTransactionModeVersionChange) {
     if (pending_second_half_open_) {
       if (committed) {
-        DCHECK_EQ(pending_second_half_open_->version(), metadata_.int_version);
+        DCHECK_EQ(pending_second_half_open_->version(), metadata_.version);
         DCHECK(metadata_.id != kInvalidId);
 
         // Connection was already minted for OnUpgradeNeeded callback.
@@ -1609,7 +1608,7 @@
 void IndexedDBDatabase::ProcessPendingCalls() {
   if (pending_run_version_change_transaction_call_ && ConnectionCount() == 1) {
     DCHECK(pending_run_version_change_transaction_call_->version() >
-           metadata_.int_version);
+           metadata_.version);
     scoped_ptr<PendingUpgradeCall> pending_call =
         std::move(pending_run_version_change_transaction_call_);
     RunVersionChangeTransactionFinal(pending_call->callbacks(),
@@ -1702,11 +1701,10 @@
     // The database was deleted then immediately re-opened; OpenInternal()
     // recreates it in the backing store.
     if (OpenInternal().ok()) {
-      DCHECK_EQ(IndexedDBDatabaseMetadata::NO_INT_VERSION,
-                metadata_.int_version);
+      DCHECK_EQ(IndexedDBDatabaseMetadata::NO_VERSION, metadata_.version);
     } else {
       base::string16 message;
-      if (connection.version == IndexedDBDatabaseMetadata::NO_INT_VERSION) {
+      if (connection.version == IndexedDBDatabaseMetadata::NO_VERSION) {
         message = ASCIIToUTF16(
             "Internal error opening database with no version specified.");
       } else {
@@ -1723,11 +1721,11 @@
   // We infer that the database didn't exist from its lack of either type of
   // version.
   bool is_new_database =
-      metadata_.int_version == IndexedDBDatabaseMetadata::NO_INT_VERSION;
+      metadata_.version == IndexedDBDatabaseMetadata::NO_VERSION;
 
-  if (connection.version == IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION) {
+  if (connection.version == IndexedDBDatabaseMetadata::DEFAULT_VERSION) {
     // For unit tests only - skip upgrade steps. Calling from script with
-    // DEFAULT_INT_VERSION throws exception.
+    // DEFAULT_VERSION throws exception.
     // TODO(jsbell): DCHECK that not in unit tests.
     DCHECK(is_new_database);
     connection.callbacks->OnSuccess(
@@ -1739,7 +1737,7 @@
 
   // We may need to change the version.
   int64_t local_version = connection.version;
-  if (local_version == IndexedDBDatabaseMetadata::NO_INT_VERSION) {
+  if (local_version == IndexedDBDatabaseMetadata::NO_VERSION) {
     if (!is_new_database) {
       connection.callbacks->OnSuccess(
           CreateConnection(connection.database_callbacks,
@@ -1752,7 +1750,7 @@
     local_version = 1;
   }
 
-  if (local_version > metadata_.int_version) {
+  if (local_version > metadata_.version) {
     RunVersionChangeTransaction(connection.callbacks,
                                 CreateConnection(connection.database_callbacks,
                                                  connection.child_process_id),
@@ -1760,16 +1758,16 @@
                                 local_version);
     return;
   }
-  if (local_version < metadata_.int_version) {
+  if (local_version < metadata_.version) {
     connection.callbacks->OnError(IndexedDBDatabaseError(
         blink::WebIDBDatabaseExceptionVersionError,
         ASCIIToUTF16("The requested version (") +
             Int64ToString16(local_version) +
             ASCIIToUTF16(") is less than the existing version (") +
-            Int64ToString16(metadata_.int_version) + ASCIIToUTF16(").")));
+            Int64ToString16(metadata_.version) + ASCIIToUTF16(").")));
     return;
   }
-  DCHECK_EQ(local_version, metadata_.int_version);
+  DCHECK_EQ(local_version, metadata_.version);
   connection.callbacks->OnSuccess(
       CreateConnection(connection.database_callbacks,
                        connection.child_process_id),
@@ -1789,7 +1787,7 @@
     // close_pending set.
     for (const auto* iter : connections_) {
       if (iter != connection.get()) {
-        iter->callbacks()->OnVersionChange(metadata_.int_version,
+        iter->callbacks()->OnVersionChange(metadata_.version,
                                            requested_version);
       }
     }
@@ -1833,7 +1831,7 @@
       // Front end ensures the event is not fired at connections that have
       // close_pending set.
       connection->callbacks()->OnVersionChange(
-          metadata_.int_version, IndexedDBDatabaseMetadata::NO_INT_VERSION);
+          metadata_.version, IndexedDBDatabaseMetadata::NO_VERSION);
     }
     // OnBlocked will be fired at the request when one of the other
     // connections acks that the OnVersionChange was ignored.
@@ -1864,9 +1862,9 @@
     }
     return;
   }
-  int64_t old_version = metadata_.int_version;
+  int64_t old_version = metadata_.version;
   metadata_.id = kInvalidId;
-  metadata_.int_version = IndexedDBDatabaseMetadata::NO_INT_VERSION;
+  metadata_.version = IndexedDBDatabaseMetadata::NO_VERSION;
   metadata_.object_stores.clear();
   callbacks->OnSuccess(old_version);
   factory_->DatabaseDeleted(identifier_);
@@ -1886,10 +1884,10 @@
 void IndexedDBDatabase::VersionChangeIgnored() {
   if (pending_run_version_change_transaction_call_)
     pending_run_version_change_transaction_call_->callbacks()->OnBlocked(
-        metadata_.int_version);
+        metadata_.version);
 
   for (const auto& pending_delete_call : pending_delete_calls_)
-    pending_delete_call->callbacks()->OnBlocked(metadata_.int_version);
+    pending_delete_call->callbacks()->OnBlocked(metadata_.version);
 }
 
 
@@ -1956,11 +1954,11 @@
 }
 
 void IndexedDBDatabase::VersionChangeAbortOperation(
-    int64_t previous_int_version,
+    int64_t previous_version,
     IndexedDBTransaction* transaction) {
   DCHECK(!transaction);
   IDB_TRACE("IndexedDBDatabase::VersionChangeAbortOperation");
-  metadata_.int_version = previous_int_version;
+  metadata_.version = previous_version;
 }
 
 }  // namespace content
diff --git a/content/browser/indexed_db/indexed_db_database.h b/content/browser/indexed_db/indexed_db_database.h
index 173ffa1..207c1f9 100644
--- a/content/browser/indexed_db/indexed_db_database.h
+++ b/content/browser/indexed_db/indexed_db_database.h
@@ -193,7 +193,7 @@
                               scoped_refptr<IndexedDBCallbacks> callbacks,
                               scoped_ptr<IndexedDBConnection> connection,
                               IndexedDBTransaction* transaction);
-  void VersionChangeAbortOperation(int64_t previous_int_version,
+  void VersionChangeAbortOperation(int64_t previous_version,
                                    IndexedDBTransaction* transaction);
   void DeleteIndexOperation(int64_t object_store_id,
                             int64_t index_id,
diff --git a/content/browser/indexed_db/indexed_db_database_callbacks.cc b/content/browser/indexed_db/indexed_db_database_callbacks.cc
index 35b15c3..69f9b16 100644
--- a/content/browser/indexed_db/indexed_db_database_callbacks.cc
+++ b/content/browser/indexed_db/indexed_db_database_callbacks.cc
@@ -35,7 +35,7 @@
   if (!dispatcher_host_.get())
     return;
 
-  dispatcher_host_->Send(new IndexedDBMsg_DatabaseCallbacksIntVersionChange(
+  dispatcher_host_->Send(new IndexedDBMsg_DatabaseCallbacksVersionChange(
       ipc_thread_id_, ipc_database_callbacks_id_, old_version, new_version));
 }
 
diff --git a/content/browser/indexed_db/indexed_db_database_unittest.cc b/content/browser/indexed_db/indexed_db_database_unittest.cc
index a837945e4..efc1bdd 100644
--- a/content/browser/indexed_db/indexed_db_database_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_database_unittest.cc
@@ -76,11 +76,8 @@
       new MockIndexedDBDatabaseCallbacks());
   const int64_t transaction_id1 = 1;
   IndexedDBPendingConnection connection1(
-      request1,
-      callbacks1,
-      kFakeChildProcessId,
-      transaction_id1,
-      IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
+      request1, callbacks1, kFakeChildProcessId, transaction_id1,
+      IndexedDBDatabaseMetadata::DEFAULT_VERSION);
   db->OpenConnection(connection1);
 
   EXPECT_FALSE(backing_store->HasOneRef());  // db, connection count > 0
@@ -90,11 +87,8 @@
       new MockIndexedDBDatabaseCallbacks());
   const int64_t transaction_id2 = 2;
   IndexedDBPendingConnection connection2(
-      request2,
-      callbacks2,
-      kFakeChildProcessId,
-      transaction_id2,
-      IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
+      request2, callbacks2, kFakeChildProcessId, transaction_id2,
+      IndexedDBDatabaseMetadata::DEFAULT_VERSION);
   db->OpenConnection(connection2);
 
   EXPECT_FALSE(backing_store->HasOneRef());  // local and connection
@@ -134,11 +128,8 @@
   scoped_refptr<MockIndexedDBCallbacks> request(new MockIndexedDBCallbacks());
   const int64_t upgrade_transaction_id = 3;
   IndexedDBPendingConnection connection(
-      request,
-      callbacks,
-      kFakeChildProcessId,
-      upgrade_transaction_id,
-      IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
+      request, callbacks, kFakeChildProcessId, upgrade_transaction_id,
+      IndexedDBDatabaseMetadata::DEFAULT_VERSION);
   database->OpenConnection(connection);
   EXPECT_EQ(database.get(), request->connection()->database());
 
@@ -198,11 +189,8 @@
       new MockIndexedDBDatabaseCallbacks());
   const int64_t transaction_id1 = 1;
   IndexedDBPendingConnection connection(
-      request1,
-      callbacks1,
-      kFakeChildProcessId,
-      transaction_id1,
-      IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
+      request1, callbacks1, kFakeChildProcessId, transaction_id1,
+      IndexedDBDatabaseMetadata::DEFAULT_VERSION);
   db->OpenConnection(connection);
 
   EXPECT_FALSE(backing_store->HasOneRef());  // local and db
@@ -246,13 +234,9 @@
     callbacks_ = new MockIndexedDBDatabaseCallbacks();
     const int64_t transaction_id = 1;
     db_->OpenConnection(IndexedDBPendingConnection(
-        request_,
-        callbacks_,
-        kFakeChildProcessId,
-        transaction_id,
-        IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION));
-    EXPECT_EQ(IndexedDBDatabaseMetadata::NO_INT_VERSION,
-              db_->metadata().int_version);
+        request_, callbacks_, kFakeChildProcessId, transaction_id,
+        IndexedDBDatabaseMetadata::DEFAULT_VERSION));
+    EXPECT_EQ(IndexedDBDatabaseMetadata::NO_VERSION, db_->metadata().version);
 
     transaction_ = IndexedDBClassFactory::Get()->CreateIndexedDBTransaction(
         transaction_id, callbacks_, std::set<int64_t>() /*scope*/,
diff --git a/content/browser/indexed_db/indexed_db_dispatcher_host.cc b/content/browser/indexed_db/indexed_db_dispatcher_host.cc
index 1801659..6e83583 100644
--- a/content/browser/indexed_db/indexed_db_dispatcher_host.cc
+++ b/content/browser/indexed_db/indexed_db_dispatcher_host.cc
@@ -278,7 +278,7 @@
   ::IndexedDBDatabaseMetadata metadata;
   metadata.id = web_metadata.id;
   metadata.name = web_metadata.name;
-  metadata.int_version = web_metadata.int_version;
+  metadata.version = web_metadata.version;
   metadata.max_object_store_id = web_metadata.max_object_store_id;
 
   for (const auto& iter : web_metadata.object_stores) {
diff --git a/content/browser/indexed_db/indexed_db_factory_unittest.cc b/content/browser/indexed_db/indexed_db_factory_unittest.cc
index 866d3f5..946799a 100644
--- a/content/browser/indexed_db/indexed_db_factory_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_factory_unittest.cc
@@ -283,11 +283,8 @@
       new MockIndexedDBDatabaseCallbacks());
   const int64_t transaction_id = 1;
   IndexedDBPendingConnection connection(
-      callbacks,
-      db_callbacks,
-      0, /* child_process_id */
-      transaction_id,
-      IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
+      callbacks, db_callbacks, 0, /* child_process_id */
+      transaction_id, IndexedDBDatabaseMetadata::DEFAULT_VERSION);
   factory()->Open(ASCIIToUTF16("db"),
                   connection,
                   NULL /* request_context */,
@@ -316,11 +313,8 @@
       new MockIndexedDBDatabaseCallbacks());
   const int64_t transaction_id = 1;
   IndexedDBPendingConnection connection(
-      callbacks,
-      db_callbacks,
-      0, /* child_process_id */
-      transaction_id,
-      IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
+      callbacks, db_callbacks, 0, /* child_process_id */
+      transaction_id, IndexedDBDatabaseMetadata::DEFAULT_VERSION);
   factory()->Open(ASCIIToUTF16("db"),
                   connection,
                   NULL /* request_context */,
@@ -411,11 +405,8 @@
       new MockIndexedDBDatabaseCallbacks());
   const int64_t transaction_id = 1;
   IndexedDBPendingConnection connection(
-      callbacks,
-      db_callbacks,
-      0, /* child_process_id */
-      transaction_id,
-      IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
+      callbacks, db_callbacks, 0, /* child_process_id */
+      transaction_id, IndexedDBDatabaseMetadata::DEFAULT_VERSION);
   factory()->Open(ASCIIToUTF16("db"),
                   connection,
                   NULL /* request_context */,
diff --git a/content/browser/indexed_db/indexed_db_fake_backing_store.cc b/content/browser/indexed_db/indexed_db_fake_backing_store.cc
index c0bfdcfc..b2aeb4c9 100644
--- a/content/browser/indexed_db/indexed_db_fake_backing_store.cc
+++ b/content/browser/indexed_db/indexed_db_fake_backing_store.cc
@@ -45,7 +45,7 @@
 
 leveldb::Status IndexedDBFakeBackingStore::CreateIDBDatabaseMetaData(
     const base::string16& name,
-    int64_t int_version,
+    int64_t version,
     int64_t* row_id) {
   return leveldb::Status::OK();
 }
diff --git a/content/browser/indexed_db/indexed_db_fake_backing_store.h b/content/browser/indexed_db/indexed_db_fake_backing_store.h
index 94fc47e..3e16869 100644
--- a/content/browser/indexed_db/indexed_db_fake_backing_store.h
+++ b/content/browser/indexed_db/indexed_db_fake_backing_store.h
@@ -30,7 +30,7 @@
                                          IndexedDBDatabaseMetadata*,
                                          bool* found) override;
   leveldb::Status CreateIDBDatabaseMetaData(const base::string16& name,
-                                            int64_t int_version,
+                                            int64_t version,
                                             int64_t* row_id) override;
   bool UpdateIDBDatabaseIntVersion(Transaction*,
                                    int64_t row_id,
diff --git a/content/browser/indexed_db/indexed_db_leveldb_coding.h b/content/browser/indexed_db/indexed_db_leveldb_coding.h
index a3edbc0..5be0eec 100644
--- a/content/browser/indexed_db/indexed_db_leveldb_coding.h
+++ b/content/browser/indexed_db/indexed_db_leveldb_coding.h
@@ -237,9 +237,9 @@
   enum MetaDataType {
     ORIGIN_NAME = 0,
     DATABASE_NAME = 1,
-    USER_VERSION = 2,  // Obsolete
+    USER_STRING_VERSION = 2,  // Obsolete
     MAX_OBJECT_STORE_ID = 3,
-    USER_INT_VERSION = 4,
+    USER_VERSION = 4,
     BLOB_KEY_GENERATOR_CURRENT_NUMBER = 5,
     MAX_SIMPLE_METADATA_TYPE = 6
   };
diff --git a/content/browser/indexed_db/indexed_db_leveldb_coding_unittest.cc b/content/browser/indexed_db/indexed_db_leveldb_coding_unittest.cc
index 2f9e141d..0c30084 100644
--- a/content/browser/indexed_db/indexed_db_leveldb_coding_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_leveldb_coding_unittest.cc
@@ -888,11 +888,11 @@
   keys.push_back(
       DatabaseMetaDataKey::Encode(1, DatabaseMetaDataKey::DATABASE_NAME));
   keys.push_back(
-      DatabaseMetaDataKey::Encode(1, DatabaseMetaDataKey::USER_VERSION));
+      DatabaseMetaDataKey::Encode(1, DatabaseMetaDataKey::USER_STRING_VERSION));
   keys.push_back(
       DatabaseMetaDataKey::Encode(1, DatabaseMetaDataKey::MAX_OBJECT_STORE_ID));
   keys.push_back(
-      DatabaseMetaDataKey::Encode(1, DatabaseMetaDataKey::USER_INT_VERSION));
+      DatabaseMetaDataKey::Encode(1, DatabaseMetaDataKey::USER_VERSION));
   keys.push_back(
       ObjectStoreMetaDataKey::Encode(1, 1, ObjectStoreMetaDataKey::NAME));
   keys.push_back(
diff --git a/content/browser/indexed_db/indexed_db_metadata.cc b/content/browser/indexed_db/indexed_db_metadata.cc
index 1ef86609..899c881ad 100644
--- a/content/browser/indexed_db/indexed_db_metadata.cc
+++ b/content/browser/indexed_db/indexed_db_metadata.cc
@@ -49,17 +49,16 @@
 IndexedDBObjectStoreMetadata& IndexedDBObjectStoreMetadata::operator=(
     const IndexedDBObjectStoreMetadata& other) = default;
 
-IndexedDBDatabaseMetadata::IndexedDBDatabaseMetadata()
-    : int_version(NO_INT_VERSION) {}
+IndexedDBDatabaseMetadata::IndexedDBDatabaseMetadata() : version(NO_VERSION) {}
 
 IndexedDBDatabaseMetadata::IndexedDBDatabaseMetadata(
     const base::string16& name,
     int64_t id,
-    int64_t int_version,
+    int64_t version,
     int64_t max_object_store_id)
     : name(name),
       id(id),
-      int_version(int_version),
+      version(version),
       max_object_store_id(max_object_store_id) {}
 
 IndexedDBDatabaseMetadata::IndexedDBDatabaseMetadata(
diff --git a/content/browser/indexed_db/indexed_db_metadata.h b/content/browser/indexed_db/indexed_db_metadata.h
index 5554709..ec9d9ac 100644
--- a/content/browser/indexed_db/indexed_db_metadata.h
+++ b/content/browser/indexed_db/indexed_db_metadata.h
@@ -61,17 +61,14 @@
 
 struct CONTENT_EXPORT IndexedDBDatabaseMetadata {
   // TODO(jsbell): These can probably be collapsed into 0.
-  enum {
-    NO_INT_VERSION = -1,
-    DEFAULT_INT_VERSION = 0
-  };
+  enum { NO_VERSION = -1, DEFAULT_VERSION = 0 };
 
   typedef std::map<int64_t, IndexedDBObjectStoreMetadata> ObjectStoreMap;
 
   IndexedDBDatabaseMetadata();
   IndexedDBDatabaseMetadata(const base::string16& name,
                             int64_t id,
-                            int64_t int_version,
+                            int64_t version,
                             int64_t max_object_store_id);
   IndexedDBDatabaseMetadata(const IndexedDBDatabaseMetadata& other);
   ~IndexedDBDatabaseMetadata();
@@ -79,7 +76,7 @@
 
   base::string16 name;
   int64_t id;
-  int64_t int_version;
+  int64_t version;
   int64_t max_object_store_id;
 
   ObjectStoreMap object_stores;
diff --git a/content/browser/indexed_db/indexed_db_pending_connection.cc b/content/browser/indexed_db/indexed_db_pending_connection.cc
index ee16aba..34f49242 100644
--- a/content/browser/indexed_db/indexed_db_pending_connection.cc
+++ b/content/browser/indexed_db/indexed_db_pending_connection.cc
@@ -18,6 +18,9 @@
       transaction_id(transaction_id_in),
       version(version_in) {}
 
+IndexedDBPendingConnection::IndexedDBPendingConnection(
+    const IndexedDBPendingConnection& other) = default;
+
 IndexedDBPendingConnection::~IndexedDBPendingConnection() {}
 
 }  // namespace content
diff --git a/content/browser/indexed_db/indexed_db_pending_connection.h b/content/browser/indexed_db/indexed_db_pending_connection.h
index b66d9cd..10e1b05d 100644
--- a/content/browser/indexed_db/indexed_db_pending_connection.h
+++ b/content/browser/indexed_db/indexed_db_pending_connection.h
@@ -24,6 +24,7 @@
       int child_process_id_in,
       int64_t transaction_id_in,
       int64_t version_in);
+  IndexedDBPendingConnection(const IndexedDBPendingConnection& other);
   ~IndexedDBPendingConnection();
   scoped_refptr<IndexedDBCallbacks> callbacks;
   scoped_refptr<IndexedDBDatabaseCallbacks> database_callbacks;
diff --git a/content/browser/indexed_db/indexed_db_unittest.cc b/content/browser/indexed_db/indexed_db_unittest.cc
index b8ae82f9..9ed1e738 100644
--- a/content/browser/indexed_db/indexed_db_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_unittest.cc
@@ -278,11 +278,8 @@
       new MockIndexedDBDatabaseCallbacks());
   const int64_t transaction_id = 1;
   IndexedDBPendingConnection connection(
-      callbacks,
-      db_callbacks,
-      0 /* child_process_id */,
-      transaction_id,
-      IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
+      callbacks, db_callbacks, 0 /* child_process_id */, transaction_id,
+      IndexedDBDatabaseMetadata::DEFAULT_VERSION);
   factory->Open(base::ASCIIToUTF16("db"),
                 connection,
                 NULL /* request_context */,
diff --git a/content/browser/level_db_wrapper_impl.cc b/content/browser/level_db_wrapper_impl.cc
new file mode 100644
index 0000000..d2f1b3e
--- /dev/null
+++ b/content/browser/level_db_wrapper_impl.cc
@@ -0,0 +1,57 @@
+// Copyright 2016 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/browser/level_db_wrapper_impl.h"
+
+#include "base/bind.h"
+
+namespace content {
+
+LevelDBWrapperImpl::LevelDBWrapperImpl(
+    const std::string& prefix, const base::Closure& no_bindings_callback)
+    : prefix_(prefix), no_bindings_callback_(no_bindings_callback) {
+  bindings_.set_connection_error_handler(base::Bind(
+      &LevelDBWrapperImpl::OnConnectionError, base::Unretained(this)));
+}
+
+void LevelDBWrapperImpl::Bind(mojo::InterfaceRequest<LevelDBWrapper> request,
+                              LevelDBObserverPtr observer) {
+  // TODO(jam): store observer and call it when changes occur.
+  bindings_.AddBinding(this, std::move(request));
+}
+
+LevelDBWrapperImpl::~LevelDBWrapperImpl() {
+  no_bindings_callback_.Run();
+}
+
+void LevelDBWrapperImpl::Put(mojo::Array<uint8_t> key,
+                             mojo::Array<uint8_t> value,
+                             const mojo::String& source,
+                             const PutCallback& callback) {
+}
+
+void LevelDBWrapperImpl::Delete(mojo::Array<uint8_t> key,
+                                const mojo::String& source,
+                                const DeleteCallback& callback) {
+}
+
+void LevelDBWrapperImpl::DeleteAll(const mojo::String& source,
+                                   const DeleteAllCallback& callback) {
+}
+
+void LevelDBWrapperImpl::Get(mojo::Array<uint8_t> key,
+                             const GetCallback& callback) {
+}
+
+void LevelDBWrapperImpl::GetAll(const GetAllCallback& callback) {
+}
+
+void LevelDBWrapperImpl::OnConnectionError() {
+  if (!bindings_.empty())
+    return;
+
+  no_bindings_callback_.Run();
+}
+
+}  // namespace content
diff --git a/content/browser/level_db_wrapper_impl.h b/content/browser/level_db_wrapper_impl.h
new file mode 100644
index 0000000..d0f74e5b
--- /dev/null
+++ b/content/browser/level_db_wrapper_impl.h
@@ -0,0 +1,59 @@
+// Copyright 2016 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_BROWSER_LEVEL_DB_WRAPPER_IMPL_H_
+#define CONTENT_BROWSER_LEVEL_DB_WRAPPER_IMPL_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "content/common/leveldb_wrapper.mojom.h"
+#include "mojo/public/cpp/bindings/weak_binding_set.h"
+
+namespace content {
+
+// This is a wrapper around a leveldb::LevelDBDatabase. It adds a couple of
+// features:
+// 1) Adds the given prefix, if any, to all keys. This allows the sharing of one
+//    database across many, possibly untrusted, consumers and ensuring that they
+//    can't access each other's values.
+// 2) Informs an observer when the given prefix' values are modified by another
+//    process.
+// 3) Throttles requests to avoid overwhelming the disk.
+class LevelDBWrapperImpl : public LevelDBWrapper {
+ public:
+  // |no_bindings_callback| will be called when this object has no more
+  // bindings.
+  LevelDBWrapperImpl(const std::string& prefix,
+                     const base::Closure& no_bindings_callback);
+  ~LevelDBWrapperImpl() override;
+
+  void Bind(mojo::InterfaceRequest<LevelDBWrapper> request,
+            LevelDBObserverPtr observer);
+
+ private:
+  // LevelDBWrapperImpl:
+  void Put(mojo::Array<uint8_t> key,
+           mojo::Array<uint8_t> value,
+           const mojo::String& source,
+           const PutCallback& callback) override;
+  void Delete(mojo::Array<uint8_t> key,
+              const mojo::String& source,
+              const DeleteCallback& callback) override;
+  void DeleteAll(const mojo::String& source,
+                 const DeleteAllCallback& callback) override;
+  void Get(mojo::Array<uint8_t> key, const GetCallback& callback) override;
+  void GetAll(const GetAllCallback& callback) override;
+
+  void OnConnectionError();
+
+  std::string prefix_;
+  mojo::WeakBindingSet<LevelDBWrapper> bindings_;
+  base::Closure no_bindings_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(LevelDBWrapperImpl);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_LEVEL_DB_WRAPPER_IMPL_H_
diff --git a/content/browser/loader/async_resource_handler.cc b/content/browser/loader/async_resource_handler.cc
index f4394499..8f02d3f 100644
--- a/content/browser/loader/async_resource_handler.cc
+++ b/content/browser/loader/async_resource_handler.cc
@@ -31,7 +31,6 @@
 #include "content/public/common/resource_response.h"
 #include "net/base/io_buffer.h"
 #include "net/base/load_flags.h"
-#include "net/base/net_util.h"
 #include "net/log/net_log.h"
 #include "net/url_request/redirect_info.h"
 
diff --git a/content/browser/media/OWNERS b/content/browser/media/OWNERS
index ea102ff..d363e52 100644
--- a/content/browser/media/OWNERS
+++ b/content/browser/media/OWNERS
@@ -2,14 +2,7 @@
 ddorwin@chromium.org
 xhwang@chromium.org
 
-# WebRTC OWNERS.
-perkj@chromium.org
-tommi@chromium.org
-
 per-file midi_*=toyoshim@chromium.org
 
 # For changes related to the tab media indicators.
 per-file audio_stream_monitor*=miu@chromium.org
-
-# For WebRTC browser tests, etc.
-per-file *webrtc*browsertest*=phoglund@chromium.org
diff --git a/content/browser/media/capture/audio_mirroring_manager.cc b/content/browser/media/capture/audio_mirroring_manager.cc
index a75eb3c..f8b8b3a 100644
--- a/content/browser/media/capture/audio_mirroring_manager.cc
+++ b/content/browser/media/capture/audio_mirroring_manager.cc
@@ -209,6 +209,9 @@
     diverter(stream_diverter),
     destination(NULL) {}
 
+AudioMirroringManager::StreamRoutingState::StreamRoutingState(
+    const StreamRoutingState& other) = default;
+
 AudioMirroringManager::StreamRoutingState::~StreamRoutingState() {}
 
 }  // namespace content
diff --git a/content/browser/media/capture/audio_mirroring_manager.h b/content/browser/media/capture/audio_mirroring_manager.h
index 4e44699..a624a082 100644
--- a/content/browser/media/capture/audio_mirroring_manager.h
+++ b/content/browser/media/capture/audio_mirroring_manager.h
@@ -122,6 +122,7 @@
 
     StreamRoutingState(const SourceFrameRef& source_frame,
                        Diverter* stream_diverter);
+    StreamRoutingState(const StreamRoutingState& other);
     ~StreamRoutingState();
   };
 
diff --git a/content/browser/media/webrtc/OWNERS b/content/browser/media/webrtc/OWNERS
new file mode 100644
index 0000000..43cd73b
--- /dev/null
+++ b/content/browser/media/webrtc/OWNERS
@@ -0,0 +1,5 @@
+perkj@chromium.org
+tommi@chromium.org
+
+# For WebRTC browser tests, etc.
+per-file *webrtc*browsertest*=phoglund@chromium.org
diff --git a/content/browser/media/webrtc_audio_debug_recordings_browsertest.cc b/content/browser/media/webrtc/webrtc_audio_debug_recordings_browsertest.cc
similarity index 99%
rename from content/browser/media/webrtc_audio_debug_recordings_browsertest.cc
rename to content/browser/media/webrtc/webrtc_audio_debug_recordings_browsertest.cc
index f42aed10..12b224b 100644
--- a/content/browser/media/webrtc_audio_debug_recordings_browsertest.cc
+++ b/content/browser/media/webrtc/webrtc_audio_debug_recordings_browsertest.cc
@@ -8,7 +8,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
-#include "content/browser/media/webrtc_internals.h"
+#include "content/browser/media/webrtc/webrtc_internals.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test_utils.h"
diff --git a/content/browser/media/webrtc_browsertest.cc b/content/browser/media/webrtc/webrtc_browsertest.cc
similarity index 100%
rename from content/browser/media/webrtc_browsertest.cc
rename to content/browser/media/webrtc/webrtc_browsertest.cc
diff --git a/content/browser/media/webrtc_getusermedia_browsertest.cc b/content/browser/media/webrtc/webrtc_getusermedia_browsertest.cc
similarity index 99%
rename from content/browser/media/webrtc_getusermedia_browsertest.cc
rename to content/browser/media/webrtc/webrtc_getusermedia_browsertest.cc
index 740f4ec..3bf34cf 100644
--- a/content/browser/media/webrtc_getusermedia_browsertest.cc
+++ b/content/browser/media/webrtc/webrtc_getusermedia_browsertest.cc
@@ -12,7 +12,7 @@
 #include "base/trace_event/trace_event_impl.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "content/browser/media/webrtc_internals.h"
+#include "content/browser/media/webrtc/webrtc_internals.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
diff --git a/content/browser/media/webrtc_identity_store.cc b/content/browser/media/webrtc/webrtc_identity_store.cc
similarity index 98%
rename from content/browser/media/webrtc_identity_store.cc
rename to content/browser/media/webrtc/webrtc_identity_store.cc
index 2ada2a1..a5b91ad 100644
--- a/content/browser/media/webrtc_identity_store.cc
+++ b/content/browser/media/webrtc/webrtc_identity_store.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/media/webrtc_identity_store.h"
+#include "content/browser/media/webrtc/webrtc_identity_store.h"
 
 #include <stddef.h>
 #include <stdint.h>
@@ -15,7 +15,7 @@
 #include "base/macros.h"
 #include "base/rand_util.h"
 #include "base/threading/worker_pool.h"
-#include "content/browser/media/webrtc_identity_store_backend.h"
+#include "content/browser/media/webrtc/webrtc_identity_store_backend.h"
 #include "content/public/browser/browser_thread.h"
 #include "crypto/rsa_private_key.h"
 #include "net/base/net_errors.h"
diff --git a/content/browser/media/webrtc_identity_store.h b/content/browser/media/webrtc/webrtc_identity_store.h
similarity index 96%
rename from content/browser/media/webrtc_identity_store.h
rename to content/browser/media/webrtc/webrtc_identity_store.h
index c788d0d..360171d 100644
--- a/content/browser/media/webrtc_identity_store.h
+++ b/content/browser/media/webrtc/webrtc_identity_store.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_MEDIA_WEBRTC_IDENTITY_STORE_H_
-#define CONTENT_BROWSER_MEDIA_WEBRTC_IDENTITY_STORE_H_
+#ifndef CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_IDENTITY_STORE_H_
+#define CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_IDENTITY_STORE_H_
 
 #include <string>
 #include <vector>
@@ -123,4 +123,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_MEDIA_WEBRTC_IDENTITY_STORE_H_
+#endif  // CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_IDENTITY_STORE_H_
diff --git a/content/browser/media/webrtc_identity_store_backend.cc b/content/browser/media/webrtc/webrtc_identity_store_backend.cc
similarity index 99%
rename from content/browser/media/webrtc_identity_store_backend.cc
rename to content/browser/media/webrtc/webrtc_identity_store_backend.cc
index 76d4827..e098841 100644
--- a/content/browser/media/webrtc_identity_store_backend.cc
+++ b/content/browser/media/webrtc/webrtc_identity_store_backend.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/media/webrtc_identity_store_backend.h"
+#include "content/browser/media/webrtc/webrtc_identity_store_backend.h"
 
 #include <stddef.h>
 #include <stdint.h>
diff --git a/content/browser/media/webrtc_identity_store_backend.h b/content/browser/media/webrtc/webrtc_identity_store_backend.h
similarity index 94%
rename from content/browser/media/webrtc_identity_store_backend.h
rename to content/browser/media/webrtc/webrtc_identity_store_backend.h
index 906f71a6..37a5d55 100644
--- a/content/browser/media/webrtc_identity_store_backend.h
+++ b/content/browser/media/webrtc/webrtc_identity_store_backend.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_MEDIA_WEBRTC_IDENTITY_STORE_BACKEND_H_
-#define CONTENT_BROWSER_MEDIA_WEBRTC_IDENTITY_STORE_BACKEND_H_
+#ifndef CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_IDENTITY_STORE_BACKEND_H_
+#define CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_IDENTITY_STORE_BACKEND_H_
 
 #include <map>
 #include <string>
@@ -120,4 +120,4 @@
 };
 }
 
-#endif  // CONTENT_BROWSER_MEDIA_WEBRTC_IDENTITY_STORE_BACKEND_H_
+#endif  // CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_IDENTITY_STORE_BACKEND_H_
diff --git a/content/browser/media/webrtc_identity_store_unittest.cc b/content/browser/media/webrtc/webrtc_identity_store_unittest.cc
similarity index 99%
rename from content/browser/media/webrtc_identity_store_unittest.cc
rename to content/browser/media/webrtc/webrtc_identity_store_unittest.cc
index 025e2f32..2e9a4da 100644
--- a/content/browser/media/webrtc_identity_store_unittest.cc
+++ b/content/browser/media/webrtc/webrtc_identity_store_unittest.cc
@@ -6,7 +6,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/test/sequenced_worker_pool_owner.h"
-#include "content/browser/media/webrtc_identity_store.h"
+#include "content/browser/media/webrtc/webrtc_identity_store.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_utils.h"
 #include "net/base/net_errors.h"
diff --git a/content/browser/media/webrtc_internals.cc b/content/browser/media/webrtc/webrtc_internals.cc
similarity index 98%
rename from content/browser/media/webrtc_internals.cc
rename to content/browser/media/webrtc/webrtc_internals.cc
index d7d5a97..aa10c5e4 100644
--- a/content/browser/media/webrtc_internals.cc
+++ b/content/browser/media/webrtc/webrtc_internals.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/media/webrtc_internals.h"
+#include "content/browser/media/webrtc/webrtc_internals.h"
 
 #include <stddef.h>
 
 #include "base/strings/string_number_conversions.h"
 #include "build/build_config.h"
-#include "content/browser/media/webrtc_internals_ui_observer.h"
+#include "content/browser/media/webrtc/webrtc_internals_ui_observer.h"
 #include "content/browser/web_contents/web_contents_view.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
diff --git a/content/browser/media/webrtc_internals.h b/content/browser/media/webrtc/webrtc_internals.h
similarity index 98%
rename from content/browser/media/webrtc_internals.h
rename to content/browser/media/webrtc/webrtc_internals.h
index 7b64ebc..57c0e44 100644
--- a/content/browser/media/webrtc_internals.h
+++ b/content/browser/media/webrtc/webrtc_internals.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_H_
-#define CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_H_
+#ifndef CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_INTERNALS_H_
+#define CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_INTERNALS_H_
 
 #include <queue>
 
@@ -239,4 +239,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_H_
+#endif  // CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_INTERNALS_H_
diff --git a/content/browser/media/webrtc_internals_browsertest.cc b/content/browser/media/webrtc/webrtc_internals_browsertest.cc
similarity index 100%
rename from content/browser/media/webrtc_internals_browsertest.cc
rename to content/browser/media/webrtc/webrtc_internals_browsertest.cc
diff --git a/content/browser/media/webrtc_internals_message_handler.cc b/content/browser/media/webrtc/webrtc_internals_message_handler.cc
similarity index 96%
rename from content/browser/media/webrtc_internals_message_handler.cc
rename to content/browser/media/webrtc/webrtc_internals_message_handler.cc
index 33a69ef..eaaea95a 100644
--- a/content/browser/media/webrtc_internals_message_handler.cc
+++ b/content/browser/media/webrtc/webrtc_internals_message_handler.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/media/webrtc_internals_message_handler.h"
+#include "content/browser/media/webrtc/webrtc_internals_message_handler.h"
 
-#include "content/browser/media/webrtc_internals.h"
+#include "content/browser/media/webrtc/webrtc_internals.h"
 #include "content/common/media/peer_connection_tracker_messages.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
diff --git a/content/browser/media/webrtc_internals_message_handler.h b/content/browser/media/webrtc/webrtc_internals_message_handler.h
similarity index 83%
rename from content/browser/media/webrtc_internals_message_handler.h
rename to content/browser/media/webrtc/webrtc_internals_message_handler.h
index 1b42f21..82e242e 100644
--- a/content/browser/media/webrtc_internals_message_handler.h
+++ b/content/browser/media/webrtc/webrtc_internals_message_handler.h
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_MESSAGE_HANDLER_H_
-#define CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_MESSAGE_HANDLER_H_
+#ifndef CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_INTERNALS_MESSAGE_HANDLER_H_
+#define CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_INTERNALS_MESSAGE_HANDLER_H_
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "content/browser/media/webrtc_internals_ui_observer.h"
+#include "content/browser/media/webrtc/webrtc_internals_ui_observer.h"
 #include "content/public/browser/web_ui_message_handler.h"
 
 namespace base {
@@ -49,4 +49,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_MESSAGE_HANDLER_H_
+#endif  // CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_INTERNALS_MESSAGE_HANDLER_H_
diff --git a/content/browser/media/webrtc_internals_ui.cc b/content/browser/media/webrtc/webrtc_internals_ui.cc
similarity index 90%
rename from content/browser/media/webrtc_internals_ui.cc
rename to content/browser/media/webrtc/webrtc_internals_ui.cc
index 6797030..c08c9f2f 100644
--- a/content/browser/media/webrtc_internals_ui.cc
+++ b/content/browser/media/webrtc/webrtc_internals_ui.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/media/webrtc_internals_ui.h"
+#include "content/browser/media/webrtc/webrtc_internals_ui.h"
 
-#include "content/browser/media/webrtc_internals_message_handler.h"
+#include "content/browser/media/webrtc/webrtc_internals_message_handler.h"
 #include "content/grit/content_resources.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
diff --git a/content/browser/media/webrtc_internals_ui.h b/content/browser/media/webrtc/webrtc_internals_ui.h
similarity index 74%
rename from content/browser/media/webrtc_internals_ui.h
rename to content/browser/media/webrtc/webrtc_internals_ui.h
index 541af02..2347ff9 100644
--- a/content/browser/media/webrtc_internals_ui.h
+++ b/content/browser/media/webrtc/webrtc_internals_ui.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_UI_H_
-#define CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_UI_H_
+#ifndef CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_INTERNALS_UI_H_
+#define CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_INTERNALS_UI_H_
 
 #include "base/macros.h"
 #include "content/public/browser/web_ui_controller.h"
@@ -21,4 +21,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_UI_H_
+#endif  // CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_INTERNALS_UI_H_
diff --git a/content/browser/media/webrtc_internals_ui_observer.h b/content/browser/media/webrtc/webrtc_internals_ui_observer.h
similarity index 75%
rename from content/browser/media/webrtc_internals_ui_observer.h
rename to content/browser/media/webrtc/webrtc_internals_ui_observer.h
index 31082b618..e7dfed1 100644
--- a/content/browser/media/webrtc_internals_ui_observer.h
+++ b/content/browser/media/webrtc/webrtc_internals_ui_observer.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_UI_OBSERVER_H_
-#define CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_UI_OBSERVER_H_
+#ifndef CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_INTERNALS_UI_OBSERVER_H_
+#define CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_INTERNALS_UI_OBSERVER_H_
 
 #include <string>
 
@@ -26,4 +26,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_MEDIA_WEBRTC_INTERNALS_UI_OBSERVER_H_
+#endif  // CONTENT_BROWSER_MEDIA_WEBRTC_WEBRTC_INTERNALS_UI_OBSERVER_H_
diff --git a/content/browser/media/webrtc_internals_unittest.cc b/content/browser/media/webrtc/webrtc_internals_unittest.cc
similarity index 98%
rename from content/browser/media/webrtc_internals_unittest.cc
rename to content/browser/media/webrtc/webrtc_internals_unittest.cc
index 6ef2137..a1ba7e73d 100644
--- a/content/browser/media/webrtc_internals_unittest.cc
+++ b/content/browser/media/webrtc/webrtc_internals_unittest.cc
@@ -6,8 +6,8 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/values.h"
-#include "content/browser/media/webrtc_internals.h"
-#include "content/browser/media/webrtc_internals_ui_observer.h"
+#include "content/browser/media/webrtc/webrtc_internals.h"
+#include "content/browser/media/webrtc/webrtc_internals_ui_observer.h"
 #include "content/public/test/test_browser_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/content/browser/media/webrtc_ip_permissions_browsertest.cc b/content/browser/media/webrtc/webrtc_ip_permissions_browsertest.cc
similarity index 100%
rename from content/browser/media/webrtc_ip_permissions_browsertest.cc
rename to content/browser/media/webrtc/webrtc_ip_permissions_browsertest.cc
diff --git a/content/browser/media/webrtc_media_recorder_browsertest.cc b/content/browser/media/webrtc/webrtc_media_recorder_browsertest.cc
similarity index 100%
rename from content/browser/media/webrtc_media_recorder_browsertest.cc
rename to content/browser/media/webrtc/webrtc_media_recorder_browsertest.cc
diff --git a/content/browser/media/webrtc_webcam_browsertest.cc b/content/browser/media/webrtc/webrtc_webcam_browsertest.cc
similarity index 100%
rename from content/browser/media/webrtc_webcam_browsertest.cc
rename to content/browser/media/webrtc/webrtc_webcam_browsertest.cc
diff --git a/content/browser/mojo/mojo_shell_context.cc b/content/browser/mojo/mojo_shell_context.cc
index 13459912..74a50e3 100644
--- a/content/browser/mojo/mojo_shell_context.cc
+++ b/content/browser/mojo/mojo_shell_context.cc
@@ -160,7 +160,7 @@
       mojo::shell::mojom::InterfaceProviderRequest request,
       mojo::shell::mojom::InterfaceProviderPtr exposed_services,
       const mojo::shell::CapabilityFilter& filter,
-      const mojo::shell::mojom::Shell::ConnectCallback& callback) {
+      const mojo::shell::mojom::Connector::ConnectCallback& callback) {
     if (task_runner_ == base::ThreadTaskRunnerHandle::Get()) {
       if (shell_context_) {
         shell_context_->ConnectToApplicationOnOwnThread(
@@ -198,9 +198,12 @@
 MojoShellContext::MojoShellContext() {
   proxy_.Get().reset(new Proxy(this));
 
+  scoped_refptr<base::SingleThreadTaskRunner> file_task_runner =
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE);
   bool register_mojo_url_schemes = false;
-  application_manager_.reset(
-      new mojo::shell::ApplicationManager(register_mojo_url_schemes));
+
+  application_manager_.reset(new mojo::shell::ApplicationManager(
+      nullptr, file_task_runner.get(), register_mojo_url_schemes, nullptr));
 
   application_manager_->set_default_loader(
       scoped_ptr<mojo::shell::ApplicationLoader>(new DefaultApplicationLoader));
@@ -259,7 +262,7 @@
     mojo::shell::mojom::InterfaceProviderRequest request,
     mojo::shell::mojom::InterfaceProviderPtr exposed_services,
     const mojo::shell::CapabilityFilter& filter,
-    const mojo::shell::mojom::Shell::ConnectCallback& callback) {
+    const mojo::shell::mojom::Connector::ConnectCallback& callback) {
   proxy_.Get()->ConnectToApplication(url, requestor_url, std::move(request),
                                      std::move(exposed_services), filter,
                                      callback);
@@ -271,12 +274,15 @@
     mojo::shell::mojom::InterfaceProviderRequest request,
     mojo::shell::mojom::InterfaceProviderPtr exposed_services,
     const mojo::shell::CapabilityFilter& filter,
-    const mojo::shell::mojom::Shell::ConnectCallback& callback) {
+    const mojo::shell::mojom::Connector::ConnectCallback& callback) {
   scoped_ptr<mojo::shell::ConnectParams> params(new mojo::shell::ConnectParams);
+  // TODO(beng): kUserRoot is obviously wrong.
   params->set_source(
       mojo::shell::Identity(requestor_url, std::string(),
+                            mojo::shell::mojom::Connector::kUserRoot,
                             mojo::shell::GetPermissiveCapabilityFilter()));
-  params->set_target(mojo::shell::Identity(url, std::string(), filter));
+  params->set_target(mojo::shell::Identity(
+      url, std::string(), mojo::shell::mojom::Connector::kUserRoot, filter));
   params->set_remote_interfaces(std::move(request));
   params->set_local_interfaces(std::move(exposed_services));
   params->set_connect_callback(callback);
diff --git a/content/browser/mojo/mojo_shell_context.h b/content/browser/mojo/mojo_shell_context.h
index d542654..50ca49c 100644
--- a/content/browser/mojo/mojo_shell_context.h
+++ b/content/browser/mojo/mojo_shell_context.h
@@ -44,7 +44,7 @@
       mojo::shell::mojom::InterfaceProviderRequest request,
       mojo::shell::mojom::InterfaceProviderPtr exposed_services,
       const mojo::shell::CapabilityFilter& filter,
-      const mojo::shell::mojom::Shell::ConnectCallback& callback);
+      const mojo::shell::mojom::Connector::ConnectCallback& callback);
 
   static void SetApplicationsForTest(const StaticApplicationMap* apps);
 
@@ -58,7 +58,7 @@
       mojo::shell::mojom::InterfaceProviderRequest request,
       mojo::shell::mojom::InterfaceProviderPtr exposed_services,
       const mojo::shell::CapabilityFilter& filter,
-      const mojo::shell::mojom::Shell::ConnectCallback& callback);
+      const mojo::shell::mojom::Connector::ConnectCallback& callback);
 
   static base::LazyInstance<scoped_ptr<Proxy>> proxy_;
 
diff --git a/content/browser/notifications/notification_message_filter.cc b/content/browser/notifications/notification_message_filter.cc
index 09bf1ddb..f0a64a7 100644
--- a/content/browser/notifications/notification_message_filter.cc
+++ b/content/browser/notifications/notification_message_filter.cc
@@ -45,6 +45,23 @@
   return sanitized_data;
 }
 
+// Returns true when |resources| looks ok, false otherwise.
+bool ValidateNotificationResources(const NotificationResources& resources) {
+  if (resources.notification_icon.width() >
+          kPlatformNotificationMaxIconSizePx ||
+      resources.notification_icon.height() >
+          kPlatformNotificationMaxIconSizePx) {
+    return false;
+  }
+  for (const auto& action_icon : resources.action_icons) {
+    if (action_icon.width() > kPlatformNotificationMaxActionIconSizePx ||
+        action_icon.height() > kPlatformNotificationMaxActionIconSizePx) {
+      return false;
+    }
+  }
+  return true;
+}
+
 }  // namespace
 
 NotificationMessageFilter::NotificationMessageFilter(
@@ -115,6 +132,11 @@
   if (!RenderProcessHost::FromID(process_id_))
     return;
 
+  if (!ValidateNotificationResources(notification_resources)) {
+    bad_message::ReceivedBadMessage(this, bad_message::NMF_INVALID_ARGUMENT);
+    return;
+  }
+
   scoped_ptr<DesktopNotificationDelegate> delegate(
       new PageNotificationDelegate(process_id_, notification_id));
 
@@ -147,6 +169,11 @@
     return;
   }
 
+  if (!ValidateNotificationResources(notification_resources)) {
+    bad_message::ReceivedBadMessage(this, bad_message::NMF_INVALID_ARGUMENT);
+    return;
+  }
+
   NotificationDatabaseData database_data;
   database_data.origin = origin;
   database_data.service_worker_registration_id = service_worker_registration_id;
diff --git a/content/browser/renderer_host/input/input_router_impl.cc b/content/browser/renderer_host/input/input_router_impl.cc
index 9f79fb4cb..410f686 100644
--- a/content/browser/renderer_host/input/input_router_impl.cc
+++ b/content/browser/renderer_host/input/input_router_impl.cc
@@ -270,6 +270,18 @@
   ack_handler_->OnTouchEventAck(event, ack_result);
 }
 
+void InputRouterImpl::OnFilteringTouchEvent(
+    const WebTouchEvent& touch_event) {
+  // The event stream given to the renderer is not guaranteed to be
+  // valid based on the current TouchEventStreamValidator rules. This event will
+  // never be given to the renderer, but in order to ensure that the event
+  // stream |output_stream_validator_| sees is valid, we give events which are
+  // filtered out to the validator. crbug.com/589111 proposes adding an
+  // additional validator for the events which are actually sent to the
+  // renderer.
+  output_stream_validator_.Validate(touch_event);
+}
+
 void InputRouterImpl::OnGestureEventAck(
     const GestureEventWithLatencyInfo& event,
     InputEventAckState ack_result) {
diff --git a/content/browser/renderer_host/input/input_router_impl.h b/content/browser/renderer_host/input/input_router_impl.h
index 6c3c89f..02f5d399 100644
--- a/content/browser/renderer_host/input/input_router_impl.h
+++ b/content/browser/renderer_host/input/input_router_impl.h
@@ -91,6 +91,8 @@
       const TouchEventWithLatencyInfo& touch_event) override;
   void OnTouchEventAck(const TouchEventWithLatencyInfo& event,
                        InputEventAckState ack_result) override;
+  void OnFilteringTouchEvent(
+      const blink::WebTouchEvent& touch_event) override;
 
   // GestureEventFilterClient
   void SendGestureEventImmediately(
diff --git a/content/browser/renderer_host/input/input_router_impl_unittest.cc b/content/browser/renderer_host/input/input_router_impl_unittest.cc
index bdd29374..8a4c7d2e 100644
--- a/content/browser/renderer_host/input/input_router_impl_unittest.cc
+++ b/content/browser/renderer_host/input/input_router_impl_unittest.cc
@@ -1880,6 +1880,38 @@
             client_overscroll.current_fling_velocity);
 }
 
+// Tests that touch event stream validation passes when events are filtered
+// out. See crbug.com/581231 for details.
+TEST_F(InputRouterImplTest, TouchValidationPassesWithFilteredInputEvents) {
+  // Touch sequence with touch handler.
+  OnHasTouchEventHandlers(true);
+  PressTouchPoint(1, 1);
+  uint32_t touch_press_event_id = SendTouchEvent();
+  SendTouchEventACK(WebInputEvent::TouchStart,
+                    INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS,
+                    touch_press_event_id);
+
+  PressTouchPoint(1, 1);
+  touch_press_event_id = SendTouchEvent();
+  SendTouchEventACK(WebInputEvent::TouchStart,
+                    INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS,
+                    touch_press_event_id);
+
+  // This event will be filtered out, since no consumer exists.
+  ReleaseTouchPoint(1);
+  uint32_t touch_release_event_id = SendTouchEvent();
+  SendTouchEventACK(WebInputEvent::TouchEnd, INPUT_EVENT_ACK_STATE_NOT_CONSUMED,
+                    touch_release_event_id);
+
+  // If the validator didn't see the filtered out release event, it will crash
+  // now, upon seeing a press for a touch which it believes to be still pressed.
+  PressTouchPoint(1, 1);
+  touch_press_event_id = SendTouchEvent();
+  SendTouchEventACK(WebInputEvent::TouchStart,
+                    INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS,
+                    touch_press_event_id);
+}
+
 namespace {
 
 class InputRouterImplScaleEventTest : public InputRouterImplTest {
diff --git a/content/browser/renderer_host/input/mouse_wheel_event_queue.cc b/content/browser/renderer_host/input/mouse_wheel_event_queue.cc
index 6d5e787..48dbad23 100644
--- a/content/browser/renderer_host/input/mouse_wheel_event_queue.cc
+++ b/content/browser/renderer_host/input/mouse_wheel_event_queue.cc
@@ -85,6 +85,10 @@
       (scrolling_device_ == blink::WebGestureDeviceUninitialized ||
        scrolling_device_ == blink::WebGestureDeviceTouchpad)) {
     GestureEventWithLatencyInfo scroll_update;
+    scroll_update.event.x = event_sent_for_gesture_ack_->event.x;
+    scroll_update.event.y = event_sent_for_gesture_ack_->event.y;
+    scroll_update.event.globalX = event_sent_for_gesture_ack_->event.globalX;
+    scroll_update.event.globalY = event_sent_for_gesture_ack_->event.globalY;
     scroll_update.event.type = WebInputEvent::GestureScrollUpdate;
     scroll_update.event.sourceDevice = blink::WebGestureDeviceTouchpad;
     scroll_update.event.resendingPluginId = -1;
@@ -154,13 +158,18 @@
   client_->SendMouseWheelEventImmediately(send_event);
 }
 
-void MouseWheelEventQueue::SendScrollEnd(
-    blink::WebGestureEvent::ScrollUnits units) {
+void MouseWheelEventQueue::SendScrollEnd(blink::WebGestureEvent update_event) {
   GestureEventWithLatencyInfo scroll_end;
   scroll_end.event.type = WebInputEvent::GestureScrollEnd;
   scroll_end.event.sourceDevice = blink::WebGestureDeviceTouchpad;
   scroll_end.event.resendingPluginId = -1;
-  scroll_end.event.data.scrollEnd.deltaUnits = units;
+  scroll_end.event.data.scrollEnd.deltaUnits =
+      update_event.data.scrollUpdate.deltaUnits;
+  scroll_end.event.x = update_event.x;
+  scroll_end.event.y = update_event.y;
+  scroll_end.event.globalX = update_event.globalX;
+  scroll_end.event.globalY = update_event.globalY;
+
   SendGesture(scroll_end);
 }
 
@@ -170,6 +179,10 @@
     case WebInputEvent::GestureScrollUpdate:
       if (needs_scroll_begin_) {
         GestureEventWithLatencyInfo scroll_begin(gesture);
+        scroll_begin.event.x = gesture.event.x;
+        scroll_begin.event.y = gesture.event.y;
+        scroll_begin.event.globalX = gesture.event.globalX;
+        scroll_begin.event.globalY = gesture.event.globalY;
         scroll_begin.event.type = WebInputEvent::GestureScrollBegin;
         scroll_begin.event.data.scrollBegin.deltaXHint =
             gesture.event.data.scrollUpdate.deltaX;
@@ -188,8 +201,7 @@
             FROM_HERE,
             base::TimeDelta::FromMilliseconds(scroll_transaction_ms_),
             base::Bind(&MouseWheelEventQueue::SendScrollEnd,
-                       base::Unretained(this),
-                       gesture.event.data.scrollUpdate.deltaUnits));
+                       base::Unretained(this), gesture.event));
       }
       break;
     case WebInputEvent::GestureScrollEnd:
diff --git a/content/browser/renderer_host/input/mouse_wheel_event_queue.h b/content/browser/renderer_host/input/mouse_wheel_event_queue.h
index 51c2bdf..3c9802e 100644
--- a/content/browser/renderer_host/input/mouse_wheel_event_queue.h
+++ b/content/browser/renderer_host/input/mouse_wheel_event_queue.h
@@ -74,7 +74,7 @@
 
  private:
   void TryForwardNextEventToRenderer();
-  void SendScrollEnd(blink::WebGestureEvent::ScrollUnits units);
+  void SendScrollEnd(blink::WebGestureEvent update_event);
   void SendGesture(const GestureEventWithLatencyInfo& gesture);
 
   MouseWheelEventQueueClient* client_;
diff --git a/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc b/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc
index d0d010c..f9e10a901 100644
--- a/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc
+++ b/content/browser/renderer_host/input/mouse_wheel_event_queue_unittest.cc
@@ -24,6 +24,10 @@
 namespace content {
 namespace {
 
+const float kWheelScrollX = 10;
+const float kWheelScrollY = 12;
+const float kWheelScrollGlobalX = 50;
+const float kWheelScrollGlobalY = 72;
 const int64_t kScrollEndTimeoutMs = 100;
 
 base::TimeDelta DefaultScrollEndTimeoutDelay() {
@@ -98,13 +102,15 @@
 
   void SendMouseWheel(float x,
                       float y,
+                      float global_x,
+                      float global_y,
                       float dX,
                       float dY,
                       int modifiers,
                       bool high_precision) {
     queue_->QueueEvent(MouseWheelEventWithLatencyInfo(
-        SyntheticWebMouseWheelEventBuilder::Build(x, y, dX, dY, modifiers,
-                                                  high_precision)));
+        SyntheticWebMouseWheelEventBuilder::Build(
+            x, y, global_x, global_y, dX, dY, modifiers, high_precision)));
   }
 
   void SendGestureEvent(WebInputEvent::Type type) {
@@ -125,13 +131,15 @@
     const WebGestureEvent::ScrollUnits scroll_units =
         high_precision ? WebGestureEvent::PrecisePixels
                        : WebGestureEvent::Pixels;
-    SendMouseWheel(10, 10, 1, 1, 0, high_precision);
+    SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+                   kWheelScrollGlobalY, 1, 1, 0, high_precision);
     EXPECT_EQ(0U, queued_event_count());
     EXPECT_TRUE(event_in_flight());
     EXPECT_EQ(1U, GetAndResetSentEventCount());
 
     // The second mouse wheel should not be sent since one is already in queue.
-    SendMouseWheel(10, 10, 5, 5, 0, high_precision);
+    SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+                   kWheelScrollGlobalY, 5, 5, 0, high_precision);
     EXPECT_EQ(1U, queued_event_count());
     EXPECT_TRUE(event_in_flight());
     EXPECT_EQ(0U, GetAndResetSentEventCount());
@@ -147,9 +155,17 @@
     EXPECT_EQ(WebInputEvent::GestureScrollBegin, all_sent_events()[0].type);
     EXPECT_EQ(scroll_units,
               sent_gesture_events()[0].data.scrollBegin.deltaHintUnits);
+    EXPECT_EQ(kWheelScrollX, sent_gesture_events()[0].x);
+    EXPECT_EQ(kWheelScrollY, sent_gesture_events()[0].y);
+    EXPECT_EQ(kWheelScrollGlobalX, sent_gesture_events()[0].globalX);
+    EXPECT_EQ(kWheelScrollGlobalY, sent_gesture_events()[0].globalY);
     EXPECT_EQ(WebInputEvent::GestureScrollUpdate, all_sent_events()[1].type);
     EXPECT_EQ(scroll_units,
               sent_gesture_events()[1].data.scrollUpdate.deltaUnits);
+    EXPECT_EQ(kWheelScrollX, sent_gesture_events()[1].x);
+    EXPECT_EQ(kWheelScrollY, sent_gesture_events()[1].y);
+    EXPECT_EQ(kWheelScrollGlobalX, sent_gesture_events()[1].globalX);
+    EXPECT_EQ(kWheelScrollGlobalY, sent_gesture_events()[1].globalY);
     EXPECT_EQ(WebInputEvent::MouseWheel, all_sent_events()[2].type);
     EXPECT_EQ(3U, GetAndResetSentEventCount());
 
@@ -157,6 +173,10 @@
     EXPECT_EQ(1U, all_sent_events().size());
     EXPECT_EQ(WebInputEvent::GestureScrollEnd, all_sent_events()[0].type);
     EXPECT_EQ(scroll_units, sent_gesture_events()[0].data.scrollEnd.deltaUnits);
+    EXPECT_EQ(kWheelScrollX, sent_gesture_events()[0].x);
+    EXPECT_EQ(kWheelScrollY, sent_gesture_events()[0].y);
+    EXPECT_EQ(kWheelScrollGlobalX, sent_gesture_events()[0].globalX);
+    EXPECT_EQ(kWheelScrollGlobalY, sent_gesture_events()[0].globalY);
   }
 
   scoped_ptr<MouseWheelEventQueue> queue_;
@@ -170,13 +190,15 @@
 
 // Tests that mouse wheel events are queued properly.
 TEST_F(MouseWheelEventQueueTest, Basic) {
-  SendMouseWheel(10, 10, 1, 1, 0, false);
+  SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+                 kWheelScrollGlobalY, 1, 1, 0, false);
   EXPECT_EQ(0U, queued_event_count());
   EXPECT_TRUE(event_in_flight());
   EXPECT_EQ(1U, GetAndResetSentEventCount());
 
   // The second mouse wheel should not be sent since one is already in queue.
-  SendMouseWheel(10, 10, 5, 5, 0, false);
+  SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+                 kWheelScrollGlobalY, 5, 5, 0, false);
   EXPECT_EQ(1U, queued_event_count());
   EXPECT_TRUE(event_in_flight());
   EXPECT_EQ(0U, GetAndResetSentEventCount());
@@ -210,7 +232,8 @@
 
 TEST_F(MouseWheelEventQueueTest, GestureSendingInterrupted) {
   SetUpForGestureTesting(true);
-  SendMouseWheel(10, 10, 1, 1, 0, false);
+  SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+                 kWheelScrollGlobalY, 1, 1, 0, false);
   EXPECT_EQ(0U, queued_event_count());
   EXPECT_TRUE(event_in_flight());
   EXPECT_EQ(1U, GetAndResetSentEventCount());
@@ -232,7 +255,8 @@
   EXPECT_EQ(WebInputEvent::GestureScrollEnd, all_sent_events()[0].type);
   EXPECT_EQ(1U, GetAndResetSentEventCount());
 
-  SendMouseWheel(10, 10, 1, 1, 0, false);
+  SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+                 kWheelScrollGlobalY, 1, 1, 0, false);
   EXPECT_EQ(0U, queued_event_count());
   EXPECT_TRUE(event_in_flight());
   EXPECT_EQ(1U, GetAndResetSentEventCount());
@@ -249,7 +273,8 @@
   SendGestureEvent(WebInputEvent::GestureScrollEnd);
   EXPECT_EQ(0U, all_sent_events().size());
 
-  SendMouseWheel(10, 10, 1, 1, 0, false);
+  SendMouseWheel(kWheelScrollX, kWheelScrollY, kWheelScrollGlobalX,
+                 kWheelScrollGlobalY, 1, 1, 0, false);
   EXPECT_EQ(0U, queued_event_count());
   EXPECT_TRUE(event_in_flight());
   EXPECT_EQ(1U, GetAndResetSentEventCount());
diff --git a/content/browser/renderer_host/input/synthetic_smooth_move_gesture.cc b/content/browser/renderer_host/input/synthetic_smooth_move_gesture.cc
index 3ddb0a3..6a9264d 100644
--- a/content/browser/renderer_host/input/synthetic_smooth_move_gesture.cc
+++ b/content/browser/renderer_host/input/synthetic_smooth_move_gesture.cc
@@ -42,6 +42,9 @@
       prevent_fling(true),
       add_slop(true) {}
 
+SyntheticSmoothMoveGestureParams::SyntheticSmoothMoveGestureParams(
+    const SyntheticSmoothMoveGestureParams& other) = default;
+
 SyntheticSmoothMoveGestureParams::~SyntheticSmoothMoveGestureParams() {}
 
 SyntheticSmoothMoveGesture::SyntheticSmoothMoveGesture(
diff --git a/content/browser/renderer_host/input/synthetic_smooth_move_gesture.h b/content/browser/renderer_host/input/synthetic_smooth_move_gesture.h
index 577a8c0..28be20e 100644
--- a/content/browser/renderer_host/input/synthetic_smooth_move_gesture.h
+++ b/content/browser/renderer_host/input/synthetic_smooth_move_gesture.h
@@ -24,6 +24,8 @@
 class CONTENT_EXPORT SyntheticSmoothMoveGestureParams {
  public:
   SyntheticSmoothMoveGestureParams();
+  SyntheticSmoothMoveGestureParams(
+      const SyntheticSmoothMoveGestureParams& other);
   ~SyntheticSmoothMoveGestureParams();
 
   enum InputType { MOUSE_DRAG_INPUT, MOUSE_WHEEL_INPUT, TOUCH_INPUT };
diff --git a/content/browser/renderer_host/input/touch_event_queue.cc b/content/browser/renderer_host/input/touch_event_queue.cc
index 0e5b3cef..265f5f11 100644
--- a/content/browser/renderer_host/input/touch_event_queue.cc
+++ b/content/browser/renderer_host/input/touch_event_queue.cc
@@ -467,6 +467,7 @@
     // yields identical results, but this avoids unnecessary allocations.
     PreFilterResult filter_result = FilterBeforeForwarding(event.event);
     if (filter_result != FORWARD_TO_RENDERER) {
+      client_->OnFilteringTouchEvent(event.event);
       client_->OnTouchEventAck(event,
                                filter_result == ACK_WITH_NO_CONSUMER_EXISTS
                                    ? INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS
@@ -537,8 +538,10 @@
   // If there are queued touch events, then try to forward them to the renderer
   // immediately, or ACK the events back to the client if appropriate.
   while (!touch_queue_.empty()) {
-    PreFilterResult filter_result =
-        FilterBeforeForwarding(touch_queue_.front()->coalesced_event().event);
+    const WebTouchEvent& event = touch_queue_.front()->coalesced_event().event;
+    PreFilterResult filter_result = FilterBeforeForwarding(event);
+    if (filter_result != FORWARD_TO_RENDERER)
+      client_->OnFilteringTouchEvent(event);
     switch (filter_result) {
       case ACK_WITH_NO_CONSUMER_EXISTS:
         PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
diff --git a/content/browser/renderer_host/input/touch_event_queue.h b/content/browser/renderer_host/input/touch_event_queue.h
index 4b69d98b..8a19586 100644
--- a/content/browser/renderer_host/input/touch_event_queue.h
+++ b/content/browser/renderer_host/input/touch_event_queue.h
@@ -35,6 +35,9 @@
   virtual void OnTouchEventAck(
       const TouchEventWithLatencyInfo& event,
       InputEventAckState ack_result) = 0;
+
+  virtual void OnFilteringTouchEvent(
+      const blink::WebTouchEvent& touch_event) = 0;
 };
 
 // A queue for throttling and coalescing touch-events.
diff --git a/content/browser/renderer_host/input/touch_event_queue_unittest.cc b/content/browser/renderer_host/input/touch_event_queue_unittest.cc
index 57b9760..01865db 100644
--- a/content/browser/renderer_host/input/touch_event_queue_unittest.cc
+++ b/content/browser/renderer_host/input/touch_event_queue_unittest.cc
@@ -84,6 +84,9 @@
     }
   }
 
+  void OnFilteringTouchEvent(const blink::WebTouchEvent& touch_event) override {
+  }
+
  protected:
   void SetUpForTouchMoveSlopTesting(double slop_length_dips) {
     slop_length_dips_ = slop_length_dips;
diff --git a/content/browser/renderer_host/input/web_input_event_builders_mac_unittest.mm b/content/browser/renderer_host/input/web_input_event_builders_mac_unittest.mm
index 3c8c5a28..d527759c 100644
--- a/content/browser/renderer_host/input/web_input_event_builders_mac_unittest.mm
+++ b/content/browser/renderer_host/input/web_input_event_builders_mac_unittest.mm
@@ -112,7 +112,8 @@
   EXPECT_EQ(ui::VKEY_OEM_4, web_event.windowsKeyCode);
   EXPECT_EQ(ui::DomCode::BRACKET_LEFT,
             static_cast<ui::DomCode>(web_event.domCode));
-  EXPECT_EQ(ui::DomKey::FromCharacter(0x1b), web_event.domKey);
+  // Will only pass on US layout.
+  EXPECT_EQ(ui::DomKey::FromCharacter('['), web_event.domKey);
 }
 
 // Test that numpad keys get mapped correctly.
@@ -246,3 +247,160 @@
   webEvent = WebKeyboardEventBuilder::Build(macEvent);
   EXPECT_TRUE(webEvent.isSystemKey);
 }
+
+// Test conversion from key combination with Control to DomKey.
+// TODO(chongz): Move DomKey tests for all platforms into one place.
+// http://crbug.com/587589
+// This test case only works for U.S. layout.
+TEST(WebInputEventBuilderMacTest, DomKeyCtrlShift) {
+  struct DomKeyTestCase {
+    int mac_key_code;
+    unichar character;
+    unichar shift_character;
+  } table[] = {
+      {kVK_ANSI_0, '0', ')'}, {kVK_ANSI_1, '1', '!'}, {kVK_ANSI_2, '2', '@'},
+      {kVK_ANSI_3, '3', '#'}, {kVK_ANSI_4, '4', '$'}, {kVK_ANSI_5, '5', '%'},
+      {kVK_ANSI_6, '6', '^'}, {kVK_ANSI_7, '7', '&'}, {kVK_ANSI_8, '8', '*'},
+      {kVK_ANSI_9, '9', '('}, {kVK_ANSI_A, 'a', 'A'}, {kVK_ANSI_B, 'b', 'B'},
+      {kVK_ANSI_C, 'c', 'C'}, {kVK_ANSI_D, 'd', 'D'}, {kVK_ANSI_E, 'e', 'E'},
+      {kVK_ANSI_F, 'f', 'F'}, {kVK_ANSI_G, 'g', 'G'}, {kVK_ANSI_H, 'h', 'H'},
+      {kVK_ANSI_I, 'i', 'I'}, {kVK_ANSI_J, 'j', 'J'}, {kVK_ANSI_K, 'k', 'K'},
+      {kVK_ANSI_L, 'l', 'L'}, {kVK_ANSI_M, 'm', 'M'}, {kVK_ANSI_N, 'n', 'N'},
+      {kVK_ANSI_O, 'o', 'O'}, {kVK_ANSI_P, 'p', 'P'}, {kVK_ANSI_Q, 'q', 'Q'},
+      {kVK_ANSI_R, 'r', 'R'}, {kVK_ANSI_S, 's', 'S'}, {kVK_ANSI_T, 't', 'T'},
+      {kVK_ANSI_U, 'u', 'U'}, {kVK_ANSI_V, 'v', 'V'}, {kVK_ANSI_W, 'w', 'W'},
+      {kVK_ANSI_X, 'x', 'X'}, {kVK_ANSI_Y, 'y', 'Y'}, {kVK_ANSI_Z, 'z', 'Z'}};
+
+  for (const DomKeyTestCase& entry : table) {
+    // Tests ctrl_dom_key.
+    NSEvent* mac_event = BuildFakeKeyEvent(entry.mac_key_code, entry.character,
+                                           NSControlKeyMask, NSKeyDown);
+    WebKeyboardEvent web_event = WebKeyboardEventBuilder::Build(mac_event);
+    EXPECT_EQ(ui::DomKey::FromCharacter(entry.character), web_event.domKey);
+    // Tests ctrl_shift_dom_key.
+    mac_event = BuildFakeKeyEvent(entry.mac_key_code, entry.shift_character,
+                                  NSControlKeyMask | NSShiftKeyMask, NSKeyDown);
+    web_event = WebKeyboardEventBuilder::Build(mac_event);
+    EXPECT_EQ(ui::DomKey::FromCharacter(entry.shift_character),
+              web_event.domKey);
+  }
+}
+
+// This test case only works for U.S. layout.
+TEST(WebInputEventBuilderMacTest, DomKeyCtrlAlt) {
+  struct DomKeyTestCase {
+    int mac_key_code;
+    unichar alt_character;
+    unichar ctrl_alt_character;
+  } table[] = {{kVK_ANSI_0, u"º"[0], u"0"[0]}, {kVK_ANSI_1, u"¡"[0], u"1"[0]},
+               {kVK_ANSI_2, u"™"[0], u"2"[0]}, {kVK_ANSI_3, u"£"[0], u"3"[0]},
+               {kVK_ANSI_4, u"¢"[0], u"4"[0]}, {kVK_ANSI_5, u"∞"[0], u"5"[0]},
+               {kVK_ANSI_6, u"§"[0], u"6"[0]}, {kVK_ANSI_7, u"¶"[0], u"7"[0]},
+               {kVK_ANSI_8, u"•"[0], u"8"[0]}, {kVK_ANSI_9, u"ª"[0], u"9"[0]},
+               {kVK_ANSI_A, u"å"[0], u"å"[0]}, {kVK_ANSI_B, u"∫"[0], u"∫"[0]},
+               {kVK_ANSI_C, u"ç"[0], u"ç"[0]}, {kVK_ANSI_D, u"∂"[0], u"∂"[0]},
+               {kVK_ANSI_E, u"´"[0], u"´"[0]}, {kVK_ANSI_F, u"ƒ"[0], u"ƒ"[0]},
+               {kVK_ANSI_G, u"©"[0], u"©"[0]}, {kVK_ANSI_H, u"˙"[0], u"˙"[0]},
+               {kVK_ANSI_I, u"ˆ"[0], u"ˆ"[0]}, {kVK_ANSI_J, u"∆"[0], u"∆"[0]},
+               {kVK_ANSI_K, u"˚"[0], u"˚"[0]}, {kVK_ANSI_L, u"¬"[0], u"¬"[0]},
+               {kVK_ANSI_M, u"µ"[0], u"µ"[0]}, {kVK_ANSI_N, u"˜"[0], u"˜"[0]},
+               {kVK_ANSI_O, u"ø"[0], u"ø"[0]}, {kVK_ANSI_P, u"π"[0], u"π"[0]},
+               {kVK_ANSI_Q, u"œ"[0], u"œ"[0]}, {kVK_ANSI_R, u"®"[0], u"®"[0]},
+               {kVK_ANSI_S, u"ß"[0], u"ß"[0]}, {kVK_ANSI_T, u"†"[0], u"†"[0]},
+               {kVK_ANSI_U, u"¨"[0], u"¨"[0]}, {kVK_ANSI_V, u"√"[0], u"√"[0]},
+               {kVK_ANSI_W, u"∑"[0], u"∑"[0]}, {kVK_ANSI_X, u"≈"[0], u"≈"[0]},
+               {kVK_ANSI_Y, u"¥"[0], u"¥"[0]}, {kVK_ANSI_Z, u"Ω"[0], u"Ω"[0]}};
+
+  for (const DomKeyTestCase& entry : table) {
+    // Tests alt_dom_key.
+    NSEvent* mac_event = BuildFakeKeyEvent(
+        entry.mac_key_code, entry.alt_character, NSAlternateKeyMask, NSKeyDown);
+    WebKeyboardEvent web_event = WebKeyboardEventBuilder::Build(mac_event);
+    EXPECT_EQ(ui::DomKey::FromCharacter(entry.alt_character), web_event.domKey)
+        << "a " << entry.alt_character;
+    // Tests ctrl_alt_dom_key.
+    mac_event = BuildFakeKeyEvent(entry.mac_key_code, entry.ctrl_alt_character,
+                                  NSAlternateKeyMask, NSKeyDown);
+    web_event = WebKeyboardEventBuilder::Build(mac_event);
+    EXPECT_EQ(ui::DomKey::FromCharacter(entry.ctrl_alt_character),
+              web_event.domKey)
+        << "a_c " << entry.ctrl_alt_character;
+  }
+}
+
+TEST(WebInputEventBuilderMacTest, DomKeyNonPrintable) {
+  struct DomKeyTestCase {
+    int mac_key_code;
+    unichar character;
+    ui::DomKey dom_key;
+  } table[] = {
+      {kVK_Return, kReturnCharCode, ui::DomKey::ENTER},
+      {kVK_Tab, kTabCharCode, ui::DomKey::TAB},
+      {kVK_Delete, kBackspaceCharCode, ui::DomKey::BACKSPACE},
+      {kVK_Escape, kEscapeCharCode, ui::DomKey::ESCAPE},
+      {kVK_F1, NSF1FunctionKey, ui::DomKey::F1},
+      {kVK_F2, NSF2FunctionKey, ui::DomKey::F2},
+      {kVK_F3, NSF3FunctionKey, ui::DomKey::F3},
+      {kVK_F4, NSF4FunctionKey, ui::DomKey::F4},
+      {kVK_F5, NSF5FunctionKey, ui::DomKey::F5},
+      {kVK_F6, NSF6FunctionKey, ui::DomKey::F6},
+      {kVK_F7, NSF7FunctionKey, ui::DomKey::F7},
+      {kVK_F8, NSF8FunctionKey, ui::DomKey::F8},
+      {kVK_F9, NSF9FunctionKey, ui::DomKey::F9},
+      {kVK_F10, NSF10FunctionKey, ui::DomKey::F10},
+      {kVK_F11, NSF11FunctionKey, ui::DomKey::F11},
+      {kVK_F12, NSF12FunctionKey, ui::DomKey::F12},
+      {kVK_F13, NSF13FunctionKey, ui::DomKey::F13},
+      {kVK_F14, NSF14FunctionKey, ui::DomKey::F14},
+      {kVK_F15, NSF15FunctionKey, ui::DomKey::F15},
+      {kVK_F16, NSF16FunctionKey, ui::DomKey::F16},
+      {kVK_F17, NSF17FunctionKey, ui::DomKey::F17},
+      {kVK_F18, NSF18FunctionKey, ui::DomKey::F18},
+      {kVK_F19, NSF19FunctionKey, ui::DomKey::F19},
+      {kVK_F20, NSF20FunctionKey, ui::DomKey::F20},
+      {kVK_Help, kHelpCharCode, ui::DomKey::HELP},
+      {kVK_Home, NSHomeFunctionKey, ui::DomKey::HOME},
+      {kVK_PageUp, NSPageUpFunctionKey, ui::DomKey::PAGE_UP},
+      {kVK_ForwardDelete, NSDeleteFunctionKey, ui::DomKey::DEL},
+      {kVK_End, NSEndFunctionKey, ui::DomKey::END},
+      {kVK_PageDown, NSPageDownFunctionKey, ui::DomKey::PAGE_DOWN},
+      {kVK_LeftArrow, NSLeftArrowFunctionKey, ui::DomKey::ARROW_LEFT},
+      {kVK_RightArrow, NSRightArrowFunctionKey, ui::DomKey::ARROW_RIGHT},
+      {kVK_DownArrow, NSDownArrowFunctionKey, ui::DomKey::ARROW_DOWN},
+      {kVK_UpArrow, NSUpArrowFunctionKey, ui::DomKey::ARROW_UP}};
+
+  for (const DomKeyTestCase& entry : table) {
+    // Tests non-printable key.
+    NSEvent* mac_event =
+        BuildFakeKeyEvent(entry.mac_key_code, entry.character, 0, NSKeyDown);
+    WebKeyboardEvent web_event = WebKeyboardEventBuilder::Build(mac_event);
+    EXPECT_EQ(entry.dom_key, web_event.domKey) << entry.mac_key_code;
+    // Tests non-printable key with Shift.
+    mac_event = BuildFakeKeyEvent(entry.mac_key_code, entry.character,
+                                  NSShiftKeyMask, NSKeyDown);
+    web_event = WebKeyboardEventBuilder::Build(mac_event);
+    EXPECT_EQ(entry.dom_key, web_event.domKey) << "s " << entry.mac_key_code;
+  }
+}
+
+TEST(WebInputEventBuilderMacTest, DomKeyFlagsChanged) {
+  struct DomKeyTestCase {
+    int mac_key_code;
+    ui::DomKey dom_key;
+  } table[] = {{kVK_Command, ui::DomKey::META},
+               {kVK_Shift, ui::DomKey::SHIFT},
+               {kVK_RightShift, ui::DomKey::SHIFT},
+               {kVK_CapsLock, ui::DomKey::CAPS_LOCK},
+               {kVK_Option, ui::DomKey::ALT},
+               {kVK_RightOption, ui::DomKey::ALT},
+               {kVK_Control, ui::DomKey::CONTROL},
+               {kVK_RightControl, ui::DomKey::CONTROL},
+               {kVK_Function, ui::DomKey::FN}};
+
+  for (const DomKeyTestCase& entry : table) {
+    NSEvent* mac_event =
+        BuildFakeKeyEvent(entry.mac_key_code, 0, 0, NSFlagsChanged);
+    WebKeyboardEvent web_event = WebKeyboardEventBuilder::Build(mac_event);
+    EXPECT_EQ(entry.dom_key, web_event.domKey) << entry.mac_key_code;
+  }
+}
diff --git a/content/browser/renderer_host/input/web_input_event_util.cc b/content/browser/renderer_host/input/web_input_event_util.cc
index ed57443..9368a26 100644
--- a/content/browser/renderer_host/input/web_input_event_util.cc
+++ b/content/browser/renderer_host/input/web_input_event_util.cc
@@ -14,7 +14,6 @@
 #include "ui/events/blink/blink_event_util.h"
 #include "ui/events/event_constants.h"
 #include "ui/events/gesture_detection/gesture_event_data.h"
-#include "ui/events/gesture_detection/motion_event.h"
 #include "ui/events/keycodes/dom/keycode_converter.h"
 #include "ui/gfx/geometry/safe_integer_conversions.h"
 
@@ -22,7 +21,6 @@
 using blink::WebInputEvent;
 using blink::WebTouchEvent;
 using blink::WebTouchPoint;
-using ui::MotionEvent;
 
 namespace content {
 
diff --git a/content/browser/renderer_host/input/web_input_event_util.h b/content/browser/renderer_host/input/web_input_event_util.h
index 3e262820..b7963a3 100644
--- a/content/browser/renderer_host/input/web_input_event_util.h
+++ b/content/browser/renderer_host/input/web_input_event_util.h
@@ -15,7 +15,6 @@
 enum class DomCode;
 struct GestureEventData;
 struct GestureEventDetails;
-class MotionEvent;
 }
 
 namespace content {
diff --git a/content/browser/renderer_host/media/audio_input_renderer_host.cc b/content/browser/renderer_host/media/audio_input_renderer_host.cc
index d4ac7ac..da9c5ea 100644
--- a/content/browser/renderer_host/media/audio_input_renderer_host.cc
+++ b/content/browser/renderer_host/media/audio_input_renderer_host.cc
@@ -18,7 +18,7 @@
 #include "build/build_config.h"
 #include "content/browser/media/capture/web_contents_audio_input_stream.h"
 #include "content/browser/media/media_internals.h"
-#include "content/browser/media/webrtc_internals.h"
+#include "content/browser/media/webrtc/webrtc_internals.h"
 #include "content/browser/renderer_host/media/audio_input_debug_writer.h"
 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
 #include "content/browser/renderer_host/media/audio_input_sync_writer.h"
diff --git a/content/browser/renderer_host/media/audio_output_device_enumerator.cc b/content/browser/renderer_host/media/audio_output_device_enumerator.cc
index cf4842d..24ef8f9e 100644
--- a/content/browser/renderer_host/media/audio_output_device_enumerator.cc
+++ b/content/browser/renderer_host/media/audio_output_device_enumerator.cc
@@ -54,6 +54,9 @@
 AudioOutputDeviceEnumeration::AudioOutputDeviceEnumeration()
     : has_actual_devices(false) {}
 
+AudioOutputDeviceEnumeration::AudioOutputDeviceEnumeration(
+    const AudioOutputDeviceEnumeration& other) = default;
+
 AudioOutputDeviceEnumeration::~AudioOutputDeviceEnumeration() {}
 
 AudioOutputDeviceEnumerator::AudioOutputDeviceEnumerator(
diff --git a/content/browser/renderer_host/media/audio_output_device_enumerator.h b/content/browser/renderer_host/media/audio_output_device_enumerator.h
index bf223a9..afb8204 100644
--- a/content/browser/renderer_host/media/audio_output_device_enumerator.h
+++ b/content/browser/renderer_host/media/audio_output_device_enumerator.h
@@ -50,6 +50,7 @@
       const std::vector<AudioOutputDeviceInfo>& devices,
       bool has_actual_devices);
   AudioOutputDeviceEnumeration();
+  AudioOutputDeviceEnumeration(const AudioOutputDeviceEnumeration& other);
   ~AudioOutputDeviceEnumeration();
 
   std::vector<AudioOutputDeviceInfo> devices;
diff --git a/content/browser/renderer_host/media/audio_sync_reader.cc b/content/browser/renderer_host/media/audio_sync_reader.cc
index 85b13f845..ddb4525 100644
--- a/content/browser/renderer_host/media/audio_sync_reader.cc
+++ b/content/browser/renderer_host/media/audio_sync_reader.cc
@@ -46,6 +46,7 @@
       packet_size_(shared_memory_->requested_size()),
       renderer_callback_count_(0),
       renderer_missed_callback_count_(0),
+      trailing_renderer_missed_callback_count_(0),
 #if defined(OS_MACOSX)
       maximum_wait_time_(params.GetBufferDuration() / 2),
 #else
@@ -66,6 +67,21 @@
   if (!renderer_callback_count_)
     return;
 
+  DVLOG(1) << "Trailing glitch count on destruction: "
+           << trailing_renderer_missed_callback_count_;
+
+  // Subtract 'trailing' count of callbacks missed just before the destructor
+  // call. This happens if the renderer process was killed or e.g. the page
+  // refreshed while the output device was open etc.
+  // This trims off the end of both the missed and total counts so that we
+  // preserve the proportion of counts before the teardown period.
+  DCHECK_LE(trailing_renderer_missed_callback_count_,
+            renderer_missed_callback_count_);
+  DCHECK_LE(trailing_renderer_missed_callback_count_, renderer_callback_count_);
+
+  renderer_missed_callback_count_ -= trailing_renderer_missed_callback_count_;
+  renderer_callback_count_ -= trailing_renderer_missed_callback_count_;
+
   // Recording the percentage of deadline misses gives us a rough overview of
   // how many users might be running into audio glitches.
   int percentage_missed =
@@ -107,6 +123,7 @@
 void AudioSyncReader::Read(AudioBus* dest) {
   ++renderer_callback_count_;
   if (!WaitUntilDataIsReady()) {
+    ++trailing_renderer_missed_callback_count_;
     ++renderer_missed_callback_count_;
     if (renderer_missed_callback_count_ <= 100) {
       LOG(WARNING) << "AudioSyncReader::Read timed out, audio glitch count="
@@ -118,6 +135,8 @@
     return;
   }
 
+  trailing_renderer_missed_callback_count_ = 0;
+
   if (mute_audio_)
     dest->Zero();
   else
diff --git a/content/browser/renderer_host/media/audio_sync_reader.h b/content/browser/renderer_host/media/audio_sync_reader.h
index 6e07e51..4f658a3 100644
--- a/content/browser/renderer_host/media/audio_sync_reader.h
+++ b/content/browser/renderer_host/media/audio_sync_reader.h
@@ -75,6 +75,7 @@
   // report a UMA stat during destruction.
   size_t renderer_callback_count_;
   size_t renderer_missed_callback_count_;
+  size_t trailing_renderer_missed_callback_count_;
 
   // The maximum amount of time to wait for data from the renderer.  Calculated
   // from the parameters given at construction.
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index 7accf3da..af820fe 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -61,18 +61,15 @@
 #include "chromeos/audio/cras_audio_handler.h"
 #endif
 
+#if defined(OS_MACOSX)
+#include "media/capture/device_monitor_mac.h"
+#endif
+
 namespace content {
 
 base::LazyInstance<base::ThreadLocalPointer<MediaStreamManager>>::Leaky
     g_media_stream_manager_tls_ptr = LAZY_INSTANCE_INITIALIZER;
 
-// Forward declaration of DeviceMonitorMac and its only useable method.
-class DeviceMonitorMac {
- public:
-  void StartMonitoring(
-    const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner);
-};
-
 namespace {
 // Creates a random label used to identify requests.
 std::string RandomLabel() {
diff --git a/content/browser/renderer_host/media/peer_connection_tracker_host.cc b/content/browser/renderer_host/media/peer_connection_tracker_host.cc
index 41580ebe..12f6edc 100644
--- a/content/browser/renderer_host/media/peer_connection_tracker_host.cc
+++ b/content/browser/renderer_host/media/peer_connection_tracker_host.cc
@@ -4,7 +4,7 @@
 #include "content/browser/renderer_host/media/peer_connection_tracker_host.h"
 
 #include "base/power_monitor/power_monitor.h"
-#include "content/browser/media/webrtc_internals.h"
+#include "content/browser/media/webrtc/webrtc_internals.h"
 #include "content/common/media/peer_connection_tracker_messages.h"
 #include "content/public/browser/render_process_host.h"
 
diff --git a/content/browser/renderer_host/media/video_capture_manager.cc b/content/browser/renderer_host/media/video_capture_manager.cc
index dcee567..04eebe46 100644
--- a/content/browser/renderer_host/media/video_capture_manager.cc
+++ b/content/browser/renderer_host/media/video_capture_manager.cc
@@ -52,14 +52,22 @@
 // by the ConsolidateCaptureFormats() method.
 bool IsCaptureFormatSmaller(const media::VideoCaptureFormat& format1,
                             const media::VideoCaptureFormat& format2) {
-  if (format1.frame_size.GetArea() == format2.frame_size.GetArea())
+  DCHECK(format1.frame_size.GetCheckedArea().IsValid());
+  DCHECK(format2.frame_size.GetCheckedArea().IsValid());
+  if (format1.frame_size.GetCheckedArea().ValueOrDefault(0) ==
+      format2.frame_size.GetCheckedArea().ValueOrDefault(0)) {
     return format1.frame_rate > format2.frame_rate;
-  return format1.frame_size.GetArea() < format2.frame_size.GetArea();
+  }
+  return format1.frame_size.GetCheckedArea().ValueOrDefault(0) <
+         format2.frame_size.GetCheckedArea().ValueOrDefault(0);
 }
 
 bool IsCaptureFormatSizeEqual(const media::VideoCaptureFormat& format1,
                               const media::VideoCaptureFormat& format2) {
-  return format1.frame_size.GetArea() == format2.frame_size.GetArea();
+  DCHECK(format1.frame_size.GetCheckedArea().IsValid());
+  DCHECK(format2.frame_size.GetCheckedArea().IsValid());
+  return format1.frame_size.GetCheckedArea().ValueOrDefault(0) ==
+         format2.frame_size.GetCheckedArea().ValueOrDefault(0);
 }
 
 // This function receives a list of capture formats, removes duplicated
diff --git a/content/browser/renderer_host/media/webrtc_identity_service_host.cc b/content/browser/renderer_host/media/webrtc_identity_service_host.cc
index dc1e590..c98d34a 100644
--- a/content/browser/renderer_host/media/webrtc_identity_service_host.cc
+++ b/content/browser/renderer_host/media/webrtc_identity_service_host.cc
@@ -7,7 +7,7 @@
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/media/webrtc_identity_store.h"
+#include "content/browser/media/webrtc/webrtc_identity_store.h"
 #include "content/common/media/webrtc_identity_messages.h"
 #include "content/public/browser/content_browser_client.h"
 #include "net/base/net_errors.h"
diff --git a/content/browser/renderer_host/media/webrtc_identity_service_host_unittest.cc b/content/browser/renderer_host/media/webrtc_identity_service_host_unittest.cc
index 1a38a45f..0fc87f7 100644
--- a/content/browser/renderer_host/media/webrtc_identity_service_host_unittest.cc
+++ b/content/browser/renderer_host/media/webrtc_identity_service_host_unittest.cc
@@ -5,7 +5,7 @@
 #include <deque>
 
 #include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/media/webrtc_identity_store.h"
+#include "content/browser/media/webrtc/webrtc_identity_store.h"
 #include "content/browser/renderer_host/media/webrtc_identity_service_host.h"
 #include "content/common/media/webrtc_identity_messages.h"
 #include "content/public/test/mock_resource_context.h"
diff --git a/content/browser/renderer_host/p2p/socket_host_tcp.cc b/content/browser/renderer_host/p2p/socket_host_tcp.cc
index f1c22101..10398dc6 100644
--- a/content/browser/renderer_host/p2p/socket_host_tcp.cc
+++ b/content/browser/renderer_host/p2p/socket_host_tcp.cc
@@ -16,7 +16,6 @@
 #include "jingle/glue/proxy_resolving_client_socket.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/socket/client_socket_factory.h"
 #include "net/socket/client_socket_handle.h"
 #include "net/socket/ssl_client_socket.h"
diff --git a/content/browser/renderer_host/p2p/socket_host_tcp_server.cc b/content/browser/renderer_host/p2p/socket_host_tcp_server.cc
index dc49bfdc..3d55c29b 100644
--- a/content/browser/renderer_host/p2p/socket_host_tcp_server.cc
+++ b/content/browser/renderer_host/p2p/socket_host_tcp_server.cc
@@ -11,7 +11,6 @@
 #include "content/common/p2p_messages.h"
 #include "net/base/address_list.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/socket/stream_socket.h"
 
 namespace {
diff --git a/content/browser/renderer_host/p2p/socket_host_udp.cc b/content/browser/renderer_host/p2p/socket_host_udp.cc
index 66ee61f4..451353603 100644
--- a/content/browser/renderer_host/p2p/socket_host_udp.cc
+++ b/content/browser/renderer_host/p2p/socket_host_udp.cc
@@ -18,7 +18,6 @@
 #include "ipc/ipc_sender.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "third_party/webrtc/media/base/rtputils.h"
 
 namespace {
@@ -85,6 +84,9 @@
   memcpy(data->data(), &content[0], size);
 }
 
+P2PSocketHostUdp::PendingPacket::PendingPacket(const PendingPacket& other) =
+    default;
+
 P2PSocketHostUdp::PendingPacket::~PendingPacket() {
 }
 
diff --git a/content/browser/renderer_host/p2p/socket_host_udp.h b/content/browser/renderer_host/p2p/socket_host_udp.h
index 93fb633..57f1db3 100644
--- a/content/browser/renderer_host/p2p/socket_host_udp.h
+++ b/content/browser/renderer_host/p2p/socket_host_udp.h
@@ -58,6 +58,7 @@
                   const std::vector<char>& content,
                   const rtc::PacketOptions& options,
                   uint64_t id);
+    PendingPacket(const PendingPacket& other);
     ~PendingPacket();
     net::IPEndPoint to;
     scoped_refptr<net::IOBuffer> data;
diff --git a/content/browser/renderer_host/pepper/pepper_file_io_host.cc b/content/browser/renderer_host/pepper/pepper_file_io_host.cc
index faead26..c3e52a6 100644
--- a/content/browser/renderer_host/pepper/pepper_file_io_host.cc
+++ b/content/browser/renderer_host/pepper/pepper_file_io_host.cc
@@ -147,6 +147,9 @@
   resolved_render_process_id = base::kNullProcessId;
 }
 
+PepperFileIOHost::UIThreadStuff::UIThreadStuff(const UIThreadStuff& other) =
+    default;
+
 PepperFileIOHost::UIThreadStuff::~UIThreadStuff() {}
 
 int32_t PepperFileIOHost::OnHostMsgOpen(
diff --git a/content/browser/renderer_host/pepper/pepper_file_io_host.h b/content/browser/renderer_host/pepper/pepper_file_io_host.h
index 90de1da..6899c2f 100644
--- a/content/browser/renderer_host/pepper/pepper_file_io_host.h
+++ b/content/browser/renderer_host/pepper/pepper_file_io_host.h
@@ -49,6 +49,7 @@
 
   struct UIThreadStuff {
     UIThreadStuff();
+    UIThreadStuff(const UIThreadStuff& other);
     ~UIThreadStuff();
     base::ProcessId resolved_render_process_id;
     scoped_refptr<storage::FileSystemContext> file_system_context;
diff --git a/content/browser/renderer_host/pepper/pepper_network_proxy_host.cc b/content/browser/renderer_host/pepper/pepper_network_proxy_host.cc
index b80d1c6f..58c220e 100644
--- a/content/browser/renderer_host/pepper/pepper_network_proxy_host.cc
+++ b/content/browser/renderer_host/pepper/pepper_network_proxy_host.cc
@@ -58,6 +58,9 @@
 
 PepperNetworkProxyHost::UIThreadData::UIThreadData() : is_allowed(false) {}
 
+PepperNetworkProxyHost::UIThreadData::UIThreadData(const UIThreadData& other) =
+    default;
+
 PepperNetworkProxyHost::UIThreadData::~UIThreadData() {}
 
 // static
diff --git a/content/browser/renderer_host/pepper/pepper_network_proxy_host.h b/content/browser/renderer_host/pepper/pepper_network_proxy_host.h
index 0992c9fc..309e692d 100644
--- a/content/browser/renderer_host/pepper/pepper_network_proxy_host.h
+++ b/content/browser/renderer_host/pepper/pepper_network_proxy_host.h
@@ -48,6 +48,7 @@
   // DidGetUIThreadData, which sets allowed_ and proxy_service_.
   struct UIThreadData {
     UIThreadData();
+    UIThreadData(const UIThreadData& other);
     ~UIThreadData();
     bool is_allowed;
     scoped_refptr<net::URLRequestContextGetter> context_getter;
diff --git a/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc b/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc
index ec685e5..5f9707ad4 100644
--- a/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc
+++ b/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc
@@ -17,7 +17,6 @@
 #include "content/public/common/socket_permission_request.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "ppapi/c/pp_errors.h"
 #include "ppapi/c/private/ppb_net_address_private.h"
 #include "ppapi/host/dispatch_host_message.h"
diff --git a/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc b/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc
index 04d9e98..b73029e6 100644
--- a/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc
+++ b/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc
@@ -60,6 +60,9 @@
     : address(address), port(port), buffer(buffer), context(context) {
 }
 
+PepperUDPSocketMessageFilter::PendingSend::PendingSend(
+    const PendingSend& other) = default;
+
 PepperUDPSocketMessageFilter::PendingSend::~PendingSend() {
 }
 
diff --git a/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h b/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h
index 314599b..7f9612ca9 100644
--- a/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h
+++ b/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h
@@ -79,6 +79,7 @@
                 int port,
                 const scoped_refptr<net::IOBufferWithSize>& buffer,
                 const ppapi::host::ReplyMessageContext& context);
+    PendingSend(const PendingSend& other);
     ~PendingSend();
 
     net::IPAddressNumber address;
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 2885ae5..8772b0c 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -222,7 +222,7 @@
 #endif
 
 #if defined(ENABLE_WEBRTC)
-#include "content/browser/media/webrtc_internals.h"
+#include "content/browser/media/webrtc/webrtc_internals.h"
 #include "content/browser/renderer_host/media/media_stream_track_metrics_host.h"
 #include "content/browser/renderer_host/media/webrtc_identity_service_host.h"
 #include "content/browser/renderer_host/p2p/socket_dispatcher_host.h"
@@ -1092,6 +1092,10 @@
       make_scoped_refptr(storage_partition_impl_->GetNavigatorConnectContext()),
       message_port_message_filter_));
 
+  mojo_application_host_->service_registry()->AddService(
+      base::Bind(&RenderProcessHostImpl::CreateStoragePartitionService,
+                 base::Unretained(this)));
+
 #if defined(OS_ANDROID)
   ServiceRegistrarAndroid::RegisterProcessHostServices(
       mojo_application_host_->service_registry_android());
@@ -1101,6 +1105,15 @@
       mojo_application_host_->service_registry());
 }
 
+void RenderProcessHostImpl::CreateStoragePartitionService(
+    mojo::InterfaceRequest<StoragePartitionService> request) {
+  // DO NOT REMOVE THIS COMMAND LINE CHECK WITHOUT SECURITY REVIEW!
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kMojoLocalStorage)) {
+    storage_partition_impl_->Bind(std::move(request));
+  }
+}
+
 int RenderProcessHostImpl::GetNextRoutingID() {
   return widget_helper_->GetNextRoutingID();
 }
@@ -1430,7 +1443,6 @@
     switches::kDomAutomationController,
     switches::kEnableBlinkFeatures,
     switches::kEnableBrowserSideNavigation,
-    switches::kEnableCredentialManagerAPI,
     switches::kEnableDisplayList2dCanvas,
     switches::kEnableDistanceFieldText,
     switches::kEnableExperimentalCanvasFeatures,
@@ -1557,7 +1569,6 @@
     switches::kEnableLowEndDeviceMode,
     switches::kDisableLowEndDeviceMode,
 #if defined(OS_ANDROID)
-    switches::kDisableWebAudio,
     switches::kEnableUnifiedMediaPipeline,
     switches::kIPCSyncCompositing,
     switches::kRendererWaitForJavaDebugger,
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index fbe8f66e..03a6f0c 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -71,6 +71,7 @@
 class RenderWidgetHostViewFrameSubscriber;
 class StoragePartition;
 class StoragePartitionImpl;
+class StoragePartitionService;
 
 typedef base::Thread* (*RendererMainThreadFactoryFunction)(
     const InProcessChildThreadParams& params);
@@ -303,6 +304,9 @@
   // Registers Mojo services to be exposed to the renderer.
   void RegisterMojoServices();
 
+  void CreateStoragePartitionService(
+      mojo::InterfaceRequest<StoragePartitionService> request);
+
   // Control message handlers.
   void OnShutdownRequest();
   void SuddenTerminationChanged(bool enabled);
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index 01dc162..db4257d8 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -403,11 +403,6 @@
       !command_line.HasSwitch(switches::kDisableLocalStorage);
   prefs.databases_enabled =
       !command_line.HasSwitch(switches::kDisableDatabases);
-#if defined(OS_ANDROID)
-  // WebAudio is enabled by default on x86 and ARM.
-  prefs.webaudio_enabled =
-      !command_line.HasSwitch(switches::kDisableWebAudio);
-#endif
 
   prefs.experimental_webgl_enabled =
       GpuProcessHost::gpu_enabled() &&
@@ -877,9 +872,6 @@
 // RenderViewHostImpl, IPC message handlers:
 
 bool RenderViewHostImpl::OnMessageReceived(const IPC::Message& msg) {
-  if (!BrowserMessageFilter::CheckCanDispatchOnUI(msg, GetWidget()))
-    return true;
-
   // Filter out most IPC messages if this renderer is swapped out.
   // We still want to handle certain ACKs to keep our state consistent.
   if (is_swapped_out_) {
diff --git a/content/browser/service_worker/service_worker_cache_writer_unittest.cc b/content/browser/service_worker/service_worker_cache_writer_unittest.cc
index bc0eac4..492d45f2 100644
--- a/content/browser/service_worker/service_worker_cache_writer_unittest.cc
+++ b/content/browser/service_worker/service_worker_cache_writer_unittest.cc
@@ -11,7 +11,6 @@
 #include <string>
 
 #include "base/macros.h"
-#include "base/stl_util.h"
 #include "content/browser/service_worker/service_worker_disk_cache.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -90,6 +89,8 @@
   size_t pending_buffer_len_;
   scoped_refptr<HttpResponseInfoIOBuffer> pending_info_;
   net::CompletionCallback pending_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockServiceWorkerResponseReader);
 };
 
 void MockServiceWorkerResponseReader::ReadInfo(
@@ -236,6 +237,8 @@
   size_t data_written_;
 
   net::CompletionCallback pending_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockServiceWorkerResponseWriter);
 };
 
 void MockServiceWorkerResponseWriter::WriteInfo(
@@ -311,14 +314,14 @@
 
 class ServiceWorkerCacheWriterTest : public ::testing::Test {
  public:
-  ServiceWorkerCacheWriterTest()
-      : readers_deleter_(&readers_), writers_deleter_(&writers_) {}
+  ServiceWorkerCacheWriterTest() {}
+  ~ServiceWorkerCacheWriterTest() override {}
 
   MockServiceWorkerResponseReader* ExpectReader() {
     scoped_ptr<MockServiceWorkerResponseReader> reader(
         new MockServiceWorkerResponseReader);
     MockServiceWorkerResponseReader* borrowed_reader = reader.get();
-    readers_.push_back(reader.release());  // give ownership to |readers_|
+    readers_.push_back(std::move(reader));
     return borrowed_reader;
   }
 
@@ -326,7 +329,7 @@
     scoped_ptr<MockServiceWorkerResponseWriter> writer(
         new MockServiceWorkerResponseWriter);
     MockServiceWorkerResponseWriter* borrowed_writer = writer.get();
-    writers_.push_back(writer.release());  // give ownership to |writers_|
+    writers_.push_back(std::move(writer));
     return borrowed_writer;
   }
 
@@ -340,17 +343,8 @@
   }
 
  protected:
-  // TODO(ellyjones): when unique_ptr<> is allowed, make these instead:
-  //   std::list<unique_ptr<...>>
-  // Right now, these cannot use scoped_ptr.
-  // Their elements are deleted by the STLElementDeleters below when this object
-  // goes out of scope.
-  std::list<MockServiceWorkerResponseReader*> readers_;
-  std::list<MockServiceWorkerResponseWriter*> writers_;
-  STLElementDeleter<std::list<MockServiceWorkerResponseReader*>>
-      readers_deleter_;
-  STLElementDeleter<std::list<MockServiceWorkerResponseWriter*>>
-      writers_deleter_;
+  std::list<scoped_ptr<MockServiceWorkerResponseReader>> readers_;
+  std::list<scoped_ptr<MockServiceWorkerResponseWriter>> writers_;
   scoped_ptr<ServiceWorkerCacheWriter> cache_writer_;
   bool write_complete_ = false;
   net::Error last_error_;
@@ -358,14 +352,15 @@
   scoped_ptr<ServiceWorkerResponseReader> CreateReader() {
     if (readers_.empty())
       return make_scoped_ptr<ServiceWorkerResponseReader>(nullptr);
-    scoped_ptr<ServiceWorkerResponseReader> reader(readers_.front());
+    scoped_ptr<ServiceWorkerResponseReader> reader(std::move(readers_.front()));
     readers_.pop_front();
     return reader;
   }
+
   scoped_ptr<ServiceWorkerResponseWriter> CreateWriter() {
     if (writers_.empty())
       return make_scoped_ptr<ServiceWorkerResponseWriter>(nullptr);
-    scoped_ptr<ServiceWorkerResponseWriter> writer(writers_.front());
+    scoped_ptr<ServiceWorkerResponseWriter> writer(std::move(writers_.front()));
     writers_.pop_front();
     return writer;
   }
@@ -391,6 +386,9 @@
     return cache_writer_->MaybeWriteData(buf.get(), data.size(),
                                          CreateWriteCallback());
   }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ServiceWorkerCacheWriterTest);
 };
 
 // Passthrough tests:
diff --git a/content/browser/service_worker/service_worker_database.cc b/content/browser/service_worker/service_worker_database.cc
index e45dabb..5254e87 100644
--- a/content/browser/service_worker/service_worker_database.cc
+++ b/content/browser/service_worker/service_worker_database.cc
@@ -284,6 +284,9 @@
       resources_total_size_bytes(0) {
 }
 
+ServiceWorkerDatabase::RegistrationData::RegistrationData(
+    const RegistrationData& other) = default;
+
 ServiceWorkerDatabase::RegistrationData::~RegistrationData() {
 }
 
diff --git a/content/browser/service_worker/service_worker_database.h b/content/browser/service_worker/service_worker_database.h
index 7d575e8..a32e60af 100644
--- a/content/browser/service_worker/service_worker_database.h
+++ b/content/browser/service_worker/service_worker_database.h
@@ -75,6 +75,7 @@
     int64_t resources_total_size_bytes;
 
     RegistrationData();
+    RegistrationData(const RegistrationData& other);
     ~RegistrationData();
   };
 
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.cc b/content/browser/service_worker/service_worker_dispatcher_host.cc
index 343e6da..40a3220 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.cc
+++ b/content/browser/service_worker/service_worker_dispatcher_host.cc
@@ -30,7 +30,6 @@
 #include "content/public/common/content_client.h"
 #include "content/public/common/origin_util.h"
 #include "ipc/ipc_message_macros.h"
-#include "net/base/net_util.h"
 #include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerError.h"
 #include "url/gurl.h"
 
diff --git a/content/browser/service_worker/service_worker_info.cc b/content/browser/service_worker/service_worker_info.cc
index 836e979..422d2eea 100644
--- a/content/browser/service_worker/service_worker_info.cc
+++ b/content/browser/service_worker/service_worker_info.cc
@@ -51,6 +51,9 @@
       thread_id(thread_id),
       devtools_agent_route_id(devtools_agent_route_id) {}
 
+ServiceWorkerVersionInfo::ServiceWorkerVersionInfo(
+    const ServiceWorkerVersionInfo& other) = default;
+
 ServiceWorkerVersionInfo::~ServiceWorkerVersionInfo() {}
 
 ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo()
@@ -87,6 +90,9 @@
       installing_version(installing_version),
       stored_version_size_bytes(stored_version_size_bytes) {}
 
+ServiceWorkerRegistrationInfo::ServiceWorkerRegistrationInfo(
+    const ServiceWorkerRegistrationInfo& other) = default;
+
 ServiceWorkerRegistrationInfo::~ServiceWorkerRegistrationInfo() {}
 
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_info.h b/content/browser/service_worker/service_worker_info.h
index b1c0a73..135f0a0 100644
--- a/content/browser/service_worker/service_worker_info.h
+++ b/content/browser/service_worker/service_worker_info.h
@@ -37,6 +37,7 @@
                            int process_id,
                            int thread_id,
                            int devtools_agent_route_id);
+  ServiceWorkerVersionInfo(const ServiceWorkerVersionInfo& other);
   ~ServiceWorkerVersionInfo();
 
   ServiceWorkerVersion::RunningStatus running_status;
@@ -69,6 +70,7 @@
       const ServiceWorkerVersionInfo& waiting_version,
       const ServiceWorkerVersionInfo& installing_version,
       int64_t active_version_total_size_bytes);
+  ServiceWorkerRegistrationInfo(const ServiceWorkerRegistrationInfo& other);
   ~ServiceWorkerRegistrationInfo();
 
   GURL pattern;
diff --git a/content/browser/service_worker/service_worker_job_coordinator.cc b/content/browser/service_worker/service_worker_job_coordinator.cc
index b8f71cf..9dd023e 100644
--- a/content/browser/service_worker/service_worker_job_coordinator.cc
+++ b/content/browser/service_worker/service_worker_job_coordinator.cc
@@ -23,6 +23,9 @@
 
 ServiceWorkerJobCoordinator::JobQueue::JobQueue() {}
 
+ServiceWorkerJobCoordinator::JobQueue::JobQueue(const JobQueue& other) =
+    default;
+
 ServiceWorkerJobCoordinator::JobQueue::~JobQueue() {
   DCHECK(jobs_.empty()) << "Destroying JobQueue with " << jobs_.size()
                         << " unfinished jobs";
diff --git a/content/browser/service_worker/service_worker_job_coordinator.h b/content/browser/service_worker/service_worker_job_coordinator.h
index 728b8206..5b4c1f19 100644
--- a/content/browser/service_worker/service_worker_job_coordinator.h
+++ b/content/browser/service_worker/service_worker_job_coordinator.h
@@ -56,6 +56,7 @@
   class JobQueue {
    public:
     JobQueue();
+    JobQueue(const JobQueue& other);
     ~JobQueue();
 
     // Adds a job to the queue. If an identical job is already at the end of the
diff --git a/content/browser/service_worker/service_worker_process_manager.cc b/content/browser/service_worker/service_worker_process_manager.cc
index a6a2394..6777fc8 100644
--- a/content/browser/service_worker/service_worker_process_manager.cc
+++ b/content/browser/service_worker/service_worker_process_manager.cc
@@ -40,6 +40,9 @@
     : process_id(process_id) {
 }
 
+ServiceWorkerProcessManager::ProcessInfo::ProcessInfo(
+    const ProcessInfo& other) = default;
+
 ServiceWorkerProcessManager::ProcessInfo::~ProcessInfo() {
 }
 
diff --git a/content/browser/service_worker/service_worker_process_manager.h b/content/browser/service_worker/service_worker_process_manager.h
index 815f5b3..ad9a7306 100644
--- a/content/browser/service_worker/service_worker_process_manager.h
+++ b/content/browser/service_worker/service_worker_process_manager.h
@@ -93,6 +93,7 @@
   struct ProcessInfo {
     explicit ProcessInfo(const scoped_refptr<SiteInstance>& site_instance);
     explicit ProcessInfo(int process_id);
+    ProcessInfo(const ProcessInfo& other);
     ~ProcessInfo();
 
     // Stores the SiteInstance the Worker lives inside. This needs to outlive
diff --git a/content/browser/service_worker/service_worker_storage.cc b/content/browser/service_worker/service_worker_storage.cc
index 3af7d06..13e39e4 100644
--- a/content/browser/service_worker/service_worker_storage.cc
+++ b/content/browser/service_worker/service_worker_storage.cc
@@ -96,6 +96,9 @@
     : registration_id(kInvalidServiceWorkerRegistrationId) {
 }
 
+ServiceWorkerStorage::DidDeleteRegistrationParams::DidDeleteRegistrationParams(
+    const DidDeleteRegistrationParams& other) = default;
+
 ServiceWorkerStorage::
 DidDeleteRegistrationParams::~DidDeleteRegistrationParams() {
 }
diff --git a/content/browser/service_worker/service_worker_storage.h b/content/browser/service_worker/service_worker_storage.h
index bf07934..55b2b21b 100644
--- a/content/browser/service_worker/service_worker_storage.h
+++ b/content/browser/service_worker/service_worker_storage.h
@@ -274,6 +274,7 @@
     StatusCallback callback;
 
     DidDeleteRegistrationParams();
+    DidDeleteRegistrationParams(const DidDeleteRegistrationParams& other);
     ~DidDeleteRegistrationParams();
   };
 
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index 105f168..28fd383e 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -205,7 +205,7 @@
 }  // namespace
 
 const int ServiceWorkerVersion::kTimeoutTimerDelaySeconds = 30;
-const int ServiceWorkerVersion::kStartInstalledWorkerTimeoutSeconds = 10;
+const int ServiceWorkerVersion::kStartInstalledWorkerTimeoutSeconds = 60;
 const int ServiceWorkerVersion::kStartNewWorkerTimeoutMinutes = 5;
 const int ServiceWorkerVersion::kRequestTimeoutMinutes = 5;
 const int ServiceWorkerVersion::kStopWorkerTimeoutSeconds = 5;
@@ -808,11 +808,6 @@
   DCHECK_EQ(RUNNING, running_status());
   RestartTick(&idle_time_);
 
-  // Reset the interval to normal. If may have been shortened so starting an
-  // existing worker can timeout quickly.
-  SetTimeoutTimerInterval(
-      base::TimeDelta::FromSeconds(kTimeoutTimerDelaySeconds));
-
   // Fire all start callbacks.
   scoped_refptr<ServiceWorkerVersion> protect(this);
   RunCallbacks(this, &start_callbacks_, SERVICE_WORKER_OK);
@@ -1392,16 +1387,9 @@
   // Ping will be activated in OnScriptLoaded.
   ping_controller_->Deactivate();
 
-  // Make the timer delay shorter for starting an existing
-  // worker so stalled in starting workers can be timed out quickly.
-  // The timer will be reset to normal in OnStarted or the next start
-  // attempt.
-  const int delay_in_seconds = IsInstalled(status_)
-                                   ? kStartInstalledWorkerTimeoutSeconds
-                                   : kTimeoutTimerDelaySeconds;
   timeout_timer_.Start(FROM_HERE,
-                       base::TimeDelta::FromSeconds(delay_in_seconds), this,
-                       &ServiceWorkerVersion::OnTimeoutTimer);
+                       base::TimeDelta::FromSeconds(kTimeoutTimerDelaySeconds),
+                       this, &ServiceWorkerVersion::OnTimeoutTimer);
 }
 
 void ServiceWorkerVersion::StopTimeoutTimer() {
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index adaeb99e..24af2a8 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -52,7 +52,7 @@
 #include "ui/gfx/switches.h"
 
 #if defined(OS_MACOSX)
-#include "ui/base/test/scoped_preferred_scroller_style_legacy_mac.h"
+#include "ui/base/test/scoped_preferred_scroller_style_mac.h"
 #endif
 
 namespace content {
@@ -2148,7 +2148,7 @@
 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
                        MAYBE_FrameOwnerPropertiesPropagationScrolling) {
 #if defined(OS_MACOSX)
-  ui::test::ScopedPreferredScrollerStyleLegacy scroller_style_override;
+  ui::test::ScopedPreferredScrollerStyle scroller_style_override(false);
 #endif
   GURL main_url(embedded_test_server()->GetURL(
       "a.com", "/frame_owner_properties_scrolling.html"));
diff --git a/content/browser/speech/speech_recognizer_impl.cc b/content/browser/speech/speech_recognizer_impl.cc
index 273187d4..c993eb9a 100644
--- a/content/browser/speech/speech_recognizer_impl.cc
+++ b/content/browser/speech/speech_recognizer_impl.cc
@@ -835,6 +835,9 @@
       engine_error(SPEECH_RECOGNITION_ERROR_NONE) {
 }
 
+SpeechRecognizerImpl::FSMEventArgs::FSMEventArgs(const FSMEventArgs& other) =
+    default;
+
 SpeechRecognizerImpl::FSMEventArgs::~FSMEventArgs() {
 }
 
diff --git a/content/browser/speech/speech_recognizer_impl.h b/content/browser/speech/speech_recognizer_impl.h
index ff2484be..007142b 100644
--- a/content/browser/speech/speech_recognizer_impl.h
+++ b/content/browser/speech/speech_recognizer_impl.h
@@ -81,6 +81,7 @@
 
   struct FSMEventArgs {
     explicit FSMEventArgs(FSMEvent event_value);
+    FSMEventArgs(const FSMEventArgs& other);
     ~FSMEventArgs();
 
     FSMEvent event;
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index 0afff15d..bf4c1f51 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -591,6 +591,14 @@
   return background_sync_context_.get();
 }
 
+void StoragePartitionImpl::OpenLocalStorage(
+    const mojo::String& origin,
+    LevelDBObserverPtr observer,
+    mojo::InterfaceRequest<LevelDBWrapper> request) {
+  dom_storage_context_->OpenLocalStorage(origin, std::move(observer),
+                                         std::move(request));
+}
+
 void StoragePartitionImpl::ClearDataImpl(
     uint32_t remove_mask,
     uint32_t quota_storage_remove_mask,
@@ -892,6 +900,11 @@
   return browser_context_;
 }
 
+void StoragePartitionImpl::Bind(
+    mojo::InterfaceRequest<StoragePartitionService> request) {
+  bindings_.AddBinding(this, std::move(request));
+}
+
 void StoragePartitionImpl::OverrideQuotaManagerForTesting(
     storage::QuotaManager* quota_manager) {
   quota_manager_ = quota_manager;
diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h
index ece0a8e..90cd7c4 100644
--- a/content/browser/storage_partition_impl.h
+++ b/content/browser/storage_partition_impl.h
@@ -18,17 +18,20 @@
 #include "content/browser/dom_storage/dom_storage_context_wrapper.h"
 #include "content/browser/host_zoom_level_context.h"
 #include "content/browser/indexed_db/indexed_db_context_impl.h"
-#include "content/browser/media/webrtc_identity_store.h"
+#include "content/browser/media/webrtc/webrtc_identity_store.h"
 #include "content/browser/navigator_connect/navigator_connect_context_impl.h"
 #include "content/browser/notifications/platform_notification_context_impl.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/common/content_export.h"
+#include "content/common/storage_partition_service.mojom.h"
 #include "content/public/browser/storage_partition.h"
+#include "mojo/public/cpp/bindings/weak_binding_set.h"
 #include "storage/browser/quota/special_storage_policy.h"
 
 namespace content {
 
-class StoragePartitionImpl : public StoragePartition {
+class StoragePartitionImpl : public StoragePartition,
+                             public StoragePartitionService {
  public:
   CONTENT_EXPORT ~StoragePartitionImpl() override;
 
@@ -61,6 +64,12 @@
   PlatformNotificationContextImpl* GetPlatformNotificationContext() override;
   BackgroundSyncContextImpl* GetBackgroundSyncContext() override;
 
+  // StoragePartitionService interface.
+  void OpenLocalStorage(
+      const mojo::String& origin,
+      LevelDBObserverPtr observer,
+      mojo::InterfaceRequest<LevelDBWrapper> request) override;
+
   void ClearDataForOrigin(uint32_t remove_mask,
                           uint32_t quota_storage_remove_mask,
                           const GURL& storage_origin,
@@ -81,6 +90,9 @@
   // Can return nullptr while |this| is being destroyed.
   BrowserContext* browser_context() const;
 
+  // Called by each renderer process once.
+  void Bind(mojo::InterfaceRequest<StoragePartitionService> request);
+
   struct DataDeletionHelper;
   struct QuotaManagedDataDeletionHelper;
 
@@ -194,6 +206,8 @@
   scoped_refptr<PlatformNotificationContextImpl> platform_notification_context_;
   scoped_refptr<BackgroundSyncContextImpl> background_sync_context_;
 
+  mojo::WeakBindingSet<StoragePartitionService> bindings_;
+
   // Raw pointer that should always be valid. The BrowserContext owns the
   // StoragePartitionImplMap which then owns StoragePartitionImpl. When the
   // BrowserContext is destroyed, |this| will be destroyed too.
diff --git a/content/browser/webui/OWNERS b/content/browser/webui/OWNERS
index 658a9f5..262db99 100644
--- a/content/browser/webui/OWNERS
+++ b/content/browser/webui/OWNERS
@@ -1 +1,2 @@
+dbeam@chromium.org
 estade@chromium.org
diff --git a/content/browser/webui/content_web_ui_controller_factory.cc b/content/browser/webui/content_web_ui_controller_factory.cc
index 196da55..9d87359d 100644
--- a/content/browser/webui/content_web_ui_controller_factory.cc
+++ b/content/browser/webui/content_web_ui_controller_factory.cc
@@ -19,7 +19,7 @@
 #include "content/public/common/url_constants.h"
 
 #if defined(ENABLE_WEBRTC)
-#include "content/browser/media/webrtc_internals_ui.h"
+#include "content/browser/media/webrtc/webrtc_internals_ui.h"
 #endif
 
 namespace content {
diff --git a/content/browser/webui/web_ui_data_source_impl.cc b/content/browser/webui/web_ui_data_source_impl.cc
index e8b5b9fd..eeac51d 100644
--- a/content/browser/webui/web_ui_data_source_impl.cc
+++ b/content/browser/webui/web_ui_data_source_impl.cc
@@ -12,9 +12,11 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
 #include "content/grit/content_resources.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/common/content_client.h"
+#include "ui/base/template_expressions.h"
 #include "ui/base/webui/jstemplate_builder.h"
 #include "ui/base/webui/web_ui_util.h"
 
@@ -35,8 +37,7 @@
 // URLDataSource.
 class WebUIDataSourceImpl::InternalDataSource : public URLDataSource {
  public:
-  InternalDataSource(WebUIDataSourceImpl* parent) : parent_(parent) {
-  }
+  explicit InternalDataSource(WebUIDataSourceImpl* parent) : parent_(parent) {}
 
   ~InternalDataSource() override {}
 
@@ -79,9 +80,7 @@
 };
 
 WebUIDataSourceImpl::WebUIDataSourceImpl(const std::string& source_name)
-    : URLDataSourceImpl(
-          source_name,
-          new InternalDataSource(this)),
+    : URLDataSourceImpl(source_name, new InternalDataSource(this)),
       source_name_(source_name),
       default_resource_(-1),
       add_csp_(true),
@@ -89,26 +88,30 @@
       frame_src_set_(false),
       deny_xframe_options_(true),
       disable_set_font_strings_(false),
-      replace_existing_source_(true) {
-}
+      replace_existing_source_(true) {}
 
 WebUIDataSourceImpl::~WebUIDataSourceImpl() {
 }
 
 void WebUIDataSourceImpl::AddString(const std::string& name,
                                     const base::string16& value) {
+  // TODO(dschuyler): Share only one copy of these strings.
   localized_strings_.SetString(name, value);
+  replacements_[name] = base::UTF16ToUTF8(value);
 }
 
 void WebUIDataSourceImpl::AddString(const std::string& name,
                                     const std::string& value) {
   localized_strings_.SetString(name, value);
+  replacements_[name] = value;
 }
 
 void WebUIDataSourceImpl::AddLocalizedString(const std::string& name,
                                              int ids) {
   localized_strings_.SetString(
       name, GetContentClient()->GetLocalizedString(ids));
+  replacements_[name] =
+      base::UTF16ToUTF8(GetContentClient()->GetLocalizedString(ids));
 }
 
 void WebUIDataSourceImpl::AddLocalizedStrings(
@@ -118,6 +121,11 @@
 
 void WebUIDataSourceImpl::AddBoolean(const std::string& name, bool value) {
   localized_strings_.SetBoolean(name, value);
+  // TODO(dschuyler): Change name of |localized_strings_| to |load_time_data_|
+  // or similar. These values haven't been found as strings for
+  // localization. The boolean values are not added to |replacements_|
+  // for the same reason, that they are used as flags, rather than string
+  // replacements.
 }
 
 void WebUIDataSourceImpl::SetJsonPath(const std::string& path) {
@@ -211,7 +219,19 @@
   if (result != path_to_idr_map_.end())
     resource_id = result->second;
   DCHECK_NE(resource_id, -1);
-  SendFromResourceBundle(callback, resource_id);
+  scoped_refptr<base::RefCountedMemory> response(
+      GetContentClient()->GetDataResourceBytes(resource_id));
+
+  // TODO(dschuyler): improve filtering of which resource to run template
+  // expansion upon.
+  if (GetMimeType(path) == "text/html") {
+    std::string replaced = ui::ReplaceTemplateExpressions(
+        base::StringPiece(response->front_as<char>(), response->size()),
+        replacements_);
+    response = base::RefCountedString::TakeString(&replaced);
+  }
+
+  callback.Run(response.get());
 }
 
 void WebUIDataSourceImpl::SendLocalizedStringsAsJSON(
@@ -226,11 +246,4 @@
   callback.Run(base::RefCountedString::TakeString(&template_data));
 }
 
-void WebUIDataSourceImpl::SendFromResourceBundle(
-    const URLDataSource::GotDataCallback& callback, int idr) {
-  scoped_refptr<base::RefCountedStaticMemory> response(
-      GetContentClient()->GetDataResourceBytes(idr));
-  callback.Run(response.get());
-}
-
 }  // namespace content
diff --git a/content/browser/webui/web_ui_data_source_impl.h b/content/browser/webui/web_ui_data_source_impl.h
index b084ba54..53cbc73 100644
--- a/content/browser/webui/web_ui_data_source_impl.h
+++ b/content/browser/webui/web_ui_data_source_impl.h
@@ -17,6 +17,7 @@
 #include "content/common/content_export.h"
 #include "content/public/browser/url_data_source.h"
 #include "content/public/browser/web_ui_data_source.h"
+#include "ui/base/template_expressions.h"
 
 namespace content {
 
@@ -51,10 +52,6 @@
   void SendLocalizedStringsAsJSON(
       const URLDataSource::GotDataCallback& callback);
 
-  // Completes a request by sending the file specified by |idr|.
-  void SendFromResourceBundle(
-      const URLDataSource::GotDataCallback& callback, int idr);
-
  private:
   class InternalDataSource;
   friend class InternalDataSource;
@@ -84,6 +81,10 @@
   int default_resource_;
   std::string json_path_;
   std::map<std::string, int> path_to_idr_map_;
+  // The |replacements_| is intended to replace |localized_strings_|.
+  // TODO(dschuyler): phase out |localized_strings_| in Q1 2016. (Or rename
+  // to |load_time_flags_| if the usage is reduced to storing flags only).
+  ui::TemplateReplacements replacements_;
   base::DictionaryValue localized_strings_;
   WebUIDataSource::HandleRequestCallback filter_callback_;
   bool add_csp_;
@@ -98,6 +99,6 @@
   DISALLOW_COPY_AND_ASSIGN(WebUIDataSourceImpl);
 };
 
-}  // content
+}  // namespace content
 
 #endif  // CONTENT_BROWSER_WEBUI_WEB_UI_DATA_SOURCE_IMPL_H_
diff --git a/content/browser/webui/web_ui_mojo_browsertest.cc b/content/browser/webui/web_ui_mojo_browsertest.cc
index 1d667ee..4fff1a4 100644
--- a/content/browser/webui/web_ui_mojo_browsertest.cc
+++ b/content/browser/webui/web_ui_mojo_browsertest.cc
@@ -46,7 +46,7 @@
   if (id.find(".mojom") != std::string::npos) {
     std::string contents;
     CHECK(base::ReadFileToString(mojo::test::GetFilePathForJSResource(id),
-                                 &contents, std::string::npos))
+                                 &contents))
         << id;
     base::RefCountedString* ref_contents = new base::RefCountedString;
     ref_contents->data() = contents;
@@ -58,8 +58,7 @@
   CHECK(base::PathService::Get(content::DIR_TEST_DATA, &path));
   path = path.AppendASCII(id.substr(0, id.find("?")));
   std::string contents;
-  CHECK(base::ReadFileToString(path, &contents, std::string::npos))
-      << path.value();
+  CHECK(base::ReadFileToString(path, &contents)) << path.value();
   base::RefCountedString* ref_contents = new base::RefCountedString;
   ref_contents->data() = contents;
   callback.Run(ref_contents);
diff --git a/content/child/blob_storage/blob_consolidation.cc b/content/child/blob_storage/blob_consolidation.cc
index a2b0925d..67b8d6b9 100644
--- a/content/child/blob_storage/blob_consolidation.cc
+++ b/content/child/blob_storage/blob_consolidation.cc
@@ -35,6 +35,9 @@
       expected_modification_time(0) {
 }
 
+BlobConsolidation::ConsolidatedItem::ConsolidatedItem(
+    const ConsolidatedItem& other) = default;
+
 BlobConsolidation::BlobConsolidation() : total_memory_(0) {
 }
 
diff --git a/content/child/blob_storage/blob_consolidation.h b/content/child/blob_storage/blob_consolidation.h
index c261b3c..7a4a3de2 100644
--- a/content/child/blob_storage/blob_consolidation.h
+++ b/content/child/blob_storage/blob_consolidation.h
@@ -45,6 +45,7 @@
     ConsolidatedItem(storage::DataElement::Type type,
                      uint64_t offset,
                      uint64_t length);
+    ConsolidatedItem(const ConsolidatedItem& other);
     ~ConsolidatedItem();
 
     storage::DataElement::Type type;
diff --git a/content/child/child_discardable_shared_memory_manager.cc b/content/child/child_discardable_shared_memory_manager.cc
index 7bb268c..5116036 100644
--- a/content/child/child_discardable_shared_memory_manager.cc
+++ b/content/child/child_discardable_shared_memory_manager.cc
@@ -4,6 +4,7 @@
 
 #include "content/child/child_discardable_shared_memory_manager.h"
 
+#include <algorithm>
 #include <utility>
 
 #include "base/atomic_sequence_num.h"
@@ -108,7 +109,8 @@
     size_t size) {
   base::AutoLock lock(lock_);
 
-  DCHECK_NE(size, 0u);
+  // TODO(reveman): Temporary diagnostics for http://crbug.com/577786.
+  CHECK_NE(size, 0u);
 
   UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.DiscardableAllocationSize",
                               size / 1024,  // In KB
@@ -117,7 +119,9 @@
                               50);
 
   // Round up to multiple of page size.
-  size_t pages = (size + base::GetPageSize() - 1) / base::GetPageSize();
+  size_t pages =
+      std::max((size + base::GetPageSize() - 1) / base::GetPageSize(),
+               static_cast<size_t>(1));
 
   // Default allocation size in pages.
   size_t allocation_pages = kAllocationSize / base::GetPageSize();
diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc
index bdc346d..442d7b67 100644
--- a/content/child/child_thread_impl.cc
+++ b/content/child/child_thread_impl.cc
@@ -260,6 +260,8 @@
       use_mojo_channel(false) {
 }
 
+ChildThreadImpl::Options::Options(const Options& other) = default;
+
 ChildThreadImpl::Options::~Options() {
 }
 
diff --git a/content/child/child_thread_impl.h b/content/child/child_thread_impl.h
index 462af37f..d7b340b8 100644
--- a/content/child/child_thread_impl.h
+++ b/content/child/child_thread_impl.h
@@ -298,6 +298,7 @@
 };
 
 struct ChildThreadImpl::Options {
+  Options(const Options& other);
   ~Options();
 
   class Builder;
diff --git a/content/child/indexed_db/indexed_db_dispatcher.cc b/content/child/indexed_db/indexed_db_dispatcher.cc
index bbe269b..2972e71 100644
--- a/content/child/indexed_db/indexed_db_dispatcher.cc
+++ b/content/child/indexed_db/indexed_db_dispatcher.cc
@@ -87,7 +87,7 @@
   WebIDBMetadata web_metadata;
   web_metadata.id = idb_metadata.id;
   web_metadata.name = idb_metadata.name;
-  web_metadata.intVersion = idb_metadata.int_version;
+  web_metadata.version = idb_metadata.version;
   web_metadata.maxObjectStoreId = idb_metadata.max_object_store_id;
   web_metadata.objectStores =
       WebVector<WebIDBMetadata::ObjectStore>(idb_metadata.object_stores.size());
@@ -151,8 +151,8 @@
     IPC_MESSAGE_HANDLER(IndexedDBMsg_CallbacksUpgradeNeeded, OnUpgradeNeeded)
     IPC_MESSAGE_HANDLER(IndexedDBMsg_DatabaseCallbacksForcedClose,
                         OnForcedClose)
-    IPC_MESSAGE_HANDLER(IndexedDBMsg_DatabaseCallbacksIntVersionChange,
-                        OnIntVersionChange)
+    IPC_MESSAGE_HANDLER(IndexedDBMsg_DatabaseCallbacksVersionChange,
+                        OnVersionChange)
     IPC_MESSAGE_HANDLER(IndexedDBMsg_DatabaseCallbacksAbort, OnAbort)
     IPC_MESSAGE_HANDLER(IndexedDBMsg_DatabaseCallbacksComplete, OnComplete)
     IPC_MESSAGE_UNHANDLED(handled = false)
@@ -780,10 +780,10 @@
   callbacks->onForcedClose();
 }
 
-void IndexedDBDispatcher::OnIntVersionChange(int32_t ipc_thread_id,
-                                             int32_t ipc_database_callbacks_id,
-                                             int64_t old_version,
-                                             int64_t new_version) {
+void IndexedDBDispatcher::OnVersionChange(int32_t ipc_thread_id,
+                                          int32_t ipc_database_callbacks_id,
+                                          int64_t old_version,
+                                          int64_t new_version) {
   DCHECK_EQ(ipc_thread_id, CurrentWorkerId());
   WebIDBDatabaseCallbacks* callbacks =
       pending_database_callbacks_.Lookup(ipc_database_callbacks_id);
diff --git a/content/child/indexed_db/indexed_db_dispatcher.h b/content/child/indexed_db/indexed_db_dispatcher.h
index 993349d4..1f84219 100644
--- a/content/child/indexed_db/indexed_db_dispatcher.h
+++ b/content/child/indexed_db/indexed_db_dispatcher.h
@@ -242,10 +242,10 @@
                   int32_t ipc_database_id,
                   int64_t transaction_id);
   void OnForcedClose(int32_t ipc_thread_id, int32_t ipc_database_id);
-  void OnIntVersionChange(int32_t ipc_thread_id,
-                          int32_t ipc_database_id,
-                          int64_t old_version,
-                          int64_t new_version);
+  void OnVersionChange(int32_t ipc_thread_id,
+                       int32_t ipc_database_id,
+                       int64_t old_version,
+                       int64_t new_version);
 
   // Reset cursor prefetch caches for all cursors except exception_cursor_id.
   void ResetCursorPrefetchCaches(int64_t transaction_id,
diff --git a/content/child/multipart_response_delegate.cc b/content/child/multipart_response_delegate.cc
index 02f725d9..03ffdd3 100644
--- a/content/child/multipart_response_delegate.cc
+++ b/content/child/multipart_response_delegate.cc
@@ -9,7 +9,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
-#include "net/base/net_util.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_util.h"
 #include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h"
diff --git a/content/child/notifications/notification_image_loader.cc b/content/child/notifications/notification_image_loader.cc
index 08a108a..4ad37f8 100644
--- a/content/child/notifications/notification_image_loader.cc
+++ b/content/child/notifications/notification_image_loader.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/single_thread_task_runner.h"
 #include "content/child/image_decoder.h"
 #include "third_party/WebKit/public/platform/Platform.h"
@@ -39,6 +40,8 @@
   DCHECK(main_task_runner_->BelongsToCurrentThread());
   DCHECK(!url_loader_);
 
+  start_time_ = base::TimeTicks::Now();
+
   WebURL image_web_url(image_url);
   WebURLRequest request(image_web_url);
   request.setRequestContext(WebURLRequest::RequestContextImage);
@@ -63,6 +66,9 @@
     int64_t total_encoded_data_length) {
   DCHECK(!completed_);
 
+  UMA_HISTOGRAM_LONG_TIMES("Notifications.Icon.LoadFinishTime",
+                           base::TimeTicks::Now() - start_time_);
+
   RunCallbackOnWorkerThread();
 }
 
@@ -71,6 +77,9 @@
   if (completed_)
     return;
 
+  UMA_HISTOGRAM_LONG_TIMES("Notifications.Icon.LoadFailTime",
+                           base::TimeTicks::Now() - start_time_);
+
   RunCallbackOnWorkerThread();
 }
 
@@ -89,6 +98,10 @@
 
 SkBitmap NotificationImageLoader::GetDecodedImage() const {
   DCHECK(completed_);
+
+  UMA_HISTOGRAM_CUSTOM_COUNTS("Notifications.Icon.FileSize", buffer_.size(), 1,
+                              10000000 /* ~10mb */, 50);
+
   if (buffer_.empty())
     return SkBitmap();
 
diff --git a/content/child/notifications/notification_image_loader.h b/content/child/notifications/notification_image_loader.h
index b9818d18..37daebfa 100644
--- a/content/child/notifications/notification_image_loader.h
+++ b/content/child/notifications/notification_image_loader.h
@@ -14,6 +14,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/sequenced_task_runner_helpers.h"
+#include "base/time/time.h"
 #include "third_party/WebKit/public/platform/WebURLLoaderClient.h"
 
 class GURL;
@@ -99,6 +100,8 @@
 
   std::vector<uint8_t> buffer_;
 
+  base::TimeTicks start_time_;
+
   DISALLOW_COPY_AND_ASSIGN(NotificationImageLoader);
 };
 
diff --git a/content/child/notifications/pending_notification.cc b/content/child/notifications/pending_notification.cc
index 0db2834..cc6542e6 100644
--- a/content/child/notifications/pending_notification.cc
+++ b/content/child/notifications/pending_notification.cc
@@ -4,16 +4,39 @@
 
 #include "content/child/notifications/pending_notification.h"
 
+#include <algorithm>
+
 #include "base/barrier_closure.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/location.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/thread_task_runner_handle.h"
+#include "content/common/notification_constants.h"
 #include "content/public/common/notification_resources.h"
+#include "skia/ext/image_operations.h"
 #include "url/gurl.h"
 
 namespace content {
 
+namespace {
+
+// Scales down |icon| to fit within |max_size_px| if its width or height is
+// larger than |max_size_px| and returns the result. Otherwise does nothing and
+// returns |icon| unchanged.
+SkBitmap ScaleDownIfNeeded(const SkBitmap& icon, int max_size_px) {
+  if (icon.width() > max_size_px || icon.height() > max_size_px) {
+    SCOPED_UMA_HISTOGRAM_TIMER("Notifications.Icon.ScaleDownTime");
+    return skia::ImageOperations::Resize(icon,
+                                         skia::ImageOperations::RESIZE_BEST,
+                                         std::min(icon.width(), max_size_px),
+                                         std::min(icon.height(), max_size_px));
+  }
+  return icon;
+}
+
+}  // namespace
+
 PendingNotification::PendingNotification(
     const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner)
     : main_task_runner_(main_task_runner), weak_factory_(this) {}
@@ -73,17 +96,18 @@
                             image_loader, image_gurl));
 }
 
-void PendingNotification::DidFetchNotificationIcon(
-    const SkBitmap& notification_icon) {
-  notification_icon_ = notification_icon;
+void PendingNotification::DidFetchNotificationIcon(const SkBitmap& icon) {
+  notification_icon_ =
+      ScaleDownIfNeeded(icon, kPlatformNotificationMaxIconSizePx);
   fetches_finished_barrier_closure_.Run();
 }
 
 void PendingNotification::DidFetchActionIcon(size_t action_index,
-                                             const SkBitmap& action_icon) {
+                                             const SkBitmap& icon) {
   DCHECK_LT(action_index, action_icons_.size());
 
-  action_icons_[action_index] = action_icon;
+  action_icons_[action_index] =
+      ScaleDownIfNeeded(icon, kPlatformNotificationMaxActionIconSizePx);
   fetches_finished_barrier_closure_.Run();
 }
 
diff --git a/content/child/notifications/pending_notifications_tracker_unittest.cc b/content/child/notifications/pending_notifications_tracker_unittest.cc
index c01917a..18cee87f 100644
--- a/content/child/notifications/pending_notifications_tracker_unittest.cc
+++ b/content/child/notifications/pending_notifications_tracker_unittest.cc
@@ -18,6 +18,7 @@
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/thread_task_runner_handle.h"
+#include "content/common/notification_constants.h"
 #include "content/public/common/notification_resources.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/Platform.h"
@@ -39,6 +40,7 @@
 const char kIcon100x100[] = "100x100.png";
 const char kIcon110x110[] = "110x110.png";
 const char kIcon120x120[] = "120x120.png";
+const char kIcon500x500[] = "500x500.png";
 
 class FakeNotificationDelegate : public blink::WebNotificationDelegate {
  public:
@@ -168,6 +170,41 @@
   ASSERT_EQ(120, GetResources(0u)->action_icons[1].width());
 }
 
+TEST_F(PendingNotificationsTrackerTest, LargeIconsAreScaledDown) {
+  blink::WebNotificationData notification_data;
+  notification_data.icon = RegisterMockedURL(kIcon500x500);
+  notification_data.actions =
+      blink::WebVector<blink::WebNotificationAction>(static_cast<size_t>(1));
+  notification_data.actions[0].icon = notification_data.icon;
+
+  tracker()->FetchResources(
+      notification_data, nullptr /* delegate */,
+      base::Bind(&PendingNotificationsTrackerTest::DidFetchResources,
+                 base::Unretained(this), 0 /* index */));
+
+  ASSERT_EQ(1u, CountPendingNotifications());
+  ASSERT_EQ(0u, CountResources());
+
+  base::RunLoop().RunUntilIdle();
+  UnitTestSupport()->serveAsynchronousMockedRequests();
+
+  ASSERT_EQ(0u, CountPendingNotifications());
+  ASSERT_EQ(1u, CountResources());
+
+  ASSERT_FALSE(GetResources(0u)->notification_icon.drawsNothing());
+  ASSERT_EQ(kPlatformNotificationMaxIconSizePx,
+            GetResources(0u)->notification_icon.width());
+  ASSERT_EQ(kPlatformNotificationMaxIconSizePx,
+            GetResources(0u)->notification_icon.height());
+
+  ASSERT_EQ(1u, GetResources(0u)->action_icons.size());
+  ASSERT_FALSE(GetResources(0u)->action_icons[0].drawsNothing());
+  ASSERT_EQ(kPlatformNotificationMaxActionIconSizePx,
+            GetResources(0u)->action_icons[0].width());
+  ASSERT_EQ(kPlatformNotificationMaxActionIconSizePx,
+            GetResources(0u)->action_icons[0].height());
+}
+
 TEST_F(PendingNotificationsTrackerTest, TwoNotifications) {
   blink::WebNotificationData notification_data;
   notification_data.icon = RegisterMockedURL(kIcon100x100);
diff --git a/content/child/resource_dispatcher.cc b/content/child/resource_dispatcher.cc
index 137d2ce..26175ce 100644
--- a/content/child/resource_dispatcher.cc
+++ b/content/child/resource_dispatcher.cc
@@ -38,7 +38,6 @@
 #include "content/public/common/resource_response.h"
 #include "content/public/common/resource_type.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/request_priority.h"
 #include "net/http/http_response_headers.h"
 
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 3bdd973..9fcb6573 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -97,9 +97,6 @@
   if (command_line.HasSwitch(switches::kDisableSharedWorkers))
     WebRuntimeFeatures::enableSharedWorker(false);
 
-  if (command_line.HasSwitch(switches::kDisableWebAudio))
-    WebRuntimeFeatures::enableWebAudio(false);
-
   if (command_line.HasSwitch(switches::kDisableSpeechAPI))
     WebRuntimeFeatures::enableScriptedSpeech(false);
 
@@ -142,8 +139,8 @@
     WebRuntimeFeatures::enableNetworkInformation(true);
   }
 
-  if (command_line.HasSwitch(switches::kEnableCredentialManagerAPI))
-    WebRuntimeFeatures::enableCredentialManagerAPI(true);
+  if (!base::FeatureList::IsEnabled(features::kCredentialManagementAPI))
+    WebRuntimeFeatures::enableCredentialManagerAPI(false);
 
   if (command_line.HasSwitch(switches::kReducedReferrerGranularity))
     WebRuntimeFeatures::enableReducedReferrerGranularity(true);
@@ -180,6 +177,9 @@
   if (command_line.HasSwitch(switches::kEnableSlimmingPaintV2))
     WebRuntimeFeatures::enableSlimmingPaintV2(true);
 
+  if (base::FeatureList::IsEnabled(features::kRenderingPipelineThrottling))
+    WebRuntimeFeatures::enableRenderingPipelineThrottling(true);
+
   // Enable explicitly enabled features, and then disable explicitly disabled
   // ones.
   if (command_line.HasSwitch(switches::kEnableBlinkFeatures)) {
diff --git a/content/child/service_worker/web_service_worker_registration_impl.cc b/content/child/service_worker/web_service_worker_registration_impl.cc
index a753de4..1897c5b 100644
--- a/content/child/service_worker/web_service_worker_registration_impl.cc
+++ b/content/child/service_worker/web_service_worker_registration_impl.cc
@@ -42,6 +42,9 @@
     const scoped_refptr<WebServiceWorkerImpl>& worker)
     : type(type), worker(worker) {}
 
+WebServiceWorkerRegistrationImpl::QueuedTask::QueuedTask(
+    const QueuedTask& other) = default;
+
 WebServiceWorkerRegistrationImpl::QueuedTask::~QueuedTask() {}
 
 WebServiceWorkerRegistrationImpl::WebServiceWorkerRegistrationImpl(
diff --git a/content/child/service_worker/web_service_worker_registration_impl.h b/content/child/service_worker/web_service_worker_registration_impl.h
index 9a17908..41da2774 100644
--- a/content/child/service_worker/web_service_worker_registration_impl.h
+++ b/content/child/service_worker/web_service_worker_registration_impl.h
@@ -86,6 +86,7 @@
   struct QueuedTask {
     QueuedTask(QueuedTaskType type,
                const scoped_refptr<WebServiceWorkerImpl>& worker);
+    QueuedTask(const QueuedTask& other);
     ~QueuedTask();
     QueuedTaskType type;
     scoped_refptr<WebServiceWorkerImpl> worker;
diff --git a/content/child/webmessageportchannel_impl.cc b/content/child/webmessageportchannel_impl.cc
index 6fdd08c..9274c7390 100644
--- a/content/child/webmessageportchannel_impl.cc
+++ b/content/child/webmessageportchannel_impl.cc
@@ -350,6 +350,8 @@
 
 WebMessagePortChannelImpl::Message::Message() {}
 
+WebMessagePortChannelImpl::Message::Message(const Message& other) = default;
+
 WebMessagePortChannelImpl::Message::~Message() {}
 
 }  // namespace content
diff --git a/content/child/webmessageportchannel_impl.h b/content/child/webmessageportchannel_impl.h
index b5c8e7b..8a766ae 100644
--- a/content/child/webmessageportchannel_impl.h
+++ b/content/child/webmessageportchannel_impl.h
@@ -106,6 +106,7 @@
 
   struct Message {
     Message();
+    Message(const Message& other);
     ~Message();
 
     MessagePortMessage message;
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index af8f370..45c63a6 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -287,10 +287,7 @@
   if (use_ozone) {
     configs += [ "//ui/ozone:vgem_map" ]
 
-    deps += [
-      "//ui/ozone:ozone",
-      "//ui/ozone:ozone_base",
-    ]
+    deps += [ "//ui/ozone" ]
   } else {
     sources -= [
       "cursors/webcursor_ozone.cc",
@@ -535,6 +532,7 @@
     "background_sync_service.mojom",
     "geolocation_service.mojom",
     "image_downloader/image_downloader.mojom",
+    "leveldb_wrapper.mojom",
     "permission_service.mojom",
     "presentation/presentation_service.mojom",
     "process_control.mojom",
@@ -542,6 +540,7 @@
     "render_widget_window_tree_client_factory.mojom",
     "service_port_service.mojom",
     "service_worker/embedded_worker_setup.mojom",
+    "storage_partition_service.mojom",
     "vr_service.mojom",
     "wake_lock_service.mojom",
   ]
@@ -549,6 +548,7 @@
   import_dirs = [ "//mojo/services" ]
 
   public_deps = [
+    "//components/leveldb/public/interfaces",
     "//components/mus/public/interfaces",
     "//content/public/common:mojo_bindings",
     "//mojo/shell/public/interfaces",
diff --git a/content/common/OWNERS b/content/common/OWNERS
index 566803fa..8ded209 100644
--- a/content/common/OWNERS
+++ b/content/common/OWNERS
@@ -100,3 +100,7 @@
 # DirectWrite
 per-file dwrite_font_platform_win*=scottmg@chromium.org
 per-file font_warmup_win.cc=scottmg@chromium.org
+
+# Web Notifications
+per-file notification_constants.h=peter@chromium.org
+per-file notification_constants.h=mvanouwerkerk@chromium.org
diff --git a/content/common/android/sync_compositor_messages.cc b/content/common/android/sync_compositor_messages.cc
index f44415f3..638483e3 100644
--- a/content/common/android/sync_compositor_messages.cc
+++ b/content/common/android/sync_compositor_messages.cc
@@ -44,9 +44,9 @@
       min_page_scale_factor(0.f),
       max_page_scale_factor(0.f),
       need_animate_scroll(false),
-      need_invalidate(false),
+      need_invalidate_count(0u),
       need_begin_frame(false),
-      did_activate_pending_tree(false) {}
+      did_activate_pending_tree_count(0u) {}
 
 SyncCompositorCommonRendererParams::~SyncCompositorCommonRendererParams() {}
 
diff --git a/content/common/android/sync_compositor_messages.h b/content/common/android/sync_compositor_messages.h
index d3a3f996..0ad1cf1 100644
--- a/content/common/android/sync_compositor_messages.h
+++ b/content/common/android/sync_compositor_messages.h
@@ -79,9 +79,9 @@
   float min_page_scale_factor;
   float max_page_scale_factor;
   bool need_animate_scroll;
-  bool need_invalidate;
+  uint32_t need_invalidate_count;
   bool need_begin_frame;
-  bool did_activate_pending_tree;
+  uint32_t did_activate_pending_tree_count;
 };
 
 }  // namespace content
@@ -131,9 +131,9 @@
   IPC_STRUCT_TRAITS_MEMBER(min_page_scale_factor)
   IPC_STRUCT_TRAITS_MEMBER(max_page_scale_factor)
   IPC_STRUCT_TRAITS_MEMBER(need_animate_scroll)
-  IPC_STRUCT_TRAITS_MEMBER(need_invalidate)
+  IPC_STRUCT_TRAITS_MEMBER(need_invalidate_count)
   IPC_STRUCT_TRAITS_MEMBER(need_begin_frame)
-  IPC_STRUCT_TRAITS_MEMBER(did_activate_pending_tree)
+  IPC_STRUCT_TRAITS_MEMBER(did_activate_pending_tree_count)
 IPC_STRUCT_TRAITS_END()
 
 // Messages sent from the browser to the renderer.
diff --git a/content/common/appcache_interfaces.cc b/content/common/appcache_interfaces.cc
index af0d8c1..8342a364 100644
--- a/content/common/appcache_interfaces.cc
+++ b/content/common/appcache_interfaces.cc
@@ -31,6 +31,8 @@
       is_complete(false) {
 }
 
+AppCacheInfo::AppCacheInfo(const AppCacheInfo& other) = default;
+
 AppCacheInfo::~AppCacheInfo() {
 }
 
@@ -46,6 +48,9 @@
       response_id(kAppCacheNoResponseId) {
 }
 
+AppCacheResourceInfo::AppCacheResourceInfo(const AppCacheResourceInfo& other) =
+    default;
+
 AppCacheResourceInfo::~AppCacheResourceInfo() {
 }
 
diff --git a/content/common/appcache_interfaces.h b/content/common/appcache_interfaces.h
index 8ba2da0..12cc7c1 100644
--- a/content/common/appcache_interfaces.h
+++ b/content/common/appcache_interfaces.h
@@ -62,6 +62,7 @@
 // Type to hold information about a single appcache resource.
 struct CONTENT_EXPORT AppCacheResourceInfo {
   AppCacheResourceInfo();
+  AppCacheResourceInfo(const AppCacheResourceInfo& other);
   ~AppCacheResourceInfo();
 
   GURL url;
diff --git a/content/common/ax_content_node_data.cc b/content/common/ax_content_node_data.cc
index fda3668..d528727 100644
--- a/content/common/ax_content_node_data.cc
+++ b/content/common/ax_content_node_data.cc
@@ -33,6 +33,8 @@
 AXContentNodeData::AXContentNodeData() {
 }
 
+AXContentNodeData::AXContentNodeData(const AXContentNodeData& other) = default;
+
 AXContentNodeData::~AXContentNodeData() {
 }
 
diff --git a/content/common/ax_content_node_data.h b/content/common/ax_content_node_data.h
index 00849cd..93ab719 100644
--- a/content/common/ax_content_node_data.h
+++ b/content/common/ax_content_node_data.h
@@ -28,6 +28,7 @@
 // content-layer-specific AX attributes.
 struct CONTENT_EXPORT AXContentNodeData : public ui::AXNodeData {
   AXContentNodeData();
+  AXContentNodeData(const AXContentNodeData& other);
   ~AXContentNodeData() override;
 
   bool HasContentIntAttribute(AXContentIntAttribute attribute) const;
diff --git a/content/common/bluetooth/bluetooth_scan_filter.cc b/content/common/bluetooth/bluetooth_scan_filter.cc
index 3ab22ae..2c5a7cb8 100644
--- a/content/common/bluetooth/bluetooth_scan_filter.cc
+++ b/content/common/bluetooth/bluetooth_scan_filter.cc
@@ -9,6 +9,9 @@
 BluetoothScanFilter::BluetoothScanFilter() : services() {
 }
 
+BluetoothScanFilter::BluetoothScanFilter(const BluetoothScanFilter& other) =
+    default;
+
 BluetoothScanFilter::~BluetoothScanFilter() {
 }
 
diff --git a/content/common/bluetooth/bluetooth_scan_filter.h b/content/common/bluetooth/bluetooth_scan_filter.h
index 2572747..6c0bb337 100644
--- a/content/common/bluetooth/bluetooth_scan_filter.h
+++ b/content/common/bluetooth/bluetooth_scan_filter.h
@@ -17,6 +17,7 @@
 // blink::WebBluetoothScanFilter.
 struct CONTENT_EXPORT BluetoothScanFilter {
   BluetoothScanFilter();
+  BluetoothScanFilter(const BluetoothScanFilter& other);
   ~BluetoothScanFilter();
 
   std::vector<device::BluetoothUUID> services;
diff --git a/content/common/cache_storage/cache_storage_types.cc b/content/common/cache_storage/cache_storage_types.cc
index c2e5175..198e6ea 100644
--- a/content/common/cache_storage/cache_storage_types.cc
+++ b/content/common/cache_storage/cache_storage_types.cc
@@ -13,4 +13,7 @@
 CacheStorageBatchOperation::CacheStorageBatchOperation() {
 }
 
+CacheStorageBatchOperation::CacheStorageBatchOperation(
+    const CacheStorageBatchOperation& other) = default;
+
 }  // namespace content
diff --git a/content/common/cache_storage/cache_storage_types.h b/content/common/cache_storage/cache_storage_types.h
index 51f44b9e..22e91c0 100644
--- a/content/common/cache_storage/cache_storage_types.h
+++ b/content/common/cache_storage/cache_storage_types.h
@@ -39,6 +39,7 @@
 // A single batch operation for the Cache API.
 struct CONTENT_EXPORT CacheStorageBatchOperation {
   CacheStorageBatchOperation();
+  CacheStorageBatchOperation(const CacheStorageBatchOperation& other);
 
   CacheStorageCacheOperationType operation_type;
   ServiceWorkerFetchRequest request;
diff --git a/content/common/gpu/client/gl_helper_scaling.cc b/content/common/gpu/client/gl_helper_scaling.cc
index f4cd6b3..9df4f1a2 100644
--- a/content/common/gpu/client/gl_helper_scaling.cc
+++ b/content/common/gpu/client/gl_helper_scaling.cc
@@ -262,6 +262,8 @@
       vertically_flip_texture(vertically_flip_texture_),
       swizzle(swizzle_) {}
 
+GLHelperScaling::ScalerStage::ScalerStage(const ScalerStage& other) = default;
+
 // The important inputs for this function is |x_ops| and
 // |y_ops|. They represent scaling operations to be done
 // on an imag of size |src_size|. If |quality| is SCALER_QUALITY_BEST,
diff --git a/content/common/gpu/client/gl_helper_scaling.h b/content/common/gpu/client/gl_helper_scaling.h
index 6157d8e..511319a 100644
--- a/content/common/gpu/client/gl_helper_scaling.h
+++ b/content/common/gpu/client/gl_helper_scaling.h
@@ -151,6 +151,7 @@
                 bool scale_x_,
                 bool vertically_flip_texture_,
                 bool swizzle_);
+    ScalerStage(const ScalerStage& other);
     ShaderType shader;
     gfx::Size src_size;
     gfx::Rect src_subrect;
diff --git a/content/common/gpu/client/gpu_channel_host.cc b/content/common/gpu/client/gpu_channel_host.cc
index b0aeda39..6eae8ad 100644
--- a/content/common/gpu/client/gpu_channel_host.cc
+++ b/content/common/gpu/client/gpu_channel_host.cc
@@ -47,6 +47,9 @@
       flush_count(0),
       flush_id(0) {}
 
+GpuChannelHost::StreamFlushInfo::StreamFlushInfo(const StreamFlushInfo& other) =
+    default;
+
 GpuChannelHost::StreamFlushInfo::~StreamFlushInfo() {}
 
 // static
@@ -468,6 +471,9 @@
 
 GpuChannelHost::MessageFilter::ListenerInfo::ListenerInfo() {}
 
+GpuChannelHost::MessageFilter::ListenerInfo::ListenerInfo(
+    const ListenerInfo& other) = default;
+
 GpuChannelHost::MessageFilter::ListenerInfo::~ListenerInfo() {}
 
 GpuChannelHost::MessageFilter::MessageFilter()
diff --git a/content/common/gpu/client/gpu_channel_host.h b/content/common/gpu/client/gpu_channel_host.h
index c29f4a95..2a1f368 100644
--- a/content/common/gpu/client/gpu_channel_host.h
+++ b/content/common/gpu/client/gpu_channel_host.h
@@ -227,6 +227,7 @@
    private:
     struct ListenerInfo {
       ListenerInfo();
+      ListenerInfo(const ListenerInfo& other);
       ~ListenerInfo();
 
       base::WeakPtr<IPC::Listener> listener;
@@ -248,6 +249,7 @@
 
   struct StreamFlushInfo {
     StreamFlushInfo();
+    StreamFlushInfo(const StreamFlushInfo& other);
     ~StreamFlushInfo();
 
     // These are global per stream.
diff --git a/content/common/gpu/gpu_command_buffer_stub.cc b/content/common/gpu/gpu_command_buffer_stub.cc
index befbe55..5fd4726 100644
--- a/content/common/gpu/gpu_command_buffer_stub.cc
+++ b/content/common/gpu/gpu_command_buffer_stub.cc
@@ -161,19 +161,6 @@
       (static_cast<uint64_t>(channel_id) << 32) | route_id);
 }
 
-gfx::GLSurface::Format GetSurfaceFormatFromAttribute(
-    const gpu::gles2::ContextCreationAttribHelper& attrib,
-    bool use_virtualized_gl_context) {
-  gfx::GLSurface::Format format = gfx::GLSurface::SURFACE_DEFAULT;  // ARGB8888
-  if (!use_virtualized_gl_context &&
-      attrib.red_size <= 5 &&
-      attrib.green_size <= 6 &&
-      attrib.blue_size <= 5 &&
-      attrib.alpha_size == 0) {
-    format = gfx::GLSurface::SURFACE_RGB565;
-  }
-  return format;
-}
 }  // namespace
 
 GpuCommandBufferStub::GpuCommandBufferStub(
@@ -251,8 +238,17 @@
   // only a single context. See crbug.com/510243 for details.
   use_virtualized_gl_context_ |= mailbox_manager->UsesSync();
 
-  surface_format_ = GetSurfaceFormatFromAttribute(attrib_parser,
-                                                  use_virtualized_gl_context_);
+#if defined(OS_ANDROID)
+  if (attrib_parser.red_size <= 5 &&
+      attrib_parser.green_size <= 6 &&
+      attrib_parser.blue_size <= 5 &&
+      attrib_parser.alpha_size == 0)
+    surface_format_ = gfx::GLSurface::SURFACE_RGB565;
+  gfx::GLSurface* defaultOffscreenSurface =
+      channel_->gpu_channel_manager()->GetDefaultOffscreenSurface();
+  if (surface_format_ != defaultOffscreenSurface->GetFormat())
+    use_virtualized_gl_context_ = false;
+#endif
 
   if (offscreen && initial_size_.IsEmpty()) {
     // If we're an offscreen surface with zero width and/or height, set to a
@@ -562,8 +558,9 @@
   }
 
   scoped_refptr<gfx::GLContext> context;
-  if (use_virtualized_gl_context_ && channel_->share_group()) {
-    context = channel_->share_group()->GetSharedContext();
+  gfx::GLShareGroup* share_group = channel_->share_group();
+  if (use_virtualized_gl_context_ && share_group) {
+    context = share_group->GetSharedContext();
     if (!context.get()) {
       context = gfx::GLContext::CreateGLContext(
           channel_->share_group(),
@@ -579,12 +576,10 @@
     // This should be a non-virtual GL context.
     DCHECK(context->GetHandle());
     context = new gpu::GLContextVirtual(
-        channel_->share_group(), context.get(), decoder_->AsWeakPtr());
+        share_group, context.get(), decoder_->AsWeakPtr());
     if (!context->Initialize(surface_.get(), gpu_preference_)) {
-      // TODO(sievers): The real context created above for the default
-      // offscreen surface might not be compatible with this surface.
-      // Need to adjust at least GLX to be able to create the initial context
-      // with a config that is compatible with onscreen and offscreen surfaces.
+      // The real context created above for the default offscreen surface
+      // might not be compatible with this surface.
       context = NULL;
 
       DLOG(ERROR) << "Failed to initialize virtual GL context.";
@@ -594,7 +589,7 @@
   }
   if (!context.get()) {
     context = gfx::GLContext::CreateGLContext(
-        channel_->share_group(), surface_.get(), gpu_preference_);
+        share_group, surface_.get(), gpu_preference_);
   }
   if (!context.get()) {
     DLOG(ERROR) << "Failed to create context.";
diff --git a/content/common/gpu/image_transport_surface_mac.mm b/content/common/gpu/image_transport_surface_mac.mm
index 9bffc3b2..330d134 100644
--- a/content/common/gpu/image_transport_surface_mac.mm
+++ b/content/common/gpu/image_transport_surface_mac.mm
@@ -26,7 +26,7 @@
  public:
   // Size doesn't matter, the surface is resized to the right size later.
   DRTSurfaceOSMesa()
-      : GLSurfaceOSMesa(gfx::OSMesaSurfaceFormatRGBA, gfx::Size(1, 1)) {}
+      : GLSurfaceOSMesa(gfx::GLSurface::SURFACE_OSMESA_RGBA, gfx::Size(1, 1)) {}
 
   // Implement a subset of GLSurface.
   gfx::SwapResult SwapBuffers() override;
diff --git a/content/common/gpu/media/android_deferred_rendering_backing_strategy.cc b/content/common/gpu/media/android_deferred_rendering_backing_strategy.cc
index a76c98d..7ef2e77f 100644
--- a/content/common/gpu/media/android_deferred_rendering_backing_strategy.cc
+++ b/content/common/gpu/media/android_deferred_rendering_backing_strategy.cc
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
 #include "content/common/gpu/media/android_deferred_rendering_backing_strategy.h"
 
 #include "base/bind.h"
@@ -13,12 +16,27 @@
 #include "content/common/gpu/media/avda_codec_image.h"
 #include "content/common/gpu/media/avda_return_on_failure.h"
 #include "content/common/gpu/media/avda_shared_state.h"
+#include "gpu/command_buffer/service/gl_stream_texture_image.h"
+#include "gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h"
 #include "gpu/command_buffer/service/texture_manager.h"
 #include "ui/gl/android/surface_texture.h"
+#include "ui/gl/egl_util.h"
 #include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_surface_egl.h"
+#include "ui/gl/scoped_binders.h"
+#include "ui/gl/scoped_make_current.h"
 
 namespace content {
 
+namespace {
+// clang-format off
+const float kIdentityMatrix[16] = {1.0f, 0.0f, 0.0f, 0.0f,
+                                   0.0f, 1.0f, 0.0f, 0.0f,
+                                   0.0f, 0.0f, 1.0f, 0.0f,
+                                   0.0f, 0.0f, 0.0f, 1.0f};
+// clang-format on
+}
+
 AndroidDeferredRenderingBackingStrategy::
     AndroidDeferredRenderingBackingStrategy(AVDAStateProvider* state_provider)
     : state_provider_(state_provider), media_codec_(nullptr) {}
@@ -64,6 +82,11 @@
   for (const std::pair<int, media::PictureBuffer>& entry : buffers)
     SetImageForPicture(entry.second, nullptr);
 
+  // If we're rendering to a SurfaceTexture we can make a copy of the current
+  // front buffer so that the PictureBuffer textures are still valid.
+  if (surface_texture_)
+    CopySurfaceTextureToPictures(buffers);
+
   // Now that no AVDACodecImages refer to the SurfaceTexture's texture, delete
   // the texture name.
   GLuint service_id = shared_state_->surface_texture_service_id();
@@ -105,7 +128,7 @@
 
 void AndroidDeferredRenderingBackingStrategy::SetImageForPicture(
     const media::PictureBuffer& picture_buffer,
-    const scoped_refptr<gl::GLImage>& image) {
+    const scoped_refptr<gpu::gles2::GLStreamTextureImage>& image) {
   gpu::gles2::TextureRef* texture_ref = GetTextureForPicture(picture_buffer);
   RETURN_IF_NULL(texture_ref);
 
@@ -145,8 +168,8 @@
   const gpu::gles2::Texture::ImageState image_state =
       surface_texture_ ? gpu::gles2::Texture::UNBOUND
                        : gpu::gles2::Texture::BOUND;
-  texture_manager->SetLevelImage(texture_ref, GetTextureTarget(), 0,
-                                 image.get(), image_state);
+  texture_manager->SetLevelStreamTextureImage(texture_ref, GetTextureTarget(),
+                                              0, image.get(), image_state);
 }
 
 void AndroidDeferredRenderingBackingStrategy::UseCodecBufferForPictureBuffer(
@@ -170,7 +193,7 @@
     const media::PictureBuffer& picture_buffer) {
   // Attach a GLImage to each texture that will use the surface texture.
   // We use a refptr here in case SetImageForPicture fails.
-  scoped_refptr<gl::GLImage> gl_image =
+  scoped_refptr<gpu::gles2::GLStreamTextureImage> gl_image =
       new AVDACodecImage(shared_state_, media_codec_,
                          state_provider_->GetGlDecoder(), surface_texture_);
   SetImageForPicture(picture_buffer, gl_image);
@@ -234,4 +257,82 @@
   return !surface_texture_;
 }
 
+void AndroidDeferredRenderingBackingStrategy::CopySurfaceTextureToPictures(
+    const AndroidVideoDecodeAccelerator::OutputBufferMap& buffers) {
+  DVLOG(3) << __FUNCTION__;
+
+  // Don't try to copy if the SurfaceTexture was never attached because that
+  // means it was never updated.
+  if (!shared_state_->surface_texture_is_attached())
+    return;
+
+  gpu::gles2::GLES2Decoder* gl_decoder = state_provider_->GetGlDecoder().get();
+  if (!gl_decoder)
+    return;
+
+  scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
+  if (!shared_state_->context()->IsCurrent(NULL)) {
+    scoped_make_current.reset(new ui::ScopedMakeCurrent(
+        shared_state_->context(), shared_state_->surface()));
+    if (!scoped_make_current->Succeeded())
+      return;
+  }
+
+  const gfx::Size size = state_provider_->GetSize();
+
+  // Create a 2D texture to hold a copy of the SurfaceTexture's front buffer.
+  GLuint tmp_texture_id;
+  glGenTextures(1, &tmp_texture_id);
+  {
+    gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, tmp_texture_id);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0,
+                 GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+  }
+
+  // TODO(liberato,watk): Use the SurfaceTexture matrix when copying.
+  gpu::CopyTextureCHROMIUMResourceManager copier;
+  copier.Initialize(
+      gl_decoder,
+      gl_decoder->GetContextGroup()->feature_info()->feature_flags());
+  copier.DoCopyTextureWithTransform(gl_decoder, GL_TEXTURE_EXTERNAL_OES,
+                                    shared_state_->surface_texture_service_id(),
+                                    GL_TEXTURE_2D, tmp_texture_id, size.width(),
+                                    size.height(), false, false, false,
+                                    kIdentityMatrix);
+
+  // Create an EGLImage from the 2D texture we just copied into. By associating
+  // the EGLImage with the PictureBuffer textures they will remain valid even
+  // after we delete the 2D texture and EGLImage.
+  const EGLImageKHR egl_image = eglCreateImageKHR(
+      gfx::GLSurfaceEGL::GetHardwareDisplay(), eglGetCurrentContext(),
+      EGL_GL_TEXTURE_2D_KHR, reinterpret_cast<EGLClientBuffer>(tmp_texture_id),
+      nullptr /* attrs */);
+
+  glDeleteTextures(1, &tmp_texture_id);
+  DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+
+  if (egl_image == EGL_NO_IMAGE_KHR) {
+    DLOG(ERROR) << "Failed creating EGLImage: " << ui::GetLastEGLErrorString();
+    return;
+  }
+
+  for (const std::pair<int, media::PictureBuffer>& entry : buffers) {
+    gpu::gles2::TextureRef* texture_ref = GetTextureForPicture(entry.second);
+    gfx::ScopedTextureBinder texture_binder(
+        GL_TEXTURE_EXTERNAL_OES, texture_ref->texture()->service_id());
+    glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_image);
+    DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+  }
+
+  EGLBoolean result =
+      eglDestroyImageKHR(gfx::GLSurfaceEGL::GetHardwareDisplay(), egl_image);
+  if (result == EGL_FALSE) {
+    DLOG(ERROR) << "Error destroying EGLImage: "
+                << ui::GetLastEGLErrorString();
+  }
+}
+
 }  // namespace content
diff --git a/content/common/gpu/media/android_deferred_rendering_backing_strategy.h b/content/common/gpu/media/android_deferred_rendering_backing_strategy.h
index 4b8bd6d..1cb8bd0 100644
--- a/content/common/gpu/media/android_deferred_rendering_backing_strategy.h
+++ b/content/common/gpu/media/android_deferred_rendering_backing_strategy.h
@@ -17,6 +17,7 @@
 
 namespace gpu {
 namespace gles2 {
+class GLStreamTextureImage;
 class TextureRef;
 }
 }
@@ -64,8 +65,16 @@
 
   // Return the AVDACodecImage for a given PictureBuffer's texture.
   AVDACodecImage* GetImageForPicture(const media::PictureBuffer&);
-  void SetImageForPicture(const media::PictureBuffer& picture_buffer,
-                          const scoped_refptr<gl::GLImage>& image);
+  void SetImageForPicture(
+      const media::PictureBuffer& picture_buffer,
+      const scoped_refptr<gpu::gles2::GLStreamTextureImage>& image);
+
+  // Make a copy of the SurfaceTexture's front buffer and associate all given
+  // picture buffer textures with it. The picture buffer textures will not
+  // dependend on |this|, the SurfaceTexture, the MediaCodec or the VDA, so it's
+  // used to back the picture buffers when the VDA is being destroyed.
+  void CopySurfaceTextureToPictures(
+      const AndroidVideoDecodeAccelerator::OutputBufferMap& buffers);
 
   scoped_refptr<AVDASharedState> shared_state_;
 
diff --git a/content/common/gpu/media/android_video_decode_accelerator.cc b/content/common/gpu/media/android_video_decode_accelerator.cc
index 5e94328b..7deb6f3 100644
--- a/content/common/gpu/media/android_video_decode_accelerator.cc
+++ b/content/common/gpu/media/android_video_decode_accelerator.cc
@@ -708,14 +708,28 @@
 void AndroidVideoDecodeAccelerator::Decode(
     const media::BitstreamBuffer& bitstream_buffer) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  if (bitstream_buffer.id() != -1 && bitstream_buffer.size() == 0) {
+
+  if (bitstream_buffer.id() >= 0 && bitstream_buffer.size() > 0) {
+    DecodeBuffer(bitstream_buffer);
+    return;
+  }
+
+  if (base::SharedMemory::IsHandleValid(bitstream_buffer.handle()))
+    base::SharedMemory::CloseHandle(bitstream_buffer.handle());
+
+  if (bitstream_buffer.id() < 0) {
+    POST_ERROR(INVALID_ARGUMENT,
+               "Invalid bistream_buffer, id: " << bitstream_buffer.id());
+  } else {
     base::MessageLoop::current()->PostTask(
         FROM_HERE,
         base::Bind(&AndroidVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer,
                    weak_this_factory_.GetWeakPtr(), bitstream_buffer.id()));
-    return;
   }
+}
 
+void AndroidVideoDecodeAccelerator::DecodeBuffer(
+    const media::BitstreamBuffer& bitstream_buffer) {
   pending_bitstream_buffers_.push(
       std::make_pair(bitstream_buffer, base::Time::Now()));
   TRACE_COUNTER1("media", "AVDA::PendingBitstreamBufferCount",
@@ -793,7 +807,7 @@
 void AndroidVideoDecodeAccelerator::Flush() {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  Decode(media::BitstreamBuffer(-1, base::SharedMemoryHandle(), 0));
+  DecodeBuffer(media::BitstreamBuffer(-1, base::SharedMemoryHandle(), 0));
 }
 
 bool AndroidVideoDecodeAccelerator::ConfigureMediaCodec() {
@@ -809,7 +823,7 @@
   // when it's known from the bitstream.
   media_codec_.reset(media::VideoCodecBridge::CreateDecoder(
       codec_, needs_protected_surface_, gfx::Size(320, 240),
-      surface_.j_surface().obj(), media_crypto));
+      surface_.j_surface().obj(), media_crypto, false));
 
   strategy_->CodecChanged(media_codec_.get(), output_picture_buffers_);
   if (!media_codec_) {
diff --git a/content/common/gpu/media/android_video_decode_accelerator.h b/content/common/gpu/media/android_video_decode_accelerator.h
index 83da713..ab2c4da 100644
--- a/content/common/gpu/media/android_video_decode_accelerator.h
+++ b/content/common/gpu/media/android_video_decode_accelerator.h
@@ -167,6 +167,10 @@
   // Requests picture buffers from the client.
   void RequestPictureBuffers();
 
+  // Decode the content in the |bitstream_buffer|. Note that a
+  // |bitstream_buffer| of id as -1 indicates a flush command.
+  void DecodeBuffer(const media::BitstreamBuffer& bitstream_buffer);
+
   // This callback is called after CDM obtained a MediaCrypto object.
   void OnMediaCryptoReady(media::MediaDrmBridge::JavaObjectPtr media_crypto,
                           bool needs_protected_surface);
diff --git a/content/common/gpu/media/avda_codec_image.cc b/content/common/gpu/media/avda_codec_image.cc
index 6b0fa8a6..e0a0cb59 100644
--- a/content/common/gpu/media/avda_codec_image.cc
+++ b/content/common/gpu/media/avda_codec_image.cc
@@ -29,11 +29,12 @@
       decoder_(decoder),
       surface_texture_(surface_texture),
       detach_surface_texture_on_destruction_(false),
-      texture_(0),
-      need_shader_info_(true),
-      texmatrix_uniform_location_(-1) {
+      texture_(0) {
+  // Default to a sane guess of "flip Y", just in case we can't get
+  // the matrix on the first call.
   memset(gl_matrix_, 0, sizeof(gl_matrix_));
-  gl_matrix_[0] = gl_matrix_[5] = gl_matrix_[10] = gl_matrix_[15] = 1.0f;
+  gl_matrix_[0] = gl_matrix_[10] = gl_matrix_[15] = 1.0f;
+  gl_matrix_[5] = -1.0f;
 }
 
 AVDACodecImage::~AVDACodecImage() {}
@@ -61,35 +62,29 @@
   if (target != GL_TEXTURE_EXTERNAL_OES)
     return false;
 
-  // Verify that the currently bound texture is the right one.  If we're not
-  // copying to a Texture that shares our service_id, then we can't do much.
-  // This will force a copy.
-  // TODO(liberato): Fall back to a copy that uses the texture matrix.
   GLint bound_service_id = 0;
   glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &bound_service_id);
+  // We insist that the currently bound texture is the right one.  We could
+  // make a new glimage from a 2D image.
   if (bound_service_id != shared_state_->surface_texture_service_id())
     return false;
 
-  // Attach the surface texture to our GL context if needed.
+  // If the surface texture isn't attached yet, then attach it.  Note that this
+  // will be to the texture in |shared_state_|, because of the checks above.
   if (!shared_state_->surface_texture_is_attached())
     AttachSurfaceTextureToContext();
 
-  // Make sure that we have the right image in the front buffer.
-  UpdateSurfaceTexture();
-
-  InstallTextureMatrix();
-
-  // TODO(liberato): Handle the texture matrix properly.
-  // Either we can update the shader with it or we can move all of the logic
-  // to updateTexImage() to the right place in the cc to send it to the shader.
-  // For now, we just skip it.  crbug.com/530681
+  // Make sure that we have the right image in the front buffer.  Note that the
+  // bound_service_id is guaranteed to be equal to the surface texture's client
+  // texture id, so we can skip preserving it if the right context is current.
+  UpdateSurfaceTexture(kDontRestoreBindings);
 
   // By setting image state to UNBOUND instead of COPIED we ensure that
   // CopyTexImage() is called each time the surface texture is used for drawing.
   // It would be nice if we could do this via asking for the currently bound
   // Texture, but the active unit never seems to change.
-  texture_->SetLevelImage(GL_TEXTURE_EXTERNAL_OES, 0, this,
-                          gpu::gles2::Texture::UNBOUND);
+  texture_->SetLevelStreamTextureImage(GL_TEXTURE_EXTERNAL_OES, 0, this,
+                                       gpu::gles2::Texture::UNBOUND);
 
   return true;
 }
@@ -123,11 +118,11 @@
                                   uint64_t process_tracing_id,
                                   const std::string& dump_name) {}
 
-void AVDACodecImage::UpdateSurfaceTexture() {
+void AVDACodecImage::UpdateSurfaceTexture(RestoreBindingsMode mode) {
   DCHECK(surface_texture_);
 
   // Render via the media codec if needed.
-  if (codec_buffer_index_ == kInvalidCodecBufferIndex || !media_codec_)
+  if (!IsCodecBufferOutstanding())
     return;
 
   // The decoder buffer is still pending.
@@ -142,12 +137,21 @@
   codec_buffer_index_ = kInvalidCodecBufferIndex;
 
   // Swap the rendered image to the front.
-  scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
-  if (!shared_state_->context()->IsCurrent(NULL)) {
-    scoped_make_current.reset(new ui::ScopedMakeCurrent(
-        shared_state_->context(), shared_state_->surface()));
-  }
+  scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current = MakeCurrentIfNeeded();
+
+  // If we changed contexts, then we always want to restore it, since the caller
+  // doesn't know that we're switching contexts.
+  if (scoped_make_current)
+    mode = kDoRestoreBindings;
+
+  // Save the current binding if requested.
+  GLint bound_service_id = 0;
+  if (mode == kDoRestoreBindings)
+    glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &bound_service_id);
+
   surface_texture_->UpdateTexImage();
+  if (mode == kDoRestoreBindings)
+    glBindTexture(GL_TEXTURE_EXTERNAL_OES, bound_service_id);
 
   // Helpfully, this is already column major.
   surface_texture_->GetTransformMatrix(gl_matrix_);
@@ -176,6 +180,8 @@
 void AVDACodecImage::AttachSurfaceTextureToContext() {
   DCHECK(surface_texture_);
 
+  // We assume that the currently bound texture is the intended one.
+
   // Attach the surface texture to the first context we're bound on, so that
   // no context switch is needed later.
   glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@@ -187,38 +193,48 @@
   // We could do this earlier, but SurfaceTexture has context affinity, and we
   // don't want to require a context switch.
   surface_texture_->AttachToGLContext();
-  shared_state_->did_attach_surface_texture();
+  shared_state_->DidAttachSurfaceTexture();
 }
 
-void AVDACodecImage::InstallTextureMatrix() {
-  DCHECK(surface_texture_);
+scoped_ptr<ui::ScopedMakeCurrent> AVDACodecImage::MakeCurrentIfNeeded() {
+  DCHECK(shared_state_->context());
+  scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
+  if (!shared_state_->context()->IsCurrent(NULL)) {
+    scoped_make_current.reset(new ui::ScopedMakeCurrent(
+        shared_state_->context(), shared_state_->surface()));
+  }
 
-  // glUseProgram() has been run already -- just modify the uniform.
-  // Updating this via VideoFrameProvider::Client::DidUpdateMatrix() would
-  // be a better solution, except that we'd definitely miss a frame at this
-  // point in drawing.
-  // Our current method assumes that we'll end up being a stream resource,
-  // and that the program has a texMatrix uniform that does what we want.
-  if (need_shader_info_) {
-    GLint program_id = -1;
-    glGetIntegerv(GL_CURRENT_PROGRAM, &program_id);
+  return scoped_make_current;
+}
 
-    if (program_id >= 0) {
-      // This is memorized from cc/output/shader.cc .
-      const char* uniformName = "texMatrix";
-
-      // Within unittests this value may be -1.
-      texmatrix_uniform_location_ =
-          glGetUniformLocation(program_id, uniformName);
+void AVDACodecImage::GetTextureMatrix(float matrix[16]) {
+  if (IsCodecBufferOutstanding() && shared_state_ && surface_texture_) {
+    // Our current matrix may be stale.  Update it if possible.
+    if (!shared_state_->surface_texture_is_attached()) {
+      // Don't attach the surface texture permanently.  Perhaps we should
+      // just attach the surface texture in avda and be done with it.
+      GLuint service_id = 0;
+      glGenTextures(1, &service_id);
+      GLint bound_service_id = 0;
+      glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &bound_service_id);
+      glBindTexture(GL_TEXTURE_EXTERNAL_OES, service_id);
+      AttachSurfaceTextureToContext();
+      UpdateSurfaceTexture(kDontRestoreBindings);
+      // Detach the surface texture, which deletes the generated texture.
+      surface_texture_->DetachFromGLContext();
+      shared_state_->DidDetachSurfaceTexture();
+      glBindTexture(GL_TEXTURE_EXTERNAL_OES, bound_service_id);
+    } else {
+      // Surface texture is already attached, so just update it.
+      UpdateSurfaceTexture(kDoRestoreBindings);
     }
-
-    // Only try once.
-    need_shader_info_ = false;
   }
 
-  if (texmatrix_uniform_location_ >= 0) {
-    glUniformMatrix4fv(texmatrix_uniform_location_, 1, false, gl_matrix_);
-  }
+  memcpy(matrix, gl_matrix_, sizeof(gl_matrix_));
+}
+
+bool AVDACodecImage::IsCodecBufferOutstanding() const {
+  return codec_buffer_index_ != kInvalidCodecBufferIndex && media_codec_;
 }
 
 }  // namespace content
diff --git a/content/common/gpu/media/avda_codec_image.h b/content/common/gpu/media/avda_codec_image.h
index 8bbcf13d..46547e4 100644
--- a/content/common/gpu/media/avda_codec_image.h
+++ b/content/common/gpu/media/avda_codec_image.h
@@ -9,13 +9,17 @@
 
 #include "base/macros.h"
 #include "content/common/gpu/media/avda_shared_state.h"
-#include "ui/gl/gl_image.h"
+#include "gpu/command_buffer/service/gl_stream_texture_image.h"
+
+namespace ui {
+class ScopedMakeCurrent;
+}
 
 namespace content {
 
 // GLImage that renders MediaCodec buffers to a SurfaceTexture or SurfaceView as
 // needed in order to draw them.
-class AVDACodecImage : public gl::GLImage {
+class AVDACodecImage : public gpu::gles2::GLStreamTextureImage {
  public:
   AVDACodecImage(const scoped_refptr<AVDASharedState>&,
                  media::VideoCodecBridge* codec,
@@ -44,6 +48,8 @@
   void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
                     uint64_t process_tracing_id,
                     const std::string& dump_name) override;
+  // gpu::gles2::GLStreamTextureMatrix implementation
+  void GetTextureMatrix(float xform[16]) override;
 
  public:
   // Decoded buffer index that has the image for us to display.
@@ -63,15 +69,31 @@
  private:
   enum { kInvalidCodecBufferIndex = -1 };
 
-  // Make sure that the surface texture's front buffer is current.
-  void UpdateSurfaceTexture();
+  // Make sure that the surface texture's front buffer is current.  This will
+  // save / restore the current context.  It will optionally restore the texture
+  // bindings in the surface texture's context, based on |mode|.  This is
+  // intended as a hint if we don't need to change contexts.  If we do need to
+  // change contexts, then we'll always preserve the texture bindings in the
+  // both contexts.  In other words, the caller is telling us whether it's
+  // okay to change the binding in the current context.
+  enum RestoreBindingsMode { kDontRestoreBindings, kDoRestoreBindings };
+  void UpdateSurfaceTexture(RestoreBindingsMode mode);
 
-  // Attach the surface texture to our GL context, with a texture that we
-  // create for it.
+  // Attach the surface texture to our GL context to whatever texture is bound
+  // on the active unit.
   void AttachSurfaceTextureToContext();
 
-  // Install the current texture matrix into the shader.
-  void InstallTextureMatrix();
+  // Make shared_state_->context() current if it isn't already.
+  scoped_ptr<ui::ScopedMakeCurrent> MakeCurrentIfNeeded();
+
+  // Return whether or not the current context is in the same share group as
+  // |surface_texture_|'s client texture.
+  // TODO(liberato): is this needed?
+  bool IsCorrectShareGroup() const;
+
+  // Return whether there is a codec buffer that we haven't rendered yet.  Will
+  // return false also if there's no codec or we otherwise can't update.
+  bool IsCodecBufferOutstanding() const;
 
   // Shared state between the AVDA and all AVDACodecImages.
   scoped_refptr<AVDASharedState> shared_state_;
@@ -99,12 +121,6 @@
   // The texture that we're attached to.
   gpu::gles2::Texture* texture_;
 
-  // Have we cached |texmatrix_uniform_location_| yet?
-  bool need_shader_info_;
-
-  // Uniform ID of the texture matrix in the shader.
-  GLint texmatrix_uniform_location_;
-
   // Texture matrix of the front buffer of the surface texture.
   float gl_matrix_[16];
 
diff --git a/content/common/gpu/media/avda_shared_state.cc b/content/common/gpu/media/avda_shared_state.cc
index c182bf0..7746254 100644
--- a/content/common/gpu/media/avda_shared_state.cc
+++ b/content/common/gpu/media/avda_shared_state.cc
@@ -4,6 +4,7 @@
 
 #include "content/common/gpu/media/avda_shared_state.h"
 
+#include "base/time/time.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/scoped_make_current.h"
 
@@ -21,10 +22,13 @@
 }
 
 void AVDASharedState::WaitForFrameAvailable() {
-  frame_available_event_.Wait();
+  // 10msec covers >99.9% of cases, so just wait for up to that much before
+  // giving up.  If an error occurs, we might not ever get a notification.
+  const base::TimeDelta max_wait_time(base::TimeDelta::FromMilliseconds(10));
+  frame_available_event_.TimedWait(max_wait_time);
 }
 
-void AVDASharedState::did_attach_surface_texture() {
+void AVDASharedState::DidAttachSurfaceTexture() {
   context_ = gfx::GLContext::GetCurrent();
   surface_ = gfx::GLSurface::GetCurrent();
   DCHECK(context_);
@@ -33,4 +37,10 @@
   surface_texture_is_attached_ = true;
 }
 
+void AVDASharedState::DidDetachSurfaceTexture() {
+  context_ = nullptr;
+  surface_ = nullptr;
+  surface_texture_is_attached_ = false;
+}
+
 }  // namespace content
diff --git a/content/common/gpu/media/avda_shared_state.h b/content/common/gpu/media/avda_shared_state.h
index eb62681f..5f80c44 100644
--- a/content/common/gpu/media/avda_shared_state.h
+++ b/content/common/gpu/media/avda_shared_state.h
@@ -50,10 +50,19 @@
     return surface_texture_is_attached_;
   }
 
+  // TODO(liberato): move the surface texture here and make these calls
+  // attach / detach it also.  There are several changes going on in avda
+  // concurrently, so I don't want to change that until the dust settles.
+  // AVDACodecImage would no longer hold the surface texture.
+
   // Call this when the SurfaceTexture is attached to a GL context.  This will
   // update surface_texture_is_attached(), and set the context() and surface()
   // to match.
-  void did_attach_surface_texture();
+  void DidAttachSurfaceTexture();
+
+  // Call this when the SurfaceTexture is detached from its GL context.  This
+  // will cause us to forget the last binding.
+  void DidDetachSurfaceTexture();
 
  private:
   // Platform gl texture Id for |surface_texture_|.  This will be zero if
diff --git a/content/common/gpu/media/dxva_video_decode_accelerator_win.cc b/content/common/gpu/media/dxva_video_decode_accelerator_win.cc
index e01c114..cb1841b 100644
--- a/content/common/gpu/media/dxva_video_decode_accelerator_win.cc
+++ b/content/common/gpu/media/dxva_video_decode_accelerator_win.cc
@@ -246,21 +246,6 @@
   return sample.Detach();
 }
 
-static IMFSample* CreateSampleFromInputBuffer(
-    const media::BitstreamBuffer& bitstream_buffer,
-    uint32_t stream_size,
-    DWORD alignment) {
-  base::SharedMemory shm(bitstream_buffer.handle(), true);
-  RETURN_ON_FAILURE(shm.Map(bitstream_buffer.size()),
-                    "Failed in base::SharedMemory::Map", NULL);
-
-  return CreateInputSample(reinterpret_cast<const uint8_t*>(shm.memory()),
-                           bitstream_buffer.size(),
-                           std::min<uint32_t>(bitstream_buffer.size(),
-                                              stream_size),
-                           alignment);
-}
-
 // Helper function to create a COM object instance from a DLL. The alternative
 // is to use the CoCreateInstance API which requires the COM apartment to be
 // initialized which is not the case on the GPU main thread. We want to avoid
@@ -942,15 +927,28 @@
     const media::BitstreamBuffer& bitstream_buffer) {
   DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
 
+  // SharedMemory will take over the ownership of handle.
+  base::SharedMemory shm(bitstream_buffer.handle(), true);
+
   State state = GetState();
   RETURN_AND_NOTIFY_ON_FAILURE((state == kNormal || state == kStopped ||
                                 state == kFlushing),
            "Invalid state: " << state, ILLEGAL_STATE,);
+  if (bitstream_buffer.id() < 0) {
+    RETURN_AND_NOTIFY_ON_FAILURE(
+        false, "Invalid bitstream_buffer, id: " << bitstream_buffer.id(),
+        INVALID_ARGUMENT, );
+  }
 
   base::win::ScopedComPtr<IMFSample> sample;
-  sample.Attach(CreateSampleFromInputBuffer(bitstream_buffer,
-                                            input_stream_info_.cbSize,
-                                            input_stream_info_.cbAlignment));
+  RETURN_AND_NOTIFY_ON_FAILURE(shm.Map(bitstream_buffer.size()),
+                               "Failed in base::SharedMemory::Map",
+                               PLATFORM_FAILURE, );
+
+  sample.Attach(CreateInputSample(
+      reinterpret_cast<const uint8_t*>(shm.memory()), bitstream_buffer.size(),
+      std::min<uint32_t>(bitstream_buffer.size(), input_stream_info_.cbSize),
+      input_stream_info_.cbAlignment));
   RETURN_AND_NOTIFY_ON_FAILURE(sample.get(), "Failed to create input sample",
                                PLATFORM_FAILURE, );
 
@@ -1167,17 +1165,17 @@
                       "msmpeg2vdec.dll required for decoding is not loaded",
                       false);
 
-    // Check version of DLL, version 6.7.7140 is blacklisted due to high crash
+    // Check version of DLL, version 6.1.7140 is blacklisted due to high crash
     // rates in browsers loading that DLL. If that is the version installed we
     // fall back to software decoding. See crbug/403440.
-    FileVersionInfo* version_info =
-        FileVersionInfo::CreateFileVersionInfoForModule(decoder_dll);
+    scoped_ptr<FileVersionInfo> version_info(
+        FileVersionInfo::CreateFileVersionInfoForModule(decoder_dll));
     RETURN_ON_FAILURE(version_info,
                       "unable to get version of msmpeg2vdec.dll",
                       false);
     base::string16 file_version = version_info->file_version();
     RETURN_ON_FAILURE(file_version.find(L"6.1.7140") == base::string16::npos,
-                      "blacklisted version of msmpeg2vdec.dll 6.7.7140",
+                      "blacklisted version of msmpeg2vdec.dll 6.1.7140",
                       false);
     codec_ = media::kCodecH264;
     clsid = __uuidof(CMSH264DecoderMFT);
diff --git a/content/common/gpu/media/fake_video_decode_accelerator.cc b/content/common/gpu/media/fake_video_decode_accelerator.cc
index 7524dd1..230c4f34 100644
--- a/content/common/gpu/media/fake_video_decode_accelerator.cc
+++ b/content/common/gpu/media/fake_video_decode_accelerator.cc
@@ -67,6 +67,16 @@
 
 void FakeVideoDecodeAccelerator::Decode(
     const media::BitstreamBuffer& bitstream_buffer) {
+  // We won't really read from the bitstream_buffer, close the handle.
+  if (base::SharedMemory::IsHandleValid(bitstream_buffer.handle()))
+    base::SharedMemory::CloseHandle(bitstream_buffer.handle());
+
+  if (bitstream_buffer.id() < 0) {
+    LOG(ERROR) << "Invalid bitstream: id=" << bitstream_buffer.id();
+    client_->NotifyError(INVALID_ARGUMENT);
+    return;
+  }
+
   int bitstream_buffer_id = bitstream_buffer.id();
   queued_bitstream_ids_.push(bitstream_buffer_id);
   child_task_runner_->PostTask(
diff --git a/content/common/gpu/media/gpu_jpeg_decode_accelerator.cc b/content/common/gpu/media/gpu_jpeg_decode_accelerator.cc
index 4b7b00c..ba0bd94d 100644
--- a/content/common/gpu/media/gpu_jpeg_decode_accelerator.cc
+++ b/content/common/gpu/media/gpu_jpeg_decode_accelerator.cc
@@ -41,12 +41,6 @@
 }
 
 bool VerifyDecodeParams(const AcceleratedJpegDecoderMsg_Decode_Params& params) {
-  if (params.input_buffer_id < 0) {
-    LOG(ERROR) << "BitstreamBuffer id " << params.input_buffer_id
-               << " out of range";
-    return false;
-  }
-
   const int kJpegMaxDimension = UINT16_MAX;
   if (params.coded_size.IsEmpty() ||
       params.coded_size.width() > kJpegMaxDimension ||
@@ -55,11 +49,6 @@
     return false;
   }
 
-  if (!base::SharedMemory::IsHandleValid(params.input_buffer_handle)) {
-    LOG(ERROR) << "invalid input_buffer_handle";
-    return false;
-  }
-
   if (!base::SharedMemory::IsHandleValid(params.output_video_frame_handle)) {
     LOG(ERROR) << "invalid output_video_frame_handle";
     return false;
diff --git a/content/common/gpu/media/gpu_video_decode_accelerator.cc b/content/common/gpu/media/gpu_video_decode_accelerator.cc
index 690b0f0..1ec0e5a 100644
--- a/content/common/gpu/media/gpu_video_decode_accelerator.cc
+++ b/content/common/gpu/media/gpu_video_decode_accelerator.cc
@@ -494,21 +494,6 @@
 void GpuVideoDecodeAccelerator::OnDecode(
     const AcceleratedVideoDecoderMsg_Decode_Params& params) {
   DCHECK(video_decode_accelerator_);
-  if (params.bitstream_buffer_id < 0) {
-    DLOG(ERROR) << "BitstreamBuffer id " << params.bitstream_buffer_id
-                << " out of range";
-    if (child_task_runner_->BelongsToCurrentThread()) {
-      NotifyError(media::VideoDecodeAccelerator::INVALID_ARGUMENT);
-    } else {
-      child_task_runner_->PostTask(
-          FROM_HERE,
-          base::Bind(&GpuVideoDecodeAccelerator::NotifyError,
-                     base::Unretained(this),
-                     media::VideoDecodeAccelerator::INVALID_ARGUMENT));
-    }
-    return;
-  }
-
   media::BitstreamBuffer bitstream_buffer(params.bitstream_buffer_id,
                                           params.buffer_handle, params.size,
                                           params.presentation_timestamp);
diff --git a/content/common/gpu/media/v4l2_jpeg_decode_accelerator.cc b/content/common/gpu/media/v4l2_jpeg_decode_accelerator.cc
index 06091a3..7f6e9ba 100644
--- a/content/common/gpu/media/v4l2_jpeg_decode_accelerator.cc
+++ b/content/common/gpu/media/v4l2_jpeg_decode_accelerator.cc
@@ -233,6 +233,14 @@
            << ", size=" << bitstream_buffer.size();
   DCHECK(io_task_runner_->BelongsToCurrentThread());
 
+  if (bitstream_buffer.id() < 0) {
+    LOG(ERROR) << "Invalid bitstream_buffer, id: " << bitstream_buffer.id();
+    if (base::SharedMemory::IsHandleValid(bitstream_buffer.handle()))
+      base::SharedMemory::CloseHandle(bitstream_buffer.handle());
+    PostNotifyError(bitstream_buffer.id(), INVALID_ARGUMENT);
+    return;
+  }
+
   if (video_frame->format() != media::PIXEL_FORMAT_I420) {
     PostNotifyError(bitstream_buffer.id(), UNSUPPORTED_JPEG);
     return;
diff --git a/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc b/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc
index fb246db..f48fc93 100644
--- a/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc
+++ b/content/common/gpu/media/v4l2_slice_video_decode_accelerator.cc
@@ -1190,6 +1190,14 @@
             << ", size=" << bitstream_buffer.size();
   DCHECK(io_task_runner_->BelongsToCurrentThread());
 
+  if (bitstream_buffer.id() < 0) {
+    LOG(ERROR) << "Invalid bitstream_buffer, id: " << bitstream_buffer.id();
+    if (base::SharedMemory::IsHandleValid(bitstream_buffer.handle()))
+      base::SharedMemory::CloseHandle(bitstream_buffer.handle());
+    NOTIFY_ERROR(INVALID_ARGUMENT);
+    return;
+  }
+
   decoder_thread_task_runner_->PostTask(
       FROM_HERE, base::Bind(&V4L2SliceVideoDecodeAccelerator::DecodeTask,
                             base::Unretained(this), bitstream_buffer));
diff --git a/content/common/gpu/media/v4l2_video_decode_accelerator.cc b/content/common/gpu/media/v4l2_video_decode_accelerator.cc
index 2c43e6e9..3ed7f9621 100644
--- a/content/common/gpu/media/v4l2_video_decode_accelerator.cc
+++ b/content/common/gpu/media/v4l2_video_decode_accelerator.cc
@@ -298,6 +298,14 @@
            << ", size=" << bitstream_buffer.size();
   DCHECK(io_task_runner_->BelongsToCurrentThread());
 
+  if (bitstream_buffer.id() < 0) {
+    LOG(ERROR) << "Invalid bitstream_buffer, id: " << bitstream_buffer.id();
+    if (base::SharedMemory::IsHandleValid(bitstream_buffer.handle()))
+      base::SharedMemory::CloseHandle(bitstream_buffer.handle());
+    NOTIFY_ERROR(INVALID_ARGUMENT);
+    return;
+  }
+
   // DecodeTask() will take care of running a DecodeBufferTask().
   decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind(
       &V4L2VideoDecodeAccelerator::DecodeTask, base::Unretained(this),
diff --git a/content/common/gpu/media/vaapi_jpeg_decode_accelerator.cc b/content/common/gpu/media/vaapi_jpeg_decode_accelerator.cc
index 8efb362..d294ae5 100644
--- a/content/common/gpu/media/vaapi_jpeg_decode_accelerator.cc
+++ b/content/common/gpu/media/vaapi_jpeg_decode_accelerator.cc
@@ -289,6 +289,15 @@
 
   DVLOG(4) << "Mapping new input buffer id: " << bitstream_buffer.id()
            << " size: " << bitstream_buffer.size();
+
+  if (bitstream_buffer.id() < 0) {
+    LOG(ERROR) << "Invalid bitstream_buffer, id: " << bitstream_buffer.id();
+    if (base::SharedMemory::IsHandleValid(bitstream_buffer.handle()))
+      base::SharedMemory::CloseHandle(bitstream_buffer.handle());
+    NotifyErrorFromDecoderThread(bitstream_buffer.id(), INVALID_ARGUMENT);
+    return;
+  }
+
   scoped_ptr<base::SharedMemory> shm(
       new base::SharedMemory(bitstream_buffer.handle(), true));
 
diff --git a/content/common/gpu/media/vaapi_video_decode_accelerator.cc b/content/common/gpu/media/vaapi_video_decode_accelerator.cc
index 271a0f7..a430438 100644
--- a/content/common/gpu/media/vaapi_video_decode_accelerator.cc
+++ b/content/common/gpu/media/vaapi_video_decode_accelerator.cc
@@ -673,6 +673,12 @@
   TRACE_EVENT1("Video Decoder", "VAVDA::Decode", "Buffer id",
                bitstream_buffer.id());
 
+  RETURN_AND_NOTIFY_ON_FAILURE(
+      bitstream_buffer.id() >= 0 &&
+          base::SharedMemory::IsHandleValid(bitstream_buffer.handle()),
+      "Invalid bitstream_buffer, id: " << bitstream_buffer.id(),
+      INVALID_ARGUMENT, );
+
   // We got a new input buffer from the client, map it and queue for later use.
   MapAndQueueNewInputBuffer(bitstream_buffer);
 
diff --git a/content/common/gpu/media/vt_video_decode_accelerator_mac.cc b/content/common/gpu/media/vt_video_decode_accelerator_mac.cc
index e7e6b5a..144605ec 100644
--- a/content/common/gpu/media/vt_video_decode_accelerator_mac.cc
+++ b/content/common/gpu/media/vt_video_decode_accelerator_mac.cc
@@ -829,6 +829,13 @@
 
 void VTVideoDecodeAccelerator::Decode(const media::BitstreamBuffer& bitstream) {
   DCHECK(gpu_thread_checker_.CalledOnValidThread());
+  if (bitstream.id() < 0) {
+    DLOG(ERROR) << "Invalid bitstream, id: " << bitstream.id();
+    if (base::SharedMemory::IsHandleValid(bitstream.handle()))
+      base::SharedMemory::CloseHandle(bitstream.handle());
+    NotifyError(INVALID_ARGUMENT, SFT_INVALID_STREAM);
+    return;
+  }
   DCHECK_EQ(0u, assigned_bitstream_ids_.count(bitstream.id()));
   assigned_bitstream_ids_.insert(bitstream.id());
   Frame* frame = new Frame(bitstream.id());
diff --git a/content/common/gpu/stream_texture_android.cc b/content/common/gpu/stream_texture_android.cc
index 2bece4d7..857bd1673 100644
--- a/content/common/gpu/stream_texture_android.cc
+++ b/content/common/gpu/stream_texture_android.cc
@@ -125,14 +125,6 @@
   scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
   bool needs_make_current =
       !owner_stub_->decoder()->GetGLContext()->IsCurrent(NULL);
-  // On Android we should not have to perform a real context switch here when
-  // using virtual contexts.
-  DCHECK(!needs_make_current ||
-         !owner_stub_->decoder()
-              ->GetContextGroup()
-              ->feature_info()
-              ->workarounds()
-              .use_virtualized_gl_contexts);
   if (needs_make_current) {
     scoped_make_current.reset(new ui::ScopedMakeCurrent(
         owner_stub_->decoder()->GetGLContext(), owner_stub_->surface()));
diff --git a/content/common/host_discardable_shared_memory_manager.cc b/content/common/host_discardable_shared_memory_manager.cc
index 7a6d480..d8d141cd 100644
--- a/content/common/host_discardable_shared_memory_manager.cc
+++ b/content/common/host_discardable_shared_memory_manager.cc
@@ -15,6 +15,7 @@
 #include "base/macros.h"
 #include "base/memory/discardable_memory.h"
 #include "base/numerics/safe_math.h"
+#include "base/process/memory.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/sys_info.h"
@@ -190,6 +191,9 @@
 scoped_ptr<base::DiscardableMemory>
 HostDiscardableSharedMemoryManager::AllocateLockedDiscardableMemory(
     size_t size) {
+  // TODO(reveman): Temporary diagnostics for http://crbug.com/577786.
+  CHECK_NE(size, 0u);
+
   DiscardableSharedMemoryId new_id =
       g_next_discardable_shared_memory_id.GetNext();
   base::ProcessHandle current_process_handle = base::GetCurrentProcessHandle();
@@ -200,10 +204,10 @@
   AllocateLockedDiscardableSharedMemory(current_process_handle,
                                         ChildProcessHost::kInvalidUniqueID,
                                         size, new_id, &handle);
-  CHECK(base::SharedMemory::IsHandleValid(handle));
   scoped_ptr<base::DiscardableSharedMemory> memory(
       new base::DiscardableSharedMemory(handle));
-  CHECK(memory->Map(size));
+  if (!memory->Map(size))
+    base::TerminateBecauseOutOfMemory(size);
   // Close file descriptor to avoid running out.
   memory->Close();
   return make_scoped_ptr(new DiscardableMemoryImpl(
diff --git a/content/common/in_process_child_thread_params.cc b/content/common/in_process_child_thread_params.cc
index 13e9390..ce245ec 100644
--- a/content/common/in_process_child_thread_params.cc
+++ b/content/common/in_process_child_thread_params.cc
@@ -12,6 +12,9 @@
     : channel_name_(channel_name), io_runner_(io_runner) {
 }
 
+InProcessChildThreadParams::InProcessChildThreadParams(
+    const InProcessChildThreadParams& other) = default;
+
 InProcessChildThreadParams::~InProcessChildThreadParams() {
 }
 
diff --git a/content/common/in_process_child_thread_params.h b/content/common/in_process_child_thread_params.h
index 938a6ef0..4e14a2a 100644
--- a/content/common/in_process_child_thread_params.h
+++ b/content/common/in_process_child_thread_params.h
@@ -21,6 +21,7 @@
   InProcessChildThreadParams(
       const std::string& channel_name,
       scoped_refptr<base::SequencedTaskRunner> io_runner);
+  InProcessChildThreadParams(const InProcessChildThreadParams& other);
   ~InProcessChildThreadParams();
 
   const std::string& channel_name() const { return channel_name_; }
diff --git a/content/common/indexed_db/indexed_db_messages.h b/content/common/indexed_db/indexed_db_messages.h
index fb558f3..4c211a7d 100644
--- a/content/common/indexed_db/indexed_db_messages.h
+++ b/content/common/indexed_db/indexed_db_messages.h
@@ -341,7 +341,7 @@
 IPC_STRUCT_BEGIN(IndexedDBDatabaseMetadata)
   IPC_STRUCT_MEMBER(int64_t, id)
   IPC_STRUCT_MEMBER(base::string16, name)
-  IPC_STRUCT_MEMBER(int64_t, int_version)
+  IPC_STRUCT_MEMBER(int64_t, version)
   IPC_STRUCT_MEMBER(int64_t, max_object_store_id)
   IPC_STRUCT_MEMBER(std::vector<IndexedDBObjectStoreMetadata>, object_stores)
 IPC_STRUCT_END()
@@ -423,7 +423,7 @@
 IPC_MESSAGE_CONTROL2(IndexedDBMsg_DatabaseCallbacksForcedClose,
                      int32_t, /* ipc_thread_id */
                      int32_t) /* ipc_database_callbacks_id */
-IPC_MESSAGE_CONTROL4(IndexedDBMsg_DatabaseCallbacksIntVersionChange,
+IPC_MESSAGE_CONTROL4(IndexedDBMsg_DatabaseCallbacksVersionChange,
                      int32_t, /* ipc_thread_id */
                      int32_t, /* ipc_database_callbacks_id */
                      int64_t, /* old_version */
diff --git a/content/common/input/synthetic_web_input_event_builders.cc b/content/common/input/synthetic_web_input_event_builders.cc
index 4ba93d31..c68c689c 100644
--- a/content/common/input/synthetic_web_input_event_builders.cc
+++ b/content/common/input/synthetic_web_input_event_builders.cc
@@ -61,8 +61,21 @@
                                                              float dy,
                                                              int modifiers,
                                                              bool precise) {
+  return Build(x, y, 0, 0, dx, dy, modifiers, precise);
+}
+
+WebMouseWheelEvent SyntheticWebMouseWheelEventBuilder::Build(float x,
+                                                             float y,
+                                                             float global_x,
+                                                             float global_y,
+                                                             float dx,
+                                                             float dy,
+                                                             int modifiers,
+                                                             bool precise) {
   WebMouseWheelEvent result;
   result.type = WebInputEvent::MouseWheel;
+  result.globalX = global_x;
+  result.globalY = global_y;
   result.x = x;
   result.y = y;
   result.deltaX = dx;
diff --git a/content/common/input/synthetic_web_input_event_builders.h b/content/common/input/synthetic_web_input_event_builders.h
index ef1a169..e865e9b2 100644
--- a/content/common/input/synthetic_web_input_event_builders.h
+++ b/content/common/input/synthetic_web_input_event_builders.h
@@ -32,6 +32,14 @@
                                          float dy,
                                          int modifiers,
                                          bool precise);
+  static blink::WebMouseWheelEvent Build(float x,
+                                         float y,
+                                         float global_x,
+                                         float global_y,
+                                         float dx,
+                                         float dy,
+                                         int modifiers,
+                                         bool precise);
 };
 
 class CONTENT_EXPORT SyntheticWebKeyboardEventBuilder {
diff --git a/content/common/leveldb_wrapper.mojom b/content/common/leveldb_wrapper.mojom
new file mode 100644
index 0000000..045b858
--- /dev/null
+++ b/content/common/leveldb_wrapper.mojom
@@ -0,0 +1,42 @@
+// Copyright 2016 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.
+
+module content;
+
+import "components/leveldb/public/interfaces/leveldb.mojom";
+
+struct KeyValue {
+  array<uint8> key;
+  array<uint8> value;
+};
+
+// A wrapper around leveldb that supports giving notifications when values
+// change.
+interface LevelDBWrapper {
+  // Sets the database entry for "key" to "value". Returns OK on success.
+  Put(array<uint8> key, array<uint8> value, string source)
+    => (leveldb.DatabaseError status);
+
+  // Remove the database entry (if any) for "key".  Returns OK on
+  // success, and a non-OK status on error.  It is not an error if "key"
+  // did not exist in the database.
+  Delete(array<uint8> key, string source) => (leveldb.DatabaseError status);
+
+  // Removes all the entries.
+  DeleteAll(string source) => (leveldb.DatabaseError status);
+
+  // Returns the value of the given key.
+  Get(array<uint8> key) => (leveldb.DatabaseError status, array<uint8> value);
+
+  // Only used with small databases. Returns all key/value pairs.
+  GetAll() => (leveldb.DatabaseError status, array<KeyValue> data);
+};
+
+// Gives information about changes to a LevelDB database.
+interface LevelDBObserver {
+  KeyChanged(array<uint8> key, array<uint8> new_value, array<uint8> old_value,
+             string source);
+  KeyDeleted(array<uint8> key, string source);
+  AllDeleted(string source);
+};
diff --git a/content/common/media/media_stream_options.cc b/content/common/media/media_stream_options.cc
index c942f46..1b2b1e2 100644
--- a/content/common/media/media_stream_options.cc
+++ b/content/common/media/media_stream_options.cc
@@ -27,6 +27,8 @@
 TrackControls::TrackControls(bool request)
     : requested(request) {}
 
+TrackControls::TrackControls(const TrackControls& other) = default;
+
 TrackControls::~TrackControls() {}
 
 StreamControls::StreamControls()
diff --git a/content/common/media/media_stream_options.h b/content/common/media/media_stream_options.h
index 4d61d57..b815c60 100644
--- a/content/common/media/media_stream_options.h
+++ b/content/common/media/media_stream_options.h
@@ -36,6 +36,7 @@
  public:
   TrackControls();
   TrackControls(bool request);
+  TrackControls(const TrackControls& other);
   ~TrackControls();
   bool requested;
 
diff --git a/content/common/mojo/mojo_shell_connection_impl.cc b/content/common/mojo/mojo_shell_connection_impl.cc
index a989a02..282b4b1 100644
--- a/content/common/mojo/mojo_shell_connection_impl.cc
+++ b/content/common/mojo/mojo_shell_connection_impl.cc
@@ -64,7 +64,7 @@
 
 void MojoShellConnectionImpl::WaitForShell(
     mojo::ScopedMessagePipeHandle handle) {
-  mojo::ShellClientRequest request;
+  mojo::shell::mojom::ShellClientRequest request;
   runner_connection_.reset(mojo::shell::RunnerConnection::ConnectToRunner(
       &request, std::move(handle)));
   shell_connection_.reset(new mojo::ShellConnection(this, std::move(request)));
@@ -73,7 +73,8 @@
 
 void MojoShellConnectionImpl::Initialize(mojo::Shell* shell,
                                          const std::string& url,
-                                         uint32_t id) {
+                                         uint32_t id,
+                                         uint32_t user_id) {
   initialized_ = true;
 }
 
diff --git a/content/common/mojo/mojo_shell_connection_impl.h b/content/common/mojo/mojo_shell_connection_impl.h
index cfdaca8..d18d73a 100644
--- a/content/common/mojo/mojo_shell_connection_impl.h
+++ b/content/common/mojo/mojo_shell_connection_impl.h
@@ -52,7 +52,7 @@
 
   // mojo::ShellClient:
   void Initialize(mojo::Shell* shell, const std::string& url,
-                  uint32_t id) override;
+                  uint32_t id, uint32_t user_id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
   // MojoShellConnection:
diff --git a/content/common/navigation_params.cc b/content/common/navigation_params.cc
index 61879793..4b7ceb67 100644
--- a/content/common/navigation_params.cc
+++ b/content/common/navigation_params.cc
@@ -61,6 +61,9 @@
       navigation_start(navigation_start) {
 }
 
+CommonNavigationParams::CommonNavigationParams(
+    const CommonNavigationParams& other) = default;
+
 CommonNavigationParams::~CommonNavigationParams() {
 }
 
@@ -84,6 +87,9 @@
       skip_service_worker(skip_service_worker),
       request_context_type(request_context_type) {}
 
+BeginNavigationParams::BeginNavigationParams(
+    const BeginNavigationParams& other) = default;
+
 StartNavigationParams::StartNavigationParams()
     : is_post(false),
 #if defined(OS_ANDROID)
@@ -112,6 +118,9 @@
       transferred_request_request_id(transferred_request_request_id) {
 }
 
+StartNavigationParams::StartNavigationParams(
+    const StartNavigationParams& other) = default;
+
 StartNavigationParams::~StartNavigationParams() {
 }
 
@@ -166,6 +175,9 @@
       should_create_service_worker(false),
       service_worker_provider_id(kInvalidServiceWorkerProviderId) {}
 
+RequestNavigationParams::RequestNavigationParams(
+    const RequestNavigationParams& other) = default;
+
 RequestNavigationParams::~RequestNavigationParams() {
 }
 
diff --git a/content/common/navigation_params.h b/content/common/navigation_params.h
index 414319d..d2888249 100644
--- a/content/common/navigation_params.h
+++ b/content/common/navigation_params.h
@@ -60,6 +60,7 @@
                          const GURL& history_url_for_data_url,
                          LoFiState lofi_state,
                          const base::TimeTicks& navigation_start);
+  CommonNavigationParams(const CommonNavigationParams& other);
   ~CommonNavigationParams();
 
   // The URL to navigate to.
@@ -134,6 +135,7 @@
                         bool has_user_gesture,
                         bool skip_service_worker,
                         RequestContextType request_context_type);
+  BeginNavigationParams(const BeginNavigationParams& other);
 
   // The request method: GET, POST, etc.
   std::string method;
@@ -179,6 +181,7 @@
 #endif
       int transferred_request_child_id,
       int transferred_request_request_id);
+  StartNavigationParams(const StartNavigationParams& other);
   ~StartNavigationParams();
 
   // Whether the navigation is a POST request (as opposed to a GET).
@@ -224,6 +227,7 @@
                           int current_history_list_length,
                           bool is_view_source,
                           bool should_clear_history_list);
+  RequestNavigationParams(const RequestNavigationParams& other);
   ~RequestNavigationParams();
 
   // Whether or not the user agent override string should be used.
diff --git a/content/common/notification_constants.h b/content/common/notification_constants.h
index 6ca8ad62..5c4a1eba 100644
--- a/content/common/notification_constants.h
+++ b/content/common/notification_constants.h
@@ -12,6 +12,14 @@
 // Maximum number of actions on a Platform Notification.
 static const size_t kPlatformNotificationMaxActions = 2;
 
+// The maximum reasonable notification icon size, scaled from dip units to
+// pixels using the largest supported scaling factor.
+static const int kPlatformNotificationMaxIconSizePx = 320;  // 80 dip * 4
+
+// The maximum reasonable action icon size, scaled from dip units to
+// pixels using the largest supported scaling factor.
+static const int kPlatformNotificationMaxActionIconSizePx = 128;  // 32 dip * 4
+
 }  // namespace content
 
 #endif  // CONTENT_COMMON_NOTIFICATION_CONSTANTS_H_
diff --git a/content/common/origin_util.cc b/content/common/origin_util.cc
index 9c6b631..4dfdc6c 100644
--- a/content/common/origin_util.cc
+++ b/content/common/origin_util.cc
@@ -8,7 +8,7 @@
 #include "base/macros.h"
 #include "base/stl_util.h"
 #include "content/public/common/content_client.h"
-#include "net/base/net_util.h"
+#include "net/base/url_util.h"
 #include "url/gurl.h"
 
 namespace content {
diff --git a/content/common/page_state_serialization.cc b/content/common/page_state_serialization.cc
index 68974ae..b9670c2f2 100644
--- a/content/common/page_state_serialization.cc
+++ b/content/common/page_state_serialization.cc
@@ -671,6 +671,9 @@
       file_modification_time(std::numeric_limits<double>::quiet_NaN()) {
 }
 
+ExplodedHttpBodyElement::ExplodedHttpBodyElement(
+    const ExplodedHttpBodyElement& other) = default;
+
 ExplodedHttpBodyElement::~ExplodedHttpBodyElement() {
 }
 
diff --git a/content/common/page_state_serialization.h b/content/common/page_state_serialization.h
index 9b6773c..24d8198 100644
--- a/content/common/page_state_serialization.h
+++ b/content/common/page_state_serialization.h
@@ -32,6 +32,7 @@
   std::string blob_uuid;
 
   ExplodedHttpBodyElement();
+  ExplodedHttpBodyElement(const ExplodedHttpBodyElement& other);
   ~ExplodedHttpBodyElement();
 };
 
diff --git a/content/common/resize_params.cc b/content/common/resize_params.cc
index 15e40b3a..ea9f18fb 100644
--- a/content/common/resize_params.cc
+++ b/content/common/resize_params.cc
@@ -13,6 +13,8 @@
       display_mode(blink::WebDisplayModeUndefined),
       needs_resize_ack(false) {}
 
+ResizeParams::ResizeParams(const ResizeParams& other) = default;
+
 ResizeParams::~ResizeParams() {}
 
 }  // namespace content
diff --git a/content/common/resize_params.h b/content/common/resize_params.h
index 23c3031..f9eb07c 100644
--- a/content/common/resize_params.h
+++ b/content/common/resize_params.h
@@ -14,6 +14,7 @@
 
 struct CONTENT_EXPORT ResizeParams {
   ResizeParams();
+  ResizeParams(const ResizeParams& other);
   ~ResizeParams();
 
   // Information about the screen (dpi, depth, etc..).
diff --git a/content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.cc b/content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.cc
index 76d8382a..5f9813f 100644
--- a/content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.cc
+++ b/content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.cc
@@ -61,7 +61,9 @@
     // TODO(rsesek): restrict clone parameters.
     case __NR_clone:
     case __NR_epoll_pwait:
+    case __NR_fdatasync:
     case __NR_flock:
+    case __NR_fsync:
     case __NR_ftruncate:
 #if defined(__i386__) || defined(__arm__) || defined(__mips__)
     case __NR_ftruncate64:
@@ -89,6 +91,8 @@
     case __NR_pwrite64:
     case __NR_rt_sigtimedwait:
     case __NR_sched_getparam:
+    case __NR_sched_getscheduler:
+    case __NR_sched_setscheduler:
     case __NR_setpriority:
     case __NR_set_tid_address:
     case __NR_sigaltstack:
diff --git a/content/common/sandbox_win.cc b/content/common/sandbox_win.cc
index 29fb557..6a2b3d7 100644
--- a/content/common/sandbox_win.cc
+++ b/content/common/sandbox_win.cc
@@ -703,6 +703,11 @@
       sandbox::MITIGATION_NONSYSTEM_FONT_DISABLE |
       sandbox::MITIGATION_IMAGE_LOAD_NO_REMOTE |
       sandbox::MITIGATION_IMAGE_LOAD_NO_LOW_LABEL;
+#if !defined(NACL_WIN64)
+  // Don't block font loading with GDI.
+  if (!gfx::win::ShouldUseDirectWrite())
+    mitigations ^= sandbox::MITIGATION_NONSYSTEM_FONT_DISABLE;
+#endif
 
   if (policy->SetProcessMitigations(mitigations) != sandbox::SBOX_ALL_OK)
     return base::Process();
diff --git a/content/common/service_worker/service_worker_client_info.cc b/content/common/service_worker/service_worker_client_info.cc
index 5019575..a412fa0 100644
--- a/content/common/service_worker/service_worker_client_info.cc
+++ b/content/common/service_worker/service_worker_client_info.cc
@@ -34,6 +34,9 @@
       last_focus_time(last_focus_time),
       client_type(client_type) {}
 
+ServiceWorkerClientInfo::ServiceWorkerClientInfo(
+    const ServiceWorkerClientInfo& other) = default;
+
 bool ServiceWorkerClientInfo::IsEmpty() const {
   return page_visibility_state == blink::WebPageVisibilityStateLast &&
          is_focused == false &&
diff --git a/content/common/service_worker/service_worker_client_info.h b/content/common/service_worker/service_worker_client_info.h
index c4b6c34a..93bfdf447 100644
--- a/content/common/service_worker/service_worker_client_info.h
+++ b/content/common/service_worker/service_worker_client_info.h
@@ -27,6 +27,7 @@
                           RequestContextFrameType frame_type,
                           base::TimeTicks last_focus_time,
                           blink::WebServiceWorkerClientType client_type);
+  ServiceWorkerClientInfo(const ServiceWorkerClientInfo& other);
 
   // Returns whether the instance is empty.
   bool IsEmpty() const;
diff --git a/content/common/service_worker/service_worker_types.cc b/content/common/service_worker/service_worker_types.cc
index 3fe66cf..56437d0 100644
--- a/content/common/service_worker/service_worker_types.cc
+++ b/content/common/service_worker/service_worker_types.cc
@@ -50,6 +50,9 @@
       is_reload(is_reload),
       fetch_type(ServiceWorkerFetchType::FETCH) {}
 
+ServiceWorkerFetchRequest::ServiceWorkerFetchRequest(
+    const ServiceWorkerFetchRequest& other) = default;
+
 ServiceWorkerFetchRequest::~ServiceWorkerFetchRequest() {}
 
 ServiceWorkerResponse::ServiceWorkerResponse()
@@ -79,6 +82,9 @@
       stream_url(stream_url),
       error(error) {}
 
+ServiceWorkerResponse::ServiceWorkerResponse(
+    const ServiceWorkerResponse& other) = default;
+
 ServiceWorkerResponse::~ServiceWorkerResponse() {}
 
 ServiceWorkerObjectInfo::ServiceWorkerObjectInfo()
diff --git a/content/common/service_worker/service_worker_types.h b/content/common/service_worker/service_worker_types.h
index c0d4b8c..e332f1c 100644
--- a/content/common/service_worker/service_worker_types.h
+++ b/content/common/service_worker/service_worker_types.h
@@ -129,6 +129,7 @@
                             const ServiceWorkerHeaderMap& headers,
                             const Referrer& referrer,
                             bool is_reload);
+  ServiceWorkerFetchRequest(const ServiceWorkerFetchRequest& other);
   ~ServiceWorkerFetchRequest();
 
   FetchRequestMode mode;
@@ -160,6 +161,7 @@
                         uint64_t blob_size,
                         const GURL& stream_url,
                         blink::WebServiceWorkerResponseError error);
+  ServiceWorkerResponse(const ServiceWorkerResponse& other);
   ~ServiceWorkerResponse();
 
   GURL url;
diff --git a/content/common/storage_partition_service.mojom b/content/common/storage_partition_service.mojom
new file mode 100644
index 0000000..86761147
--- /dev/null
+++ b/content/common/storage_partition_service.mojom
@@ -0,0 +1,13 @@
+// Copyright 2016 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.
+
+module content;
+
+import "content/common/leveldb_wrapper.mojom";
+
+// Returns services related to the current storage partition.
+interface StoragePartitionService {
+  OpenLocalStorage(string origin, LevelDBObserver observer,
+                   LevelDBWrapper& database);
+};
diff --git a/content/common/webplugin_geometry.cc b/content/common/webplugin_geometry.cc
index ff290d2..800f79d5 100644
--- a/content/common/webplugin_geometry.cc
+++ b/content/common/webplugin_geometry.cc
@@ -12,6 +12,8 @@
       visible(false) {
 }
 
+WebPluginGeometry::WebPluginGeometry(const WebPluginGeometry& other) = default;
+
 WebPluginGeometry::~WebPluginGeometry() {
 }
 
diff --git a/content/common/webplugin_geometry.h b/content/common/webplugin_geometry.h
index 7f727a1..7ac99f0 100644
--- a/content/common/webplugin_geometry.h
+++ b/content/common/webplugin_geometry.h
@@ -15,6 +15,7 @@
 // Describes the new location for a plugin window.
 struct WebPluginGeometry {
   WebPluginGeometry();
+  WebPluginGeometry(const WebPluginGeometry& other);
   ~WebPluginGeometry();
 
   bool Equals(const WebPluginGeometry& rhs) const;
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 95ba8499..e0dac55 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -536,8 +536,6 @@
       # needed on all platforms.
       'browser/compositor/surface_utils.cc',
       'browser/compositor/surface_utils.h',
-      'browser/device_monitor_mac.h',
-      'browser/device_monitor_mac.mm',
       'browser/device_sensors/ambient_light_mac.cc',
       'browser/device_sensors/ambient_light_mac.h',
       'browser/device_sensors/data_fetcher_shared_memory.h',
@@ -946,6 +944,8 @@
       'browser/indexed_db/leveldb/leveldb_transaction.h',
       'browser/indexed_db/leveldb/leveldb_write_batch.cc',
       'browser/indexed_db/leveldb/leveldb_write_batch.h',
+      'browser/level_db_wrapper_impl.cc',
+      'browser/level_db_wrapper_impl.h',
       'browser/loader/async_resource_handler.cc',
       'browser/loader/async_resource_handler.h',
       'browser/loader/async_revalidation_driver.cc',
@@ -1069,10 +1069,10 @@
       'browser/media/media_web_contents_observer.h',
       'browser/media/midi_host.cc',
       'browser/media/midi_host.h',
-      'browser/media/webrtc_identity_store.cc',
-      'browser/media/webrtc_identity_store.h',
-      'browser/media/webrtc_identity_store_backend.cc',
-      'browser/media/webrtc_identity_store_backend.h',
+      'browser/media/webrtc/webrtc_identity_store.cc',
+      'browser/media/webrtc/webrtc_identity_store.h',
+      'browser/media/webrtc/webrtc_identity_store_backend.cc',
+      'browser/media/webrtc/webrtc_identity_store_backend.h',
       'browser/memory/memory_message_filter.cc',
       'browser/memory/memory_message_filter.h',
       'browser/memory/memory_pressure_controller_impl.cc',
@@ -1713,13 +1713,13 @@
       'browser/accessibility/browser_accessibility_manager_auralinux.h',
     ],
     'webrtc_browser_sources': [
-      'browser/media/webrtc_internals.cc',
-      'browser/media/webrtc_internals.h',
-      'browser/media/webrtc_internals_message_handler.cc',
-      'browser/media/webrtc_internals_message_handler.h',
-      'browser/media/webrtc_internals_ui.cc',
-      'browser/media/webrtc_internals_ui.h',
-      'browser/media/webrtc_internals_ui_observer.h',
+      'browser/media/webrtc/webrtc_internals.cc',
+      'browser/media/webrtc/webrtc_internals.h',
+      'browser/media/webrtc/webrtc_internals_message_handler.cc',
+      'browser/media/webrtc/webrtc_internals_message_handler.h',
+      'browser/media/webrtc/webrtc_internals_ui.cc',
+      'browser/media/webrtc/webrtc_internals_ui.h',
+      'browser/media/webrtc/webrtc_internals_ui_observer.h',
       'browser/renderer_host/media/peer_connection_tracker_host.cc',
       'browser/renderer_host/media/peer_connection_tracker_host.h',
       'browser/renderer_host/media/webrtc_identity_service_host.cc',
@@ -2080,6 +2080,7 @@
         'browser/geolocation/empty_wifi_data_provider.cc',
       ],
       'dependencies': [
+        '../media/media.gyp:media',
         '../third_party/mozilla/mozilla.gyp:mozilla',
         '../third_party/sudden_motion_sensor/sudden_motion_sensor.gyp:sudden_motion_sensor',
         '../ui/accelerated_widget_mac/accelerated_widget_mac.gyp:accelerated_widget_mac',
diff --git a/content/content_child.gypi b/content/content_child.gypi
index d1b0a8f..37fad58 100644
--- a/content/content_child.gypi
+++ b/content/content_child.gypi
@@ -12,7 +12,7 @@
     '../ipc/ipc.gyp:ipc',
     '../mojo/mojo_base.gyp:mojo_environment_chromium',
     '../mojo/mojo_base.gyp:mojo_common_lib',
-    '../mojo/mojo_base.gyp:mojo_message_pump_lib',
+    '../mojo/mojo_public.gyp:mojo_message_pump_lib',
     '../skia/skia.gyp:skia',
     '../storage/storage_common.gyp:storage_common',
     '../third_party/WebKit/public/blink.gyp:blink',
diff --git a/content/content_common_mojo_bindings.gyp b/content/content_common_mojo_bindings.gyp
index aba33f1c..a174591e 100644
--- a/content/content_common_mojo_bindings.gyp
+++ b/content/content_common_mojo_bindings.gyp
@@ -5,41 +5,54 @@
 {
   'targets': [
     {
-      'target_name': 'content_common_mojo_bindings',
-      'type': 'static_library',
+      # GN version: //content/common:mojo_bindings
+      'target_name': 'content_common_mojo_bindings_mojom',
+      'type': 'none',
       'variables': {
-        'enable_wexit_time_destructors': 1,
-      },
-      'sources': [
-        # NOTE: Sources duplicated in //content/common/BUILD.gn:mojo_bindings.
-        'common/application_setup.mojom',
-        'common/background_sync_service.mojom',
-        'common/geolocation_service.mojom',
-        'common/image_downloader/image_downloader.mojom',
-        'common/permission_service.mojom',
-        'common/presentation/presentation_service.mojom',
-        'common/process_control.mojom',
-        'common/render_frame_setup.mojom',
-        'common/service_port_service.mojom',
-        'common/service_worker/embedded_worker_setup.mojom',
-        'common/vr_service.mojom',
-        'common/wake_lock_service.mojom',
+        'mojom_files': [
+          # NOTE: Sources duplicated in //content/common/BUILD.gn:mojo_bindings.
+          'common/application_setup.mojom',
+          'common/background_sync_service.mojom',
+          'common/geolocation_service.mojom',
+          'common/image_downloader/image_downloader.mojom',
+          'common/leveldb_wrapper.mojom',
+          'common/permission_service.mojom',
+          'common/presentation/presentation_service.mojom',
+          'common/process_control.mojom',
+          'common/render_frame_setup.mojom',
+          'common/service_port_service.mojom',
+          'common/service_worker/embedded_worker_setup.mojom',
+          'common/storage_partition_service.mojom',
+          'common/vr_service.mojom',
+          'common/wake_lock_service.mojom',
 
-        # NOTE: Sources duplicated in
-        # //content/public/common/BUILD.gn:mojo_bindings.
-        'public/common/background_sync.mojom',
-        'public/common/mojo_geoposition.mojom',
-        'public/common/permission_status.mojom',
-        'public/common/service_worker_event_status.mojom',
-      ],
+          # NOTE: Sources duplicated in
+          # //content/public/common/BUILD.gn:mojo_bindings.
+          'public/common/background_sync.mojom',
+          'public/common/mojo_geoposition.mojom',
+          'public/common/permission_status.mojom',
+          'public/common/service_worker_event_status.mojom',
+        ],
+      },
       'dependencies': [
+        '../components/leveldb/leveldb.gyp:leveldb_bindings_mojom',
         '../mojo/mojo_base.gyp:mojo_application_bindings',
         '../mojo/mojo_base.gyp:mojo_environment_chromium',
         '../mojo/mojo_public.gyp:mojo_cpp_bindings',
         '../skia/skia.gyp:skia_mojo',
         '../ui/mojo/geometry/mojo_bindings.gyp:mojo_geometry_bindings',
       ],
-      'includes': [ '../mojo/mojom_bindings_generator.gypi' ],
+      'includes': [ '../mojo/mojom_bindings_generator_explicit.gypi' ], 
+    },
+    {
+      'target_name': 'content_common_mojo_bindings',
+      'type': 'static_library',
+      'variables': {
+        'enable_wexit_time_destructors': 1,
+      },
+      'dependencies': [
+        'content_common_mojo_bindings_mojom',
+      ],
     },
   ]
 }
diff --git a/content/content_shell.gypi b/content/content_shell.gypi
index 43b456d..1ce43443 100644
--- a/content/content_shell.gypi
+++ b/content/content_shell.gypi
@@ -128,6 +128,8 @@
         'shell/browser/layout_test/layout_test_url_request_context_getter.h',
         'shell/browser/layout_test/notify_done_forwarder.cc',
         'shell/browser/layout_test/notify_done_forwarder.h',
+        'shell/browser/layout_test/test_info_extractor.cc',
+        'shell/browser/layout_test/test_info_extractor.h',
         'shell/browser/shell.cc',
         'shell/browser/shell.h',
         'shell/browser/shell_access_token_store.cc',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 42e66383..a7e31a64 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -109,8 +109,8 @@
       'test/content_browser_sanity_checker.h',
       'test/content_test_suite.cc',
       'test/content_test_suite.h',
-      'test/dwrite_font_fake_sender_win.h',
       'test/dwrite_font_fake_sender_win.cc',
+      'test/dwrite_font_fake_sender_win.h',
       'test/fake_compositor_dependencies.cc',
       'test/fake_compositor_dependencies.h',
       'test/fake_plugin_service.cc',
@@ -292,13 +292,13 @@
       'shell/android/browsertests_apk/content_browser_tests_jni_onload.cc',
     ],
     'content_browsertests_webrtc_sources': [
-      'browser/media/webrtc_audio_debug_recordings_browsertest.cc',
-      'browser/media/webrtc_browsertest.cc',
-      'browser/media/webrtc_getusermedia_browsertest.cc',
-      'browser/media/webrtc_internals_browsertest.cc',
-      'browser/media/webrtc_ip_permissions_browsertest.cc',
-      'browser/media/webrtc_media_recorder_browsertest.cc',
-      'browser/media/webrtc_webcam_browsertest.cc',
+      'browser/media/webrtc/webrtc_audio_debug_recordings_browsertest.cc',
+      'browser/media/webrtc/webrtc_browsertest.cc',
+      'browser/media/webrtc/webrtc_getusermedia_browsertest.cc',
+      'browser/media/webrtc/webrtc_internals_browsertest.cc',
+      'browser/media/webrtc/webrtc_ip_permissions_browsertest.cc',
+      'browser/media/webrtc/webrtc_media_recorder_browsertest.cc',
+      'browser/media/webrtc/webrtc_webcam_browsertest.cc',
       'test/webrtc_content_browsertest_base.cc',
       'test/webrtc_content_browsertest_base.h',
     ],
@@ -500,8 +500,8 @@
       'browser/loader/temporary_file_stream_unittest.cc',
       'browser/loader/upload_data_stream_builder_unittest.cc',
       'browser/mach_broker_mac_unittest.cc',
-      'browser/media/android/media_session_uma_helper_unittest.cc',
       'browser/media/android/media_session_controller_unittest.cc',
+      'browser/media/android/media_session_uma_helper_unittest.cc',
       'browser/media/audible_metrics_unittest.cc',
       'browser/media/audio_stream_monitor_unittest.cc',
       'browser/media/capture/audio_mirroring_manager_unittest.cc',
@@ -510,7 +510,7 @@
       'browser/media/capture/web_contents_video_capture_device_unittest.cc',
       'browser/media/media_internals_unittest.cc',
       'browser/media/midi_host_unittest.cc',
-      'browser/media/webrtc_identity_store_unittest.cc',
+      'browser/media/webrtc/webrtc_identity_store_unittest.cc',
       'browser/net/quota_policy_cookie_store_unittest.cc',
       'browser/notification_service_impl_unittest.cc',
       'browser/notifications/notification_database_data_unittest.cc',
@@ -764,7 +764,7 @@
     ],
     # WebRTC-specific sources. Put WebRTC plugin-related stuff further below.
     'content_unittests_webrtc_sources': [
-      'browser/media/webrtc_internals_unittest.cc',
+      'browser/media/webrtc/webrtc_internals_unittest.cc',
       'browser/renderer_host/media/webrtc_identity_service_host_unittest.cc',
       'browser/renderer_host/p2p/socket_host_tcp_server_unittest.cc',
       'browser/renderer_host/p2p/socket_host_tcp_unittest.cc',
diff --git a/content/content_utility.gypi b/content/content_utility.gypi
index c1980da..a826636 100644
--- a/content/content_utility.gypi
+++ b/content/content_utility.gypi
@@ -9,8 +9,8 @@
     '../mojo/mojo_base.gyp:mojo_application_base',
     '../mojo/mojo_base.gyp:mojo_application_bindings',
     '../mojo/mojo_base.gyp:mojo_common_lib',
-    '../mojo/mojo_base.gyp:mojo_message_pump_lib',
     '../mojo/mojo_public.gyp:mojo_cpp_bindings',
+    '../mojo/mojo_public.gyp:mojo_message_pump_lib',
     '../mojo/mojo_shell.gyp:mojo_shell_lib',
     '../url/url.gyp:url_lib',
   ],
diff --git a/content/gpu/gpu_watchdog_thread.cc b/content/gpu/gpu_watchdog_thread.cc
index 22982db..4cfde4f9 100644
--- a/content/gpu/gpu_watchdog_thread.cc
+++ b/content/gpu/gpu_watchdog_thread.cc
@@ -42,6 +42,10 @@
       timeout_(base::TimeDelta::FromMilliseconds(timeout)),
       armed_(false),
       task_observer_(this),
+#if defined(OS_WIN)
+      watched_thread_handle_(0),
+      arm_cpu_time_(),
+#endif
       suspended_(false),
 #if defined(USE_X11)
       display_(NULL),
@@ -51,6 +55,20 @@
       weak_factory_(this) {
   DCHECK(timeout >= 0);
 
+#if defined(OS_WIN)
+  // GetCurrentThread returns a pseudo-handle that cannot be used by one thread
+  // to identify another. DuplicateHandle creates a "real" handle that can be
+  // used for this purpose.
+  BOOL result = DuplicateHandle(GetCurrentProcess(),
+                                GetCurrentThread(),
+                                GetCurrentProcess(),
+                                &watched_thread_handle_,
+                                THREAD_QUERY_INFORMATION,
+                                FALSE,
+                                0);
+  DCHECK(result);
+#endif
+
 #if defined(OS_CHROMEOS)
   tty_file_ = base::OpenFile(base::FilePath(kTtyFilePath), "r");
 #endif
@@ -106,6 +124,10 @@
   // implicitly by the destructor, CleanUp() will not be called.
   DCHECK(!weak_factory_.HasWeakPtrs());
 
+#if defined(OS_WIN)
+  CloseHandle(watched_thread_handle_);
+#endif
+
   base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
   if (power_monitor)
     power_monitor->RemoveObserver(this);
@@ -164,6 +186,10 @@
   // miss the false -> true transition.
   armed_ = true;
 
+#if defined(OS_WIN)
+  arm_cpu_time_ = GetWatchedThreadTime();
+#endif
+
   // Immediately after the computer is woken up from being suspended it might
   // be pretty sluggish, so allow some extra time before the next timeout.
   base::TimeDelta timeout = timeout_ * (after_suspend ? 3 : 1);
@@ -189,6 +215,21 @@
   // Should not get here while the system is suspended.
   DCHECK(!suspended_);
 
+#if defined(OS_WIN)
+  // Defer termination until a certain amount of CPU time has elapsed on the
+  // watched thread.
+  base::TimeDelta time_since_arm = GetWatchedThreadTime() - arm_cpu_time_;
+  if (time_since_arm < timeout_) {
+    message_loop()->PostDelayedTask(
+        FROM_HERE,
+        base::Bind(
+            &GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang,
+            weak_factory_.GetWeakPtr()),
+        timeout_ - time_since_arm);
+    return;
+  }
+#endif
+
   // If the watchdog woke up significantly behind schedule, disarm and reset
   // the watchdog check. This is to prevent the watchdog thread from terminating
   // when a machine wakes up from sleep or hibernation, which would otherwise
@@ -329,4 +370,37 @@
   OnCheck(true);
 }
 
+#if defined(OS_WIN)
+base::TimeDelta GpuWatchdogThread::GetWatchedThreadTime() {
+  FILETIME creation_time;
+  FILETIME exit_time;
+  FILETIME user_time;
+  FILETIME kernel_time;
+  BOOL result = GetThreadTimes(watched_thread_handle_,
+                               &creation_time,
+                               &exit_time,
+                               &kernel_time,
+                               &user_time);
+  DCHECK(result);
+
+  ULARGE_INTEGER user_time64;
+  user_time64.HighPart = user_time.dwHighDateTime;
+  user_time64.LowPart = user_time.dwLowDateTime;
+
+  ULARGE_INTEGER kernel_time64;
+  kernel_time64.HighPart = kernel_time.dwHighDateTime;
+  kernel_time64.LowPart = kernel_time.dwLowDateTime;
+
+  // Time is reported in units of 100 nanoseconds. Kernel and user time are
+  // summed to deal with to kinds of hangs. One is where the GPU process is
+  // stuck in user level, never calling into the kernel and kernel time is
+  // not increasing. The other is where either the kernel hangs and never
+  // returns to user level or where user level code
+  // calls into kernel level repeatedly, giving up its quanta before it is
+  // tracked, for example a loop that repeatedly Sleeps.
+  return base::TimeDelta::FromMilliseconds(static_cast<int64_t>(
+      (user_time64.QuadPart + kernel_time64.QuadPart) / 10000));
+}
+#endif
+
 }  // namespace content
diff --git a/content/gpu/gpu_watchdog_thread.h b/content/gpu/gpu_watchdog_thread.h
index 9be3a39..4370d83 100644
--- a/content/gpu/gpu_watchdog_thread.h
+++ b/content/gpu/gpu_watchdog_thread.h
@@ -88,11 +88,20 @@
   void OnSuspend() override;
   void OnResume() override;
 
+#if defined(OS_WIN)
+  base::TimeDelta GetWatchedThreadTime();
+#endif
+
   base::MessageLoop* watched_message_loop_;
   base::TimeDelta timeout_;
   volatile bool armed_;
   GpuWatchdogTaskObserver task_observer_;
 
+#if defined(OS_WIN)
+  void* watched_thread_handle_;
+  base::TimeDelta arm_cpu_time_;
+#endif
+
   // Time after which it's assumed that the computer has been suspended since
   // the task was posted.
   base::Time suspension_timeout_;
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java
index fe929a7d..f7fed6a 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java
@@ -578,8 +578,10 @@
      * in parallel to other startup work. Must not be called on the UI thread. Spare connection is
      * created in sandboxed child process.
      * @param context the application context used for the connection.
+     * @param params child process creation params.
      */
-    public static void warmUp(Context context) {
+    public static void warmUp(Context context, ChildProcessCreationParams params) {
+        setChildProcessCreationParams(params);
         synchronized (ChildProcessLauncher.class) {
             assert !ThreadUtils.runningOnUiThread();
             if (sSpareSandboxedConnection == null) {
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java
index 276a13e..473d18db 100644
--- a/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java
+++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java
@@ -41,6 +41,7 @@
     private static final int ACTION_SET_TEXT = 0x200000;
     private static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE =
             "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
+    private static final int WINDOW_CONTENT_CHANGED_DELAY_MS = 500;
 
     private final AccessibilityNodeProvider mAccessibilityNodeProvider;
     private ContentViewCore mContentViewCore;
@@ -61,6 +62,7 @@
     private int mSelectionEndIndex;
     protected int mAccessibilityFocusId;
     protected boolean mVisible = true;
+    private Runnable mSendWindowContentChangedRunnable;
 
     /**
      * Create a BrowserAccessibilityManager object, which is owned by the C++
@@ -148,7 +150,7 @@
         if (visible == mVisible) return;
 
         mVisible = visible;
-        mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+        sendWindowContentChangedOnView();
     }
 
     /**
@@ -326,6 +328,10 @@
 
         if (event.getAction() == MotionEvent.ACTION_HOVER_EXIT) {
             mIsHovering = false;
+            if (mLastHoverId != View.NO_ID) {
+                sendAccessibilityEvent(mLastHoverId, AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
+                mLastHoverId = View.NO_ID;
+            }
             if (mPendingScrollToMakeNodeVisible) {
                 nativeScrollToMakeNodeVisible(
                         mNativeObj, mAccessibilityFocusId);
@@ -361,7 +367,7 @@
 
         // Invalidate the container view, since the chrome accessibility tree is now
         // ready and listed as the child of the container view.
-        mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+        sendWindowContentChangedOnView();
 
         // (Re-) focus focused element, since we weren't able to create an
         // AccessibilityNodeInfo for this element before.
@@ -516,6 +522,39 @@
         moveAccessibilityFocusToId(newAccessibilityFocusId);
     }
 
+    /**
+     * Send a WINDOW_CONTENT_CHANGED event after a short delay. This helps throttle such
+     * events from firing too quickly during animations, for example.
+     */
+    @CalledByNative
+    private void sendDelayedWindowContentChangedEvent() {
+        if (mSendWindowContentChangedRunnable != null) return;
+
+        mSendWindowContentChangedRunnable = new Runnable() {
+            @Override
+            public void run() {
+                sendWindowContentChangedOnView();
+            }
+        };
+
+        mView.postDelayed(mSendWindowContentChangedRunnable, WINDOW_CONTENT_CHANGED_DELAY_MS);
+    }
+
+    private void sendWindowContentChangedOnView() {
+        // This can be called from a timeout, so we need to make sure we're still valid.
+        if (mNativeObj == 0 || mContentViewCore == null || mView == null) return;
+
+        if (mSendWindowContentChangedRunnable != null) {
+            mView.removeCallbacks(mSendWindowContentChangedRunnable);
+            mSendWindowContentChangedRunnable = null;
+        }
+        mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+    }
+
+    private void sendWindowContentChangedOnVirtualView(int virtualViewId) {
+        sendAccessibilityEvent(virtualViewId, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+    }
+
     private void sendAccessibilityEvent(int virtualViewId, int eventType) {
         // The container view is indicated by a virtualViewId of NO_ID; post these events directly
         // since there's no web-specific information to attach.
@@ -656,9 +695,9 @@
         int rootId = nativeGetRootId(mNativeObj);
         if (rootId != mCurrentRootId) {
             mCurrentRootId = rootId;
-            mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+            sendWindowContentChangedOnView();
         } else {
-            sendAccessibilityEvent(id, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+            sendWindowContentChangedOnVirtualView(id);
         }
     }
 
@@ -668,7 +707,7 @@
         mAccessibilityFocusRect = null;
         mUserHasTouchExplored = false;
         // Invalidate the host, since its child is now gone.
-        mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+        sendWindowContentChangedOnView();
     }
 
     @CalledByNative
@@ -684,10 +723,13 @@
     @CalledByNative
     private void handleHover(int id) {
         if (mLastHoverId == id) return;
+        if (!mIsHovering) return;
 
         // Always send the ENTER and then the EXIT event, to match a standard Android View.
         sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
-        sendAccessibilityEvent(mLastHoverId, AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
+        if (mLastHoverId != View.NO_ID) {
+            sendAccessibilityEvent(mLastHoverId, AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
+        }
         mLastHoverId = id;
     }
 
diff --git a/content/public/browser/android/download_controller_android.h b/content/public/browser/android/download_controller_android.h
index 08fe6f7..e048afd 100644
--- a/content/public/browser/android/download_controller_android.h
+++ b/content/public/browser/android/download_controller_android.h
@@ -57,6 +57,10 @@
   // Called by unit test to approve or disapprove file access request.
   virtual void SetApproveFileAccessRequestForTesting(bool approve) {};
 
+  // Called to set the default download file name if it cannot be resolved
+  // from url and content disposition
+  virtual void SetDefaultDownloadFileName(const std::string& file_name) {}
+
  protected:
   ~DownloadControllerAndroid() override {};
   static DownloadControllerAndroid* download_controller_;
diff --git a/content/public/browser/ax_event_notification_details.cc b/content/public/browser/ax_event_notification_details.cc
index ead942c..703f76f 100644
--- a/content/public/browser/ax_event_notification_details.cc
+++ b/content/public/browser/ax_event_notification_details.cc
@@ -12,6 +12,9 @@
       ax_tree_id(-1) {
 }
 
+AXEventNotificationDetails::AXEventNotificationDetails(
+    const AXEventNotificationDetails& other) = default;
+
 AXEventNotificationDetails::~AXEventNotificationDetails() {}
 
 }  // namespace content
diff --git a/content/public/browser/ax_event_notification_details.h b/content/public/browser/ax_event_notification_details.h
index 50eeeb0..7054452e 100644
--- a/content/public/browser/ax_event_notification_details.h
+++ b/content/public/browser/ax_event_notification_details.h
@@ -19,6 +19,7 @@
 struct CONTENT_EXPORT AXEventNotificationDetails {
  public:
   AXEventNotificationDetails();
+  AXEventNotificationDetails(const AXEventNotificationDetails& other);
   ~AXEventNotificationDetails();
 
   ui::AXTreeUpdate update;
diff --git a/content/public/browser/browser_message_filter.cc b/content/public/browser/browser_message_filter.cc
index b2482cd..76a0e049 100644
--- a/content/public/browser/browser_message_filter.cc
+++ b/content/public/browser/browser_message_filter.cc
@@ -69,11 +69,6 @@
       return DispatchMessage(message);
     }
 
-    if (thread == BrowserThread::UI &&
-        !BrowserMessageFilter::CheckCanDispatchOnUI(message, filter_.get())) {
-      return true;
-    }
-
     BrowserThread::PostTask(
         thread, FROM_HERE,
         base::Bind(
@@ -157,31 +152,6 @@
   return nullptr;
 }
 
-bool BrowserMessageFilter::CheckCanDispatchOnUI(const IPC::Message& message,
-                                                IPC::Sender* sender) {
-#if defined(OS_WIN)
-  // On Windows there's a potential deadlock with sync messsages going in
-  // a circle from browser -> plugin -> renderer -> browser.
-  // On Linux we can avoid this by avoiding sync messages from browser->plugin.
-  // On Mac we avoid this by not supporting windowed plugins.
-  if (message.is_sync() && !message.is_caller_pumping_messages()) {
-    // NOTE: IF YOU HIT THIS ASSERT, THE SOLUTION IS ALMOST NEVER TO RUN A
-    // NESTED MESSAGE LOOP IN THE RENDERER!!!
-    // That introduces reentrancy which causes hard to track bugs.  You should
-    // find a way to either turn this into an asynchronous message, or one
-    // that can be answered on the IO thread.
-    NOTREACHED() << "Can't send sync messages to UI thread without pumping "
-        "messages in the renderer or else deadlocks can occur if the page "
-        "has windowed plugins! (message type " << message.type() << ")";
-    IPC::Message* reply = IPC::SyncMessage::GenerateReply(&message);
-    reply->set_reply_error();
-    sender->Send(reply);
-    return false;
-  }
-#endif
-  return true;
-}
-
 void BrowserMessageFilter::ShutdownForBadMessage() {
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   if (command_line->HasSwitch(switches::kDisableKillAfterBadIPC))
diff --git a/content/public/browser/browser_message_filter.h b/content/public/browser/browser_message_filter.h
index 8f652ec..22b0e7d 100644
--- a/content/public/browser/browser_message_filter.h
+++ b/content/public/browser/browser_message_filter.h
@@ -92,11 +92,6 @@
     peer_process_ = std::move(peer_process);
   }
 
-  // Checks that the given message can be dispatched on the UI thread, depending
-  // on the platform.  If not, returns false and an error ot the sender.
-  static bool CheckCanDispatchOnUI(const IPC::Message& message,
-                                   IPC::Sender* sender);
-
   // Called by bad_message.h helpers if a message couldn't be deserialized. This
   // kills the renderer.  Can be called on any thread.  This doesn't log the
   // error details to UMA, so use the bad_message.h for your module instead.
diff --git a/content/public/browser/download_manager.h b/content/public/browser/download_manager.h
index 16d161b..b53151ac 100644
--- a/content/public/browser/download_manager.h
+++ b/content/public/browser/download_manager.h
@@ -114,17 +114,14 @@
       scoped_ptr<ByteStreamReader> stream,
       const DownloadUrlParameters::OnStartedCallback& on_started) = 0;
 
-  // Remove downloads which are same-origin with the given origin and pertain to
-  // the given time constraints. (See |RemoveDownloadsBetween|.)
-  virtual int RemoveDownloadsByOriginAndTime(const url::Origin& origin,
-                                             base::Time remove_begin,
-                                             base::Time remove_end) = 0;
-
-  // Remove downloads after remove_begin (inclusive) and before remove_end
-  // (exclusive). You may pass in null Time values to do an unbounded delete
-  // in either direction.
-  virtual int RemoveDownloadsBetween(base::Time remove_begin,
-                                     base::Time remove_end) = 0;
+  // Remove downloads whose URLs match the |url_filter| and are within
+  // the given time constraints - after remove_begin (inclusive) and before
+  // remove_end (exclusive). You may pass in null Time values to do an unbounded
+  // delete in either direction.
+  virtual int RemoveDownloadsByURLAndTime(
+      const base::Callback<bool(const GURL&)>& url_filter,
+      base::Time remove_begin,
+      base::Time remove_end) = 0;
 
   // Remove all downloads will delete all downloads. The number of downloads
   // deleted is returned back to the caller.
diff --git a/content/public/browser/navigation_details.cc b/content/public/browser/navigation_details.cc
index 19d62998..88f247f 100644
--- a/content/public/browser/navigation_details.cc
+++ b/content/public/browser/navigation_details.cc
@@ -16,4 +16,7 @@
       http_status_code(0) {
 }
 
+LoadCommittedDetails::LoadCommittedDetails(const LoadCommittedDetails& other) =
+    default;
+
 }  // namespace content
diff --git a/content/public/browser/navigation_details.h b/content/public/browser/navigation_details.h
index b344105..dc473878 100644
--- a/content/public/browser/navigation_details.h
+++ b/content/public/browser/navigation_details.h
@@ -22,6 +22,7 @@
   // By default, the entry will be filled according to a new main frame
   // navigation.
   LoadCommittedDetails();
+  LoadCommittedDetails(const LoadCommittedDetails& other);
 
   // The committed entry. This will be the active entry in the controller.
   NavigationEntry* entry;
diff --git a/content/public/browser/page_navigator.cc b/content/public/browser/page_navigator.cc
index c919ee2..40225e1a 100644
--- a/content/public/browser/page_navigator.cc
+++ b/content/public/browser/page_navigator.cc
@@ -51,6 +51,8 @@
       user_gesture(true) {
 }
 
+OpenURLParams::OpenURLParams(const OpenURLParams& other) = default;
+
 OpenURLParams::~OpenURLParams() {
 }
 
diff --git a/content/public/browser/page_navigator.h b/content/public/browser/page_navigator.h
index 3e06d568..51f0234 100644
--- a/content/public/browser/page_navigator.h
+++ b/content/public/browser/page_navigator.h
@@ -37,6 +37,7 @@
                 WindowOpenDisposition disposition,
                 ui::PageTransition transition,
                 bool is_renderer_initiated);
+  OpenURLParams(const OpenURLParams& other);
   ~OpenURLParams();
 
   // The URL/referrer to be opened.
diff --git a/content/public/browser/service_worker_usage_info.cc b/content/public/browser/service_worker_usage_info.cc
index 6d72ea3f..fdc3830b8 100644
--- a/content/public/browser/service_worker_usage_info.cc
+++ b/content/public/browser/service_worker_usage_info.cc
@@ -16,6 +16,9 @@
 ServiceWorkerUsageInfo::ServiceWorkerUsageInfo() : total_size_bytes(0) {
 }
 
+ServiceWorkerUsageInfo::ServiceWorkerUsageInfo(
+    const ServiceWorkerUsageInfo& other) = default;
+
 ServiceWorkerUsageInfo::~ServiceWorkerUsageInfo() {
 }
 
diff --git a/content/public/browser/service_worker_usage_info.h b/content/public/browser/service_worker_usage_info.h
index 4c69d95c..6e50cc9 100644
--- a/content/public/browser/service_worker_usage_info.h
+++ b/content/public/browser/service_worker_usage_info.h
@@ -19,6 +19,7 @@
   ServiceWorkerUsageInfo(const GURL& origin, const std::vector<GURL>& scopes);
   ServiceWorkerUsageInfo(const GURL& origin);
   ServiceWorkerUsageInfo();
+  ServiceWorkerUsageInfo(const ServiceWorkerUsageInfo& other);
   ~ServiceWorkerUsageInfo();
 
   // The origin this object is describing.
diff --git a/content/public/browser/speech_recognition_session_context.cc b/content/public/browser/speech_recognition_session_context.cc
index b185be8..1e4ae1c 100644
--- a/content/public/browser/speech_recognition_session_context.cc
+++ b/content/public/browser/speech_recognition_session_context.cc
@@ -18,6 +18,9 @@
       request_id(0) {
 }
 
+SpeechRecognitionSessionContext::SpeechRecognitionSessionContext(
+    const SpeechRecognitionSessionContext& other) = default;
+
 SpeechRecognitionSessionContext::~SpeechRecognitionSessionContext() {
 }
 
diff --git a/content/public/browser/speech_recognition_session_context.h b/content/public/browser/speech_recognition_session_context.h
index 9493189..d868c9d 100644
--- a/content/public/browser/speech_recognition_session_context.h
+++ b/content/public/browser/speech_recognition_session_context.h
@@ -22,6 +22,7 @@
 // SpeechRecognitionManager::LookupSessionByContext methods).
 struct CONTENT_EXPORT SpeechRecognitionSessionContext {
   SpeechRecognitionSessionContext();
+  SpeechRecognitionSessionContext(const SpeechRecognitionSessionContext& other);
   ~SpeechRecognitionSessionContext();
 
   int render_process_id;
diff --git a/content/public/browser/web_contents.cc b/content/public/browser/web_contents.cc
index 1b6d8a68..d4b5fd0 100644
--- a/content/public/browser/web_contents.cc
+++ b/content/public/browser/web_contents.cc
@@ -28,6 +28,8 @@
       context(nullptr),
       renderer_initiated_creation(false) {}
 
+WebContents::CreateParams::CreateParams(const CreateParams& other) = default;
+
 WebContents::CreateParams::~CreateParams() {
 }
 
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index c1babd64..4f8a3f2 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -89,6 +89,7 @@
  public:
   struct CONTENT_EXPORT CreateParams {
     explicit CreateParams(BrowserContext* context);
+    CreateParams(const CreateParams& other);
     ~CreateParams();
     CreateParams(BrowserContext* context, SiteInstance* site);
 
diff --git a/content/public/common/appcache_info.h b/content/public/common/appcache_info.h
index 75b5499..a8f186d 100644
--- a/content/public/common/appcache_info.h
+++ b/content/public/common/appcache_info.h
@@ -32,6 +32,7 @@
 
 struct CONTENT_EXPORT AppCacheInfo {
   AppCacheInfo();
+  AppCacheInfo(const AppCacheInfo& other);
   ~AppCacheInfo();
 
   GURL manifest_url;
diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h
index e3a1dcf..b0cf1d1 100644
--- a/content/public/common/common_param_traits_macros.h
+++ b/content/public/common/common_param_traits_macros.h
@@ -142,7 +142,6 @@
   IPC_STRUCT_TRAITS_MEMBER(hyperlink_auditing_enabled)
   IPC_STRUCT_TRAITS_MEMBER(allow_universal_access_from_file_urls)
   IPC_STRUCT_TRAITS_MEMBER(allow_file_access_from_file_urls)
-  IPC_STRUCT_TRAITS_MEMBER(webaudio_enabled)
   IPC_STRUCT_TRAITS_MEMBER(experimental_webgl_enabled)
   IPC_STRUCT_TRAITS_MEMBER(pepper_3d_enabled)
   IPC_STRUCT_TRAITS_MEMBER(inert_visual_viewport)
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 9a396b5..5582e9e1 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -14,6 +14,11 @@
 const base::Feature kBrotliEncoding{"brotli-encoding",
                                     base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enables the credential management API:
+// https://w3c.github.io/webappsec-credential-management/
+const base::Feature kCredentialManagementAPI{"CredentialManagementAPI",
+                                             base::FEATURE_ENABLED_BY_DEFAULT};
+
 // Downloads resumption will be controllable via a flag until it's enabled
 // permanently. See https://crbug.com/7648
 const base::Feature kDownloadResumption{"DownloadResumption",
@@ -29,6 +34,10 @@
     "OptimizeForSmallResource",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Throttle Blink's rendering pipeline based on frame visibility.
+const base::Feature kRenderingPipelineThrottling{
+    "RenderingPipelineThrottling", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Scrolls to compensate for layout movements (bit.ly/scroll-anchoring).
 const base::Feature kScrollAnchoring{"ScrollAnchoring",
                                      base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index ace7c61..92681729 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -17,9 +17,11 @@
 // All features in alphabetical order. The features should be documented
 // alongside the definition of their values in the .cc file.
 CONTENT_EXPORT extern const base::Feature kBrotliEncoding;
+CONTENT_EXPORT extern const base::Feature kCredentialManagementAPI;
 CONTENT_EXPORT extern const base::Feature kDownloadResumption;
 CONTENT_EXPORT extern const base::Feature kExperimentalFramework;
 CONTENT_EXPORT extern const base::Feature kOptimizeIPCForSmallResource;
+CONTENT_EXPORT extern const base::Feature kRenderingPipelineThrottling;
 CONTENT_EXPORT extern const base::Feature kScrollAnchoring;
 CONTENT_EXPORT extern const base::Feature kTokenBinding;
 CONTENT_EXPORT extern const base::Feature kUpdateRendererPriorityOnStartup;
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index f4749f7f..e54fa00 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -324,9 +324,6 @@
 // Only valid if GPU rasterization is enabled as well.
 const char kEnableDistanceFieldText[]       = "enable-distance-field-text";
 
-// Enable the experimental Credential Manager JavaScript API.
-const char kEnableCredentialManagerAPI[]    = "enable-credential-manager-api";
-
 // Enable the creation of compositing layers when it would prevent LCD text.
 const char kEnablePreferCompositingToLCDText[] =
     "enable-prefer-compositing-to-lcd-text";
@@ -801,6 +798,12 @@
 // TODO(gab): Get rid of this switch entirely.
 const char kSkipGpuDataLoading[]            = "skip-gpu-data-loading";
 
+// Skips reencoding bitmaps as PNGs when the encoded data is unavailable
+// during SKP capture.  This allows for obtaining an accurate sample of
+// the types of images on the web, rather than being weighted towards PNGs
+// that we have encoded ourselves.
+const char kSkipReencodingOnSKPCapture[]    = "skip-reencoding-on-skp-capture";
+
 // Specifies if the browser should start in fullscreen mode, like if the user
 // had pressed F11 right after startup.
 const char kStartFullscreen[] = "start-fullscreen";
@@ -969,9 +972,6 @@
 const char kEnableAggressiveDOMStorageFlushing[] =
     "enable-aggressive-domstorage-flushing";
 
-// Disable web audio API.
-const char kDisableWebAudio[]               = "disable-webaudio";
-
 // Enable audio for desktop share.
 const char kEnableAudioSupportForDesktopShare[] =
     "enable-audio-support-for-desktop-share";
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index e9b4619c..a4a32ba 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -102,7 +102,6 @@
 extern const char kEnable2dCanvasClipAntialiasing[];
 CONTENT_EXPORT extern const char kEnableAggressiveDOMStorageFlushing[];
 CONTENT_EXPORT extern const char kEnableAudioSupportForDesktopShare[];
-CONTENT_EXPORT extern const char kEnableCredentialManagerAPI[];
 CONTENT_EXPORT extern const char kEnablePreferCompositingToLCDText[];
 CONTENT_EXPORT extern const char kEnableBlinkFeatures[];
 CONTENT_EXPORT extern const char kEnableBrowserSideNavigation[];
@@ -224,6 +223,7 @@
 CONTENT_EXPORT extern const char kSingleProcess[];
 CONTENT_EXPORT extern const char kSitePerProcess[];
 CONTENT_EXPORT extern const char kSkipGpuDataLoading[];
+extern const char kSkipReencodingOnSKPCapture[];
 CONTENT_EXPORT extern const char kStartFullscreen[];
 CONTENT_EXPORT extern const char kStatsCollectionController[];
 CONTENT_EXPORT extern const char kTabCaptureDownscaleQuality[];
@@ -280,8 +280,6 @@
 CONTENT_EXPORT extern const char kRendererWaitForJavaDebugger[];
 #endif
 
-CONTENT_EXPORT extern const char kDisableWebAudio[];
-
 #if defined(OS_CHROMEOS)
 CONTENT_EXPORT extern const char kDisablePanelFitting[];
 CONTENT_EXPORT extern const char kDisableVaapiAcceleratedVideoEncode[];
diff --git a/content/public/common/context_menu_params.cc b/content/public/common/context_menu_params.cc
index ebd5455..e29305b 100644
--- a/content/public/common/context_menu_params.cc
+++ b/content/public/common/context_menu_params.cc
@@ -35,6 +35,8 @@
       input_field_type(blink::WebContextMenuData::InputFieldTypeNone) {
 }
 
+ContextMenuParams::ContextMenuParams(const ContextMenuParams& other) = default;
+
 ContextMenuParams::~ContextMenuParams() {
 }
 
diff --git a/content/public/common/context_menu_params.h b/content/public/common/context_menu_params.h
index 46510e8..3bf6fce0 100644
--- a/content/public/common/context_menu_params.h
+++ b/content/public/common/context_menu_params.h
@@ -54,6 +54,7 @@
 //              could be used for more contextual actions.
 struct CONTENT_EXPORT ContextMenuParams {
   ContextMenuParams();
+  ContextMenuParams(const ContextMenuParams& other);
   ~ContextMenuParams();
 
   // This is the type of Context Node that the context menu was invoked on.
diff --git a/content/public/common/drop_data.cc b/content/public/common/drop_data.cc
index 5f9466b3..c3bb925 100644
--- a/content/public/common/drop_data.cc
+++ b/content/public/common/drop_data.cc
@@ -10,6 +10,8 @@
     : did_originate_from_renderer(false),
       referrer_policy(blink::WebReferrerPolicyDefault) {}
 
+DropData::DropData(const DropData& other) = default;
+
 DropData::~DropData() {
 }
 
diff --git a/content/public/common/drop_data.h b/content/public/common/drop_data.h
index e589184b..fce6db1 100644
--- a/content/public/common/drop_data.h
+++ b/content/public/common/drop_data.h
@@ -33,6 +33,7 @@
   };
 
   DropData();
+  DropData(const DropData& other);
   ~DropData();
 
   // Whether this drag originated from a renderer.
diff --git a/content/public/common/favicon_url.cc b/content/public/common/favicon_url.cc
index 68ba481b..80debff6 100644
--- a/content/public/common/favicon_url.cc
+++ b/content/public/common/favicon_url.cc
@@ -15,6 +15,8 @@
                        const std::vector<gfx::Size>& sizes)
     : icon_url(url), icon_type(type), icon_sizes(sizes) {}
 
+FaviconURL::FaviconURL(const FaviconURL& other) = default;
+
 FaviconURL::~FaviconURL() {
 }
 
diff --git a/content/public/common/favicon_url.h b/content/public/common/favicon_url.h
index 43770c2b8..349fc878 100644
--- a/content/public/common/favicon_url.h
+++ b/content/public/common/favicon_url.h
@@ -28,6 +28,7 @@
   FaviconURL(const GURL& url,
              IconType type,
              const std::vector<gfx::Size>& sizes);
+  FaviconURL(const FaviconURL& other);
   ~FaviconURL();
 
   // The url of the icon.
diff --git a/content/public/common/file_chooser_file_info.cc b/content/public/common/file_chooser_file_info.cc
index 9f9a028..8605b12 100644
--- a/content/public/common/file_chooser_file_info.cc
+++ b/content/public/common/file_chooser_file_info.cc
@@ -9,6 +9,9 @@
 FileChooserFileInfo::FileChooserFileInfo() : length(0), is_directory(false) {
 }
 
+FileChooserFileInfo::FileChooserFileInfo(const FileChooserFileInfo& other) =
+    default;
+
 FileChooserFileInfo::~FileChooserFileInfo() {
 }
 
diff --git a/content/public/common/file_chooser_file_info.h b/content/public/common/file_chooser_file_info.h
index d2bb5e0..0f33823 100644
--- a/content/public/common/file_chooser_file_info.h
+++ b/content/public/common/file_chooser_file_info.h
@@ -17,6 +17,7 @@
 // Result of file chooser.
 struct CONTENT_EXPORT FileChooserFileInfo {
   FileChooserFileInfo();
+  FileChooserFileInfo(const FileChooserFileInfo& other);
   ~FileChooserFileInfo();
 
   base::FilePath file_path;
diff --git a/content/public/common/file_chooser_params.cc b/content/public/common/file_chooser_params.cc
index 97de9e3..da1ca6f 100644
--- a/content/public/common/file_chooser_params.cc
+++ b/content/public/common/file_chooser_params.cc
@@ -9,6 +9,8 @@
 FileChooserParams::FileChooserParams() : mode(Open), need_local_path(true) {
 }
 
+FileChooserParams::FileChooserParams(const FileChooserParams& other) = default;
+
 FileChooserParams::~FileChooserParams() {
 }
 
diff --git a/content/public/common/file_chooser_params.h b/content/public/common/file_chooser_params.h
index ef43f7b..c189785 100644
--- a/content/public/common/file_chooser_params.h
+++ b/content/public/common/file_chooser_params.h
@@ -18,6 +18,7 @@
 // Struct used by WebContentsDelegate.
 struct CONTENT_EXPORT FileChooserParams {
   FileChooserParams();
+  FileChooserParams(const FileChooserParams& other);
   ~FileChooserParams();
 
   enum Mode {
diff --git a/content/public/common/frame_navigate_params.cc b/content/public/common/frame_navigate_params.cc
index bcc90b5e..d15f4c1 100644
--- a/content/public/common/frame_navigate_params.cc
+++ b/content/public/common/frame_navigate_params.cc
@@ -15,6 +15,9 @@
       should_update_history(false) {
 }
 
+FrameNavigateParams::FrameNavigateParams(const FrameNavigateParams& other) =
+    default;
+
 FrameNavigateParams::~FrameNavigateParams() {
 }
 
diff --git a/content/public/common/frame_navigate_params.h b/content/public/common/frame_navigate_params.h
index 2c80fd29..3b8dd90 100644
--- a/content/public/common/frame_navigate_params.h
+++ b/content/public/common/frame_navigate_params.h
@@ -21,6 +21,7 @@
 // Struct used by WebContentsObserver.
 struct CONTENT_EXPORT FrameNavigateParams {
   FrameNavigateParams();
+  FrameNavigateParams(const FrameNavigateParams& other);
   ~FrameNavigateParams();
 
   // Page ID of this navigation. The renderer creates a new unique page ID
diff --git a/content/public/common/geoposition.cc b/content/public/common/geoposition.cc
index 3a0f1f08..d885d4e 100644
--- a/content/public/common/geoposition.cc
+++ b/content/public/common/geoposition.cc
@@ -29,6 +29,8 @@
       error_code(ERROR_CODE_NONE) {
 }
 
+Geoposition::Geoposition(const Geoposition& other) = default;
+
 bool Geoposition::Validate() const {
   return latitude >= -90. && latitude <= 90. &&
          longitude >= -180. && longitude <= 180. &&
diff --git a/content/public/common/geoposition.h b/content/public/common/geoposition.h
index 0bcb839e..23b2907 100644
--- a/content/public/common/geoposition.h
+++ b/content/public/common/geoposition.h
@@ -32,6 +32,8 @@
   // error code is set to ERROR_CODE_NONE.
   Geoposition();
 
+  Geoposition(const Geoposition& other);
+
   // A valid fix has a valid latitude, longitude, accuracy and timestamp.
   bool Validate() const;
 
diff --git a/content/public/common/manifest.cc b/content/public/common/manifest.cc
index 744be0e..e38a904 100644
--- a/content/public/common/manifest.cc
+++ b/content/public/common/manifest.cc
@@ -19,6 +19,8 @@
     : density(kDefaultDensity) {
 }
 
+Manifest::Icon::Icon(const Icon& other) = default;
+
 Manifest::Icon::~Icon() {
 }
 
@@ -36,6 +38,8 @@
       background_color(Manifest::kInvalidOrMissingColor) {
 }
 
+Manifest::Manifest(const Manifest& other) = default;
+
 Manifest::~Manifest() {
 }
 
diff --git a/content/public/common/manifest.h b/content/public/common/manifest.h
index 35671b8..7dc15ca 100644
--- a/content/public/common/manifest.h
+++ b/content/public/common/manifest.h
@@ -27,6 +27,7 @@
   // http://w3c.github.io/manifest/#dfn-icon-object
   struct CONTENT_EXPORT Icon {
     Icon();
+    Icon(const Icon& other);
     ~Icon();
 
     // MUST be a valid url. If an icon doesn't have a valid URL, it will not be
@@ -71,6 +72,7 @@
   };
 
   Manifest();
+  Manifest(const Manifest& other);
   ~Manifest();
 
   // Returns whether this Manifest had no attribute set. A newly created
diff --git a/content/public/common/media_stream_request.cc b/content/public/common/media_stream_request.cc
index 72a4b16..d1dd847e 100644
--- a/content/public/common/media_stream_request.cc
+++ b/content/public/common/media_stream_request.cc
@@ -57,6 +57,8 @@
       input(sample_rate, channel_layout, frames_per_buffer) {
 }
 
+MediaStreamDevice::MediaStreamDevice(const MediaStreamDevice& other) = default;
+
 MediaStreamDevice::~MediaStreamDevice() {}
 
 bool MediaStreamDevice::IsEqual(const MediaStreamDevice& second) const {
@@ -96,6 +98,9 @@
       frames_per_buffer(frames_per_buffer),
       effects() {}
 
+MediaStreamDevice::AudioDeviceParameters::AudioDeviceParameters(
+    const AudioDeviceParameters& other) = default;
+
 MediaStreamDevice::AudioDeviceParameters::~AudioDeviceParameters() {}
 
 MediaStreamRequest::MediaStreamRequest(
@@ -122,6 +127,9 @@
       all_ancestors_have_same_origin(false) {
 }
 
+MediaStreamRequest::MediaStreamRequest(const MediaStreamRequest& other) =
+    default;
+
 MediaStreamRequest::~MediaStreamRequest() {}
 
 }  // namespace content
diff --git a/content/public/common/media_stream_request.h b/content/public/common/media_stream_request.h
index c4b6a7e..7486fd59 100644
--- a/content/public/common/media_stream_request.h
+++ b/content/public/common/media_stream_request.h
@@ -106,6 +106,8 @@
       int channel_layout,
       int frames_per_buffer);
 
+  MediaStreamDevice(const MediaStreamDevice& other);
+
   ~MediaStreamDevice();
 
   bool IsEqual(const MediaStreamDevice& second) const;
@@ -134,6 +136,7 @@
     AudioDeviceParameters(int sample_rate,
                           int channel_layout,
                           int frames_per_buffer);
+    AudioDeviceParameters(const AudioDeviceParameters& other);
 
     ~AudioDeviceParameters();
 
@@ -203,6 +206,8 @@
       MediaStreamType audio_type,
       MediaStreamType video_type);
 
+  MediaStreamRequest(const MediaStreamRequest& other);
+
   ~MediaStreamRequest();
 
   // This is the render process id for the renderer associated with generating
diff --git a/content/public/common/notification_resources.cc b/content/public/common/notification_resources.cc
index b4ea9ab..75619a0a 100644
--- a/content/public/common/notification_resources.cc
+++ b/content/public/common/notification_resources.cc
@@ -8,6 +8,9 @@
 
 NotificationResources::NotificationResources() {}
 
+NotificationResources::NotificationResources(
+    const NotificationResources& other) = default;
+
 NotificationResources::~NotificationResources() {}
 
 }  // namespace content
diff --git a/content/public/common/notification_resources.h b/content/public/common/notification_resources.h
index 23c5477..c3b938d6 100644
--- a/content/public/common/notification_resources.h
+++ b/content/public/common/notification_resources.h
@@ -15,6 +15,7 @@
 // Structure to hold the resources associated with a Web Notification.
 struct CONTENT_EXPORT NotificationResources {
   NotificationResources();
+  NotificationResources(const NotificationResources& other);
   ~NotificationResources();
 
   // Main icon for the notification. The bitmap may be empty if the developer
diff --git a/content/public/common/pepper_plugin_info.cc b/content/public/common/pepper_plugin_info.cc
index 25b00c3..03f83fd0 100644
--- a/content/public/common/pepper_plugin_info.cc
+++ b/content/public/common/pepper_plugin_info.cc
@@ -21,6 +21,8 @@
       permissions(0) {
 }
 
+PepperPluginInfo::PepperPluginInfo(const PepperPluginInfo& other) = default;
+
 PepperPluginInfo::~PepperPluginInfo() {
 }
 
diff --git a/content/public/common/pepper_plugin_info.h b/content/public/common/pepper_plugin_info.h
index 253d821..34dc4861 100644
--- a/content/public/common/pepper_plugin_info.h
+++ b/content/public/common/pepper_plugin_info.h
@@ -37,6 +37,7 @@
   };
 
   PepperPluginInfo();
+  PepperPluginInfo(const PepperPluginInfo& other);
   ~PepperPluginInfo();
 
   WebPluginInfo ToWebPluginInfo() const;
diff --git a/content/public/common/platform_notification_data.cc b/content/public/common/platform_notification_data.cc
index dba6c16..8c4d131 100644
--- a/content/public/common/platform_notification_data.cc
+++ b/content/public/common/platform_notification_data.cc
@@ -12,6 +12,9 @@
 
 PlatformNotificationData::PlatformNotificationData() {}
 
+PlatformNotificationData::PlatformNotificationData(
+    const PlatformNotificationData& other) = default;
+
 PlatformNotificationData::~PlatformNotificationData() {}
 
 }  // namespace content
diff --git a/content/public/common/platform_notification_data.h b/content/public/common/platform_notification_data.h
index defb7aa..a704efa 100644
--- a/content/public/common/platform_notification_data.h
+++ b/content/public/common/platform_notification_data.h
@@ -37,6 +37,7 @@
 // synchronized with the WebNotificationData structure defined in the Blink API.
 struct CONTENT_EXPORT PlatformNotificationData {
   PlatformNotificationData();
+  PlatformNotificationData(const PlatformNotificationData& other);
   ~PlatformNotificationData();
 
   // The maximum size of developer-provided data to be stored in the |data|
diff --git a/content/public/common/renderer_preferences.cc b/content/public/common/renderer_preferences.cc
index 9bb824cc..2a9f8676 100644
--- a/content/public/common/renderer_preferences.cc
+++ b/content/public/common/renderer_preferences.cc
@@ -52,6 +52,9 @@
       , default_font_size(0)
 {}
 
+RendererPreferences::RendererPreferences(const RendererPreferences& other) =
+    default;
+
 RendererPreferences::~RendererPreferences() { }
 
 }  // namespace content
diff --git a/content/public/common/renderer_preferences.h b/content/public/common/renderer_preferences.h
index 975394a7..2b085ae 100644
--- a/content/public/common/renderer_preferences.h
+++ b/content/public/common/renderer_preferences.h
@@ -35,6 +35,7 @@
 
 struct CONTENT_EXPORT RendererPreferences {
   RendererPreferences();
+  RendererPreferences(const RendererPreferences& other);
   ~RendererPreferences();
 
   // Whether the renderer's current browser context accept drops from the OS
diff --git a/content/public/common/resource_response_info.cc b/content/public/common/resource_response_info.cc
index f05ee19..39131cf 100644
--- a/content/public/common/resource_response_info.cc
+++ b/content/public/common/resource_response_info.cc
@@ -25,6 +25,9 @@
           blink::WebServiceWorkerResponseTypeDefault),
       is_using_lofi(false) {}
 
+ResourceResponseInfo::ResourceResponseInfo(const ResourceResponseInfo& other) =
+    default;
+
 ResourceResponseInfo::~ResourceResponseInfo() {
 }
 
diff --git a/content/public/common/resource_response_info.h b/content/public/common/resource_response_info.h
index e7b7c7a7..340407ec 100644
--- a/content/public/common/resource_response_info.h
+++ b/content/public/common/resource_response_info.h
@@ -27,6 +27,7 @@
 // in resource_response.cc.
 struct ResourceResponseInfo {
   CONTENT_EXPORT ResourceResponseInfo();
+  CONTENT_EXPORT ResourceResponseInfo(const ResourceResponseInfo& other);
   CONTENT_EXPORT ~ResourceResponseInfo();
 
   // The time at which the request was made that resulted in this response.
diff --git a/content/public/common/speech_recognition_result.cc b/content/public/common/speech_recognition_result.cc
index af05fc7e..9f4c2ca 100644
--- a/content/public/common/speech_recognition_result.cc
+++ b/content/public/common/speech_recognition_result.cc
@@ -10,6 +10,9 @@
     : is_provisional(false) {
 }
 
+SpeechRecognitionResult::SpeechRecognitionResult(
+    const SpeechRecognitionResult& other) = default;
+
 SpeechRecognitionResult::~SpeechRecognitionResult() {
 }
 
diff --git a/content/public/common/speech_recognition_result.h b/content/public/common/speech_recognition_result.h
index 980abdd..6c3f2ab3 100644
--- a/content/public/common/speech_recognition_result.h
+++ b/content/public/common/speech_recognition_result.h
@@ -33,6 +33,7 @@
   bool is_provisional;
 
   SpeechRecognitionResult();
+  SpeechRecognitionResult(const SpeechRecognitionResult& other);
   ~SpeechRecognitionResult();
 };
 
diff --git a/content/public/common/ssl_status.cc b/content/public/common/ssl_status.cc
index eaaed41..3490a81c 100644
--- a/content/public/common/ssl_status.cc
+++ b/content/public/common/ssl_status.cc
@@ -32,6 +32,8 @@
       content_status(NORMAL_CONTENT),
       signed_certificate_timestamp_ids(signed_certificate_timestamp_ids) {}
 
+SSLStatus::SSLStatus(const SSLStatus& other) = default;
+
 SSLStatus::~SSLStatus() {}
 
 }  // namespace content
diff --git a/content/public/common/ssl_status.h b/content/public/common/ssl_status.h
index bb3501c..79c4ef40 100644
--- a/content/public/common/ssl_status.h
+++ b/content/public/common/ssl_status.h
@@ -39,6 +39,7 @@
             const SignedCertificateTimestampIDStatusList&
                 signed_certificate_timestamp_ids,
             const net::SSLInfo& ssl_info);
+  SSLStatus(const SSLStatus& other);
   ~SSLStatus();
 
   bool Equals(const SSLStatus& status) const {
diff --git a/content/public/common/web_preferences.cc b/content/public/common/web_preferences.cc
index 86c522af..d44642f 100644
--- a/content/public/common/web_preferences.cc
+++ b/content/public/common/web_preferences.cc
@@ -85,7 +85,6 @@
       hyperlink_auditing_enabled(true),
       allow_universal_access_from_file_urls(false),
       allow_file_access_from_file_urls(false),
-      webaudio_enabled(false),
       experimental_webgl_enabled(false),
       pepper_3d_enabled(false),
       flash_3d_enabled(true),
@@ -209,6 +208,8 @@
       base::ASCIIToUTF16("Times New Roman");
 }
 
+WebPreferences::WebPreferences(const WebPreferences& other) = default;
+
 WebPreferences::~WebPreferences() {
 }
 
diff --git a/content/public/common/web_preferences.h b/content/public/common/web_preferences.h
index fcd58f5..636f7a2 100644
--- a/content/public/common/web_preferences.h
+++ b/content/public/common/web_preferences.h
@@ -107,7 +107,6 @@
   bool hyperlink_auditing_enabled;
   bool allow_universal_access_from_file_urls;
   bool allow_file_access_from_file_urls;
-  bool webaudio_enabled;
   bool experimental_webgl_enabled;
   bool pepper_3d_enabled;
   bool flash_3d_enabled;
@@ -228,6 +227,7 @@
   // chrome, except for the cases where it would require lots of extra work for
   // the embedder to use the same default value.
   WebPreferences();
+  WebPreferences(const WebPreferences& other);
   ~WebPreferences();
 };
 
diff --git a/content/public/common/webplugininfo.cc b/content/public/common/webplugininfo.cc
index 95a7bfc..6546afd 100644
--- a/content/public/common/webplugininfo.cc
+++ b/content/public/common/webplugininfo.cc
@@ -27,6 +27,8 @@
   file_extensions.push_back(f);
 }
 
+WebPluginMimeType::WebPluginMimeType(const WebPluginMimeType& other) = default;
+
 WebPluginMimeType::~WebPluginMimeType() {}
 
 WebPluginInfo::WebPluginInfo()
diff --git a/content/public/common/webplugininfo.h b/content/public/common/webplugininfo.h
index f487a4e..3d5feee 100644
--- a/content/public/common/webplugininfo.h
+++ b/content/public/common/webplugininfo.h
@@ -26,6 +26,7 @@
   WebPluginMimeType(const std::string& m,
                     const std::string& f,
                     const std::string& d);
+  WebPluginMimeType(const WebPluginMimeType& other);
   ~WebPluginMimeType();
 
   // The name of the mime type (e.g., "application/x-shockwave-flash").
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/DOMUtils.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/DOMUtils.java
index 1f43af6d..0d00b86d 100644
--- a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/DOMUtils.java
+++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/DOMUtils.java
@@ -4,6 +4,8 @@
 
 package org.chromium.content.browser.test.util;
 
+import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
+
 import android.graphics.Rect;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.JsonReader;
@@ -15,12 +17,17 @@
 
 import java.io.IOException;
 import java.io.StringReader;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
 /**
  * Collection of DOM-based utilities.
  */
 public class DOMUtils {
+
+    private static final long MEDIA_TIMEOUT_SECONDS = scaleTimeout(10);
+    private static final long MEDIA_TIMEOUT_MILLISECONDS = MEDIA_TIMEOUT_SECONDS * 1000;
+
     /**
      * Plays the media with given {@code id}.
      * @param webContents The WebContents in which the media element lives.
@@ -34,7 +41,8 @@
         sb.append("  if (media) media.play();");
         sb.append("})();");
         JavaScriptUtils.executeJavaScriptAndWaitForResult(
-                webContents, sb.toString());
+                webContents, sb.toString(),
+                MEDIA_TIMEOUT_SECONDS, TimeUnit.SECONDS);
     }
 
     /**
@@ -50,7 +58,8 @@
         sb.append("  if (media) media.pause();");
         sb.append("})();");
         JavaScriptUtils.executeJavaScriptAndWaitForResult(
-                webContents, sb.toString());
+                webContents, sb.toString(),
+                MEDIA_TIMEOUT_SECONDS, TimeUnit.SECONDS);
     }
 
     /**
@@ -108,7 +117,7 @@
                     return false;
                 }
             }
-        });
+        }, MEDIA_TIMEOUT_MILLISECONDS, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
     }
 
     /**
diff --git a/content/public/test/mock_download_manager.h b/content/public/test/mock_download_manager.h
index 8dadb52..77a883f 100644
--- a/content/public/test/mock_download_manager.h
+++ b/content/public/test/mock_download_manager.h
@@ -90,12 +90,10 @@
 
   MOCK_METHOD2(MockStartDownload,
                void(DownloadCreateInfo*, ByteStreamReader*));
-  MOCK_METHOD3(RemoveDownloadsByOriginAndTime,
-               int(const url::Origin& origin,
+  MOCK_METHOD3(RemoveDownloadsByURLAndTime,
+               int(const base::Callback<bool(const GURL&)>& url_filter,
                    base::Time remove_begin,
                    base::Time remove_end));
-  MOCK_METHOD2(RemoveDownloadsBetween,
-               int(base::Time remove_begin, base::Time remove_end));
   MOCK_METHOD0(RemoveAllDownloads, int());
   MOCK_METHOD1(DownloadUrlMock, void(DownloadUrlParameters*));
   void DownloadUrl(scoped_ptr<DownloadUrlParameters> params) override {
diff --git a/content/public/test/test_mojo_app.cc b/content/public/test/test_mojo_app.cc
index f2b117f..cc80175 100644
--- a/content/public/test/test_mojo_app.cc
+++ b/content/public/test/test_mojo_app.cc
@@ -21,7 +21,7 @@
 }
 
 void TestMojoApp::Initialize(mojo::Shell* shell, const std::string& url,
-                             uint32_t id) {
+                             uint32_t id, uint32_t user_id) {
   shell_ = shell;
 }
 
diff --git a/content/public/test/test_mojo_app.h b/content/public/test/test_mojo_app.h
index c354613..edf0ad28 100644
--- a/content/public/test/test_mojo_app.h
+++ b/content/public/test/test_mojo_app.h
@@ -28,7 +28,7 @@
  private:
   // mojo::ShellClient:
   void Initialize(mojo::Shell* shell, const std::string& url,
-                  uint32_t id) override;
+                  uint32_t id, uint32_t user_id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
   // mojo::InterfaceFactory<TestMojoService>:
diff --git a/content/renderer/accessibility/renderer_accessibility.cc b/content/renderer/accessibility/renderer_accessibility.cc
index 843644f..a6922a8c 100644
--- a/content/renderer/accessibility/renderer_accessibility.cc
+++ b/content/renderer/accessibility/renderer_accessibility.cc
@@ -70,6 +70,15 @@
       ack_pending_(false),
       reset_token_(0),
       weak_factory_(this) {
+  // There's only one AXObjectCache for the root of a local frame tree,
+  // so if this frame's parent is local we can safely do nothing.
+  if (render_frame_ &&
+      render_frame_->GetWebFrame() &&
+      render_frame_->GetWebFrame()->parent() &&
+      render_frame_->GetWebFrame()->parent()->isWebLocalFrame()) {
+    return;
+  }
+
   WebView* web_view = render_frame_->GetRenderView()->GetWebView();
   WebSettings* settings = web_view->settings();
   settings->setAccessibilityEnabled(true);
diff --git a/content/renderer/android/synchronous_compositor_proxy.cc b/content/renderer/android/synchronous_compositor_proxy.cc
index 74063daf7..b9859497 100644
--- a/content/renderer/android/synchronous_compositor_proxy.cc
+++ b/content/renderer/android/synchronous_compositor_proxy.cc
@@ -46,9 +46,9 @@
       min_page_scale_factor_(0.f),
       max_page_scale_factor_(0.f),
       need_animate_scroll_(false),
-      need_invalidate_(false),
+      need_invalidate_count_(0u),
       need_begin_frame_(false),
-      did_activate_pending_tree_(false) {
+      did_activate_pending_tree_count_(0u) {
   DCHECK(output_surface_);
   DCHECK(begin_frame_source_);
   DCHECK(input_handler_proxy_);
@@ -106,12 +106,12 @@
 }
 
 void SynchronousCompositorProxy::Invalidate() {
-  need_invalidate_ = true;
+  ++need_invalidate_count_;
   SendAsyncRendererStateIfNeeded();
 }
 
 void SynchronousCompositorProxy::DidActivatePendingTree() {
-  did_activate_pending_tree_ = true;
+  ++did_activate_pending_tree_count_;
   SendAsyncRendererStateIfNeeded();
   DeliverMessages();
 }
@@ -133,7 +133,7 @@
 }
 
 void SynchronousCompositorProxy::PopulateCommonParams(
-    SyncCompositorCommonRendererParams* params) {
+    SyncCompositorCommonRendererParams* params) const {
   params->version = ++version_;
   params->total_scroll_offset = total_scroll_offset_;
   params->max_scroll_offset = max_scroll_offset_;
@@ -142,12 +142,9 @@
   params->min_page_scale_factor = min_page_scale_factor_;
   params->max_page_scale_factor = max_page_scale_factor_;
   params->need_animate_scroll = need_animate_scroll_;
-  params->need_invalidate = need_invalidate_;
+  params->need_invalidate_count = need_invalidate_count_;
   params->need_begin_frame = need_begin_frame_;
-  params->did_activate_pending_tree = did_activate_pending_tree_;
-
-  need_invalidate_ = false;
-  did_activate_pending_tree_ = false;
+  params->did_activate_pending_tree_count = did_activate_pending_tree_count_;
 }
 
 void SynchronousCompositorProxy::OnMessageReceived(
diff --git a/content/renderer/android/synchronous_compositor_proxy.h b/content/renderer/android/synchronous_compositor_proxy.h
index 62108f4..534e7db6 100644
--- a/content/renderer/android/synchronous_compositor_proxy.h
+++ b/content/renderer/android/synchronous_compositor_proxy.h
@@ -83,7 +83,7 @@
 
   void ProcessCommonParams(
       const SyncCompositorCommonBrowserParams& common_params);
-  void PopulateCommonParams(SyncCompositorCommonRendererParams* params);
+  void PopulateCommonParams(SyncCompositorCommonRendererParams* params) const;
 
   // IPC handlers.
   void HandleInputEvent(
@@ -137,7 +137,7 @@
   scoped_ptr<SharedMemoryWithSize> software_draw_shm_;
 
   // To browser.
-  uint32_t version_;
+  mutable uint32_t version_;  // Mustable so PopulateCommonParams can be const.
   gfx::ScrollOffset total_scroll_offset_;  // Modified by both.
   gfx::ScrollOffset max_scroll_offset_;
   gfx::SizeF scrollable_size_;
@@ -145,9 +145,9 @@
   float min_page_scale_factor_;
   float max_page_scale_factor_;
   bool need_animate_scroll_;
-  bool need_invalidate_;
+  uint32_t need_invalidate_count_;
   bool need_begin_frame_;
-  bool did_activate_pending_tree_;
+  uint32_t did_activate_pending_tree_count_;
 
   DISALLOW_COPY_AND_ASSIGN(SynchronousCompositorProxy);
 };
diff --git a/content/renderer/dom_serializer_browsertest.cc b/content/renderer/dom_serializer_browsertest.cc
index bf725866..a16ee720 100644
--- a/content/renderer/dom_serializer_browsertest.cc
+++ b/content/renderer/dom_serializer_browsertest.cc
@@ -152,7 +152,8 @@
 
       ASSERT_TRUE(web_frame != NULL);
 
-      web_frame->loadData(data, "text/html", encoding_info, base_url);
+      web_frame->toWebLocalFrame()->loadData(data, "text/html", encoding_info,
+                                             base_url);
     }
 
     runner->Run();
diff --git a/content/renderer/dom_storage/DEPS b/content/renderer/dom_storage/DEPS
index 8ad6594..4e583a9 100644
--- a/content/renderer/dom_storage/DEPS
+++ b/content/renderer/dom_storage/DEPS
@@ -1,6 +1,7 @@
 specific_include_rules = {
   'local_storage\.*': [
     "-content/renderer",
+    "+components/leveldb/public/interfaces",
     "+content/renderer/dom_storage/local_storage_area.h",
     "+content/renderer/dom_storage/local_storage_namespace.h",
   ],
diff --git a/content/renderer/dom_storage/local_storage_area.cc b/content/renderer/dom_storage/local_storage_area.cc
index 115bb8b..0c91bf94 100644
--- a/content/renderer/dom_storage/local_storage_area.cc
+++ b/content/renderer/dom_storage/local_storage_area.cc
@@ -4,13 +4,20 @@
 
 #include "content/renderer/dom_storage/local_storage_area.h"
 
+#include "content/common/storage_partition_service.mojom.h"
+
 using blink::WebString;
 using blink::WebURL;
 
 namespace content {
 
-LocalStorageArea::LocalStorageArea(const url::Origin& origin)
-    : origin_(origin) {
+LocalStorageArea::LocalStorageArea(
+    const url::Origin& origin,
+    StoragePartitionService* storage_partition_service)
+    : origin_(origin), binding_(this) {
+  storage_partition_service->OpenLocalStorage(
+      origin_.Serialize(), binding_.CreateInterfacePtrAndBind(),
+      mojo::GetProxy(&leveldb_));
 }
 
 LocalStorageArea::~LocalStorageArea() {
@@ -44,4 +51,17 @@
   return 0u;
 }
 
+void LocalStorageArea::KeyChanged(mojo::Array<uint8_t> key,
+                                  mojo::Array<uint8_t> new_value,
+                                  mojo::Array<uint8_t> old_value,
+                                  const mojo::String& source) {
+}
+
+void LocalStorageArea::KeyDeleted(mojo::Array<uint8_t> key,
+                                  const mojo::String& source) {
+}
+
+void LocalStorageArea::AllDeleted(const mojo::String& source) {
+}
+
 }  // namespace content
diff --git a/content/renderer/dom_storage/local_storage_area.h b/content/renderer/dom_storage/local_storage_area.h
index d796c78b..506a1cab 100644
--- a/content/renderer/dom_storage/local_storage_area.h
+++ b/content/renderer/dom_storage/local_storage_area.h
@@ -6,14 +6,23 @@
 #define CONTENT_RENDERER_DOM_STORAGE_LOCAL_STORAGE_AREA_H_
 
 #include "base/macros.h"
+#include "content/common/leveldb_wrapper.mojom.h"
+#include "mojo/public/cpp/bindings/binding.h"
 #include "third_party/WebKit/public/platform/WebStorageArea.h"
 #include "url/origin.h"
 
 namespace content {
+class StoragePartitionService;
 
-class LocalStorageArea : public blink::WebStorageArea {
+// Maintains a complete cache of the origin's Map of key/value pairs for fast
+// access. The cache is primed on first access and changes are written to the
+// backend through the level db interface pointer. Mutations originating in
+// other processes are applied to the cache via the ApplyMutation method.
+class LocalStorageArea : public blink::WebStorageArea,
+                         public LevelDBObserver {
  public:
-  explicit LocalStorageArea(const url::Origin& origin);
+  LocalStorageArea(const url::Origin& origin,
+                   StoragePartitionService* storage_partition_service);
   ~LocalStorageArea() override;
 
   // blink::WebStorageArea.h:
@@ -29,8 +38,19 @@
   void clear(const blink::WebURL& url) override;
   size_t memoryBytesUsedByCache() const override;
 
+  // LevelDBObserver:
+  void KeyChanged(mojo::Array<uint8_t> key,
+                  mojo::Array<uint8_t> new_value,
+                  mojo::Array<uint8_t> old_value,
+                  const mojo::String& source) override;
+  void KeyDeleted(mojo::Array<uint8_t> key,
+                  const mojo::String& source) override;
+  void AllDeleted(const mojo::String& source) override;
+
  private:
   url::Origin origin_;
+  LevelDBWrapperPtr leveldb_;
+  mojo::Binding<LevelDBObserver> binding_;
 
   DISALLOW_COPY_AND_ASSIGN(LocalStorageArea);
 };
diff --git a/content/renderer/dom_storage/local_storage_namespace.cc b/content/renderer/dom_storage/local_storage_namespace.cc
index 01cc58c..5dd50e4 100644
--- a/content/renderer/dom_storage/local_storage_namespace.cc
+++ b/content/renderer/dom_storage/local_storage_namespace.cc
@@ -15,7 +15,9 @@
 
 namespace content {
 
-LocalStorageNamespace::LocalStorageNamespace() {
+LocalStorageNamespace::LocalStorageNamespace(
+    StoragePartitionService* storage_partition_service)
+    : storage_partition_service_(storage_partition_service) {
 }
 
 LocalStorageNamespace::~LocalStorageNamespace() {
@@ -23,7 +25,8 @@
 
 WebStorageArea* LocalStorageNamespace::createStorageArea(
     const WebString& origin) {
-  return new LocalStorageArea(url::Origin(blink::WebStringToGURL(origin)));
+  return new LocalStorageArea(
+      url::Origin(blink::WebStringToGURL(origin)), storage_partition_service_);
 }
 
 bool LocalStorageNamespace::isSameNamespace(
diff --git a/content/renderer/dom_storage/local_storage_namespace.h b/content/renderer/dom_storage/local_storage_namespace.h
index 77abae2..36b7bd8 100644
--- a/content/renderer/dom_storage/local_storage_namespace.h
+++ b/content/renderer/dom_storage/local_storage_namespace.h
@@ -9,11 +9,13 @@
 #include "third_party/WebKit/public/platform/WebStorageNamespace.h"
 
 namespace content {
+class StoragePartitionService;
 
 // An in-process implementation of LocalStorage using a LevelDB Mojo service.
 class LocalStorageNamespace : public blink::WebStorageNamespace {
  public:
-  LocalStorageNamespace();
+  explicit LocalStorageNamespace(
+      StoragePartitionService* storage_partition_service);
   ~LocalStorageNamespace() override;
 
   // blink::WebStorageNamespace:
@@ -22,6 +24,8 @@
   bool isSameNamespace(const WebStorageNamespace&) const override;
 
  private:
+  StoragePartitionService* const storage_partition_service_;
+
   DISALLOW_COPY_AND_ASSIGN(LocalStorageNamespace);
 };
 
diff --git a/content/renderer/gpu/gpu_benchmarking_extension.cc b/content/renderer/gpu/gpu_benchmarking_extension.cc
index 8a807ff..f471360 100644
--- a/content/renderer/gpu/gpu_benchmarking_extension.cc
+++ b/content/renderer/gpu/gpu_benchmarking_extension.cc
@@ -9,6 +9,7 @@
 #include <utility>
 
 #include "base/base64.h"
+#include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/macros.h"
@@ -21,6 +22,7 @@
 #include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
 #include "content/common/input/synthetic_tap_gesture_params.h"
 #include "content/public/child/v8_value_converter.h"
+#include "content/public/common/content_switches.h"
 #include "content/public/renderer/chrome_object_extensions_utils.h"
 #include "content/public/renderer/render_thread.h"
 #include "content/renderer/gpu/render_widget_compositor.h"
@@ -54,19 +56,52 @@
 
 namespace {
 
-class PNGSerializer : public SkPixelSerializer {
+class EncodingSerializer : public SkPixelSerializer {
  protected:
   bool onUseEncodedData(const void* data, size_t len) override { return true; }
 
   SkData* onEncode(const SkPixmap& pixmap) override {
-    SkBitmap bm;
-    // The const_cast is fine, since we only read from the bitmap.
-    if (bm.installPixels(pixmap.info(),
-                         const_cast<void*>(pixmap.addr()),
-                         pixmap.rowBytes())) {
-      std::vector<unsigned char> vector;
-      if (gfx::PNGCodec::EncodeBGRASkBitmap(bm, false, &vector)) {
+    std::vector<uint8_t> vector;
+
+    const base::CommandLine& commandLine =
+        *base::CommandLine::ForCurrentProcess();
+    if (commandLine.HasSwitch(switches::kSkipReencodingOnSKPCapture)) {
+        // In this case, we just want to store some useful information
+        // about the image to replace the missing encoded data.
+
+        // First make sure that the data does not accidentally match any
+        // image signatures.
+        vector.push_back(0xFF);
+        vector.push_back(0xFF);
+        vector.push_back(0xFF);
+        vector.push_back(0xFF);
+
+        // Save the width and height.
+        uint32_t width = pixmap.width();
+        uint32_t height = pixmap.height();
+        vector.push_back(width & 0xFF);
+        vector.push_back((width >> 8) & 0xFF);
+        vector.push_back((width >> 16) & 0xFF);
+        vector.push_back((width >> 24) & 0xFF);
+        vector.push_back(height & 0xFF);
+        vector.push_back((height >> 8) & 0xFF);
+        vector.push_back((height >> 16) & 0xFF);
+        vector.push_back((height >> 24) & 0xFF);
+
+        // Save any additional information about the bitmap that may be
+        // interesting.
+        vector.push_back(pixmap.colorType());
+        vector.push_back(pixmap.alphaType());
         return SkData::NewWithCopy(&vector.front(), vector.size());
+    } else {
+      SkBitmap bm;
+      // The const_cast is fine, since we only read from the bitmap.
+      if (bm.installPixels(pixmap.info(),
+                           const_cast<void*>(pixmap.addr()),
+                           pixmap.rowBytes())) {
+        if (gfx::PNGCodec::EncodeBGRASkBitmap(bm, false, &vector)) {
+          return SkData::NewWithCopy(&vector.front(), vector.size());
+        }
       }
     }
     return nullptr;
@@ -106,7 +141,7 @@
     SkFILEWStream file(filepath.c_str());
     DCHECK(file.isValid());
 
-    PNGSerializer serializer;
+    EncodingSerializer serializer;
     picture->serialize(&file, &serializer);
     file.fsync();
   }
diff --git a/content/renderer/media/android/media_source_delegate.cc b/content/renderer/media/android/media_source_delegate.cc
index 7504c34..5d547c8f 100644
--- a/content/renderer/media/android/media_source_delegate.cc
+++ b/content/renderer/media/android/media_source_delegate.cc
@@ -148,7 +148,7 @@
     const MediaSourceOpenedCB& media_source_opened_cb,
     const media::Demuxer::EncryptedMediaInitDataCB&
         encrypted_media_init_data_cb,
-    const media::SetCdmReadyCB& set_cdm_ready_cb,
+    const SetCdmReadyCB& set_cdm_ready_cb,
     const UpdateNetworkStateCB& update_network_state_cb,
     const DurationChangeCB& duration_change_cb,
     const base::Closure& waiting_for_decryption_key_cb) {
diff --git a/content/renderer/media/android/media_source_delegate.h b/content/renderer/media/android/media_source_delegate.h
index 4186378..6d9228ff 100644
--- a/content/renderer/media/android/media_source_delegate.h
+++ b/content/renderer/media/android/media_source_delegate.h
@@ -51,6 +51,14 @@
       UpdateNetworkStateCB;
   typedef base::Callback<void(const base::TimeDelta&)> DurationChangeCB;
 
+  // Callback to notify that a CDM is ready. CdmAttachedCB is called when the
+  // CDM has been completely attached to the media pipeline.
+  typedef base::Callback<void(media::CdmContext*, const media::CdmAttachedCB&)>
+      CdmReadyCB;
+
+  // Callback to set a CdmReadyCB, which will be called when a CDM is ready.
+  typedef base::Callback<void(const CdmReadyCB&)> SetCdmReadyCB;
+
   MediaSourceDelegate(
       RendererDemuxerAndroid* demuxer_client,
       int demuxer_client_id,
@@ -64,7 +72,7 @@
       const MediaSourceOpenedCB& media_source_opened_cb,
       const media::Demuxer::EncryptedMediaInitDataCB&
           encrypted_media_init_data_cb,
-      const media::SetCdmReadyCB& set_cdm_ready_cb,
+      const SetCdmReadyCB& set_cdm_ready_cb,
       const UpdateNetworkStateCB& update_network_state_cb,
       const DurationChangeCB& duration_change_cb,
       const base::Closure& waiting_for_decryption_key_cb);
@@ -196,7 +204,7 @@
   scoped_ptr<media::ChunkDemuxer> chunk_demuxer_;
   bool is_demuxer_ready_;
 
-  media::SetCdmReadyCB set_cdm_ready_cb_;
+  SetCdmReadyCB set_cdm_ready_cb_;
   media::CdmContext* cdm_context_;
   media::CdmAttachedCB pending_cdm_attached_cb_;
 
diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc
index 83508ce2..059e96f 100644
--- a/content/renderer/media/android/webmediaplayer_android.cc
+++ b/content/renderer/media/android/webmediaplayer_android.cc
@@ -84,8 +84,6 @@
 using media::VideoFrame;
 
 namespace {
-// Prefix for histograms related to Encrypted Media Extensions.
-const char* kMediaEme = "Media.EME.";
 
 // Values for Media.Android.IsHttpLiveStreamingMediaPredictionResult UMA.
 // Never reuse values!
@@ -1490,7 +1488,8 @@
     return;
   }
 
-  UMA_HISTOGRAM_COUNTS(kMediaEme + std::string("NeedKey"), 1);
+  // TODO(xhwang): Update this UMA name. https://crbug.com/589251
+  UMA_HISTOGRAM_COUNTS("Media.EME.NeedKey", 1);
 
   DCHECK(init_data_type != media::EmeInitDataType::UNKNOWN);
 
@@ -1594,7 +1593,7 @@
 }
 
 void WebMediaPlayerAndroid::SetCdmReadyCB(
-    const media::CdmReadyCB& cdm_ready_cb) {
+    const MediaSourceDelegate::CdmReadyCB& cdm_ready_cb) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
   DCHECK(is_player_initialized_);
 
diff --git a/content/renderer/media/android/webmediaplayer_android.h b/content/renderer/media/android/webmediaplayer_android.h
index 5b9eff8c..a661150 100644
--- a/content/renderer/media/android/webmediaplayer_android.h
+++ b/content/renderer/media/android/webmediaplayer_android.h
@@ -299,7 +299,7 @@
   // |cdm_ready_cb| provided.
   // If |cdm_ready_cb| is null, the existing callback will be fired with
   // NULL immediately and reset.
-  void SetCdmReadyCB(const media::CdmReadyCB& cdm_ready_cb);
+  void SetCdmReadyCB(const MediaSourceDelegate::CdmReadyCB& cdm_ready_cb);
 
   // Called when the ContentDecryptionModule has been attached to the
   // pipeline/decoders.
@@ -463,7 +463,7 @@
   // side CDM will be used. This is similar to WebMediaPlayerImpl. For other key
   // systems, a browser side CDM will be used and we set CDM by calling
   // player_manager_->SetCdm() directly.
-  media::CdmReadyCB cdm_ready_cb_;
+  MediaSourceDelegate::CdmReadyCB cdm_ready_cb_;
 
   SkBitmap bitmap_;
 
diff --git a/content/renderer/media/audio_renderer_mixer_manager.cc b/content/renderer/media/audio_renderer_mixer_manager.cc
index 23b67a6..309eaa84 100644
--- a/content/renderer/media/audio_renderer_mixer_manager.cc
+++ b/content/renderer/media/audio_renderer_mixer_manager.cc
@@ -174,4 +174,6 @@
       device_id(device_id),
       security_origin(security_origin) {}
 
+AudioRendererMixerManager::MixerKey::MixerKey(const MixerKey& other) = default;
+
 }  // namespace content
diff --git a/content/renderer/media/audio_renderer_mixer_manager.h b/content/renderer/media/audio_renderer_mixer_manager.h
index d33dbc3..8b13388 100644
--- a/content/renderer/media/audio_renderer_mixer_manager.h
+++ b/content/renderer/media/audio_renderer_mixer_manager.h
@@ -80,6 +80,7 @@
              const media::AudioParameters& params,
              const std::string& device_id,
              const url::Origin& security_origin);
+    MixerKey(const MixerKey& other);
     int source_render_frame_id;
     media::AudioParameters params;
     std::string device_id;
diff --git a/content/renderer/media/media_stream_audio_processor.cc b/content/renderer/media/media_stream_audio_processor.cc
index 7ae75a0c..3e529a8 100644
--- a/content/renderer/media/media_stream_audio_processor.cc
+++ b/content/renderer/media/media_stream_audio_processor.cc
@@ -486,8 +486,7 @@
 
   // Audio mirroring can be enabled even though audio processing is otherwise
   // disabled.
-  audio_mirroring_ = audio_constraints.GetProperty(
-      MediaAudioConstraints::kGoogAudioMirroring);
+  audio_mirroring_ = audio_constraints.GetGoogAudioMirroring();
 
 #if defined(OS_IOS)
   // On iOS, VPIO provides built-in AGC and AEC.
@@ -496,28 +495,24 @@
 #else
   const bool echo_cancellation =
       audio_constraints.GetEchoCancellationProperty();
-  const bool goog_agc = audio_constraints.GetProperty(
-      MediaAudioConstraints::kGoogAutoGainControl);
+  const bool goog_agc = audio_constraints.GetGoogAutoGainControl();
 #endif
 
 #if defined(OS_IOS) || defined(OS_ANDROID)
   const bool goog_experimental_aec = false;
   const bool goog_typing_detection = false;
 #else
-  const bool goog_experimental_aec = audio_constraints.GetProperty(
-      MediaAudioConstraints::kGoogExperimentalEchoCancellation);
-  const bool goog_typing_detection = audio_constraints.GetProperty(
-      MediaAudioConstraints::kGoogTypingNoiseDetection);
+  const bool goog_experimental_aec =
+      audio_constraints.GetGoogExperimentalEchoCancellation();
+  const bool goog_typing_detection =
+      audio_constraints.GetGoogTypingNoiseDetection();
 #endif
 
-  const bool goog_ns = audio_constraints.GetProperty(
-      MediaAudioConstraints::kGoogNoiseSuppression);
-  const bool goog_experimental_ns = audio_constraints.GetProperty(
-      MediaAudioConstraints::kGoogExperimentalNoiseSuppression);
-  const bool goog_beamforming = audio_constraints.GetProperty(
-      MediaAudioConstraints::kGoogBeamforming);
-  const bool goog_high_pass_filter = audio_constraints.GetProperty(
-      MediaAudioConstraints::kGoogHighpassFilter);
+  const bool goog_ns = audio_constraints.GetGoogNoiseSuppression();
+  const bool goog_experimental_ns =
+      audio_constraints.GetGoogExperimentalNoiseSuppression();
+  const bool goog_beamforming = audio_constraints.GetGoogBeamforming();
+  const bool goog_high_pass_filter = audio_constraints.GetGoogHighpassFilter();
   // Return immediately if no goog constraint is enabled.
   if (!echo_cancellation && !goog_experimental_aec && !goog_ns &&
       !goog_high_pass_filter && !goog_typing_detection &&
@@ -544,8 +539,7 @@
   }
 
   // If the experimental AGC is enabled, check for overridden config params.
-  if (audio_constraints.GetProperty(
-          MediaAudioConstraints::kGoogExperimentalAutoGainControl)) {
+  if (audio_constraints.GetGoogExperimentalAutoGainControl()) {
     int startup_min_volume = 0;
     if (GetStartupMinVolumeForAgc(&startup_min_volume)) {
       config.Set<webrtc::ExperimentalAgc>(
diff --git a/content/renderer/media/media_stream_audio_processor_options.cc b/content/renderer/media/media_stream_audio_processor_options.cc
index c8889ba..a822d9f 100644
--- a/content/renderer/media/media_stream_audio_processor_options.cc
+++ b/content/renderer/media/media_stream_audio_processor_options.cc
@@ -18,7 +18,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "content/common/media/media_stream_options.h"
-#include "content/renderer/media/media_stream_constraints_util.h"
 #include "content/renderer/media/media_stream_source.h"
 #include "content/renderer/media/rtc_media_constraints.h"
 #include "media/audio/audio_parameters.h"
@@ -118,6 +117,26 @@
   return webrtc_points;
 }
 
+// Scan the basic and advanced constraints until a value is found.
+// If nothing is found, the default is returned.
+// Argument 2 is a pointer to class data member.
+bool ScanConstraintsForBoolean(
+    const blink::WebMediaConstraints& constraints,
+    blink::BooleanConstraint blink::WebMediaTrackConstraintSet::*picker,
+    bool the_default) {
+  const auto& the_field = constraints.basic().*picker;
+  if (the_field.hasExact()) {
+    return the_field.exact();
+  }
+  for (const auto& advanced_constraint : constraints.advanced()) {
+    const auto& the_field = advanced_constraint.*picker;
+    if (the_field.hasExact()) {
+      return the_field.exact();
+    }
+  }
+  return the_default;
+}
+
 }  // namespace
 
 // TODO(xians): Remove this method after the APM in WebRtc is deprecated.
@@ -148,34 +167,14 @@
   //   and screen capture.
   // - |kEchoCancellation| is explicitly set to false.
   std::string value_str;
-  bool value_bool = false;
-  if ((GetConstraintValueAsString(constraints, kMediaStreamSource,
-                                  &value_str)) ||
-      (GetConstraintValueAsBoolean(constraints_, kEchoCancellation,
-                                   &value_bool) && !value_bool)) {
+  if (!constraints.basic().mediaStreamSource.isEmpty() ||
+      !constraints.basic().echoCancellation.matches(true)) {
     default_audio_processing_constraint_value_ = false;
   }
 }
 
 MediaAudioConstraints::~MediaAudioConstraints() {}
 
-bool MediaAudioConstraints::GetProperty(const std::string& key) const {
-  // Return the value if the constraint is specified in |constraints|,
-  // otherwise return the default value.
-  bool value = false;
-  if (!GetConstraintValueAsBoolean(constraints_, key, &value))
-    value = GetDefaultValueForConstraint(constraints_, key);
-
-  return value;
-}
-
-std::string MediaAudioConstraints::GetPropertyAsString(
-    const std::string& key) const {
-  std::string value;
-  GetConstraintValueAsString(constraints_, key, &value);
-  return value;
-}
-
 bool MediaAudioConstraints::GetEchoCancellationProperty() const {
   // If platform echo canceller is enabled, disable the software AEC.
   if (effects_ & media::AudioParameters::ECHO_CANCELLER)
@@ -183,44 +182,37 @@
 
   // If |kEchoCancellation| is specified in the constraints, it will
   // override the value of |kGoogEchoCancellation|.
-  bool value = false;
-  if (GetConstraintValueAsBoolean(constraints_, kEchoCancellation, &value))
-    return value;
-
-  return GetProperty(kGoogEchoCancellation);
+  const blink::WebMediaTrackConstraintSet& basic = constraints_.basic();
+  if (basic.echoCancellation.hasExact()) {
+    return basic.echoCancellation.exact();
+  }
+  for (const auto& advanced_constraint : constraints_.advanced()) {
+    if (advanced_constraint.echoCancellation.hasExact()) {
+      return advanced_constraint.echoCancellation.exact();
+    }
+  }
+  return ScanConstraintsForBoolean(
+      constraints_, &blink::WebMediaTrackConstraintSet::googEchoCancellation,
+      GetDefaultValueForConstraint(kGoogEchoCancellation));
 }
 
 bool MediaAudioConstraints::IsValid() const {
-  blink::WebVector<blink::WebMediaConstraint> mandatory;
-  constraints_.getMandatoryConstraints(mandatory);
-  for (size_t i = 0; i < mandatory.size(); ++i) {
-    const std::string key = mandatory[i].m_name.utf8();
-    if (key == kMediaStreamSource || key == kMediaStreamSourceId ||
-        key == MediaStreamSource::kSourceId) {
-      // Ignore Chrome specific Tab capture and |kSourceId| constraints.
-      continue;
-    }
-
-    bool valid = false;
-    for (size_t j = 0; j < arraysize(kDefaultAudioConstraints); ++j) {
-      if (key == kDefaultAudioConstraints[j].key) {
-        bool value = false;
-        valid = GetMandatoryConstraintValueAsBoolean(constraints_, key, &value);
-        break;
-      }
-    }
-
-    if (!valid) {
-      DLOG(ERROR) << "Invalid MediaStream constraint. Name: " << key;
-      return false;
-    }
+  std::vector<std::string> legal_names(
+      {constraints_.basic().mediaStreamSource.name(),
+       constraints_.basic().deviceId.name()});
+  for (size_t j = 0; j < arraysize(kDefaultAudioConstraints); ++j) {
+    legal_names.push_back(kDefaultAudioConstraints[j].key);
   }
-
+  std::string failing_name;
+  if (constraints_.basic().hasMandatoryOutsideSet(legal_names, failing_name)) {
+    DLOG(ERROR) << "Invalid MediaStream constraint for audio. Name: "
+                << failing_name;
+    return false;
+  }
   return true;
 }
 
 bool MediaAudioConstraints::GetDefaultValueForConstraint(
-    const blink::WebMediaConstraints& constraints,
     const std::string& key) const {
   if (!default_audio_processing_constraint_value_)
     return false;
@@ -233,6 +225,77 @@
   return false;
 }
 
+bool MediaAudioConstraints::GetGoogAudioMirroring() const {
+  return ScanConstraintsForBoolean(
+      constraints_, &blink::WebMediaTrackConstraintSet::googAudioMirroring,
+      GetDefaultValueForConstraint(kGoogAudioMirroring));
+}
+
+bool MediaAudioConstraints::GetGoogAutoGainControl() const {
+  return ScanConstraintsForBoolean(
+      constraints_, &blink::WebMediaTrackConstraintSet::googAutoGainControl,
+      GetDefaultValueForConstraint(kGoogAutoGainControl));
+}
+
+bool MediaAudioConstraints::GetGoogExperimentalEchoCancellation() const {
+  return ScanConstraintsForBoolean(
+      constraints_,
+      &blink::WebMediaTrackConstraintSet::googExperimentalEchoCancellation,
+      GetDefaultValueForConstraint(kGoogExperimentalEchoCancellation));
+}
+
+bool MediaAudioConstraints::GetGoogTypingNoiseDetection() const {
+  return ScanConstraintsForBoolean(
+      constraints_,
+      &blink::WebMediaTrackConstraintSet::googTypingNoiseDetection,
+      GetDefaultValueForConstraint(kGoogTypingNoiseDetection));
+}
+bool MediaAudioConstraints::GetGoogNoiseSuppression() const {
+  return ScanConstraintsForBoolean(
+      constraints_, &blink::WebMediaTrackConstraintSet::googNoiseSuppression,
+      GetDefaultValueForConstraint(kGoogNoiseSuppression));
+}
+
+bool MediaAudioConstraints::GetGoogExperimentalNoiseSuppression() const {
+  return ScanConstraintsForBoolean(
+      constraints_,
+      &blink::WebMediaTrackConstraintSet::googExperimentalNoiseSuppression,
+      GetDefaultValueForConstraint(kGoogExperimentalNoiseSuppression));
+}
+
+bool MediaAudioConstraints::GetGoogBeamforming() const {
+  return ScanConstraintsForBoolean(
+      constraints_, &blink::WebMediaTrackConstraintSet::googBeamforming,
+      GetDefaultValueForConstraint(kGoogBeamforming));
+}
+
+bool MediaAudioConstraints::GetGoogHighpassFilter() const {
+  return ScanConstraintsForBoolean(
+      constraints_, &blink::WebMediaTrackConstraintSet::googHighpassFilter,
+      GetDefaultValueForConstraint(kGoogHighpassFilter));
+}
+
+bool MediaAudioConstraints::GetGoogExperimentalAutoGainControl() const {
+  return ScanConstraintsForBoolean(
+      constraints_,
+      &blink::WebMediaTrackConstraintSet::googExperimentalAutoGainControl,
+      GetDefaultValueForConstraint(kGoogExperimentalAutoGainControl));
+}
+
+std::string MediaAudioConstraints::GetGoogArrayGeometry() const {
+  const auto& the_field = constraints_.basic().googArrayGeometry;
+  if (the_field.hasMandatory()) {
+    return the_field.exact()[0].utf8();
+  }
+  for (const auto& advanced_constraint : constraints_.advanced()) {
+    const auto& the_field = advanced_constraint.googArrayGeometry;
+    if (the_field.hasMandatory()) {
+      return the_field.exact()[0].utf8();
+    }
+  }
+  return "";
+}
+
 EchoInformation::EchoInformation()
     : num_chunks_(0), echo_frames_received_(false) {
 }
@@ -394,8 +457,7 @@
     const MediaAudioConstraints& audio_constraints,
     const MediaStreamDevice::AudioDeviceParameters& input_params) {
   const std::string constraints_geometry =
-      audio_constraints.GetPropertyAsString(
-          MediaAudioConstraints::kGoogArrayGeometry);
+      audio_constraints.GetGoogArrayGeometry();
 
   // Give preference to the audio constraint over the device-supplied mic
   // positions. This is mainly for testing purposes.
diff --git a/content/renderer/media/media_stream_audio_processor_options.h b/content/renderer/media/media_stream_audio_processor_options.h
index ea583e1..0d3be88 100644
--- a/content/renderer/media/media_stream_audio_processor_options.h
+++ b/content/renderer/media/media_stream_audio_processor_options.h
@@ -62,17 +62,16 @@
                         int effects);
   virtual ~MediaAudioConstraints();
 
-  // Gets the property of the constraint named by |key| in |constraints_|.
-  // Returns the constraint's value if the key is found; otherwise returns the
-  // default value of the constraint.
-  // Note, for constraint of |kEchoCancellation| or |kGoogEchoCancellation|,
-  // clients should use GetEchoCancellationProperty().
-  bool GetProperty(const std::string& key) const;
-
-  // Gets the property of the constraint named by |key| in |constraints_| as a
-  // string. Returns the constraint's string value if the key is found;
-  // otherwise returns an empty string.
-  std::string GetPropertyAsString(const std::string& key) const;
+  bool GetGoogAudioMirroring() const;
+  bool GetGoogAutoGainControl() const;
+  bool GetGoogExperimentalEchoCancellation() const;
+  bool GetGoogTypingNoiseDetection() const;
+  bool GetGoogNoiseSuppression() const;
+  bool GetGoogExperimentalNoiseSuppression() const;
+  bool GetGoogBeamforming() const;
+  bool GetGoogHighpassFilter() const;
+  bool GetGoogExperimentalAutoGainControl() const;
+  std::string GetGoogArrayGeometry() const;
 
   // Gets the property of echo cancellation defined in |constraints_|. The
   // returned value depends on a combination of |effects_|, |kEchoCancellation|
@@ -85,10 +84,7 @@
 
  private:
   // Gets the default value of constraint named by |key| in |constraints|.
-  bool GetDefaultValueForConstraint(
-      const blink::WebMediaConstraints& constraints,
-      const std::string& key) const;
-
+  bool GetDefaultValueForConstraint(const std::string& key) const;
   const blink::WebMediaConstraints constraints_;
   const int effects_;
   bool default_audio_processing_constraint_value_;
diff --git a/content/renderer/media/media_stream_audio_processor_unittest.cc b/content/renderer/media/media_stream_audio_processor_unittest.cc
index 62e4db8..63ebe098 100644
--- a/content/renderer/media/media_stream_audio_processor_unittest.cc
+++ b/content/renderer/media/media_stream_audio_processor_unittest.cc
@@ -18,7 +18,7 @@
 #include "content/public/common/media_stream_request.h"
 #include "content/renderer/media/media_stream_audio_processor.h"
 #include "content/renderer/media/media_stream_audio_processor_options.h"
-#include "content/renderer/media/mock_media_constraint_factory.h"
+#include "content/renderer/media/mock_constraint_factory.h"
 #include "media/audio/audio_parameters.h"
 #include "media/base/audio_bus.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -207,7 +207,7 @@
 #define MAYBE_WithAudioProcessing WithAudioProcessing
 #endif
 TEST_F(MediaStreamAudioProcessorTest, MAYBE_WithAudioProcessing) {
-  MockMediaConstraintFactory constraint_factory;
+  MockConstraintFactory constraint_factory;
   scoped_refptr<WebRtcAudioDeviceImpl> webrtc_audio_device(
       new WebRtcAudioDeviceImpl());
   scoped_refptr<MediaStreamAudioProcessor> audio_processor(
@@ -231,10 +231,10 @@
   scoped_refptr<WebRtcAudioDeviceImpl> webrtc_audio_device(
       new WebRtcAudioDeviceImpl());
   // Create MediaStreamAudioProcessor instance for kMediaStreamSourceTab source.
-  MockMediaConstraintFactory tab_constraint_factory;
+  MockConstraintFactory tab_constraint_factory;
   const std::string tab_string = kMediaStreamSourceTab;
-  tab_constraint_factory.AddMandatory(kMediaStreamSource,
-                                      tab_string);
+  tab_constraint_factory.basic().mediaStreamSource.setExact(
+      blink::WebString::fromUTF8(tab_string));
   scoped_refptr<MediaStreamAudioProcessor> audio_processor(
       new rtc::RefCountedObject<MediaStreamAudioProcessor>(
           tab_constraint_factory.CreateWebMediaConstraints(),
@@ -249,10 +249,10 @@
 
   // Create MediaStreamAudioProcessor instance for kMediaStreamSourceSystem
   // source.
-  MockMediaConstraintFactory system_constraint_factory;
+  MockConstraintFactory system_constraint_factory;
   const std::string system_string = kMediaStreamSourceSystem;
-  system_constraint_factory.AddMandatory(kMediaStreamSource,
-                                         system_string);
+  system_constraint_factory.basic().mediaStreamSource.setExact(
+      blink::WebString::fromUTF8(system_string));
   audio_processor = new rtc::RefCountedObject<MediaStreamAudioProcessor>(
       system_constraint_factory.CreateWebMediaConstraints(),
       input_device_params_, webrtc_audio_device.get());
@@ -265,7 +265,7 @@
 
 TEST_F(MediaStreamAudioProcessorTest, TurnOffDefaultConstraints) {
   // Turn off the default constraints and pass it to MediaStreamAudioProcessor.
-  MockMediaConstraintFactory constraint_factory;
+  MockConstraintFactory constraint_factory;
   constraint_factory.DisableDefaultAudioConstraints();
   scoped_refptr<WebRtcAudioDeviceImpl> webrtc_audio_device(
       new WebRtcAudioDeviceImpl());
@@ -286,43 +286,9 @@
 }
 
 TEST_F(MediaStreamAudioProcessorTest, VerifyConstraints) {
-  static const char* kDefaultAudioConstraints[] = {
-    MediaAudioConstraints::kEchoCancellation,
-    MediaAudioConstraints::kGoogAudioMirroring,
-    MediaAudioConstraints::kGoogAutoGainControl,
-    MediaAudioConstraints::kGoogEchoCancellation,
-    MediaAudioConstraints::kGoogExperimentalEchoCancellation,
-    MediaAudioConstraints::kGoogExperimentalAutoGainControl,
-    MediaAudioConstraints::kGoogExperimentalNoiseSuppression,
-    MediaAudioConstraints::kGoogHighpassFilter,
-    MediaAudioConstraints::kGoogNoiseSuppression,
-    MediaAudioConstraints::kGoogTypingNoiseDetection,
-    kMediaStreamAudioHotword
-  };
-
-  // Verify mandatory constraints.
-  for (size_t i = 0; i < arraysize(kDefaultAudioConstraints); ++i) {
-    MockMediaConstraintFactory constraint_factory;
-    constraint_factory.AddMandatory(kDefaultAudioConstraints[i], false);
-    blink::WebMediaConstraints constraints =
-        constraint_factory.CreateWebMediaConstraints();
-    MediaAudioConstraints audio_constraints(constraints, 0);
-    EXPECT_FALSE(audio_constraints.GetProperty(kDefaultAudioConstraints[i]));
-  }
-
-  // Verify optional constraints.
-  for (size_t i = 0; i < arraysize(kDefaultAudioConstraints); ++i) {
-    MockMediaConstraintFactory constraint_factory;
-    constraint_factory.AddOptional(kDefaultAudioConstraints[i], false);
-    blink::WebMediaConstraints constraints =
-        constraint_factory.CreateWebMediaConstraints();
-    MediaAudioConstraints audio_constraints(constraints, 0);
-    EXPECT_FALSE(audio_constraints.GetProperty(kDefaultAudioConstraints[i]));
-  }
-
   {
-    // Verify echo cancellation is off when platform aec effect is on.
-    MockMediaConstraintFactory constraint_factory;
+    // Verify that echo cancellation is off when platform aec effect is on.
+    MockConstraintFactory constraint_factory;
     MediaAudioConstraints audio_constraints(
         constraint_factory.CreateWebMediaConstraints(),
         media::AudioParameters::ECHO_CANCELLER);
@@ -331,61 +297,44 @@
 
   {
     // Verify |kEchoCancellation| overwrite |kGoogEchoCancellation|.
-    MockMediaConstraintFactory constraint_factory_1;
-    constraint_factory_1.AddOptional(MediaAudioConstraints::kEchoCancellation,
-                                   true);
-    constraint_factory_1.AddOptional(
-        MediaAudioConstraints::kGoogEchoCancellation, false);
+    MockConstraintFactory constraint_factory_1;
+    constraint_factory_1.AddAdvanced().echoCancellation.setExact(true);
+    constraint_factory_1.AddAdvanced().googEchoCancellation.setExact(false);
     blink::WebMediaConstraints constraints_1 =
         constraint_factory_1.CreateWebMediaConstraints();
     MediaAudioConstraints audio_constraints_1(constraints_1, 0);
     EXPECT_TRUE(audio_constraints_1.GetEchoCancellationProperty());
 
-    MockMediaConstraintFactory constraint_factory_2;
-    constraint_factory_2.AddOptional(MediaAudioConstraints::kEchoCancellation,
-                                     false);
-    constraint_factory_2.AddOptional(
-        MediaAudioConstraints::kGoogEchoCancellation, true);
+    MockConstraintFactory constraint_factory_2;
+    constraint_factory_2.AddAdvanced().echoCancellation.setExact(false);
+    constraint_factory_2.AddAdvanced().googEchoCancellation.setExact(true);
     blink::WebMediaConstraints constraints_2 =
         constraint_factory_2.CreateWebMediaConstraints();
     MediaAudioConstraints audio_constraints_2(constraints_2, 0);
     EXPECT_FALSE(audio_constraints_2.GetEchoCancellationProperty());
   }
-
   {
     // When |kEchoCancellation| is explicitly set to false, the default values
     // for all the constraints are false.
-    MockMediaConstraintFactory constraint_factory;
-    constraint_factory.AddOptional(MediaAudioConstraints::kEchoCancellation,
-                                   false);
+    MockConstraintFactory constraint_factory;
+    constraint_factory.AddAdvanced().echoCancellation.setExact(false);
     blink::WebMediaConstraints constraints =
         constraint_factory.CreateWebMediaConstraints();
     MediaAudioConstraints audio_constraints(constraints, 0);
-    for (size_t i = 0; i < arraysize(kDefaultAudioConstraints); ++i) {
-      EXPECT_FALSE(audio_constraints.GetProperty(kDefaultAudioConstraints[i]));
-    }
-  }
-
-  {
-    // |kMediaStreamAudioHotword| is always off by default.
-    MockMediaConstraintFactory constraint_factory;
-    MediaAudioConstraints audio_constraints(
-        constraint_factory.CreateWebMediaConstraints(), 0);
-    EXPECT_FALSE(audio_constraints.GetProperty(kMediaStreamAudioHotword));
   }
 }
 
 TEST_F(MediaStreamAudioProcessorTest, ValidateConstraints) {
-  MockMediaConstraintFactory constraint_factory;
-  const std::string dummy_constraint = "dummy";
-  constraint_factory.AddMandatory(dummy_constraint, true);
+  MockConstraintFactory constraint_factory;
+  // Add a constraint that is not valid for audio.
+  constraint_factory.basic().width.setExact(240);
   MediaAudioConstraints audio_constraints(
       constraint_factory.CreateWebMediaConstraints(), 0);
   EXPECT_FALSE(audio_constraints.IsValid());
 }
 
 MediaAudioConstraints MakeMediaAudioConstraints(
-    const MockMediaConstraintFactory& constraint_factory) {
+    const MockConstraintFactory& constraint_factory) {
   return MediaAudioConstraints(constraint_factory.CreateWebMediaConstraints(),
                                AudioParameters::NO_EFFECTS);
 }
@@ -400,7 +349,7 @@
 
   {
     // Both geometries empty.
-    MockMediaConstraintFactory constraint_factory;
+    MockConstraintFactory constraint_factory;
     MediaStreamDevice::AudioDeviceParameters input_params;
 
     const auto& actual_geometry = GetArrayGeometryPreferringConstraints(
@@ -409,7 +358,7 @@
   }
   {
     // Constraints geometry empty.
-    MockMediaConstraintFactory constraint_factory;
+    MockConstraintFactory constraint_factory;
     MediaStreamDevice::AudioDeviceParameters input_params;
     input_params.mic_positions.push_back(media::Point(0, 0, 0));
     input_params.mic_positions.push_back(media::Point(0, 0.05f, 0));
@@ -420,9 +369,9 @@
   }
   {
     // Input device geometry empty.
-    MockMediaConstraintFactory constraint_factory;
-    constraint_factory.AddOptional(MediaAudioConstraints::kGoogArrayGeometry,
-                                   std::string("-0.02 0 0 0.02 0 0"));
+    MockConstraintFactory constraint_factory;
+    constraint_factory.AddAdvanced().googArrayGeometry.setExact(
+        blink::WebString::fromUTF8("-0.02 0 0 0.02 0 0"));
     MediaStreamDevice::AudioDeviceParameters input_params;
 
     const auto& actual_geometry = GetArrayGeometryPreferringConstraints(
@@ -431,9 +380,9 @@
   }
   {
     // Both geometries existing.
-    MockMediaConstraintFactory constraint_factory;
-    constraint_factory.AddOptional(MediaAudioConstraints::kGoogArrayGeometry,
-                                   std::string("-0.02 0 0 0.02 0 0"));
+    MockConstraintFactory constraint_factory;
+    constraint_factory.AddAdvanced().googArrayGeometry.setExact(
+        blink::WebString::fromUTF8("-0.02 0 0 0.02 0 0"));
     MediaStreamDevice::AudioDeviceParameters input_params;
     input_params.mic_positions.push_back(media::Point(0, 0, 0));
     input_params.mic_positions.push_back(media::Point(0, 0.05f, 0));
@@ -452,7 +401,7 @@
 #define MAYBE_TestAllSampleRates TestAllSampleRates
 #endif
 TEST_F(MediaStreamAudioProcessorTest, MAYBE_TestAllSampleRates) {
-  MockMediaConstraintFactory constraint_factory;
+  MockConstraintFactory constraint_factory;
   scoped_refptr<WebRtcAudioDeviceImpl> webrtc_audio_device(
       new WebRtcAudioDeviceImpl());
   scoped_refptr<MediaStreamAudioProcessor> audio_processor(
@@ -493,7 +442,7 @@
       new AecDumpMessageFilter(message_loop.task_runner(),
                                message_loop.task_runner(), nullptr));
 
-  MockMediaConstraintFactory constraint_factory;
+  MockConstraintFactory constraint_factory;
   scoped_refptr<WebRtcAudioDeviceImpl> webrtc_audio_device(
       new WebRtcAudioDeviceImpl());
   scoped_refptr<MediaStreamAudioProcessor> audio_processor(
@@ -509,11 +458,9 @@
 TEST_F(MediaStreamAudioProcessorTest, TestStereoAudio) {
   // Set up the correct constraints to turn off the audio processing and turn
   // on the stereo channels mirroring.
-  MockMediaConstraintFactory constraint_factory;
-  constraint_factory.AddMandatory(MediaAudioConstraints::kEchoCancellation,
-                                  false);
-  constraint_factory.AddMandatory(MediaAudioConstraints::kGoogAudioMirroring,
-                                  true);
+  MockConstraintFactory constraint_factory;
+  constraint_factory.basic().echoCancellation.setExact(false);
+  constraint_factory.basic().googAudioMirroring.setExact(true);
   scoped_refptr<WebRtcAudioDeviceImpl> webrtc_audio_device(
       new WebRtcAudioDeviceImpl());
   scoped_refptr<MediaStreamAudioProcessor> audio_processor(
@@ -525,7 +472,8 @@
       media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
       media::CHANNEL_LAYOUT_STEREO, 48000, 16, 480);
   audio_processor->OnCaptureFormatChanged(source_params);
-  EXPECT_EQ(audio_processor->OutputFormat().channels(), 2);
+  // There's no sense in continuing if this fails.
+  ASSERT_EQ(2, audio_processor->OutputFormat().channels());
 
   // Construct left and right channels, and assign different values to the
   // first data of the left channel and right channel.
@@ -575,9 +523,8 @@
 #endif
 
 TEST_F(MediaStreamAudioProcessorTest, MAYBE_TestWithKeyboardMicChannel) {
-  MockMediaConstraintFactory constraint_factory;
-  constraint_factory.AddMandatory(
-      MediaAudioConstraints::kGoogExperimentalNoiseSuppression, true);
+  MockConstraintFactory constraint_factory;
+  constraint_factory.basic().googExperimentalNoiseSuppression.setExact(true);
   scoped_refptr<WebRtcAudioDeviceImpl> webrtc_audio_device(
       new WebRtcAudioDeviceImpl());
   scoped_refptr<MediaStreamAudioProcessor> audio_processor(
diff --git a/content/renderer/media/media_stream_video_source.cc b/content/renderer/media/media_stream_video_source.cc
index 942d248..c0094b9 100644
--- a/content/renderer/media/media_stream_video_source.cc
+++ b/content/renderer/media/media_stream_video_source.cc
@@ -576,6 +576,9 @@
       callback(callback) {
 }
 
+MediaStreamVideoSource::TrackDescriptor::TrackDescriptor(
+    const TrackDescriptor& other) = default;
+
 MediaStreamVideoSource::TrackDescriptor::~TrackDescriptor() {
 }
 
diff --git a/content/renderer/media/media_stream_video_source.h b/content/renderer/media/media_stream_video_source.h
index cd403750..e86a7d1 100644
--- a/content/renderer/media/media_stream_video_source.h
+++ b/content/renderer/media/media_stream_video_source.h
@@ -164,6 +164,7 @@
                     const VideoCaptureDeliverFrameCB& frame_callback,
                     const blink::WebMediaConstraints& constraints,
                     const ConstraintsCallback& callback);
+    TrackDescriptor(const TrackDescriptor& other);
     ~TrackDescriptor();
 
     MediaStreamVideoTrack* track;
diff --git a/content/renderer/media/mock_constraint_factory.cc b/content/renderer/media/mock_constraint_factory.cc
index 63ae5f0..f271816 100644
--- a/content/renderer/media/mock_constraint_factory.cc
+++ b/content/renderer/media/mock_constraint_factory.cc
@@ -29,4 +29,17 @@
   return constraints;
 }
 
+void MockConstraintFactory::DisableDefaultAudioConstraints() {
+  basic_.googEchoCancellation.setExact(false);
+  basic_.googExperimentalEchoCancellation.setExact(false);
+  basic_.googAutoGainControl.setExact(false);
+  basic_.googExperimentalAutoGainControl.setExact(false);
+  basic_.googNoiseSuppression.setExact(false);
+  basic_.googNoiseSuppression.setExact(false);
+  basic_.googHighpassFilter.setExact(false);
+  basic_.googTypingNoiseDetection.setExact(false);
+  basic_.googExperimentalNoiseSuppression.setExact(false);
+  basic_.googBeamforming.setExact(false);
+}
+
 }  // namespace content
diff --git a/content/renderer/media/mock_constraint_factory.h b/content/renderer/media/mock_constraint_factory.h
index e9d4da0..74dfbe0 100644
--- a/content/renderer/media/mock_constraint_factory.h
+++ b/content/renderer/media/mock_constraint_factory.h
@@ -21,6 +21,8 @@
   blink::WebMediaTrackConstraintSet& basic() { return basic_; }
   blink::WebMediaTrackConstraintSet& AddAdvanced();
 
+  void DisableDefaultAudioConstraints();
+
  private:
   blink::WebMediaTrackConstraintSet basic_;
   std::vector<blink::WebMediaTrackConstraintSet> advanced_;
diff --git a/content/renderer/media/render_media_log.cc b/content/renderer/media/render_media_log.cc
index eae60c0..180d2b22 100644
--- a/content/renderer/media/render_media_log.cc
+++ b/content/renderer/media/render_media_log.cc
@@ -9,6 +9,7 @@
 #include "base/logging.h"
 #include "base/single_thread_task_runner.h"
 #include "base/thread_task_runner_handle.h"
+#include "base/time/default_tick_clock.h"
 #include "content/common/view_messages.h"
 #include "content/public/renderer/render_thread.h"
 
diff --git a/content/renderer/media/render_media_log.h b/content/renderer/media/render_media_log.h
index bc48630..a67927d 100644
--- a/content/renderer/media/render_media_log.h
+++ b/content/renderer/media/render_media_log.h
@@ -12,6 +12,10 @@
 #include "content/common/content_export.h"
 #include "media/base/media_log.h"
 
+namespace base {
+class TickClock;
+}
+
 namespace content {
 
 // RenderMediaLog is an implementation of MediaLog that forwards events to the
diff --git a/content/renderer/media/video_capture_impl.cc b/content/renderer/media/video_capture_impl.cc
index 8e50ede..bef9f3be 100644
--- a/content/renderer/media/video_capture_impl.cc
+++ b/content/renderer/media/video_capture_impl.cc
@@ -101,6 +101,7 @@
 };
 
 VideoCaptureImpl::ClientInfo::ClientInfo() {}
+VideoCaptureImpl::ClientInfo::ClientInfo(const ClientInfo& other) = default;
 VideoCaptureImpl::ClientInfo::~ClientInfo() {}
 
 VideoCaptureImpl::VideoCaptureImpl(
diff --git a/content/renderer/media/video_capture_impl.h b/content/renderer/media/video_capture_impl.h
index cd2a8090..c320775 100644
--- a/content/renderer/media/video_capture_impl.h
+++ b/content/renderer/media/video_capture_impl.h
@@ -96,6 +96,7 @@
   // for capturing and callbacks to the client.
   struct ClientInfo {
     ClientInfo();
+    ClientInfo(const ClientInfo& other);
     ~ClientInfo();
     media::VideoCaptureParams params;
     VideoCaptureStateUpdateCB state_update_cb;
diff --git a/content/renderer/media/webaudio_capturer_source.cc b/content/renderer/media/webaudio_capturer_source.cc
index bcebcbb3..2d66343 100644
--- a/content/renderer/media/webaudio_capturer_source.cc
+++ b/content/renderer/media/webaudio_capturer_source.cc
@@ -4,27 +4,26 @@
 
 #include "content/renderer/media/webaudio_capturer_source.h"
 
+#include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "base/logging.h"
-#include "base/time/time.h"
 #include "content/renderer/media/webrtc_local_audio_track.h"
 
 using media::AudioBus;
-using media::AudioFifo;
 using media::AudioParameters;
 using media::ChannelLayout;
 using media::CHANNEL_LAYOUT_MONO;
 using media::CHANNEL_LAYOUT_STEREO;
 
-static const int kMaxNumberOfBuffersInFifo = 5;
-
 namespace content {
 
 WebAudioCapturerSource::WebAudioCapturerSource(
     const blink::WebMediaStreamSource& blink_source)
     : track_(NULL),
       audio_format_changed_(false),
-      blink_source_(blink_source) {
-}
+      fifo_(base::Bind(&WebAudioCapturerSource::DeliverRebufferedAudio,
+                       base::Unretained(this))),
+      blink_source_(blink_source) {}
 
 WebAudioCapturerSource::~WebAudioCapturerSource() {
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -48,20 +47,19 @@
   // Set the format used by this WebAudioCapturerSource. We are using 10ms data
   // as buffer size since that is the native buffer size of WebRtc packet
   // running on.
+  fifo_.Reset(sample_rate / 100);
   params_.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout,
-                sample_rate, 16, sample_rate / 100);
+                sample_rate, 16, fifo_.frames_per_buffer());
 
   // Take care of the discrete channel layout case.
   params_.set_channels_for_discrete(number_of_channels);
 
   audio_format_changed_ = true;
 
-  wrapper_bus_ = AudioBus::CreateWrapper(params_.channels());
-  capture_bus_ = AudioBus::Create(params_);
-
-  fifo_.reset(new AudioFifo(
-      params_.channels(),
-      kMaxNumberOfBuffersInFifo * params_.frames_per_buffer()));
+  if (!wrapper_bus_ ||
+      wrapper_bus_->channels() != static_cast<int>(number_of_channels)) {
+    wrapper_bus_ = AudioBus::CreateWrapper(params_.channels());
+  }
 }
 
 void WebAudioCapturerSource::Start(WebRtcLocalAudioTrack* track) {
@@ -85,6 +83,11 @@
 void WebAudioCapturerSource::consumeAudio(
     const blink::WebVector<const float*>& audio_data,
     size_t number_of_frames) {
+  // TODO(miu): Plumbing is needed to determine the actual capture timestamp
+  // of the audio, instead of just snapshotting TimeTicks::Now(), for proper
+  // audio/video sync.  http://crbug.com/335335
+  current_reference_time_ = base::TimeTicks::Now();
+
   base::AutoLock auto_lock(lock_);
   if (!track_)
     return;
@@ -96,36 +99,25 @@
   }
 
   wrapper_bus_->set_frames(number_of_frames);
-
-  // Make sure WebKit is honoring what it told us up front
-  // about the channels.
   DCHECK_EQ(params_.channels(), static_cast<int>(audio_data.size()));
-
   for (size_t i = 0; i < audio_data.size(); ++i)
     wrapper_bus_->SetChannelData(i, const_cast<float*>(audio_data[i]));
 
-  // Handle mismatch between WebAudio buffer-size and WebRTC.
-  int available = fifo_->max_frames() - fifo_->frames();
-  if (available < static_cast<int>(number_of_frames)) {
-    NOTREACHED() << "WebAudioCapturerSource::Consume() : FIFO overrun.";
-    return;
-  }
+  // The following will result in zero, one, or multiple synchronous calls to
+  // DeliverRebufferedAudio().
+  fifo_.Push(*wrapper_bus_);
+}
 
-  // Compute the estimated capture time of the first sample frame of audio that
-  // will be consumed from the FIFO in the loop below.
-  base::TimeTicks estimated_capture_time = base::TimeTicks::Now() -
-      fifo_->frames() * base::TimeDelta::FromSeconds(1) / params_.sample_rate();
-
-  fifo_->Push(wrapper_bus_.get());
-  while (fifo_->frames() >= capture_bus_->frames()) {
-    fifo_->Consume(capture_bus_.get(), 0, capture_bus_->frames());
-    track_->Capture(*capture_bus_, estimated_capture_time, false);
-
-    // Advance the estimated capture time for the next FIFO consume operation.
-    estimated_capture_time +=
-        capture_bus_->frames() * base::TimeDelta::FromSeconds(1) /
-            params_.sample_rate();
-  }
+void WebAudioCapturerSource::DeliverRebufferedAudio(
+    const media::AudioBus& audio_bus,
+    int frame_delay) {
+  lock_.AssertAcquired();
+  const base::TimeTicks reference_time =
+      current_reference_time_ +
+      base::TimeDelta::FromMicroseconds(frame_delay *
+                                        base::Time::kMicrosecondsPerSecond /
+                                        params_.sample_rate());
+  track_->Capture(audio_bus, reference_time, false);
 }
 
 // If registered as audio consumer in |blink_source_|, deregister from
diff --git a/content/renderer/media/webaudio_capturer_source.h b/content/renderer/media/webaudio_capturer_source.h
index b0ee262..d5b3bb5 100644
--- a/content/renderer/media/webaudio_capturer_source.h
+++ b/content/renderer/media/webaudio_capturer_source.h
@@ -11,9 +11,11 @@
 #include "base/memory/ref_counted.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
+#include "base/time/time.h"
 #include "media/audio/audio_parameters.h"
+#include "media/base/audio_bus.h"
 #include "media/base/audio_capturer_source.h"
-#include "media/base/audio_fifo.h"
+#include "media/base/audio_push_fifo.h"
 #include "third_party/WebKit/public/platform/WebAudioDestinationConsumer.h"
 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
 #include "third_party/WebKit/public/platform/WebVector.h"
@@ -58,6 +60,12 @@
   ~WebAudioCapturerSource() override;
 
  private:
+  // Called by AudioPushFifo zero or more times during the call to
+  // consumeAudio().  Delivers audio data with the required buffer size to the
+  // track.
+  void DeliverRebufferedAudio(const media::AudioBus& audio_bus,
+                              int frame_delay);
+
   // Removes this object from a blink::WebMediaStreamSource with which it
   // might be registered. The goal is to avoid dangling pointers.
   void removeFromBlinkSource();
@@ -75,14 +83,18 @@
   // Flag to help notify the |track_| when the audio format has changed.
   bool audio_format_changed_;
 
-  // Wraps data coming from HandleCapture().
+  // A wrapper used for providing audio to |fifo_|.
   scoped_ptr<media::AudioBus> wrapper_bus_;
 
-  // Bus for reading from FIFO and calling the CaptureCallback.
-  scoped_ptr<media::AudioBus> capture_bus_;
+  // Takes in the audio data passed to consumeAudio() and re-buffers it into 10
+  // ms chunks for the track.  This ensures each chunk of audio delivered to the
+  // track has the required buffer size, regardless of the amount of audio
+  // provided via each consumeAudio() call.
+  media::AudioPushFifo fifo_;
 
-  // Handles mismatch between WebAudio buffer size and WebRTC.
-  scoped_ptr<media::AudioFifo> fifo_;
+  // Used to pass the reference timestamp between DeliverDecodedAudio() and
+  // DeliverRebufferedAudio().
+  base::TimeTicks current_reference_time_;
 
   // Synchronizes HandleCapture() with AudioCapturerSource calls.
   base::Lock lock_;
diff --git a/content/renderer/media/webrtc_audio_capturer.cc b/content/renderer/media/webrtc_audio_capturer.cc
index 113233e..9c56be0b 100644
--- a/content/renderer/media/webrtc_audio_capturer.cc
+++ b/content/renderer/media/webrtc_audio_capturer.cc
@@ -170,9 +170,8 @@
   // If KEYBOARD_MIC effect is set, change the layout to the corresponding
   // layout that includes the keyboard mic.
   if ((device_info_.device.input.effects &
-          media::AudioParameters::KEYBOARD_MIC) &&
-      audio_constraints.GetProperty(
-          MediaAudioConstraints::kGoogExperimentalNoiseSuppression)) {
+       media::AudioParameters::KEYBOARD_MIC) &&
+      audio_constraints.GetGoogExperimentalNoiseSuppression()) {
     if (channel_layout == media::CHANNEL_LAYOUT_STEREO) {
       channel_layout = media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC;
       DVLOG(1) << "Changed stereo layout to stereo + keyboard mic layout due "
diff --git a/content/renderer/media/webrtc_audio_capturer_unittest.cc b/content/renderer/media/webrtc_audio_capturer_unittest.cc
index 306ca98..a93aede 100644
--- a/content/renderer/media/webrtc_audio_capturer_unittest.cc
+++ b/content/renderer/media/webrtc_audio_capturer_unittest.cc
@@ -5,7 +5,7 @@
 #include "base/logging.h"
 #include "build/build_config.h"
 #include "content/public/renderer/media_stream_audio_sink.h"
-#include "content/renderer/media/mock_media_constraint_factory.h"
+#include "content/renderer/media/mock_constraint_factory.h"
 #include "content/renderer/media/webrtc/webrtc_local_audio_track_adapter.h"
 #include "content/renderer/media/webrtc_audio_capturer.h"
 #include "content/renderer/media/webrtc_local_audio_track.h"
@@ -126,15 +126,16 @@
 TEST_F(WebRtcAudioCapturerTest, VerifyAudioParamsWithAudioProcessing) {
   // Turn off the default constraints to verify that the sink will get packets
   // with a buffer size smaller than 10ms.
-  MockMediaConstraintFactory constraint_factory;
+  MockConstraintFactory constraint_factory;
   constraint_factory.DisableDefaultAudioConstraints();
   VerifyAudioParams(constraint_factory.CreateWebMediaConstraints(), false);
 }
 
 TEST_F(WebRtcAudioCapturerTest, FailToCreateCapturerWithWrongConstraints) {
-  MockMediaConstraintFactory constraint_factory;
+  MockConstraintFactory constraint_factory;
   const std::string dummy_constraint = "dummy";
-  constraint_factory.AddMandatory(dummy_constraint, true);
+  // Set a non-audio constraint.
+  constraint_factory.basic().width.setExact(240);
 
   scoped_refptr<WebRtcAudioCapturer> capturer(
       WebRtcAudioCapturer::CreateCapturer(
diff --git a/content/renderer/media/webrtc_identity_service.cc b/content/renderer/media/webrtc_identity_service.cc
index c38d192..16cdd99 100644
--- a/content/renderer/media/webrtc_identity_service.cc
+++ b/content/renderer/media/webrtc_identity_service.cc
@@ -20,6 +20,9 @@
       success_callback(success_callback),
       failure_callback(failure_callback) {}
 
+WebRTCIdentityService::RequestInfo::RequestInfo(const RequestInfo& other) =
+    default;
+
 WebRTCIdentityService::RequestInfo::~RequestInfo() {}
 
 WebRTCIdentityService::WebRTCIdentityService() : next_request_id_(1) {
diff --git a/content/renderer/media/webrtc_identity_service.h b/content/renderer/media/webrtc_identity_service.h
index 6092f8a..927700d 100644
--- a/content/renderer/media/webrtc_identity_service.h
+++ b/content/renderer/media/webrtc_identity_service.h
@@ -69,6 +69,7 @@
     RequestInfo(const WebRTCIdentityMsg_RequestIdentity_Params& params,
                 const SuccessCallback& success_callback,
                 const FailureCallback& failure_callback);
+    RequestInfo(const RequestInfo& other);
     ~RequestInfo();
 
     WebRTCIdentityMsg_RequestIdentity_Params params;
diff --git a/content/renderer/media/webrtc_local_audio_track_unittest.cc b/content/renderer/media/webrtc_local_audio_track_unittest.cc
index 986a536..7c478c8 100644
--- a/content/renderer/media/webrtc_local_audio_track_unittest.cc
+++ b/content/renderer/media/webrtc_local_audio_track_unittest.cc
@@ -8,7 +8,7 @@
 #include "build/build_config.h"
 #include "content/public/renderer/media_stream_audio_sink.h"
 #include "content/renderer/media/media_stream_audio_source.h"
-#include "content/renderer/media/mock_media_constraint_factory.h"
+#include "content/renderer/media/mock_constraint_factory.h"
 #include "content/renderer/media/webrtc/webrtc_local_audio_track_adapter.h"
 #include "content/renderer/media/webrtc_audio_capturer.h"
 #include "content/renderer/media/webrtc_local_audio_track.h"
@@ -156,7 +156,7 @@
   void SetUp() override {
     params_.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
                   media::CHANNEL_LAYOUT_STEREO, 48000, 16, 480);
-    MockMediaConstraintFactory constraint_factory;
+    MockConstraintFactory constraint_factory;
     blink_source_.initialize("dummy", blink::WebMediaStreamSource::TypeAudio,
                              "dummy",
                              false /* remote */, true /* readonly */);
@@ -415,7 +415,7 @@
   track_1->AddSink(sink_1.get());
 
   // Create a new capturer with new source with different audio format.
-  MockMediaConstraintFactory constraint_factory;
+  MockConstraintFactory constraint_factory;
   StreamDeviceInfo device(MEDIA_DEVICE_AUDIO_CAPTURE,
                           std::string(), std::string());
   scoped_refptr<WebRtcAudioCapturer> new_capturer(
@@ -469,7 +469,7 @@
                                 media::CHANNEL_LAYOUT_STEREO, 48000, 16, 128);
 
   // Create a capturer with new source which works with the format above.
-  MockMediaConstraintFactory factory;
+  MockConstraintFactory factory;
   factory.DisableDefaultAudioConstraints();
   scoped_refptr<WebRtcAudioCapturer> capturer(
       WebRtcAudioCapturer::CreateCapturer(
diff --git a/content/renderer/p2p/ipc_network_manager.cc b/content/renderer/p2p/ipc_network_manager.cc
index 1c9acb9..025fc0cd 100644
--- a/content/renderer/p2p/ipc_network_manager.cc
+++ b/content/renderer/p2p/ipc_network_manager.cc
@@ -15,7 +15,6 @@
 #include "content/public/common/content_switches.h"
 #include "jingle/glue/utils.h"
 #include "net/base/ip_address_number.h"
-#include "net/base/net_util.h"
 #include "net/base/network_change_notifier.h"
 #include "net/base/network_interfaces.h"
 #include "third_party/webrtc/base/socketaddress.h"
diff --git a/content/renderer/p2p/ipc_network_manager_unittest.cc b/content/renderer/p2p/ipc_network_manager_unittest.cc
index 7baaaf25..31fcd47 100644
--- a/content/renderer/p2p/ipc_network_manager_unittest.cc
+++ b/content/renderer/p2p/ipc_network_manager_unittest.cc
@@ -6,7 +6,6 @@
 #include "content/renderer/p2p/ipc_network_manager.h"
 #include "content/renderer/p2p/network_list_manager.h"
 #include "net/base/ip_address_number.h"
-#include "net/base/net_util.h"
 #include "net/base/network_change_notifier.h"
 #include "net/base/network_interfaces.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/content/renderer/pepper/pepper_broker.cc b/content/renderer/pepper/pepper_broker.cc
index b1e0626..0869e80 100644
--- a/content/renderer/pepper/pepper_broker.cc
+++ b/content/renderer/pepper/pepper_broker.cc
@@ -208,6 +208,9 @@
 
 PepperBroker::PendingConnection::PendingConnection() : is_authorized(false) {}
 
+PepperBroker::PendingConnection::PendingConnection(
+    const PendingConnection& other) = default;
+
 PepperBroker::PendingConnection::~PendingConnection() {}
 
 void PepperBroker::ReportFailureToClients(int error_code) {
diff --git a/content/renderer/pepper/pepper_broker.h b/content/renderer/pepper/pepper_broker.h
index 1140d4e..fda0045 100644
--- a/content/renderer/pepper/pepper_broker.h
+++ b/content/renderer/pepper/pepper_broker.h
@@ -72,6 +72,7 @@
 
   struct PendingConnection {
     PendingConnection();
+    PendingConnection(const PendingConnection& other);
     ~PendingConnection();
 
     bool is_authorized;
diff --git a/content/renderer/pepper/pepper_compositor_host.cc b/content/renderer/pepper/pepper_compositor_host.cc
index 939cd98..3225424 100644
--- a/content/renderer/pepper/pepper_compositor_host.cc
+++ b/content/renderer/pepper/pepper_compositor_host.cc
@@ -145,6 +145,8 @@
     const scoped_refptr<cc::Layer>& cc,
     const ppapi::CompositorLayerData& pp) : cc_layer(cc), pp_layer(pp) {}
 
+PepperCompositorHost::LayerData::LayerData(const LayerData& other) = default;
+
 PepperCompositorHost::LayerData::~LayerData() {}
 
 PepperCompositorHost::PepperCompositorHost(
diff --git a/content/renderer/pepper/pepper_compositor_host.h b/content/renderer/pepper/pepper_compositor_host.h
index fab64176..599f3469 100644
--- a/content/renderer/pepper/pepper_compositor_host.h
+++ b/content/renderer/pepper/pepper_compositor_host.h
@@ -91,6 +91,7 @@
   struct LayerData {
     LayerData(const scoped_refptr<cc::Layer>& cc,
               const ppapi::CompositorLayerData& pp);
+    LayerData(const LayerData& other);
     ~LayerData();
 
     scoped_refptr<cc::Layer> cc_layer;
diff --git a/content/renderer/pepper/pepper_video_capture_host.cc b/content/renderer/pepper/pepper_video_capture_host.cc
index 4e08661..e960474 100644
--- a/content/renderer/pepper/pepper_video_capture_host.cc
+++ b/content/renderer/pepper/pepper_video_capture_host.cc
@@ -412,6 +412,9 @@
     : in_use(false), data(NULL), buffer() {
 }
 
+PepperVideoCaptureHost::BufferInfo::BufferInfo(const BufferInfo& other) =
+    default;
+
 PepperVideoCaptureHost::BufferInfo::~BufferInfo() {
 }
 
diff --git a/content/renderer/pepper/pepper_video_capture_host.h b/content/renderer/pepper/pepper_video_capture_host.h
index 01d678b..5a2dead 100644
--- a/content/renderer/pepper/pepper_video_capture_host.h
+++ b/content/renderer/pepper/pepper_video_capture_host.h
@@ -95,6 +95,7 @@
   // Buffers of video frame.
   struct BufferInfo {
     BufferInfo();
+    BufferInfo(const BufferInfo& other);
     ~BufferInfo();
 
     bool in_use;
diff --git a/content/renderer/pepper/plugin_power_saver_helper.cc b/content/renderer/pepper/plugin_power_saver_helper.cc
index 10f0954..36d65e3f 100644
--- a/content/renderer/pepper/plugin_power_saver_helper.cc
+++ b/content/renderer/pepper/plugin_power_saver_helper.cc
@@ -33,6 +33,9 @@
     : content_origin(content_origin),
       unthrottle_callback(unthrottle_callback) {}
 
+PluginPowerSaverHelper::PeripheralPlugin::PeripheralPlugin(
+    const PeripheralPlugin& other) = default;
+
 PluginPowerSaverHelper::PeripheralPlugin::~PeripheralPlugin() {
 }
 
diff --git a/content/renderer/pepper/plugin_power_saver_helper.h b/content/renderer/pepper/plugin_power_saver_helper.h
index 95fbc88..2f3bb4426 100644
--- a/content/renderer/pepper/plugin_power_saver_helper.h
+++ b/content/renderer/pepper/plugin_power_saver_helper.h
@@ -37,6 +37,7 @@
   struct PeripheralPlugin {
     PeripheralPlugin(const url::Origin& content_origin,
                      const base::Closure& unthrottle_callback);
+    PeripheralPlugin(const PeripheralPlugin& other);
     ~PeripheralPlugin();
 
     url::Origin content_origin;
diff --git a/content/renderer/raster_worker_pool.cc b/content/renderer/raster_worker_pool.cc
index 0924c0a..73ec4ef6 100644
--- a/content/renderer/raster_worker_pool.cc
+++ b/content/renderer/raster_worker_pool.cc
@@ -21,19 +21,22 @@
 // categories.
 class RasterWorkerPoolThread : public base::SimpleThread {
  public:
-  explicit RasterWorkerPoolThread(const std::string& name_prefix,
-                                  const Options& options,
-                                  RasterWorkerPool* pool,
-                                  std::vector<cc::TaskCategory> categories)
+  RasterWorkerPoolThread(const std::string& name_prefix,
+                         const Options& options,
+                         RasterWorkerPool* pool,
+                         std::vector<cc::TaskCategory> categories,
+                         base::ConditionVariable* has_ready_to_run_tasks_cv)
       : SimpleThread(name_prefix, options),
         pool_(pool),
-        categories_(categories) {}
+        categories_(categories),
+        has_ready_to_run_tasks_cv_(has_ready_to_run_tasks_cv) {}
 
-  void Run() override { pool_->Run(categories_); }
+  void Run() override { pool_->Run(categories_, has_ready_to_run_tasks_cv_); }
 
  private:
   RasterWorkerPool* const pool_;
   const std::vector<cc::TaskCategory> categories_;
+  base::ConditionVariable* const has_ready_to_run_tasks_cv_;
 };
 
 }  // namespace
@@ -116,7 +119,8 @@
 
 RasterWorkerPool::RasterWorkerPool()
     : namespace_token_(GetNamespaceToken()),
-      has_ready_to_run_tasks_cv_(&lock_),
+      has_ready_to_run_foreground_tasks_cv_(&lock_),
+      has_ready_to_run_background_tasks_cv_(&lock_),
       has_namespaces_with_finished_running_tasks_cv_(&lock_),
       shutdown_(false) {}
 
@@ -124,31 +128,35 @@
     int num_threads,
     const base::SimpleThread::Options& thread_options) {
   DCHECK(threads_.empty());
-  while (threads_.size() < static_cast<size_t>(num_threads)) {
-    // Determine the categories that each thread can run.
-    std::vector<cc::TaskCategory> task_categories;
 
-    // The first thread can run nonconcurrent tasks.
-    if (threads_.size() == 0) {
-      task_categories.push_back(cc::TASK_CATEGORY_NONCONCURRENT_FOREGROUND);
-    }
+  // Start |num_threads| threads for foreground work, including nonconcurrent
+  // foreground work.
+  std::vector<cc::TaskCategory> foreground_categories;
+  foreground_categories.push_back(cc::TASK_CATEGORY_NONCONCURRENT_FOREGROUND);
+  foreground_categories.push_back(cc::TASK_CATEGORY_FOREGROUND);
 
-    // All threads can run foreground tasks.
-    task_categories.push_back(cc::TASK_CATEGORY_FOREGROUND);
-
-    // The last thread can run background tasks.
-    if (threads_.size() == (static_cast<size_t>(num_threads) - 1)) {
-      task_categories.push_back(cc::TASK_CATEGORY_BACKGROUND);
-    }
-
+  for (int i = 0; i < num_threads; i++) {
     scoped_ptr<base::SimpleThread> thread(new RasterWorkerPoolThread(
         base::StringPrintf("CompositorTileWorker%u",
                            static_cast<unsigned>(threads_.size() + 1))
             .c_str(),
-        thread_options, this, task_categories));
+        thread_options, this, foreground_categories,
+        &has_ready_to_run_foreground_tasks_cv_));
     thread->Start();
     threads_.push_back(std::move(thread));
   }
+
+  // Start a single thread for background work.
+  std::vector<cc::TaskCategory> background_categories;
+  background_categories.push_back(cc::TASK_CATEGORY_BACKGROUND);
+  scoped_ptr<base::SimpleThread> thread(new RasterWorkerPoolThread(
+      base::StringPrintf("CompositorTileWorker%u",
+                         static_cast<unsigned>(threads_.size() + 1))
+          .c_str(),
+      thread_options, this, background_categories,
+      &has_ready_to_run_background_tasks_cv_));
+  thread->Start();
+  threads_.push_back(std::move(thread));
 }
 
 void RasterWorkerPool::Shutdown() {
@@ -165,7 +173,8 @@
     shutdown_ = true;
 
     // Wake up all workers so they exit.
-    has_ready_to_run_tasks_cv_.Broadcast();
+    has_ready_to_run_foreground_tasks_cv_.Broadcast();
+    has_ready_to_run_background_tasks_cv_.Broadcast();
   }
   while (!threads_.empty()) {
     threads_.back()->Join();
@@ -211,17 +220,22 @@
   return true;
 }
 
-void RasterWorkerPool::Run(const std::vector<cc::TaskCategory>& categories) {
+void RasterWorkerPool::Run(const std::vector<cc::TaskCategory>& categories,
+                           base::ConditionVariable* has_ready_to_run_tasks_cv) {
   base::AutoLock lock(lock_);
 
   while (true) {
     if (!RunTaskWithLockAcquired(categories)) {
+      // We are no longer running tasks, which may allow another category to
+      // start running. Signal other worker threads.
+      SignalHasReadyToRunTasksWithLockAcquired();
+
       // Exit when shutdown is set and no more tasks are pending.
       if (shutdown_)
         break;
 
       // Wait for more tasks.
-      has_ready_to_run_tasks_cv_.Wait();
+      has_ready_to_run_tasks_cv->Wait();
       continue;
     }
   }
@@ -266,9 +280,8 @@
 
   work_queue_.ScheduleTasks(token, graph);
 
-  // If there is more work available, wake up the other worker threads.
-  if (work_queue_.HasReadyToRunTasks())
-    has_ready_to_run_tasks_cv_.Broadcast();
+  // There may be more work available, so wake up another worker thread.
+  SignalHasReadyToRunTasksWithLockAcquired();
 }
 
 void RasterWorkerPool::WaitForTasksToFinishRunning(cc::NamespaceToken token) {
@@ -288,6 +301,10 @@
 
     while (!work_queue_.HasFinishedRunningTasksInNamespace(task_namespace))
       has_namespaces_with_finished_running_tasks_cv_.Wait();
+
+    // There may be other namespaces that have finished running tasks, so wake
+    // up another origin thread.
+    has_namespaces_with_finished_running_tasks_cv_.Signal();
   }
 }
 
@@ -313,7 +330,7 @@
 bool RasterWorkerPool::RunTaskWithLockAcquired(
     const std::vector<cc::TaskCategory>& categories) {
   for (const auto& category : categories) {
-    if (work_queue_.HasReadyToRunTasksForCategory(category)) {
+    if (ShouldRunTaskForCategoryWithLockAcquired(category)) {
       RunTaskInCategoryWithLockAcquired(category);
       return true;
     }
@@ -330,6 +347,9 @@
   auto prioritized_task = work_queue_.GetNextTaskToRun(category);
   cc::Task* task = prioritized_task.task;
 
+  // There may be more work available, so wake up another worker thread.
+  SignalHasReadyToRunTasksWithLockAcquired();
+
   // Call WillRun() before releasing |lock_| and running task.
   task->WillRun();
 
@@ -344,14 +364,57 @@
 
   work_queue_.CompleteTask(prioritized_task);
 
-  // We may have just dequeued more tasks, wake up the other worker threads.
-  if (work_queue_.HasReadyToRunTasks())
-    has_ready_to_run_tasks_cv_.Broadcast();
-
   // If namespace has finished running all tasks, wake up origin threads.
   if (work_queue_.HasFinishedRunningTasksInNamespace(
           prioritized_task.task_namespace))
-    has_namespaces_with_finished_running_tasks_cv_.Broadcast();
+    has_namespaces_with_finished_running_tasks_cv_.Signal();
+}
+
+bool RasterWorkerPool::ShouldRunTaskForCategoryWithLockAcquired(
+    cc::TaskCategory category) {
+  lock_.AssertAcquired();
+
+  if (!work_queue_.HasReadyToRunTasksForCategory(category))
+    return false;
+
+  if (category == cc::TASK_CATEGORY_BACKGROUND) {
+    // Only run background tasks if there are no foreground tasks running or
+    // ready to run.
+    size_t num_running_foreground_tasks =
+        work_queue_.NumRunningTasksForCategory(
+            cc::TASK_CATEGORY_NONCONCURRENT_FOREGROUND) +
+        work_queue_.NumRunningTasksForCategory(cc::TASK_CATEGORY_FOREGROUND);
+    bool has_ready_to_run_foreground_tasks =
+        work_queue_.HasReadyToRunTasksForCategory(
+            cc::TASK_CATEGORY_NONCONCURRENT_FOREGROUND) ||
+        work_queue_.HasReadyToRunTasksForCategory(cc::TASK_CATEGORY_FOREGROUND);
+
+    if (num_running_foreground_tasks > 0 || has_ready_to_run_foreground_tasks)
+      return false;
+  }
+
+  // Enforce that only one nonconcurrent task runs at a time.
+  if (category == cc::TASK_CATEGORY_NONCONCURRENT_FOREGROUND &&
+      work_queue_.NumRunningTasksForCategory(
+          cc::TASK_CATEGORY_NONCONCURRENT_FOREGROUND) > 0) {
+    return false;
+  }
+
+  return true;
+}
+
+void RasterWorkerPool::SignalHasReadyToRunTasksWithLockAcquired() {
+  lock_.AssertAcquired();
+
+  if (ShouldRunTaskForCategoryWithLockAcquired(cc::TASK_CATEGORY_FOREGROUND) ||
+      ShouldRunTaskForCategoryWithLockAcquired(
+          cc::TASK_CATEGORY_NONCONCURRENT_FOREGROUND)) {
+    has_ready_to_run_foreground_tasks_cv_.Signal();
+  }
+
+  if (ShouldRunTaskForCategoryWithLockAcquired(cc::TASK_CATEGORY_BACKGROUND)) {
+    has_ready_to_run_background_tasks_cv_.Signal();
+  }
 }
 
 RasterWorkerPool::ClosureTask::ClosureTask(const base::Closure& closure)
diff --git a/content/renderer/raster_worker_pool.h b/content/renderer/raster_worker_pool.h
index 1d6fc04..dfa325c 100644
--- a/content/renderer/raster_worker_pool.h
+++ b/content/renderer/raster_worker_pool.h
@@ -48,7 +48,8 @@
 
   // Runs a task from one of the provided categories. Categories listed first
   // have higher priority.
-  void Run(const std::vector<cc::TaskCategory>& categories);
+  void Run(const std::vector<cc::TaskCategory>& categories,
+           base::ConditionVariable* has_ready_to_run_tasks_cv);
 
   void FlushForTesting();
 
@@ -75,14 +76,6 @@
   class RasterWorkerPoolSequencedTaskRunner;
   friend class RasterWorkerPoolSequencedTaskRunner;
 
-  // Runs a task from one of the provided categories. Categories listed first
-  // have higher priority. Returns false if there were no tasks to run.
-  bool RunTaskWithLockAcquired(const std::vector<cc::TaskCategory>& categories);
-
-  // Run next task for the given category. Caller must acquire |lock_| prior to
-  // calling this function and make sure at least one task is ready to run.
-  void RunTaskInCategoryWithLockAcquired(cc::TaskCategory category);
-
   // Simple Task for the TaskGraphRunner that wraps a closure.
   // This class is used to schedule TaskRunner tasks on the
   // |task_graph_runner_|.
@@ -107,6 +100,22 @@
   void CollectCompletedTasksWithLockAcquired(cc::NamespaceToken token,
                                              cc::Task::Vector* completed_tasks);
 
+  // Runs a task from one of the provided categories. Categories listed first
+  // have higher priority. Returns false if there were no tasks to run.
+  bool RunTaskWithLockAcquired(const std::vector<cc::TaskCategory>& categories);
+
+  // Run next task for the given category. Caller must acquire |lock_| prior to
+  // calling this function and make sure at least one task is ready to run.
+  void RunTaskInCategoryWithLockAcquired(cc::TaskCategory category);
+
+  // Helper function which signals worker threads if tasks are ready to run.
+  void SignalHasReadyToRunTasksWithLockAcquired();
+
+  // Determines if we should run a new task for the given category. This factors
+  // in whether a task is available and whether the count of running tasks is
+  // low enough to start a new one.
+  bool ShouldRunTaskForCategoryWithLockAcquired(cc::TaskCategory category);
+
   // The actual threads where work is done.
   std::vector<scoped_ptr<base::SimpleThread>> threads_;
 
@@ -124,9 +133,9 @@
   // Cached vector to avoid allocation when getting the list of complete
   // tasks.
   cc::Task::Vector completed_tasks_;
-  // Condition variable that is waited on by Run() until new tasks are ready to
-  // run or shutdown starts.
-  base::ConditionVariable has_ready_to_run_tasks_cv_;
+  // Condition variables for foreground and background tasks.
+  base::ConditionVariable has_ready_to_run_foreground_tasks_cv_;
+  base::ConditionVariable has_ready_to_run_background_tasks_cv_;
   // Condition variable that is waited on by origin threads until a namespace
   // has finished running all associated tasks.
   base::ConditionVariable has_namespaces_with_finished_running_tasks_cv_;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 07b3293..c53f627 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -5059,14 +5059,16 @@
 
   WebRect selection_rect;
   bool result = false;
+  bool active_now = false;
 
   // If something is selected when we start searching it means we cannot just
   // increment the current match ordinal; we need to re-generate it.
   WebRange current_selection = focused_frame->selectionRange();
 
   do {
-    result = search_frame->find(request_id, search_text, options,
-                                wrap_within_frame, &selection_rect);
+    result =
+        search_frame->find(request_id, search_text, options, wrap_within_frame,
+                           &selection_rect, &active_now);
 
     if (!result) {
       // Don't leave text selected as you move to the next frame.
@@ -5095,14 +5097,14 @@
       if (multi_frame && search_frame == focused_frame) {
         result = search_frame->find(request_id, search_text, options,
                                     true,  // Force wrapping.
-                                    &selection_rect);
+                                    &selection_rect, &active_now);
       }
     }
 
     render_view_->webview()->setFocusedFrame(search_frame);
   } while (!result && search_frame != focused_frame);
 
-  if (options.findNext && current_selection.isNull()) {
+  if (options.findNext && current_selection.isNull() && active_now) {
     // Force the main_frame to report the actual count.
     main_frame->increaseMatchCount(0, request_id);
   } else {
@@ -5482,6 +5484,13 @@
       load_type = blink::WebFrameLoadType::ReplaceCurrentItem;
     }
 
+    // PlzNavigate: check if the navigation being committed originated as a
+    // client redirect.
+    bool is_client_redirect =
+        browser_side_navigation
+            ? !!(common_params.transition & ui::PAGE_TRANSITION_CLIENT_REDIRECT)
+            : false;
+
     // Perform a navigation to a data url if needed.
     // Note: the base URL might be invalid, so also check the data URL string.
     if (!common_params.base_url_for_data_url.is_empty() ||
@@ -5490,15 +5499,10 @@
 #endif
         (browser_side_navigation &&
          common_params.url.SchemeIs(url::kDataScheme))) {
-      LoadDataURL(common_params, request_params, frame_, load_type);
+      LoadDataURL(common_params, request_params, frame_, load_type,
+                  item_for_history_navigation, history_load_type,
+                  is_client_redirect);
     } else {
-      // PlzNavigate: check if the navigation being committed originated as a
-      // client redirect.
-      bool is_client_redirect = browser_side_navigation
-                                    ? !!(common_params.transition &
-                                         ui::PAGE_TRANSITION_CLIENT_REDIRECT)
-                                    : false;
-
       // Load the request.
       frame_->load(request, load_type, item_for_history_navigation,
                    history_load_type, is_client_redirect);
@@ -5744,10 +5748,14 @@
       GetRequestBodyForWebURLRequest(*request)));
 }
 
-void RenderFrameImpl::LoadDataURL(const CommonNavigationParams& params,
-                                  const RequestNavigationParams& request_params,
-                                  WebFrame* frame,
-                                  blink::WebFrameLoadType load_type) {
+void RenderFrameImpl::LoadDataURL(
+    const CommonNavigationParams& params,
+    const RequestNavigationParams& request_params,
+    WebLocalFrame* frame,
+    blink::WebFrameLoadType load_type,
+    blink::WebHistoryItem item_for_history_navigation,
+    blink::WebHistoryLoadType history_load_type,
+    bool is_client_redirect) {
   // A loadData request with a specified base URL.
   GURL data_url = params.url;
 #if defined(OS_ANDROID)
@@ -5771,14 +5779,13 @@
         params.url : params.base_url_for_data_url;
     bool replace = load_type == blink::WebFrameLoadType::ReloadFromOrigin ||
                    load_type == blink::WebFrameLoadType::Reload;
+
     frame->loadData(
-        WebData(data.c_str(), data.length()),
-        WebString::fromUTF8(mime_type),
-        WebString::fromUTF8(charset),
-        base_url,
+        WebData(data.c_str(), data.length()), WebString::fromUTF8(mime_type),
+        WebString::fromUTF8(charset), base_url,
         // Needed so that history-url-only changes don't become reloads.
-        params.history_url_for_data_url,
-        replace);
+        params.history_url_for_data_url, replace, load_type,
+        item_for_history_navigation, history_load_type, is_client_redirect);
   } else {
     CHECK(false) << "Invalid URL passed: "
                  << params.url.possibly_invalid_spec();
@@ -6072,9 +6079,12 @@
   mojo::Array<mojo::String> all_interfaces;
   all_interfaces.push_back("*");
   filter->filter.insert("*", std::move(all_interfaces));
-  mojo_shell_->Connect(
-      url.spec(), GetProxy(&interface_provider), nullptr,
-      std::move(filter), base::Bind(&OnGotInstanceID));
+  mojo::shell::mojom::ConnectorPtr connector;
+  mojo_shell_->GetConnector(GetProxy(&connector));
+  connector->Connect(
+      url.spec(), mojo::shell::mojom::Connector::kUserInherit,
+      GetProxy(&interface_provider), nullptr, std::move(filter),
+      base::Bind(&OnGotInstanceID));
   return interface_provider;
 }
 
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index bf873ed..ed336f4 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -902,8 +902,11 @@
   // Loads a data url.
   void LoadDataURL(const CommonNavigationParams& params,
                    const RequestNavigationParams& request_params,
-                   blink::WebFrame* frame,
-                   blink::WebFrameLoadType load_type);
+                   blink::WebLocalFrame* frame,
+                   blink::WebFrameLoadType load_type,
+                   blink::WebHistoryItem item_for_history_navigation,
+                   blink::WebHistoryLoadType history_load_type,
+                   bool is_client_redirect);
 
   // Sends a proper FrameHostMsg_DidFailProvisionalLoadWithError_Params IPC for
   // the failed request |request|.
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 12e31bd..5b5f16c 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -863,6 +863,9 @@
   if (MojoShellConnection::Get())
     CreateRenderWidgetWindowTreeClientFactory();
 #endif
+
+  service_registry()->ConnectToRemoteService(
+      mojo::GetProxy(&storage_partition_service_));
 }
 
 RenderThreadImpl::~RenderThreadImpl() {
@@ -1138,6 +1141,10 @@
   CHECK(result.second) << "Inserting a duplicate item.";
 }
 
+StoragePartitionService* RenderThreadImpl::GetStoragePartitionService() {
+  return storage_partition_service_.get();
+}
+
 int RenderThreadImpl::GenerateRoutingID() {
   int routing_id = MSG_ROUTING_NONE;
   Send(new ViewHostMsg_GenerateRoutingID(&routing_id));
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index ab67cd9e..c285e52 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -26,6 +26,7 @@
 #include "content/common/content_export.h"
 #include "content/common/frame_replication_state.h"
 #include "content/common/gpu/client/gpu_channel_host.h"
+#include "content/common/storage_partition_service.mojom.h"
 #include "content/public/renderer/render_thread.h"
 #include "content/renderer/gpu/compositor_dependencies.h"
 #include "net/base/network_change_notifier.h"
@@ -455,6 +456,8 @@
       mojo::shell::mojom::InterfaceProviderRequest services,
       mojo::shell::mojom::InterfaceProviderPtr exposed_services);
 
+  StoragePartitionService* GetStoragePartitionService();
+
  protected:
   RenderThreadImpl(const InProcessChildThreadParams& params,
                    scoped_ptr<scheduler::RendererScheduler> scheduler);
@@ -703,6 +706,8 @@
       PendingRenderFrameConnectMap;
   PendingRenderFrameConnectMap pending_render_frame_connects_;
 
+  StoragePartitionServicePtr storage_partition_service_;
+
   DISALLOW_COPY_AND_ASSIGN(RenderThreadImpl);
 };
 
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index eb0b33d8..3f7c05a8 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -961,9 +961,6 @@
   settings->setAllowFileAccessFromFileURLs(
       prefs.allow_file_access_from_file_urls);
 
-  // Enable the web audio API if requested on the command line.
-  settings->setWebAudioEnabled(prefs.webaudio_enabled);
-
   // Enable experimental WebGL support if requested on command line
   // and support is compiled in.
   settings->setExperimentalWebGLEnabled(prefs.experimental_webgl_enabled);
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 539cecbc..e2d537f0 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -419,7 +419,8 @@
 WebStorageNamespace* RendererBlinkPlatformImpl::createLocalStorageNamespace() {
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kMojoLocalStorage)) {
-    return new LocalStorageNamespace();
+    return new LocalStorageNamespace(
+        RenderThreadImpl::current()->GetStoragePartitionService());
   }
   return new WebStorageNamespaceImpl();
 }
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn
index 57538e9..4ed444a0 100644
--- a/content/shell/BUILD.gn
+++ b/content/shell/BUILD.gn
@@ -80,6 +80,8 @@
     "browser/layout_test/layout_test_url_request_context_getter.h",
     "browser/layout_test/notify_done_forwarder.cc",
     "browser/layout_test/notify_done_forwarder.h",
+    "browser/layout_test/test_info_extractor.cc",
+    "browser/layout_test/test_info_extractor.h",
     "browser/shell.cc",
     "browser/shell.h",
     "browser/shell_access_token_store.cc",
diff --git a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc
index cced25f3d..d2a9899 100644
--- a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc
+++ b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc
@@ -59,16 +59,20 @@
     NiceMockBluetoothGattNotifySession;
 
 namespace {
-// Bluetooth UUIDs suitable to pass to BluetoothUUID().
+// Bluetooth UUIDs suitable to pass to BluetoothUUID():
+// Services:
 const char kBatteryServiceUUID[] = "180f";
+const char kDeviceInformationServiceUUID[] = "180a";
 const char kGenericAccessServiceUUID[] = "1800";
 const char kGlucoseServiceUUID[] = "1808";
 const char kHeartRateServiceUUID[] = "180d";
 const char kHumanInterfaceDeviceServiceUUID[] = "1812";
 const char kTxPowerServiceUUID[] = "1804";
-const char kHeartRateMeasurementUUID[] = "2a37";
+// Characteristics:
 const char kBodySensorLocation[] = "2a38";
 const char kDeviceNameUUID[] = "2a00";
+const char kHeartRateMeasurementUUID[] = "2a37";
+const char kSerialNumberStringUUID[] = "2a25";
 
 const int kDefaultTxPower = -10;  // TxPower of a device broadcasting at 0.1mW.
 const int kDefaultRssi = -51;     // RSSI at 1m from a device broadcasting at
@@ -480,7 +484,7 @@
   // TODO(ortuno): Implement the rest of the service's characteristics
   // See: http://crbug.com/529975
 
-  device->AddMockService(GetGenericAccessService(adapter.get(), device.get()));
+  device->AddMockService(GetGenericAccessService(device.get()));
   device->AddMockService(GetHeartRateService(adapter.get(), device.get()));
   adapter->AddMockDevice(std::move(device));
 
@@ -493,13 +497,16 @@
   scoped_refptr<NiceMockBluetoothAdapter> adapter(GetEmptyAdapter());
 
   BluetoothDevice::UUIDList uuids;
+  uuids.push_back(BluetoothUUID(kDeviceInformationServiceUUID));
+  uuids.push_back(BluetoothUUID(kGenericAccessServiceUUID));
   uuids.push_back(BluetoothUUID(kHeartRateServiceUUID));
   uuids.push_back(BluetoothUUID(kHumanInterfaceDeviceServiceUUID));
 
   scoped_ptr<NiceMockBluetoothDevice> device(
       GetConnectableDevice(adapter.get(), "Heart Rate And HID Device", uuids));
 
-  device->AddMockService(GetGenericAccessService(adapter.get(), device.get()));
+  device->AddMockService(GetDeviceInformationService(device.get()));
+  device->AddMockService(GetGenericAccessService(device.get()));
   device->AddMockService(GetHeartRateService(adapter.get(), device.get()));
   device->AddMockService(
       GetBaseGATTService(device.get(), kHumanInterfaceDeviceServiceUUID));
@@ -618,8 +625,9 @@
 LayoutTestBluetoothAdapterProvider::GetGlucoseDevice(
     MockBluetoothAdapter* adapter) {
   BluetoothDevice::UUIDList uuids;
-  uuids.push_back(BluetoothUUID(kTxPowerServiceUUID));
+  uuids.push_back(BluetoothUUID(kGenericAccessServiceUUID));
   uuids.push_back(BluetoothUUID(kGlucoseServiceUUID));
+  uuids.push_back(BluetoothUUID(kTxPowerServiceUUID));
 
   return GetBaseDevice(adapter, "Glucose Device", uuids, makeMACAddress(0x2));
 }
@@ -672,6 +680,7 @@
 LayoutTestBluetoothAdapterProvider::GetHeartRateDevice(
     MockBluetoothAdapter* adapter) {
   BluetoothDevice::UUIDList uuids;
+  uuids.push_back(BluetoothUUID(kGenericAccessServiceUUID));
   uuids.push_back(BluetoothUUID(kHeartRateServiceUUID));
 
   return GetConnectableDevice(adapter, "Heart Rate Device", uuids);
@@ -702,9 +711,35 @@
 
 // static
 scoped_ptr<NiceMockBluetoothGattService>
+LayoutTestBluetoothAdapterProvider::GetDeviceInformationService(
+    device::MockBluetoothDevice* device) {
+  scoped_ptr<NiceMockBluetoothGattService> device_information(
+      GetBaseGATTService(device, kDeviceInformationServiceUUID));
+
+  scoped_ptr<NiceMockBluetoothGattCharacteristic> serial_number_string(
+      GetBaseGATTCharacteristic(device_information.get(),
+                                kSerialNumberStringUUID,
+                                BluetoothGattCharacteristic::PROPERTY_READ));
+
+  // Crash if ReadRemoteCharacteristic called. Not using GoogleMock's Expect
+  // because this is used in layout tests that may not report a mock expectation
+  // error correctly as a layout test failure.
+  ON_CALL(*serial_number_string, ReadRemoteCharacteristic(_, _))
+      .WillByDefault(
+          Invoke([](const BluetoothGattCharacteristic::ValueCallback&,
+                    const BluetoothGattCharacteristic::ErrorCallback&) {
+            NOTREACHED();
+          }));
+
+  device_information->AddMockCharacteristic(std::move(serial_number_string));
+
+  return device_information;
+}
+
+// static
+scoped_ptr<NiceMockBluetoothGattService>
 LayoutTestBluetoothAdapterProvider::GetGenericAccessService(
-    MockBluetoothAdapter* adapter,
-    MockBluetoothDevice* device) {
+    device::MockBluetoothDevice* device) {
   scoped_ptr<NiceMockBluetoothGattService> generic_access(
       GetBaseGATTService(device, kGenericAccessServiceUUID));
 
diff --git a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h
index 2beaf6f..3b7d328 100644
--- a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h
+++ b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h
@@ -173,7 +173,8 @@
   // Inherits from |EmptyAdapter|
   // Internal Structure:
   //   - Heart Rate Device
-  //      - Advertised UUIDs:
+  //      - UUIDs:
+  //         - Generic Access UUID (0x1800)
   //         - Heart Rate UUID (0x180d)
   static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
   GetMissingServiceHeartRateAdapter();
@@ -183,7 +184,8 @@
   // The services in this adapter do not contain any characteristics.
   // Internal Structure:
   //   - Heart Rate Device
-  //      - Advertised UUIDs:
+  //      - UUIDs:
+  //         - Generic Access UUID (0x1800)
   //         - Heart Rate UUID (0x180d)
   //      - Services:
   //         - Generic Access Service
@@ -195,7 +197,8 @@
   // Inherits from |EmptyAdapter|
   // Internal Structure:
   //   - Heart Rate Device
-  //      - Advertised UUIDs:
+  //      - UUIDs:
+  //         - Generic Access UUID (0x1800)
   //         - Heart Rate UUID (0x180d)
   //      - Services:
   //         - Generic Access Service - Characteristics as described in
@@ -209,10 +212,14 @@
   // Inherits from |EmptyAdapter|
   // Internal Structure:
   //   - |ConnectableDevice|(adapter, "Heart Rate And HID Device", uuids)
-  //      - Advertised UUIDs:
+  //      - UUIDs:
+  //         - Device Information UUID (0x180a)
+  //         - Generic Access UUID (0x1800)
   //         - Heart Rate UUID (0x180d)
   //         - Human Interface Device UUID (0x1812) (a blacklisted service)
   //      - Services:
+  //         - Device Information Service - Characteristics as described in
+  //           GetDeviceInformationService.
   //         - Generic Access Service - Characteristics as described in
   //           GetGenericAccessService.
   //         - Heart Rate Service - Characteristics as described in
@@ -327,7 +334,7 @@
   // Devices
 
   // |BaseDevice|
-  // Adv UUIDs added:
+  // UUIDs added:
   // None.
   // Services added:
   // None.
@@ -366,8 +373,7 @@
   // |BatteryDevice|
   // Inherits from |BaseDevice|(adapter, "Battery Device", uuids,
   //                            "00:00:00:00:00:01")
-  // Adv UUIDs added:
-  //   - Generic Access (0x1800)
+  // UUIDs added:
   //   - Battery Service UUID (0x180F)
   // Services added:
   // None.
@@ -377,9 +383,10 @@
   // |GlucoseDevice|
   // Inherits from |BaseDevice|(adapter, "Glucose Device", uuids,
   //                            "00:00:00:00:00:02")
-  // Adv UUIDs added:
+  // UUIDs added:
   //   - Generic Access (0x1800)
   //   - Glucose UUID (0x1808)
+  //   - Tx Power (0x1804)
   // Services added:
   // None.
   static scoped_ptr<testing::NiceMock<device::MockBluetoothDevice>>
@@ -387,7 +394,7 @@
 
   // |ConnectableDevice|
   // Inherits from |BaseDevice|(adapter, device_name)
-  // Adv UUIDs added:
+  // UUIDs added:
   // None.
   // Services added:
   // None.
@@ -403,7 +410,7 @@
 
   // |UnconnectableDevice|
   // Inherits from |BaseDevice|(adapter, device_name)
-  // Adv UUIDs added:
+  // UUIDs added:
   //  - errorUUID(error_code)
   // Services added:
   // None.
@@ -418,7 +425,8 @@
 
   // |HeartRateDevice|
   // Inherits from |ConnectableDevice|(adapter, "Heart Rate Device", uuids)
-  // Adv UUIDs added:
+  // UUIDs added:
+  //   - Generic Access (0x1800)
   //   - Heart Rate UUID (0x180D)
   // Services added:
   // None. Each user of the HeartRateDevice is in charge of adding the
@@ -451,6 +459,17 @@
   GetBaseGATTService(device::MockBluetoothDevice* device,
                      const std::string& uuid);
 
+  // |GetDeviceInformationService|
+  // Internal Structure:
+  //  - Characteristics:
+  //     - Serial Number String: (a blacklisted characteristic)
+  //        - Mock Functions:
+  //           - Read: Fails test.
+  //           - GetProperties: Returns
+  //               BluetoothGattCharacteristic::PROPERTY_READ
+  static scoped_ptr<testing::NiceMock<device::MockBluetoothGattService>>
+  GetDeviceInformationService(device::MockBluetoothDevice* device);
+
   // |GenericAccessService|
   // Internal Structure:
   //  - Characteristics:
@@ -462,8 +481,7 @@
   //               BluetoothGattCharacteristic::PROPERTY_READ |
   //               BluetoothGattCharacteristic::PROPERTY_WRITE
   static scoped_ptr<testing::NiceMock<device::MockBluetoothGattService>>
-  GetGenericAccessService(device::MockBluetoothAdapter* adapter,
-                          device::MockBluetoothDevice* device);
+  GetGenericAccessService(device::MockBluetoothDevice* device);
 
   // |HeartRateService|
   // Internal Structure:
diff --git a/content/shell/browser/layout_test/layout_test_browser_main.cc b/content/shell/browser/layout_test/layout_test_browser_main.cc
index 90285c1..2984a09 100644
--- a/content/shell/browser/layout_test/layout_test_browser_main.cc
+++ b/content/shell/browser/layout_test/layout_test_browser_main.cc
@@ -19,10 +19,10 @@
 #include "base/thread_task_runner_handle.h"
 #include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
-#include "components/test_runner/test_info_extractor.h"
 #include "content/public/browser/browser_main_runner.h"
 #include "content/public/common/url_constants.h"
 #include "content/shell/browser/layout_test/blink_test_controller.h"
+#include "content/shell/browser/layout_test/test_info_extractor.h"
 #include "content/shell/browser/shell.h"
 #include "content/shell/common/shell_switches.h"
 #include "content/shell/renderer/layout_test/blink_test_helpers.h"
@@ -35,7 +35,7 @@
 
 namespace {
 
-bool RunOneTest(const test_runner::TestInfo& test_info,
+bool RunOneTest(const content::TestInfo& test_info,
                 bool* ran_at_least_once,
                 const scoped_ptr<content::BrowserMainRunner>& main_runner) {
   if (!content::BlinkTestController::Get()->PrepareForLayoutTest(
@@ -81,9 +81,9 @@
 
   base::CommandLine::StringVector args =
       base::CommandLine::ForCurrentProcess()->GetArgs();
-  test_runner::TestInfoExtractor test_extractor(args);
+  content::TestInfoExtractor test_extractor(args);
   bool ran_at_least_once = false;
-  scoped_ptr<test_runner::TestInfo> test_info;
+  scoped_ptr<content::TestInfo> test_info;
   while ((test_info = test_extractor.GetNextTest())) {
     if (!RunOneTest(*test_info, &ran_at_least_once, main_runner))
       break;
diff --git a/content/shell/browser/layout_test/layout_test_javascript_dialog_manager.cc b/content/shell/browser/layout_test/layout_test_javascript_dialog_manager.cc
index e6352b0..969b680 100644
--- a/content/shell/browser/layout_test/layout_test_javascript_dialog_manager.cc
+++ b/content/shell/browser/layout_test/layout_test_javascript_dialog_manager.cc
@@ -11,7 +11,6 @@
 #include "content/shell/browser/layout_test/blink_test_controller.h"
 #include "content/shell/browser/shell_javascript_dialog.h"
 #include "content/shell/common/shell_switches.h"
-#include "net/base/net_util.h"
 
 namespace content {
 
diff --git a/components/test_runner/test_info_extractor.cc b/content/shell/browser/layout_test/test_info_extractor.cc
similarity index 97%
rename from components/test_runner/test_info_extractor.cc
rename to content/shell/browser/layout_test/test_info_extractor.cc
index 42e0e48..a3759403 100644
--- a/components/test_runner/test_info_extractor.cc
+++ b/content/shell/browser/layout_test/test_info_extractor.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/test_runner/test_info_extractor.h"
+#include "content/shell/browser/layout_test/test_info_extractor.h"
 
 #include <iostream>
 
@@ -15,7 +15,7 @@
 #include "build/build_config.h"
 #include "net/base/filename_util.h"
 
-namespace test_runner {
+namespace content {
 
 namespace {
 
@@ -146,4 +146,4 @@
   return GetTestInfoFromLayoutTestName(test_string);
 }
 
-}  // namespace test_runner
+}  // namespace content
diff --git a/components/test_runner/test_info_extractor.h b/content/shell/browser/layout_test/test_info_extractor.h
similarity index 72%
rename from components/test_runner/test_info_extractor.h
rename to content/shell/browser/layout_test/test_info_extractor.h
index 4f4a11cf..1988eac 100644
--- a/components/test_runner/test_info_extractor.h
+++ b/content/shell/browser/layout_test/test_info_extractor.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_TEST_RUNNER_TEST_INFO_EXTRACTOR_H_
-#define COMPONENTS_TEST_RUNNER_TEST_INFO_EXTRACTOR_H_
+#ifndef CONTENT_SHELL_BROWSER_LAYOUT_TEST_TEST_INFO_EXTRACTOR_H_
+#define CONTENT_SHELL_BROWSER_LAYOUT_TEST_TEST_INFO_EXTRACTOR_H_
 
 #include <stddef.h>
 
@@ -12,12 +12,11 @@
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
-#include "components/test_runner/test_runner_export.h"
 #include "url/gurl.h"
 
-namespace test_runner {
+namespace content {
 
-struct TEST_RUNNER_EXPORT TestInfo {
+struct TestInfo {
   TestInfo(const GURL& url,
            bool enable_pixel_dumping,
            const std::string& expected_pixel_hash,
@@ -30,7 +29,7 @@
   base::FilePath current_working_directory;
 };
 
-class TEST_RUNNER_EXPORT TestInfoExtractor {
+class TestInfoExtractor {
  public:
   explicit TestInfoExtractor(const base::CommandLine::StringVector& cmd_args);
   ~TestInfoExtractor();
@@ -44,6 +43,6 @@
   DISALLOW_COPY_AND_ASSIGN(TestInfoExtractor);
 };
 
-}  // namespace test_runner
+}  // namespace content
 
-#endif  // COMPONENTS_TEST_RUNNER_TEST_INFO_EXTRACTOR_H_
+#endif  // CONTENT_SHELL_BROWSER_LAYOUT_TEST_TEST_INFO_EXTRACTOR_H_
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index dac93bc..c29e053 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -800,10 +800,7 @@
   }
 
   if (use_ozone) {
-    deps += [
-      "//ui/ozone",
-      "//ui/ozone:ozone_base",
-    ]
+    deps += [ "//ui/ozone" ]
   } else {
     sources -=
         [ "../browser/compositor/software_output_device_ozone_unittest.cc" ]
diff --git a/content/test/data/accessibility/html/img-empty-alt-expected-blink.txt b/content/test/data/accessibility/html/img-empty-alt-expected-blink.txt
new file mode 100644
index 0000000..3a5cd10c
--- /dev/null
+++ b/content/test/data/accessibility/html/img-empty-alt-expected-blink.txt
@@ -0,0 +1,8 @@
+rootWebArea
+++group
+++++link name='unread '
+++++++staticText name='unread '
+++++++++inlineTextBox name='unread '
+++++link name='read'
+++++++staticText name='read'
+++++++++inlineTextBox name='read'
diff --git a/content/test/data/accessibility/html/img-empty-alt-expected-mac.txt b/content/test/data/accessibility/html/img-empty-alt-expected-mac.txt
new file mode 100644
index 0000000..fc45552a
--- /dev/null
+++ b/content/test/data/accessibility/html/img-empty-alt-expected-mac.txt
@@ -0,0 +1,6 @@
+AXWebArea
+++AXGroup
+++++AXLink AXTitle='unread '
+++++++AXStaticText AXValue='unread '
+++++AXLink AXTitle='read'
+++++++AXStaticText AXValue='read'
diff --git a/content/test/data/accessibility/html/img-empty-alt.html b/content/test/data/accessibility/html/img-empty-alt.html
new file mode 100644
index 0000000..1ee58ee
--- /dev/null
+++ b/content/test/data/accessibility/html/img-empty-alt.html
@@ -0,0 +1,11 @@
+<html>
+  <body>
+    <a href="foo">
+      <img src="unread.jpg" alt="" role="presentation">unread
+    </a>
+    <a href="foo">
+      <img src="read.jpg" alt="">read
+    </a>
+  </body>
+</html>
+
diff --git a/content/test/data/notifications/500x500.png b/content/test/data/notifications/500x500.png
new file mode 100644
index 0000000..a46b980
--- /dev/null
+++ b/content/test/data/notifications/500x500.png
Binary files differ
diff --git a/content/test/data/web_ui_mojo_shell_test.js b/content/test/data/web_ui_mojo_shell_test.js
index 6b0f7e1..b9083507 100644
--- a/content/test/data/web_ui_mojo_shell_test.js
+++ b/content/test/data/web_ui_mojo_shell_test.js
@@ -30,7 +30,14 @@
     domAutomationController.setAutomationId(0);
     var shellPipe = serviceRegistry.connectToService(shellMojom.Shell.name);
     var shell = new shellMojom.Shell.proxyClass(new router.Router(shellPipe));
-    shell.connect(TEST_APP_URL,
+
+    var pipe = core.createMessagePipe();
+    var connector =
+        new shellMojom.Connector.proxyClass(new router.Router(pipe.handle0));
+    shell.getConnector(pipe.handle1);
+
+    connector.connect(
+        TEST_APP_URL, 1,
         function (services) {
           var test = connectToService(services, testMojom.TestMojoService);
           test.getRequestorURL().then(function(response) {
diff --git a/content/test/fake_renderer_scheduler.cc b/content/test/fake_renderer_scheduler.cc
index 9725341..28c612fc 100644
--- a/content/test/fake_renderer_scheduler.cc
+++ b/content/test/fake_renderer_scheduler.cc
@@ -123,13 +123,4 @@
 void FakeRendererScheduler::SetTimerQueueSuspensionWhenBackgroundedEnabled(
     bool enabled) {}
 
-double FakeRendererScheduler::VirtualTimeSeconds() const {
-  return 0.0;
-}
-
-double FakeRendererScheduler::
-    MonotonicallyIncreasingVirtualTimeSeconds() const {
-  return 0.0;
-}
-
 }  // namespace content
diff --git a/content/test/fake_renderer_scheduler.h b/content/test/fake_renderer_scheduler.h
index 2e08700..ef6d4e15 100644
--- a/content/test/fake_renderer_scheduler.h
+++ b/content/test/fake_renderer_scheduler.h
@@ -53,8 +53,6 @@
   void SuspendTimerQueue() override;
   void ResumeTimerQueue() override;
   void SetTimerQueueSuspensionWhenBackgroundedEnabled(bool enabled) override;
-  double VirtualTimeSeconds() const override;
-  double MonotonicallyIncreasingVirtualTimeSeconds() const override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(FakeRendererScheduler);
diff --git a/content/test/gpu/generate_buildbot_json.py b/content/test/gpu/generate_buildbot_json.py
index 0e41bc4..925beaf 100755
--- a/content/test/gpu/generate_buildbot_json.py
+++ b/content/test/gpu/generate_buildbot_json.py
@@ -212,16 +212,6 @@
       'swarming': True,
       'os_type': 'win',
     },
-    'Win7 Release dEQP (NVIDIA)': {
-      'deqp': True,
-      'swarming_dimensions': {
-        'gpu': '10de:104a',
-        'os': 'Windows-2008ServerR2-SP1'
-      },
-      'build_config': 'Release',
-      'swarming': True,
-      'os_type': 'win',
-    },
     'Win7 x64 Release (NVIDIA)': {
       'swarming_dimensions': {
         'gpu': '10de:104a',
@@ -360,19 +350,6 @@
       'swarming': True,
       'os_type': 'linux',
     },
-    'Linux Release dEQP (NVIDIA)': {
-      'deqp': True,
-      'swarming_dimensions': {
-        'gpu': '10de:104a',
-        'os': 'Linux'
-      },
-      'build_config': 'Release',
-      # TODO(kbr): switch this to use Swarming, and put the physical
-      # machine into the Swarming pool, once we're convinced it's
-      # working well.
-      'swarming': False,
-      'os_type': 'linux',
-    },
 
     # The following "optional" testers don't actually exist on the
     # waterfall. They are present here merely to specify additional
@@ -463,6 +440,32 @@
     ],
     'swarming_shards': 4
   },
+
+  'angle_deqp_gles3_tests': {
+    'tester_configs': [
+      {
+        'fyi_only': True,
+        # TODO(jmadill): Run this on the optional tryservers.
+        'run_on_optional': False,
+        # Run only on the Win7 and Linux Release NVIDIA 32-bit bots
+        # (and trybots) for the time being, at least until more capacity is
+        # added.
+        'build_configs': ['Release'],
+        'swarming_dimension_sets': [
+          {
+            'gpu': '10de:104a',
+            'os': 'Windows-2008ServerR2-SP1'
+          },
+          {
+            'gpu': '10de:104a',
+            'os': 'Linux'
+          }
+        ],
+      }
+    ],
+    'swarming_shards': 12
+  },
+
   # Until we have more capacity, run angle_end2end_tests only on the
   # FYI waterfall, the ANGLE trybots (which mirror the FYI waterfall),
   # and the optional trybots (mainly used during ANGLE rolls).
@@ -566,17 +569,6 @@
   }
 }
 
-DEQP_GTESTS = {
-  'angle_deqp_gles3_tests': {
-    'tester_configs': [
-      {
-        'os_types': ['win', 'linux']
-      }
-    ],
-    'swarming_shards': 12
-  },
-}
-
 TELEMETRY_TESTS = {
   'context_lost': {},
   'gpu_process_launch_tests': {'target_name': 'gpu_process'},
@@ -842,14 +834,10 @@
     tests[builder] = {}
   for name, config in waterfall['testers'].iteritems():
     gtests = []
-    if config.get('deqp'):
-      gtests.extend(generate_gtests(name, config, DEQP_GTESTS, is_fyi))
-    else:
-      gtests.extend(generate_gtests(name, config, COMMON_GTESTS, is_fyi))
+    gtests.extend(generate_gtests(name, config, COMMON_GTESTS, is_fyi))
     isolated_scripts = []
-    if not config.get('deqp'):
-      isolated_scripts.extend(generate_telemetry_tests(
-          name, config, TELEMETRY_TESTS, is_fyi))
+    isolated_scripts.extend(generate_telemetry_tests(
+        name, config, TELEMETRY_TESTS, is_fyi))
     cur_tests = {}
     if gtests:
       cur_tests['gtest_tests'] = sorted(gtests, key=lambda x: x['test'])
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
index 59bd2e1..bec8263 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -61,6 +61,8 @@
     self.Fail('conformance/glsl/constructors/' +
               'glsl-construct-vec-mat-index.html',
               ['win'], bug=525188)
+    self.Flaky('conformance/extensions/ext-disjoint-timer-query.html',
+        ['win'], bug=588617)
 
     # Win7 / Intel failures
     self.Fail('conformance/textures/misc/' +
diff --git a/crypto/openssl_util.cc b/crypto/openssl_util.cc
index 48ec3e2e3..410cab5a 100644
--- a/crypto/openssl_util.cc
+++ b/crypto/openssl_util.cc
@@ -48,13 +48,12 @@
 #if defined(OS_ANDROID) && defined(ARCH_CPU_ARMEL)
     const bool has_neon =
         (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0;
-    // CRYPTO_set_NEON_capable is called before |SSL_library_init| because this
-    // stops BoringSSL from probing for NEON support via SIGILL in the case
-    // that getauxval isn't present.
-    CRYPTO_set_NEON_capable(has_neon);
-    // See https://code.google.com/p/chromium/issues/detail?id=341598
     base::CPU cpu;
-    CRYPTO_set_NEON_functional(!cpu.has_broken_neon());
+    // CRYPTO_set_NEON_capable is called before |SSL_library_init| because this
+    // stops BoringSSL from probing for NEON support via SIGILL in the case that
+    // getauxval isn't present. Also workaround a CPU with broken NEON
+    // support. See https://code.google.com/p/chromium/issues/detail?id=341598
+    CRYPTO_set_NEON_capable(has_neon && !cpu.has_broken_neon());
 #endif
 
     SSL_library_init();
diff --git a/device/bluetooth/bluetooth_adapter_bluez.cc b/device/bluetooth/bluetooth_adapter_bluez.cc
index f8df754..1d22ef7 100644
--- a/device/bluetooth/bluetooth_adapter_bluez.cc
+++ b/device/bluetooth/bluetooth_adapter_bluez.cc
@@ -469,6 +469,7 @@
   }
 
   if (property_name == properties->bluetooth_class.name() ||
+      property_name == properties->appearance.name() ||
       property_name == properties->address.name() ||
       property_name == properties->alias.name() ||
       property_name == properties->paired.name() ||
diff --git a/device/bluetooth/bluetooth_adapter_mac.mm b/device/bluetooth/bluetooth_adapter_mac.mm
index 72554ed..76dad60 100644
--- a/device/bluetooth/bluetooth_adapter_mac.mm
+++ b/device/bluetooth/bluetooth_adapter_mac.mm
@@ -82,8 +82,7 @@
         [[BluetoothLowEnergyCentralManagerDelegate alloc]
             initWithDiscoveryManager:low_energy_discovery_manager_.get()
                           andAdapter:this]);
-    Class aClass = NSClassFromString(@"CBCentralManager");
-    low_energy_central_manager_.reset([[aClass alloc]
+    low_energy_central_manager_.reset([[CBCentralManager alloc]
         initWithDelegate:low_energy_central_manager_delegate_.get()
                    queue:dispatch_get_main_queue()]);
     low_energy_discovery_manager_->SetCentralManager(
@@ -225,8 +224,7 @@
 void BluetoothAdapterMac::SetCentralManagerForTesting(
     CBCentralManager* central_manager) {
   CHECK(BluetoothAdapterMac::IsLowEnergyAvailable());
-  [central_manager performSelector:@selector(setDelegate:)
-                        withObject:low_energy_central_manager_delegate_];
+  central_manager.delegate = low_energy_central_manager_delegate_;
   low_energy_central_manager_.reset(central_manager);
   low_energy_discovery_manager_->SetCentralManager(
       low_energy_central_manager_.get());
diff --git a/device/bluetooth/bluetooth_bluez_unittest.cc b/device/bluetooth/bluetooth_bluez_unittest.cc
index 309aec0..f99caab 100644
--- a/device/bluetooth/bluetooth_bluez_unittest.cc
+++ b/device/bluetooth/bluetooth_bluez_unittest.cc
@@ -2160,6 +2160,118 @@
   EXPECT_EQ(BluetoothDevice::DEVICE_MOUSE, devices[idx]->GetDeviceType());
 }
 
+TEST_F(BluetoothBlueZTest, DeviceAppearance) {
+  // Simulate a device with appearance.
+  GetAdapter();
+
+  BluetoothAdapter::DeviceList devices = adapter_->GetDevices();
+  ASSERT_EQ(2U, devices.size());
+
+  int idx = GetDeviceIndexByAddress(
+      devices, bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress);
+  ASSERT_NE(-1, idx);
+  ASSERT_EQ(BluetoothDevice::DEVICE_COMPUTER, devices[idx]->GetDeviceType());
+
+  // Install an observer; expect the DeviceChanged method to be called when
+  // we change the appearance of the device.
+  TestBluetoothAdapterObserver observer(adapter_);
+
+  bluez::FakeBluetoothDeviceClient::Properties* properties =
+      fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath(
+          bluez::FakeBluetoothDeviceClient::kPairedDevicePath));
+
+  // Let the device come without bluetooth_class.
+  properties->appearance.ReplaceValue(0);       // DeviceChanged method called
+  EXPECT_EQ(1, observer.device_changed_count());
+  EXPECT_EQ(devices[idx], observer.last_device());
+
+  // Set the device appearance as keyboard (961).
+  properties->appearance.ReplaceValue(961);     // DeviceChanged method called
+  properties->appearance.set_valid(true);
+  EXPECT_EQ(2, observer.device_changed_count());
+  EXPECT_EQ(devices[idx], observer.last_device());
+  EXPECT_EQ(961, devices[idx]->GetAppearance());
+  // When discovery is over, the value should be invalidated.
+  properties->appearance.set_valid(false);
+  // DeviceChanged method called by NotifyPropertyChanged()
+  properties->NotifyPropertyChanged(properties->appearance.name());
+  EXPECT_EQ(3, observer.device_changed_count());
+  EXPECT_EQ(devices[idx], observer.last_device());
+  EXPECT_EQ((int) BluetoothDevice::kAppearanceNotPresent,
+            devices[idx]->GetAppearance());
+
+  // Change the device appearance to mouse (962).
+  properties->appearance.ReplaceValue(962);     // DeviceChanged method called
+  properties->appearance.set_valid(true);
+  EXPECT_EQ(4, observer.device_changed_count());
+  EXPECT_EQ(devices[idx], observer.last_device());
+  EXPECT_EQ(962, devices[idx]->GetAppearance());
+  // When discovery is over, the value should be invalidated.
+  properties->appearance.set_valid(false);
+  // DeviceChanged method called by NotifyPropertyChanged()
+  properties->NotifyPropertyChanged(properties->appearance.name());
+  EXPECT_EQ(5, observer.device_changed_count());
+  EXPECT_EQ(devices[idx], observer.last_device());
+  EXPECT_EQ((int) BluetoothDevice::kAppearanceNotPresent,
+            devices[idx]->GetAppearance());
+}
+
+TEST_F(BluetoothBlueZTest, DeviceTypebyAppearanceNotBluetoothClass) {
+  // Test device type of a device with appearance but without bluetooth class.
+  GetAdapter();
+
+  BluetoothAdapter::DeviceList devices = adapter_->GetDevices();
+  ASSERT_EQ(2U, devices.size());
+
+  int idx = GetDeviceIndexByAddress(
+      devices, bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress);
+  ASSERT_NE(-1, idx);
+  ASSERT_EQ(BluetoothDevice::DEVICE_COMPUTER, devices[idx]->GetDeviceType());
+
+  // Install an observer; expect the DeviceChanged method to be called when
+  // we change the appearance of the device.
+  TestBluetoothAdapterObserver observer(adapter_);
+
+  bluez::FakeBluetoothDeviceClient::Properties* properties =
+      fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath(
+          bluez::FakeBluetoothDeviceClient::kPairedDevicePath));
+
+  // Let the device come without bluetooth_class.
+  properties->bluetooth_class.ReplaceValue(0);  // DeviceChanged method called
+  properties->appearance.ReplaceValue(0);       // DeviceChanged method called
+  EXPECT_EQ(BluetoothDevice::DEVICE_UNKNOWN, devices[idx]->GetDeviceType());
+  EXPECT_EQ(2, observer.device_changed_count());
+  EXPECT_EQ(devices[idx], observer.last_device());
+
+  // Set the device appearance as keyboard.
+  properties->appearance.ReplaceValue(961);     // DeviceChanged method called
+  properties->appearance.set_valid(true);
+  EXPECT_EQ(BluetoothDevice::DEVICE_KEYBOARD, devices[idx]->GetDeviceType());
+  EXPECT_EQ(3, observer.device_changed_count());
+  EXPECT_EQ(devices[idx], observer.last_device());
+  // When discovery is over, the value should be invalidated.
+  properties->appearance.set_valid(false);
+  // DeviceChanged method called by NotifyPropertyChanged()
+  properties->NotifyPropertyChanged(properties->appearance.name());
+  EXPECT_EQ(4, observer.device_changed_count());
+  EXPECT_EQ(devices[idx], observer.last_device());
+  EXPECT_EQ(BluetoothDevice::DEVICE_UNKNOWN, devices[idx]->GetDeviceType());
+
+  // Change the device appearance to mouse.
+  properties->appearance.ReplaceValue(962);     // DeviceChanged method called
+  properties->appearance.set_valid(true);
+  EXPECT_EQ(BluetoothDevice::DEVICE_MOUSE, devices[idx]->GetDeviceType());
+  EXPECT_EQ(5, observer.device_changed_count());
+  EXPECT_EQ(devices[idx], observer.last_device());
+  // When discovery is over, the value should be invalidated.
+  properties->appearance.set_valid(false);
+  // DeviceChanged method called by NotifyPropertyChanged()
+  properties->NotifyPropertyChanged(properties->appearance.name());
+  EXPECT_EQ(6, observer.device_changed_count());
+  EXPECT_EQ(devices[idx], observer.last_device());
+  EXPECT_EQ(BluetoothDevice::DEVICE_UNKNOWN, devices[idx]->GetDeviceType());
+}
+
 TEST_F(BluetoothBlueZTest, DeviceNameChanged) {
   // Simulate a change of name of a device.
   GetAdapter();
diff --git a/device/bluetooth/bluetooth_classic_device_mac.h b/device/bluetooth/bluetooth_classic_device_mac.h
index c582d6d..acd1dca 100644
--- a/device/bluetooth/bluetooth_classic_device_mac.h
+++ b/device/bluetooth/bluetooth_classic_device_mac.h
@@ -34,6 +34,7 @@
   uint16_t GetVendorID() const override;
   uint16_t GetProductID() const override;
   uint16_t GetDeviceID() const override;
+  uint16_t GetAppearance() const override;
   bool IsPaired() const override;
   bool IsConnected() const override;
   bool IsGattConnected() const override;
diff --git a/device/bluetooth/bluetooth_classic_device_mac.mm b/device/bluetooth/bluetooth_classic_device_mac.mm
index d1c3f634..985596e 100644
--- a/device/bluetooth/bluetooth_classic_device_mac.mm
+++ b/device/bluetooth/bluetooth_classic_device_mac.mm
@@ -102,6 +102,13 @@
   return 0;
 }
 
+uint16_t BluetoothClassicDeviceMac::GetAppearance() const {
+  // TODO(crbug.com/588083): Implementing GetAppearance()
+  // on mac, win, and android platforms for chrome
+  NOTIMPLEMENTED();
+  return 0;
+}
+
 bool BluetoothClassicDeviceMac::IsPaired() const {
   return [device_ isPaired];
 }
diff --git a/device/bluetooth/bluetooth_device.cc b/device/bluetooth/bluetooth_device.cc
index c85af11..5696632 100644
--- a/device/bluetooth/bluetooth_device.cc
+++ b/device/bluetooth/bluetooth_device.cc
@@ -171,6 +171,39 @@
       break;
   }
 
+  // Some bluetooth devices, e.g., Microsoft Universal Foldable Keyboard,
+  // do not expose its bluetooth class. Use its appearance as a work-around.
+  // https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml
+  uint16_t appearance = GetAppearance();
+  // appearance: 10-bit category and 6-bit sub-category
+  switch ((appearance & 0xffc0) >> 6) {
+    case 0x01:
+      // Generic phone
+      return DEVICE_PHONE;
+    case 0x02:
+      // Generic computer
+      return DEVICE_COMPUTER;
+    case 0x0f:
+      // HID subtype
+      switch (appearance & 0x3f) {
+        case 0x01:
+          // Keyboard.
+          return DEVICE_KEYBOARD;
+        case 0x02:
+          // Mouse
+          return DEVICE_MOUSE;
+        case 0x03:
+          // Joystick
+          return DEVICE_JOYSTICK;
+        case 0x04:
+          // Gamepad
+          return DEVICE_GAMEPAD;
+        case 0x05:
+          // Digitizer tablet
+          return DEVICE_TABLET;
+      }
+  }
+
   return DEVICE_UNKNOWN;
 }
 
diff --git a/device/bluetooth/bluetooth_device.h b/device/bluetooth/bluetooth_device.h
index 2bf6f35b..82cc1ce 100644
--- a/device/bluetooth/bluetooth_device.h
+++ b/device/bluetooth/bluetooth_device.h
@@ -78,6 +78,8 @@
 
   // The value returned if the RSSI or transmit power cannot be read.
   static const int kUnknownPower = 127;
+  // The value returned if the appearance is not present.
+  static const uint16_t kAppearanceNotPresent = 0xffc0;
 
   struct DEVICE_BLUETOOTH_EXPORT ConnectionInfo {
     int rssi;
@@ -223,6 +225,9 @@
   // number in BCD format, where available.
   virtual uint16_t GetDeviceID() const = 0;
 
+  // Returns the appearance of the device.
+  virtual uint16_t GetAppearance() const = 0;
+
   // Returns the name of the device suitable for displaying, this may
   // be a synthesized string containing the address and localized type name
   // if the device has no obtained name.
@@ -232,6 +237,11 @@
   // aware of, by decoding the bluetooth class information. The returned
   // values are unique, and do not overlap, so DEVICE_KEYBOARD is not also
   // DEVICE_PERIPHERAL.
+  //
+  // Returns the type of the device, limited to those we support or are aware
+  // of, by decoding the bluetooth class information for Classic devices or
+  // by decoding the device's appearance for LE devices. For example,
+  // Microsoft Universal Foldable Keyboard only advertises the appearance.
   DeviceType GetDeviceType() const;
 
   // Indicates whether the device is known to support pairing based on its
diff --git a/device/bluetooth/bluetooth_device_android.cc b/device/bluetooth/bluetooth_device_android.cc
index 27fdbaf..6149732 100644
--- a/device/bluetooth/bluetooth_device_android.cc
+++ b/device/bluetooth/bluetooth_device_android.cc
@@ -96,6 +96,13 @@
   return 0;
 }
 
+uint16_t BluetoothDeviceAndroid::GetAppearance() const {
+  // TODO(crbug.com/588083): Implementing GetAppearance()
+  // on mac, win, and android platforms for chrome
+  NOTIMPLEMENTED();
+  return 0;
+}
+
 bool BluetoothDeviceAndroid::IsPaired() const {
   return Java_ChromeBluetoothDevice_isPaired(AttachCurrentThread(),
                                              j_device_.obj());
diff --git a/device/bluetooth/bluetooth_device_android.h b/device/bluetooth/bluetooth_device_android.h
index 2fc634d..84e47bb4 100644
--- a/device/bluetooth/bluetooth_device_android.h
+++ b/device/bluetooth/bluetooth_device_android.h
@@ -58,6 +58,7 @@
   uint16_t GetVendorID() const override;
   uint16_t GetProductID() const override;
   uint16_t GetDeviceID() const override;
+  uint16_t GetAppearance() const override;
   bool IsPaired() const override;
   bool IsConnected() const override;
   bool IsGattConnected() const override;
diff --git a/device/bluetooth/bluetooth_device_bluez.cc b/device/bluetooth/bluetooth_device_bluez.cc
index 4001f90..5ee49a4c 100644
--- a/device/bluetooth/bluetooth_device_bluez.cc
+++ b/device/bluetooth/bluetooth_device_bluez.cc
@@ -244,6 +244,18 @@
   return device_id;
 }
 
+uint16_t BluetoothDeviceBlueZ::GetAppearance() const {
+  bluez::BluetoothDeviceClient::Properties* properties =
+      bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties(
+          object_path_);
+  DCHECK(properties);
+
+  if (!properties->appearance.is_valid())
+    return kAppearanceNotPresent;
+
+  return properties->appearance.value();
+}
+
 bool BluetoothDeviceBlueZ::IsPaired() const {
   bluez::BluetoothDeviceClient::Properties* properties =
       bluez::BluezDBusManager::Get()->GetBluetoothDeviceClient()->GetProperties(
diff --git a/device/bluetooth/bluetooth_device_bluez.h b/device/bluetooth/bluetooth_device_bluez.h
index 595bab4..4b15aea 100644
--- a/device/bluetooth/bluetooth_device_bluez.h
+++ b/device/bluetooth/bluetooth_device_bluez.h
@@ -47,6 +47,7 @@
   uint16_t GetVendorID() const override;
   uint16_t GetProductID() const override;
   uint16_t GetDeviceID() const override;
+  uint16_t GetAppearance() const override;
   bool IsPaired() const override;
   bool IsConnected() const override;
   bool IsGattConnected() const override;
diff --git a/device/bluetooth/bluetooth_device_win.cc b/device/bluetooth/bluetooth_device_win.cc
index d63b9d04..310aa9d 100644
--- a/device/bluetooth/bluetooth_device_win.cc
+++ b/device/bluetooth/bluetooth_device_win.cc
@@ -70,6 +70,13 @@
   return 0;
 }
 
+uint16_t BluetoothDeviceWin::GetAppearance() const {
+  // TODO(crbug.com/588083): Implementing GetAppearance()
+  // on mac, win, and android platforms for chrome
+  NOTIMPLEMENTED();
+  return 0;
+}
+
 bool BluetoothDeviceWin::IsPaired() const {
   return paired_;
 }
diff --git a/device/bluetooth/bluetooth_device_win.h b/device/bluetooth/bluetooth_device_win.h
index 6166032..bba7fb3 100644
--- a/device/bluetooth/bluetooth_device_win.h
+++ b/device/bluetooth/bluetooth_device_win.h
@@ -40,6 +40,7 @@
   uint16_t GetVendorID() const override;
   uint16_t GetProductID() const override;
   uint16_t GetDeviceID() const override;
+  uint16_t GetAppearance() const override;
   bool IsPaired() const override;
   bool IsConnected() const override;
   bool IsGattConnected() const override;
diff --git a/device/bluetooth/bluetooth_low_energy_device_mac.h b/device/bluetooth/bluetooth_low_energy_device_mac.h
index 19cbb01..ad713a5 100644
--- a/device/bluetooth/bluetooth_low_energy_device_mac.h
+++ b/device/bluetooth/bluetooth_low_energy_device_mac.h
@@ -46,6 +46,7 @@
   uint16_t GetVendorID() const override;
   uint16_t GetProductID() const override;
   uint16_t GetDeviceID() const override;
+  uint16_t GetAppearance() const override;
   bool IsPaired() const override;
   bool IsConnected() const override;
   bool IsGattConnected() const override;
@@ -108,9 +109,6 @@
   friend class BluetoothAdapterMac;
   friend class BluetoothAdapterMacTest;
 
-  // Equivalent to [peripheral_ state].  Allows compilation on OS X 10.6.
-  CBPeripheralState GetPeripheralState() const;
-
   // CoreBluetooth data structure.
   base::scoped_nsobject<CBPeripheral> peripheral_;
 
diff --git a/device/bluetooth/bluetooth_low_energy_device_mac.mm b/device/bluetooth/bluetooth_low_energy_device_mac.mm
index 677c5955..00712ae8 100644
--- a/device/bluetooth/bluetooth_low_energy_device_mac.mm
+++ b/device/bluetooth/bluetooth_low_energy_device_mac.mm
@@ -106,6 +106,13 @@
   return 0;
 }
 
+uint16_t BluetoothLowEnergyDeviceMac::GetAppearance() const {
+  // TODO(crbug.com/588083): Implementing GetAppearance()
+  // on mac, win, and android platforms for chrome
+  NOTIMPLEMENTED();
+  return 0;
+}
+
 int BluetoothLowEnergyDeviceMac::GetRSSI() const {
   return rssi_;
 }
@@ -119,7 +126,7 @@
 }
 
 bool BluetoothLowEnergyDeviceMac::IsGattConnected() const {
-  return (GetPeripheralState() == CBPeripheralStateConnected);
+  return ([peripheral_ state] == CBPeripheralStateConnected);
 }
 
 bool BluetoothLowEnergyDeviceMac::IsConnectable() const {
@@ -258,17 +265,3 @@
   std::string hash = base::HexEncode(raw, sizeof(raw));
   return BluetoothDevice::CanonicalizeAddress(hash);
 }
-
-CBPeripheralState BluetoothLowEnergyDeviceMac::GetPeripheralState() const {
-  Class peripheral_class = NSClassFromString(@"CBPeripheral");
-  base::scoped_nsobject<NSMethodSignature> signature([[peripheral_class
-      instanceMethodSignatureForSelector:@selector(state)] retain]);
-  base::scoped_nsobject<NSInvocation> invocation(
-      [[NSInvocation invocationWithMethodSignature:signature] retain]);
-  [invocation setTarget:peripheral_];
-  [invocation setSelector:@selector(state)];
-  [invocation invoke];
-  CBPeripheralState state = CBPeripheralStateDisconnected;
-  [invocation getReturnValue:&state];
-  return state;
-}
diff --git a/device/bluetooth/bluetooth_low_energy_discovery_manager_mac.mm b/device/bluetooth/bluetooth_low_energy_discovery_manager_mac.mm
index d14b578..5a0dbe9 100644
--- a/device/bluetooth/bluetooth_low_energy_discovery_manager_mac.mm
+++ b/device/bluetooth/bluetooth_low_energy_discovery_manager_mac.mm
@@ -57,8 +57,7 @@
     for (auto& service_uuid : services_uuids_) {
       NSString* uuidString =
           base::SysUTF8ToNSString(service_uuid.canonical_value().c_str());
-      Class aClass = NSClassFromString(@"CBUUID");
-      CBUUID* uuid = [aClass UUIDWithString:uuidString];
+      CBUUID* uuid = [CBUUID UUIDWithString:uuidString];
       [services addObject:uuid];
     }
   };
diff --git a/device/bluetooth/bluetooth_socket_mac.mm b/device/bluetooth/bluetooth_socket_mac.mm
index c82e5d2b..235168a 100644
--- a/device/bluetooth/bluetooth_socket_mac.mm
+++ b/device/bluetooth/bluetooth_socket_mac.mm
@@ -264,7 +264,7 @@
 
 // Converts the given |integer| to a string.
 NSString* IntToNSString(int integer) {
-  return [[NSNumber numberWithInt:integer] stringValue];
+  return [@(integer) stringValue];
 }
 
 // Returns a dictionary containing the Bluetooth service definition
@@ -305,20 +305,17 @@
     const BluetoothUUID& uuid,
     const BluetoothAdapter::ServiceOptions& options) {
   int channel_id = options.channel ? *options.channel : kInvalidRfcommChannelId;
-  NSArray* rfcomm_protocol_definition =
-      @[
-        @[
-          [IOBluetoothSDPUUID uuid16:kBluetoothSDPUUID16L2CAP]
-        ],
-        @[
-          [IOBluetoothSDPUUID uuid16:kBluetoothSDPUUID16RFCOMM],
-          @{
-            @"DataElementType": @1,  // Unsigned integer.
-            @"DataElementSize": @1,  // 1 byte.
-            @"DataElementValue": [NSNumber numberWithInt:channel_id]
-          }
-        ]
-      ];
+  NSArray* rfcomm_protocol_definition = @[
+    @[ [IOBluetoothSDPUUID uuid16:kBluetoothSDPUUID16L2CAP] ],
+    @[
+      [IOBluetoothSDPUUID uuid16:kBluetoothSDPUUID16RFCOMM],
+      @{
+        @"DataElementType" : @1,  // Unsigned integer.
+        @"DataElementSize" : @1,  // 1 byte.
+        @"DataElementValue" : @(channel_id),
+      },
+    ],
+  ];
   return BuildServiceDefinition(
       uuid, options.name.get(), rfcomm_protocol_definition);
 }
@@ -329,17 +326,16 @@
     const BluetoothUUID& uuid,
     const BluetoothAdapter::ServiceOptions& options) {
   int psm = options.psm ? *options.psm : kInvalidL2capPsm;
-  NSArray* l2cap_protocol_definition =
-      @[
-        @[
-          [IOBluetoothSDPUUID uuid16:kBluetoothSDPUUID16L2CAP],
-          @{
-            @"DataElementType": @1,  // Unsigned integer.
-            @"DataElementSize": @2,  // 2 bytes.
-            @"DataElementValue": [NSNumber numberWithInt:psm]
-          }
-        ]
-      ];
+  NSArray* l2cap_protocol_definition = @[
+    @[
+      [IOBluetoothSDPUUID uuid16:kBluetoothSDPUUID16L2CAP],
+      @{
+        @"DataElementType" : @1,  // Unsigned integer.
+        @"DataElementSize" : @2,  // 2 bytes.
+        @"DataElementValue" : @(psm),
+      },
+    ],
+  ];
   return BuildServiceDefinition(
       uuid, options.name.get(), l2cap_protocol_definition);
 }
diff --git a/device/bluetooth/test/bluetooth_test_mac.mm b/device/bluetooth/test/bluetooth_test_mac.mm
index 110e9f9..d64b5f7 100644
--- a/device/bluetooth/test/bluetooth_test_mac.mm
+++ b/device/bluetooth/test/bluetooth_test_mac.mm
@@ -127,7 +127,7 @@
       [central_manager_delegate centralManager:central_manager
                          didDiscoverPeripheral:peripheral
                              advertisementData:advertisement_data
-                                          RSSI:[NSNumber numberWithInt:0]];
+                                          RSSI:@(0)];
       break;
     }
     case 2: {
@@ -147,7 +147,7 @@
       [central_manager_delegate centralManager:central_manager
                          didDiscoverPeripheral:peripheral
                              advertisementData:advertisement_data
-                                          RSSI:[NSNumber numberWithInt:0]];
+                                          RSSI:@(0)];
       break;
     }
     case 3: {
@@ -160,7 +160,7 @@
       [central_manager_delegate centralManager:central_manager
                          didDiscoverPeripheral:peripheral
                              advertisementData:advertisement_data
-                                          RSSI:[NSNumber numberWithInt:0]];
+                                          RSSI:@(0)];
       break;
     }
     case 4: {
@@ -173,7 +173,7 @@
       [central_manager_delegate centralManager:central_manager
                          didDiscoverPeripheral:peripheral
                              advertisementData:advertisement_data
-                                          RSSI:[NSNumber numberWithInt:0]];
+                                          RSSI:@(0)];
       break;
     }
   }
diff --git a/device/bluetooth/test/mock_bluetooth_device.h b/device/bluetooth/test/mock_bluetooth_device.h
index 5aab0921..801a936 100644
--- a/device/bluetooth/test/mock_bluetooth_device.h
+++ b/device/bluetooth/test/mock_bluetooth_device.h
@@ -41,6 +41,7 @@
   MOCK_CONST_METHOD0(GetDeviceID, uint16_t());
   MOCK_CONST_METHOD0(GetName, base::string16());
   MOCK_CONST_METHOD0(GetDeviceType, BluetoothDevice::DeviceType());
+  MOCK_CONST_METHOD0(GetAppearance, uint16_t());
   MOCK_CONST_METHOD0(IsPaired, bool());
   MOCK_CONST_METHOD0(IsConnected, bool());
   MOCK_CONST_METHOD0(IsGattConnected, bool());
diff --git a/device/hid/hid_collection_info.cc b/device/hid/hid_collection_info.cc
index 4c55d087..43406de2 100644
--- a/device/hid/hid_collection_info.cc
+++ b/device/hid/hid_collection_info.cc
@@ -11,6 +11,8 @@
             HidUsageAndPage::kPageUndefined) {
 }
 
+HidCollectionInfo::HidCollectionInfo(const HidCollectionInfo& other) = default;
+
 HidCollectionInfo::~HidCollectionInfo() {
 }
 
diff --git a/device/hid/hid_collection_info.h b/device/hid/hid_collection_info.h
index 3b35e5e..05e40d7 100644
--- a/device/hid/hid_collection_info.h
+++ b/device/hid/hid_collection_info.h
@@ -13,6 +13,7 @@
 
 struct HidCollectionInfo {
   HidCollectionInfo();
+  HidCollectionInfo(const HidCollectionInfo& other);
   ~HidCollectionInfo();
 
   // Collection's usage ID.
diff --git a/device/hid/hid_connection.cc b/device/hid/hid_connection.cc
index 208a565a..5a904fe 100644
--- a/device/hid/hid_connection.cc
+++ b/device/hid/hid_connection.cc
@@ -196,10 +196,14 @@
 
 PendingHidReport::PendingHidReport() {}
 
+PendingHidReport::PendingHidReport(const PendingHidReport& other) = default;
+
 PendingHidReport::~PendingHidReport() {}
 
 PendingHidRead::PendingHidRead() {}
 
+PendingHidRead::PendingHidRead(const PendingHidRead& other) = default;
+
 PendingHidRead::~PendingHidRead() {}
 
 }  // namespace device
diff --git a/device/hid/hid_connection.h b/device/hid/hid_connection.h
index 9cc8aaf..1bf8d2e 100644
--- a/device/hid/hid_connection.h
+++ b/device/hid/hid_connection.h
@@ -97,6 +97,7 @@
 
 struct PendingHidReport {
   PendingHidReport();
+  PendingHidReport(const PendingHidReport& other);
   ~PendingHidReport();
 
   scoped_refptr<net::IOBuffer> buffer;
@@ -105,6 +106,7 @@
 
 struct PendingHidRead {
   PendingHidRead();
+  PendingHidRead(const PendingHidRead& other);
   ~PendingHidRead();
 
   HidConnection::ReadCallback callback;
diff --git a/device/hid/input_service_linux.cc b/device/hid/input_service_linux.cc
index c39a73d..dd8b38b3 100644
--- a/device/hid/input_service_linux.cc
+++ b/device/hid/input_service_linux.cc
@@ -166,6 +166,9 @@
       is_touchpad(false),
       is_touchscreen(false) {}
 
+InputServiceLinux::InputDeviceInfo::InputDeviceInfo(
+    const InputDeviceInfo& other) = default;
+
 InputServiceLinux::InputServiceLinux() {
 }
 
diff --git a/device/hid/input_service_linux.h b/device/hid/input_service_linux.h
index dfb11d1b..ca395b0 100644
--- a/device/hid/input_service_linux.h
+++ b/device/hid/input_service_linux.h
@@ -30,6 +30,7 @@
     enum Type { TYPE_BLUETOOTH, TYPE_USB, TYPE_SERIO, TYPE_UNKNOWN };
 
     InputDeviceInfo();
+    InputDeviceInfo(const InputDeviceInfo& other);
 
     std::string id;
     std::string name;
diff --git a/device/usb/usb_descriptors.cc b/device/usb/usb_descriptors.cc
index 6defda8..d3ef4bfa2 100644
--- a/device/usb/usb_descriptors.cc
+++ b/device/usb/usb_descriptors.cc
@@ -102,6 +102,9 @@
       usage_type(usage_type),
       polling_interval(polling_interval) {}
 
+UsbEndpointDescriptor::UsbEndpointDescriptor(
+    const UsbEndpointDescriptor& other) = default;
+
 UsbEndpointDescriptor::~UsbEndpointDescriptor() = default;
 
 UsbInterfaceDescriptor::UsbInterfaceDescriptor(uint8_t interface_number,
@@ -115,6 +118,9 @@
       interface_subclass(interface_subclass),
       interface_protocol(interface_protocol) {}
 
+UsbInterfaceDescriptor::UsbInterfaceDescriptor(
+    const UsbInterfaceDescriptor& other) = default;
+
 UsbInterfaceDescriptor::~UsbInterfaceDescriptor() = default;
 
 UsbConfigDescriptor::UsbConfigDescriptor(uint8_t configuration_value,
@@ -126,6 +132,9 @@
       remote_wakeup(remote_wakeup),
       maximum_power(maximum_power) {}
 
+UsbConfigDescriptor::UsbConfigDescriptor(const UsbConfigDescriptor& other) =
+    default;
+
 UsbConfigDescriptor::~UsbConfigDescriptor() = default;
 
 bool ParseUsbStringDescriptor(const std::vector<uint8_t>& descriptor,
diff --git a/device/usb/usb_descriptors.h b/device/usb/usb_descriptors.h
index c99a6def..ba7169a 100644
--- a/device/usb/usb_descriptors.h
+++ b/device/usb/usb_descriptors.h
@@ -57,6 +57,7 @@
                         UsbUsageType usage_type,
                         uint16_t polling_interval);
   UsbEndpointDescriptor() = delete;
+  UsbEndpointDescriptor(const UsbEndpointDescriptor& other);
   ~UsbEndpointDescriptor();
 
   uint8_t address;
@@ -76,6 +77,7 @@
                          uint8_t interface_subclass,
                          uint8_t interface_protocol);
   UsbInterfaceDescriptor() = delete;
+  UsbInterfaceDescriptor(const UsbInterfaceDescriptor& other);
   ~UsbInterfaceDescriptor();
 
   uint8_t interface_number;
@@ -93,6 +95,7 @@
                       bool remote_wakeup,
                       uint16_t maximum_power);
   UsbConfigDescriptor() = delete;
+  UsbConfigDescriptor(const UsbConfigDescriptor& other);
   ~UsbConfigDescriptor();
 
   uint8_t configuration_value;
diff --git a/device/usb/usb_device_filter.cc b/device/usb/usb_device_filter.cc
index b8d47fa..52d1356e 100644
--- a/device/usb/usb_device_filter.cc
+++ b/device/usb/usb_device_filter.cc
@@ -30,6 +30,8 @@
       interface_protocol_set_(false) {
 }
 
+UsbDeviceFilter::UsbDeviceFilter(const UsbDeviceFilter& other) = default;
+
 UsbDeviceFilter::~UsbDeviceFilter() {
 }
 
diff --git a/device/usb/usb_device_filter.h b/device/usb/usb_device_filter.h
index 84553041..05f4038 100644
--- a/device/usb/usb_device_filter.h
+++ b/device/usb/usb_device_filter.h
@@ -23,6 +23,7 @@
 class UsbDeviceFilter {
  public:
   UsbDeviceFilter();
+  UsbDeviceFilter(const UsbDeviceFilter& other);
   ~UsbDeviceFilter();
 
   void SetVendorId(uint16_t vendor_id);
diff --git a/device/usb/webusb_descriptors.cc b/device/usb/webusb_descriptors.cc
index 27a3d38e..de2309e 100644
--- a/device/usb/webusb_descriptors.cc
+++ b/device/usb/webusb_descriptors.cc
@@ -359,11 +359,17 @@
 
 WebUsbFunctionSubset::WebUsbFunctionSubset() : first_interface(0) {}
 
+WebUsbFunctionSubset::WebUsbFunctionSubset(const WebUsbFunctionSubset& other) =
+    default;
+
 WebUsbFunctionSubset::~WebUsbFunctionSubset() {}
 
 WebUsbConfigurationSubset::WebUsbConfigurationSubset()
     : configuration_value(0) {}
 
+WebUsbConfigurationSubset::WebUsbConfigurationSubset(
+    const WebUsbConfigurationSubset& other) = default;
+
 WebUsbConfigurationSubset::~WebUsbConfigurationSubset() {}
 
 WebUsbAllowedOrigins::WebUsbAllowedOrigins() {}
diff --git a/device/usb/webusb_descriptors.h b/device/usb/webusb_descriptors.h
index 44f9c1c4..516adfc 100644
--- a/device/usb/webusb_descriptors.h
+++ b/device/usb/webusb_descriptors.h
@@ -18,6 +18,7 @@
 
 struct WebUsbFunctionSubset {
   WebUsbFunctionSubset();
+  WebUsbFunctionSubset(const WebUsbFunctionSubset& other);
   ~WebUsbFunctionSubset();
 
   uint8_t first_interface;
@@ -27,6 +28,7 @@
 
 struct WebUsbConfigurationSubset {
   WebUsbConfigurationSubset();
+  WebUsbConfigurationSubset(const WebUsbConfigurationSubset& other);
   ~WebUsbConfigurationSubset();
 
   uint8_t configuration_value;
diff --git a/docs/ccache_mac.md b/docs/ccache_mac.md
index 09f5e2ad..cd5492d5 100644
--- a/docs/ccache_mac.md
+++ b/docs/ccache_mac.md
@@ -70,7 +70,7 @@
 You just need to set the use\_ccache variable. Do so like the following:
 
 ```shell
-gn gen out-gn --args='use_ccache=true'
+gn gen out-gn --args='cc_wrapper="ccache"'
 ```
 
 ## Build
diff --git a/extensions/BUILD.gn b/extensions/BUILD.gn
index 3d97214..5741f96 100644
--- a/extensions/BUILD.gn
+++ b/extensions/BUILD.gn
@@ -301,7 +301,6 @@
     "//components/resources",
     "//components/strings",
     "//components/translate/core/common",
-    "//components/user_manager:test_support",
     "//crypto:platform",
     "//crypto:test_support",
     "//device/bluetooth:mocks",
@@ -336,6 +335,10 @@
     "//ui/web_dialogs:test_support",
     "//v8",
   ]
+
+  if (is_chromeos) {
+    deps += [ "//components/user_manager:test_support" ]
+  }
 }
 
 # TODO(rockot) bug 505926: This should be deleted for the same reason as
diff --git a/extensions/browser/api/app_runtime/app_runtime_api.cc b/extensions/browser/api/app_runtime/app_runtime_api.cc
index 67f3ead..fca709b 100644
--- a/extensions/browser/api/app_runtime/app_runtime_api.cc
+++ b/extensions/browser/api/app_runtime/app_runtime_api.cc
@@ -11,6 +11,7 @@
 #include "base/metrics/histogram.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "extensions/browser/entry_info.h"
 #include "extensions/browser/event_router.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extensions_browser_client.h"
@@ -162,7 +163,7 @@
     BrowserContext* context,
     const Extension* extension,
     const std::string& handler_id,
-    const std::vector<std::string>& mime_types,
+    const std::vector<EntryInfo>& entries,
     const std::vector<GrantedFileEntry>& file_entries) {
   // TODO(sergeygs): Use the same way of creating an event (using the generated
   // boilerplate) as below in DispatchOnLaunchedEventWithUrl.
@@ -176,14 +177,15 @@
   }
 
   scoped_ptr<base::ListValue> items(new base::ListValue);
-  DCHECK(file_entries.size() == mime_types.size());
+  DCHECK(file_entries.size() == entries.size());
   for (size_t i = 0; i < file_entries.size(); ++i) {
     scoped_ptr<base::DictionaryValue> launch_item(new base::DictionaryValue);
 
     launch_item->SetString("fileSystemId", file_entries[i].filesystem_id);
     launch_item->SetString("baseName", file_entries[i].registered_name);
-    launch_item->SetString("mimeType", mime_types[i]);
+    launch_item->SetString("mimeType", entries[i].mime_type);
     launch_item->SetString("entryId", file_entries[i].id);
+    launch_item->SetBoolean("isDirectory", entries[i].is_directory);
     items->Append(launch_item.release());
   }
   launch_data->Set("items", items.release());
diff --git a/extensions/browser/api/app_runtime/app_runtime_api.h b/extensions/browser/api/app_runtime/app_runtime_api.h
index 38f6fd6..35a28d22 100644
--- a/extensions/browser/api/app_runtime/app_runtime_api.h
+++ b/extensions/browser/api/app_runtime/app_runtime_api.h
@@ -25,6 +25,7 @@
 namespace extensions {
 
 class Extension;
+struct EntryInfo;
 struct GrantedFileEntry;
 
 class AppRuntimeEventRouter {
@@ -64,7 +65,7 @@
       content::BrowserContext* context,
       const Extension* extension,
       const std::string& handler_id,
-      const std::vector<std::string>& mime_types,
+      const std::vector<EntryInfo>& entries,
       const std::vector<GrantedFileEntry>& file_entries);
 
   // |handler_id| corresponds to the id of the url_handlers item
diff --git a/extensions/browser/api/cast_channel/cast_channel_api.cc b/extensions/browser/api/cast_channel/cast_channel_api.cc
index c0f8821..b5593f7f 100644
--- a/extensions/browser/api/cast_channel/cast_channel_api.cc
+++ b/extensions/browser/api/cast_channel/cast_channel_api.cc
@@ -28,7 +28,6 @@
 #include "extensions/common/api/cast_channel/logging.pb.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 
 // Default timeout interval for connection setup.
 // Used if not otherwise specified at ConnectInfo::timeout.
diff --git a/extensions/browser/api/cast_channel/cast_socket.cc b/extensions/browser/api/cast_channel/cast_socket.cc
index 6a330e3..12df2bf 100644
--- a/extensions/browser/api/cast_channel/cast_socket.cc
+++ b/extensions/browser/api/cast_channel/cast_socket.cc
@@ -28,7 +28,6 @@
 #include "net/base/address_list.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/cert/cert_verifier.h"
 #include "net/cert/cert_verify_result.h"
 #include "net/cert/x509_certificate.h"
diff --git a/extensions/browser/api/cast_channel/cast_socket_unittest.cc b/extensions/browser/api/cast_channel/cast_socket_unittest.cc
index f79ce16..dbc46dc 100644
--- a/extensions/browser/api/cast_channel/cast_socket_unittest.cc
+++ b/extensions/browser/api/cast_channel/cast_socket_unittest.cc
@@ -26,7 +26,6 @@
 #include "extensions/common/api/cast_channel/cast_channel.pb.h"
 #include "net/base/address_list.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/log/test_net_log.h"
 #include "net/socket/socket_test_util.h"
 #include "net/socket/ssl_client_socket.h"
diff --git a/extensions/browser/api/socket/socket_api.cc b/extensions/browser/api/socket/socket_api.cc
index 7653f56a..88b2a83 100644
--- a/extensions/browser/api/socket/socket_api.cc
+++ b/extensions/browser/api/socket/socket_api.cc
@@ -25,8 +25,8 @@
 #include "net/base/io_buffer.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/network_interfaces.h"
+#include "net/base/url_util.h"
 #include "net/log/net_log.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
diff --git a/extensions/browser/entry_info.h b/extensions/browser/entry_info.h
new file mode 100644
index 0000000..eb5f5d5
--- /dev/null
+++ b/extensions/browser/entry_info.h
@@ -0,0 +1,28 @@
+// Copyright 2016 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 EXTENSIONS_BROWSER_ENTRY_INFO_H_
+#define EXTENSIONS_BROWSER_ENTRY_INFO_H_
+
+#include <string>
+
+#include "base/files/file_path.h"
+
+namespace extensions {
+
+// Contains information about files and directories.
+struct EntryInfo {
+  EntryInfo(const base::FilePath& path,
+            const std::string& mime_type,
+            bool is_directory)
+      : path(path), mime_type(mime_type), is_directory(is_directory) {}
+
+  base::FilePath path;
+  std::string mime_type;  // Useful only if is_directory = false.
+  bool is_directory;
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_ENTRY_INFO_H_
diff --git a/extensions/browser/extension_event_histogram_value.h b/extensions/browser/extension_event_histogram_value.h
index cc7ea53c..18caf832e 100644
--- a/extensions/browser/extension_event_histogram_value.h
+++ b/extensions/browser/extension_event_histogram_value.h
@@ -413,6 +413,7 @@
   DISPLAY_SOURCE_ON_SINKS_UPDATED,
   INPUT_IME_ON_COMPOSITION_BOUNDS_CHANGED,
   INPUT_METHOD_PRIVATE_ON_IME_MENU_ACTIVATION_CHANGED,
+  INPUT_METHOD_PRIVATE_ON_IME_MENU_LIST_CHANGED,
   // Last entry: Add new entries above, then run:
   // python tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/extensions/browser/extension_throttle_manager.cc b/extensions/browser/extension_throttle_manager.cc
index 6a9f253..16d9501b 100644
--- a/extensions/browser/extension_throttle_manager.cc
+++ b/extensions/browser/extension_throttle_manager.cc
@@ -12,7 +12,7 @@
 #include "base/strings/string_util.h"
 #include "extensions/browser/extension_request_limiting_throttle.h"
 #include "extensions/common/constants.h"
-#include "net/base/net_util.h"
+#include "net/base/url_util.h"
 #include "net/log/net_log.h"
 #include "net/url_request/url_request.h"
 
diff --git a/extensions/common/api/_permission_features.json b/extensions/common/api/_permission_features.json
index 494731d..2f9d159e 100644
--- a/extensions/common/api/_permission_features.json
+++ b/extensions/common/api/_permission_features.json
@@ -148,7 +148,9 @@
       "BD8781D757D830FC2E85470A1B6E8A718B7EE0D9",  // http://crbug.com/407693
       "4AC2B6C63C6480D150DFDA13E4A5956EB1D0DDBB",  // http://crbug.com/407693
       "81986D4F846CEDDDB962643FA501D1780DD441BB",  // http://crbug.com/407693
-      "89715614FAA2B4C2853802D70261D2A9D0756FC8"   // http://crbug.com/455986
+      "89715614FAA2B4C2853802D70261D2A9D0756FC8",  // http://crbug.com/455986
+      "61FF4757F9420B62B19BA5C96084649339DB31F5",  // http://crbug.com/587613
+      "F3013F58BED982D1BC75943792FF877E5D458672"   // http://crbug.com/587613
     ]
   },
   "cast": {
diff --git a/extensions/common/api/app_runtime.idl b/extensions/common/api/app_runtime.idl
index e3339bd..daf953c 100644
--- a/extensions/common/api/app_runtime.idl
+++ b/extensions/common/api/app_runtime.idl
@@ -8,11 +8,11 @@
 namespace app.runtime {
 
   [inline_doc] dictionary LaunchItem {
-    // FileEntry for the file.
-    [instanceOf=FileEntry] object entry;
+    // Entry for the item.
+    [instanceOf=Entry] object entry;
 
     // The MIME type of the file.
-    DOMString type;
+    DOMString? type;
   };
 
   // Enumeration of app launch sources.
diff --git a/extensions/common/api/usb.idl b/extensions/common/api/usb.idl
index 77163e7..21e4bd3c 100644
--- a/extensions/common/api/usb.idl
+++ b/extensions/common/api/usb.idl
@@ -119,15 +119,16 @@
     // The request type.
     RequestType requestType;
 
-    // The <code>bRequest</code> field, see <i>Universal Serial Bus Specification
-    // Revision 1.1</i> &sect; 9.3.
+    // The <code>bRequest</code> field, see <i>Universal Serial Bus
+    // Specification Revision 1.1</i> &sect; 9.3.
     long request;
     // The <code>wValue</code> field, see <i>Ibid</i>.
     long value;
     // The <code>wIndex</code> field, see <i>Ibid</i>.
     long index;
 
-    // The amount of data to receive (required only by input transfers).
+    // The maximum number of bytes to receive (required only by input
+    // transfers).
     long? length;
 
     // The data to transmit (required only by output transfers).
@@ -146,7 +147,8 @@
     // be claimed.
     long endpoint;
 
-    // The amount of data to receive (required only by input transfers).
+    // The maximum number of bytes to receive (required only by input
+    // transfers).
     long? length;
 
     // The data to transmit (required only by output transfers).
diff --git a/extensions/common/manifest_constants.cc b/extensions/common/manifest_constants.cc
index 7195dda..85775ef 100644
--- a/extensions/common/manifest_constants.cc
+++ b/extensions/common/manifest_constants.cc
@@ -392,8 +392,11 @@
     "Invalid value for 'file_handlers[*].extensions'.";
 const char kInvalidFileHandlerExtensionElement[] =
     "Invalid value for 'file_handlers[*].extensions[*]'.";
+const char kInvalidFileHandlerIncludeDirectories[] =
+    "Invalid value for 'include_directories'.";
 const char kInvalidFileHandlerNoTypeOrExtension[] =
-    "'file_handlers[*]' must contain a non-empty 'types' or 'extensions'.";
+    "'file_handlers[*]' must contain a non-empty 'types', 'extensions' "
+    "or 'include_directories'.";
 const char kInvalidFileHandlerType[] =
     "Invalid value for 'file_handlers[*].types'.";
 const char kInvalidFileHandlerTypeElement[] =
diff --git a/extensions/common/manifest_constants.h b/extensions/common/manifest_constants.h
index 9051aa8..81f8fc5 100644
--- a/extensions/common/manifest_constants.h
+++ b/extensions/common/manifest_constants.h
@@ -318,6 +318,7 @@
 extern const char kInvalidFileHandlersTooManyTypesAndExtensions[];
 extern const char kInvalidFileHandlerExtension[];
 extern const char kInvalidFileHandlerExtensionElement[];
+extern const char kInvalidFileHandlerIncludeDirectories[];
 extern const char kInvalidFileHandlerNoTypeOrExtension[];
 extern const char kInvalidFileHandlerType[];
 extern const char kInvalidFileHandlerTypeElement[];
diff --git a/extensions/common/manifest_handlers/file_handler_info.cc b/extensions/common/manifest_handlers/file_handler_info.cc
index 9b0989a..b525c14 100644
--- a/extensions/common/manifest_handlers/file_handler_info.cc
+++ b/extensions/common/manifest_handlers/file_handler_info.cc
@@ -25,7 +25,7 @@
 const char kNotRecognized[] = "'%s' is not a recognized file handler property.";
 }
 
-FileHandlerInfo::FileHandlerInfo() {}
+FileHandlerInfo::FileHandlerInfo() : include_directories(false) {}
 FileHandlerInfo::~FileHandlerInfo() {}
 
 FileHandlers::FileHandlers() {}
@@ -71,8 +71,18 @@
     return false;
   }
 
+  handler.include_directories = false;
+  if (handler_info.HasKey("include_directories") &&
+      !handler_info.GetBoolean("include_directories",
+                               &handler.include_directories)) {
+    *error = ErrorUtils::FormatErrorMessageUTF16(
+        errors::kInvalidFileHandlerIncludeDirectories, handler_id);
+    return false;
+  }
+
   if ((!mime_types || mime_types->empty()) &&
-      (!file_extensions || file_extensions->empty())) {
+      (!file_extensions || file_extensions->empty()) &&
+      !handler.include_directories) {
     *error = ErrorUtils::FormatErrorMessageUTF16(
         errors::kInvalidFileHandlerNoTypeOrExtension,
         handler_id);
diff --git a/extensions/common/manifest_handlers/file_handler_info.h b/extensions/common/manifest_handlers/file_handler_info.h
index ac458e1..ac9e51de 100644
--- a/extensions/common/manifest_handlers/file_handler_info.h
+++ b/extensions/common/manifest_handlers/file_handler_info.h
@@ -27,6 +27,9 @@
 
   // MIME types associated with this handler.
   std::set<std::string> types;
+
+  // True if the handler can manage directories.
+  bool include_directories;
 };
 
 typedef std::vector<FileHandlerInfo> FileHandlersInfo;
diff --git a/extensions/renderer/resources/app_runtime_custom_bindings.js b/extensions/renderer/resources/app_runtime_custom_bindings.js
index 0364b66f..3f0dbd2 100644
--- a/extensions/renderer/resources/app_runtime_custom_bindings.js
+++ b/extensions/renderer/resources/app_runtime_custom_bindings.js
@@ -57,12 +57,21 @@
     };
     $Array.forEach(launchData.items, function(item) {
       var fs = GetIsolatedFileSystem(item.fileSystemId);
-      fs.root.getFile(item.baseName, {}, function(fileEntry) {
-        entryIdManager.registerEntry(item.entryId, fileEntry);
-        itemLoaded(null, { entry: fileEntry, type: item.mimeType });
-      }, function(fileError) {
-        itemLoaded(fileError);
-      });
+      if (item.isDirectory) {
+        fs.root.getDirectory(item.baseName, {}, function(dirEntry) {
+          entryIdManager.registerEntry(item.entryId, dirEntry);
+          itemLoaded(null, {entry: dirEntry});
+        }, function(fileError) {
+          itemLoaded(fileError);
+        });
+      } else {
+        fs.root.getFile(item.baseName, {}, function(fileEntry) {
+          entryIdManager.registerEntry(item.entryId, fileEntry);
+          itemLoaded(null, {entry: fileEntry, type: item.mimeType});
+        }, function(fileError) {
+          itemLoaded(fileError);
+        });
+      }
     });
   } else {
     // Default case. This currently covers an onLaunched corresponding to
diff --git a/google_apis/google_api_keys.cc b/google_apis/google_api_keys.cc
index 52542cf..4721575 100644
--- a/google_apis/google_api_keys.cc
+++ b/google_apis/google_api_keys.cc
@@ -33,6 +33,10 @@
 #define GOOGLE_API_KEY_SAFESITES DUMMY_API_TOKEN
 #endif
 
+#if !defined(GOOGLE_API_KEY_REMOTING)
+#define GOOGLE_API_KEY_REMOTING DUMMY_API_TOKEN
+#endif
+
 #if !defined(GOOGLE_CLIENT_ID_MAIN)
 #define GOOGLE_CLIENT_ID_MAIN DUMMY_API_TOKEN
 #endif
@@ -104,6 +108,14 @@
                           environment.get(),
                           command_line);
 
+    api_key_remoting_ =
+        CalculateKeyValue(GOOGLE_API_KEY_REMOTING,
+                          STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_REMOTING),
+                          NULL,
+                          std::string(),
+                          environment.get(),
+                          command_line);
+
     std::string default_client_id =
         CalculateKeyValue(GOOGLE_DEFAULT_CLIENT_ID,
                           STRINGIZE_NO_EXPANSION(GOOGLE_DEFAULT_CLIENT_ID),
@@ -188,6 +200,7 @@
 
   std::string api_key() const { return api_key_; }
   std::string api_key_safesites() const { return api_key_safesites_; }
+  std::string api_key_remoting() const { return api_key_remoting_; }
 
   std::string GetClientID(OAuth2Client client) const {
     DCHECK_LT(client, CLIENT_NUM_ITEMS);
@@ -254,6 +267,7 @@
 
   std::string api_key_;
   std::string api_key_safesites_;
+  std::string api_key_remoting_;
   std::string client_ids_[CLIENT_NUM_ITEMS];
   std::string client_secrets_[CLIENT_NUM_ITEMS];
 };
@@ -284,6 +298,10 @@
   return g_api_key_cache.Get().api_key_safesites();
 }
 
+std::string GetRemotingAPIKey() {
+  return g_api_key_cache.Get().api_key_remoting();
+}
+
 std::string GetOAuth2ClientID(OAuth2Client client) {
   return g_api_key_cache.Get().GetClientID(client);
 }
diff --git a/google_apis/google_api_keys.h b/google_apis/google_api_keys.h
index b4b6fac..56f91c3 100644
--- a/google_apis/google_api_keys.h
+++ b/google_apis/google_api_keys.h
@@ -70,6 +70,8 @@
 
 std::string GetSafeSitesAPIKey();
 
+std::string GetRemotingAPIKey();
+
 // Represents the different sets of client IDs and secrets in use.
 enum OAuth2Client {
   CLIENT_MAIN,         // Several different features use this.
diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_copy_texture.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_copy_texture.txt
index 71a84b8b..3accfa8 100644
--- a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_copy_texture.txt
+++ b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_copy_texture.txt
@@ -74,6 +74,9 @@
     no alpha processing occurs.  This is the equivalent of having neither flag
     set.
 
+    When <source_id> refers to a stream texture, the texture matrix will be
+    applied as part of the copy operation.
+
     INVALID_OPERATION is generated if <internal_format> is not one of the valid formats
     described above.
 
diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_image.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_image.txt
index 2ba1e39..809a560 100644
--- a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_image.txt
+++ b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_image.txt
@@ -46,7 +46,7 @@
     INVALID_VALUE is generated if <width> or <height> is nonpositive.
 
     INVALID_VALUE is generated if <internalformat> is not one of
-    RED, RGB, RGBA, BGRA_EXT, ATC_RGB_AMD, ATC_RGBA_INTERPOLATED_ALPHA_AMD,
+    R8, RGB, RGBA, BGRA_EXT, ATC_RGB_AMD, ATC_RGBA_INTERPOLATED_ALPHA_AMD,
     COMPRESSED_RGB_S3TC_DXT1_EXT, COMPRESSED_RGBA_S3TC_DXT5_EXT or
     ETC1_RGB8_OES.
 
@@ -64,7 +64,7 @@
 Dependencies on ARB_texture_rg
 
     If ARB_texture_rg is not supported:
-     * delete any reference to the RED format.
+     * delete any reference to the R8 format.
 
 Dependencies on AMD_compressed_ATC_texture
 
@@ -100,3 +100,4 @@
     2/7/2015    Add R8 format.
     5/13/2015   Add compressed formats.
     11/5/2015   Change R8 format to RED.
+    2/18/2016   Change back RED internal format to R8.
diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_stream_texture_matrix.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_stream_texture_matrix.txt
new file mode 100644
index 0000000..d0bfe88
--- /dev/null
+++ b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_stream_texture_matrix.txt
@@ -0,0 +1,58 @@
+Name
+
+    CHROMIUM_stream_texture_matrix
+
+Name Strings
+
+    CHROMIUM_stream_texture_matrix
+
+Version
+
+    Last Modifed Date: February 16, 2016
+
+Dependencies
+
+    OpenGL ES 2.0 is required.
+
+Overview
+
+    Allows clients to set the value of a 4x4 uniform to the current texture
+    matrix of a stream texture.
+
+    Allows shader access to the texture matrix for the current front buffer
+    of a stream texture.  Intended for use with Android SurfaceTexture, which
+    doesn't provide the value until the front buffer is latched.
+
+New Procedures and Functions
+
+    The command
+
+       void UniformMatrix4fvStreamTextureMatrixCHROMIUM(
+               GLintUniformLocation location,
+               GLbooleanFalseOnly transpose,
+               const GLfloat* default_value)
+
+    Updates a uniform to match the current stream texture's texture matrix.
+    The stream texture must be bound to the GL_TEXTURE_EXTERNAL_OES target on
+    the active texture unit.
+
+    If the bound texture is not a stream texture, then the default value is
+    used instead.
+
+    <location> Specifies the 4x4f uniform location to be modified.
+    <transpose> Specifies whether the matrix should be transposed.
+    <default_value> Provides the default matrix.
+
+    The default value is a transitionary step.  It will be removed.
+
+Errors
+
+    None.
+
+New State
+
+    None.
+
+Revision History
+
+    02/16/2016    Documented the extension
diff --git a/gpu/GLES2/gl2chromium_autogen.h b/gpu/GLES2/gl2chromium_autogen.h
index aa7febf..8909cd7 100644
--- a/gpu/GLES2/gl2chromium_autogen.h
+++ b/gpu/GLES2/gl2chromium_autogen.h
@@ -379,5 +379,7 @@
   GLES2_GET_FUN(BindFragDataLocationIndexedEXT)
 #define glBindFragDataLocationEXT GLES2_GET_FUN(BindFragDataLocationEXT)
 #define glGetFragDataIndexEXT GLES2_GET_FUN(GetFragDataIndexEXT)
+#define glUniformMatrix4fvStreamTextureMatrixCHROMIUM \
+  GLES2_GET_FUN(UniformMatrix4fvStreamTextureMatrixCHROMIUM)
 
 #endif  // GPU_GLES2_GL2CHROMIUM_AUTOGEN_H_
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index 8f755ec..81d796a 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -3905,6 +3905,14 @@
     'decoder_func': 'DoUniformMatrix4fv',
     'unit_test': False,
   },
+  'UniformMatrix4fvStreamTextureMatrixCHROMIUM': {
+    'type': 'PUT',
+    'count': 16,
+    'decoder_func': 'DoUniformMatrix4fvStreamTextureMatrixCHROMIUM',
+    'extension': "CHROMIUM_uniform_stream_texture_matrix",
+    'unit_test': False,
+    'client_test': False,
+  },
   'UniformMatrix4x2fv': {
     'type': 'PUTn',
     'count': 8,
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h
index e35f6d1..1aa3cbde 100644
--- a/gpu/command_buffer/client/gles2_c_lib_autogen.h
+++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -1712,6 +1712,13 @@
 GLint GL_APIENTRY GLES2GetFragDataIndexEXT(GLuint program, const char* name) {
   return gles2::GetGLContext()->GetFragDataIndexEXT(program, name);
 }
+void GL_APIENTRY
+GLES2UniformMatrix4fvStreamTextureMatrixCHROMIUM(GLint location,
+                                                 GLboolean transpose,
+                                                 const GLfloat* default_value) {
+  gles2::GetGLContext()->UniformMatrix4fvStreamTextureMatrixCHROMIUM(
+      location, transpose, default_value);
+}
 
 namespace gles2 {
 
@@ -3013,6 +3020,11 @@
         reinterpret_cast<GLES2FunctionPointer>(glGetFragDataIndexEXT),
     },
     {
+        "glUniformMatrix4fvStreamTextureMatrixCHROMIUM",
+        reinterpret_cast<GLES2FunctionPointer>(
+            glUniformMatrix4fvStreamTextureMatrixCHROMIUM),
+    },
+    {
         NULL, NULL,
     },
 };
diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
index 8dd89f1..f8b3dcb 100644
--- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
+++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -3196,4 +3196,19 @@
   }
 }
 
+void UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate(
+    GLint location,
+    GLboolean transpose,
+    const GLfloat* default_value) {
+  const uint32_t size = gles2::cmds::
+      UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate::ComputeSize();
+  gles2::cmds::UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate* c =
+      GetImmediateCmdSpaceTotalSize<
+          gles2::cmds::UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate>(
+          size);
+  if (c) {
+    c->Init(location, transpose, default_value);
+  }
+}
+
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_CMD_HELPER_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index aeaa5655..0610c1a 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -5686,7 +5686,7 @@
       return capabilities.texture_format_dxt5;
     case GL_ETC1_RGB8_OES:
       return capabilities.texture_format_etc1;
-    case GL_RED:
+    case GL_R8:
     case GL_RGB:
     case GL_RGBA:
     case GL_RGB_YCBCR_422_CHROMIUM:
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h
index 2a4914f..deba71c 100644
--- a/gpu/command_buffer/client/gles2_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -1187,4 +1187,9 @@
 
 GLint GetFragDataIndexEXT(GLuint program, const char* name) override;
 
+void UniformMatrix4fvStreamTextureMatrixCHROMIUM(
+    GLint location,
+    GLboolean transpose,
+    const GLfloat* default_value) override;
+
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
index 4ed0561..0a56dc8 100644
--- a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
@@ -3576,4 +3576,21 @@
   CheckGLError();
 }
 
+void GLES2Implementation::UniformMatrix4fvStreamTextureMatrixCHROMIUM(
+    GLint location,
+    GLboolean transpose,
+    const GLfloat* default_value) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix()
+                     << "] glUniformMatrix4fvStreamTextureMatrixCHROMIUM("
+                     << location << ", " << GLES2Util::GetStringBool(transpose)
+                     << ", " << static_cast<const void*>(default_value) << ")");
+  size_t count = 16;
+  for (size_t ii = 0; ii < count; ++ii)
+    GPU_CLIENT_LOG("value[" << ii << "]: " << default_value[ii]);
+  helper_->UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate(
+      location, transpose, default_value);
+  CheckGLError();
+}
+
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_IMPL_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h
index 6cd390d..1020ce2a 100644
--- a/gpu/command_buffer/client/gles2_interface_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -886,4 +886,8 @@
                                      GLuint colorNumber,
                                      const char* name) = 0;
 virtual GLint GetFragDataIndexEXT(GLuint program, const char* name) = 0;
+virtual void UniformMatrix4fvStreamTextureMatrixCHROMIUM(
+    GLint location,
+    GLboolean transpose,
+    const GLfloat* default_value) = 0;
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
index 84611a6..50e39cd4 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -859,4 +859,8 @@
                              GLuint colorNumber,
                              const char* name) override;
 GLint GetFragDataIndexEXT(GLuint program, const char* name) override;
+void UniformMatrix4fvStreamTextureMatrixCHROMIUM(
+    GLint location,
+    GLboolean transpose,
+    const GLfloat* default_value) override;
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_STUB_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
index b43c773..5ac7eba5 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -1165,4 +1165,8 @@
                                               const char* /* name */) {
   return 0;
 }
+void GLES2InterfaceStub::UniformMatrix4fvStreamTextureMatrixCHROMIUM(
+    GLint /* location */,
+    GLboolean /* transpose */,
+    const GLfloat* /* default_value */) {}
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_STUB_IMPL_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
index 24c96c6..ad35a36 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -859,4 +859,8 @@
                              GLuint colorNumber,
                              const char* name) override;
 GLint GetFragDataIndexEXT(GLuint program, const char* name) override;
+void UniformMatrix4fvStreamTextureMatrixCHROMIUM(
+    GLint location,
+    GLboolean transpose,
+    const GLfloat* default_value) override;
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_TRACE_IMPLEMENTATION_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
index bc2a21bb..5f8e3caa 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -2492,4 +2492,14 @@
   return gl_->GetFragDataIndexEXT(program, name);
 }
 
+void GLES2TraceImplementation::UniformMatrix4fvStreamTextureMatrixCHROMIUM(
+    GLint location,
+    GLboolean transpose,
+    const GLfloat* default_value) {
+  TRACE_EVENT_BINARY_EFFICIENT0(
+      "gpu", "GLES2Trace::UniformMatrix4fvStreamTextureMatrixCHROMIUM");
+  gl_->UniformMatrix4fvStreamTextureMatrixCHROMIUM(location, transpose,
+                                                   default_value);
+}
+
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_TRACE_IMPLEMENTATION_IMPL_AUTOGEN_H_
diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt
index 809a841..119f3f2 100644
--- a/gpu/command_buffer/cmd_buffer_functions.txt
+++ b/gpu/command_buffer/cmd_buffer_functions.txt
@@ -360,3 +360,5 @@
 GL_APICALL void         GL_APIENTRY glBindFragDataLocationEXT (GLidProgram program, GLuint colorNumber, const char* name);
 GL_APICALL GLint        GL_APIENTRY glGetFragDataIndexEXT (GLidProgram program, const char* name);
 
+// Extension CHROMIUM_stream_texture_matrix
+GL_APICALL void         GL_APIENTRY glUniformMatrix4fvStreamTextureMatrixCHROMIUM (GLintUniformLocation location, GLbooleanFalseOnly transpose, const GLfloat* default_value);
diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
index 7d678ca..3f3fe78 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -15704,4 +15704,61 @@
 static_assert(offsetof(GetFragDataIndexEXT, index_shm_offset) == 16,
               "offset of GetFragDataIndexEXT index_shm_offset should be 16");
 
+struct UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate {
+  typedef UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate ValueType;
+  static const CommandId kCmdId =
+      kUniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate;
+  static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeDataSize() {
+    return static_cast<uint32_t>(sizeof(GLfloat) * 16);
+  }
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType) + ComputeDataSize());
+  }
+
+  void SetHeader() { header.SetCmdByTotalSize<ValueType>(ComputeSize()); }
+
+  void Init(GLint _location,
+            GLboolean _transpose,
+            const GLfloat* _default_value) {
+    SetHeader();
+    location = _location;
+    transpose = _transpose;
+    memcpy(ImmediateDataAddress(this), _default_value, ComputeDataSize());
+  }
+
+  void* Set(void* cmd,
+            GLint _location,
+            GLboolean _transpose,
+            const GLfloat* _default_value) {
+    static_cast<ValueType*>(cmd)->Init(_location, _transpose, _default_value);
+    const uint32_t size = ComputeSize();
+    return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+  }
+
+  gpu::CommandHeader header;
+  int32_t location;
+  uint32_t transpose;
+};
+
+static_assert(sizeof(UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate) ==
+                  12,
+              "size of UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate "
+              "should be 12");
+static_assert(offsetof(UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate,
+                       header) == 0,
+              "offset of UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate "
+              "header should be 0");
+static_assert(offsetof(UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate,
+                       location) == 4,
+              "offset of UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate "
+              "location should be 4");
+static_assert(offsetof(UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate,
+                       transpose) == 8,
+              "offset of UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate "
+              "transpose should be 8");
+
 #endif  // GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_AUTOGEN_H_
diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
index 19d86ace..cee91671 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
@@ -5329,4 +5329,41 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(GLES2FormatTest, UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate) {
+  const int kSomeBaseValueToTestWith = 51;
+  static GLfloat data[] = {
+      static_cast<GLfloat>(kSomeBaseValueToTestWith + 0),
+      static_cast<GLfloat>(kSomeBaseValueToTestWith + 1),
+      static_cast<GLfloat>(kSomeBaseValueToTestWith + 2),
+      static_cast<GLfloat>(kSomeBaseValueToTestWith + 3),
+      static_cast<GLfloat>(kSomeBaseValueToTestWith + 4),
+      static_cast<GLfloat>(kSomeBaseValueToTestWith + 5),
+      static_cast<GLfloat>(kSomeBaseValueToTestWith + 6),
+      static_cast<GLfloat>(kSomeBaseValueToTestWith + 7),
+      static_cast<GLfloat>(kSomeBaseValueToTestWith + 8),
+      static_cast<GLfloat>(kSomeBaseValueToTestWith + 9),
+      static_cast<GLfloat>(kSomeBaseValueToTestWith + 10),
+      static_cast<GLfloat>(kSomeBaseValueToTestWith + 11),
+      static_cast<GLfloat>(kSomeBaseValueToTestWith + 12),
+      static_cast<GLfloat>(kSomeBaseValueToTestWith + 13),
+      static_cast<GLfloat>(kSomeBaseValueToTestWith + 14),
+      static_cast<GLfloat>(kSomeBaseValueToTestWith + 15),
+  };
+  cmds::UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate& cmd =
+      *GetBufferAs<
+          cmds::UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLint>(11), static_cast<GLboolean>(12), data);
+  EXPECT_EQ(
+      static_cast<uint32_t>(
+          cmds::UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate::kCmdId),
+      cmd.header.command);
+  EXPECT_EQ(sizeof(cmd) + RoundSizeToMultipleOfEntries(sizeof(data)),
+            cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLint>(11), cmd.location);
+  EXPECT_EQ(static_cast<GLboolean>(12), cmd.transpose);
+  CheckBytesWrittenMatchesExpectedSize(
+      next_cmd, sizeof(cmd) + RoundSizeToMultipleOfEntries(sizeof(data)));
+}
+
 #endif  // GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_TEST_AUTOGEN_H_
diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
index fedffa2..03161998 100644
--- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
@@ -11,329 +11,330 @@
 #ifndef GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_IDS_AUTOGEN_H_
 #define GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_IDS_AUTOGEN_H_
 
-#define GLES2_COMMAND_LIST(OP)                              \
-  OP(ActiveTexture)                               /* 256 */ \
-  OP(AttachShader)                                /* 257 */ \
-  OP(BindAttribLocationBucket)                    /* 258 */ \
-  OP(BindBuffer)                                  /* 259 */ \
-  OP(BindBufferBase)                              /* 260 */ \
-  OP(BindBufferRange)                             /* 261 */ \
-  OP(BindFramebuffer)                             /* 262 */ \
-  OP(BindRenderbuffer)                            /* 263 */ \
-  OP(BindSampler)                                 /* 264 */ \
-  OP(BindTexture)                                 /* 265 */ \
-  OP(BindTransformFeedback)                       /* 266 */ \
-  OP(BlendColor)                                  /* 267 */ \
-  OP(BlendEquation)                               /* 268 */ \
-  OP(BlendEquationSeparate)                       /* 269 */ \
-  OP(BlendFunc)                                   /* 270 */ \
-  OP(BlendFuncSeparate)                           /* 271 */ \
-  OP(BufferData)                                  /* 272 */ \
-  OP(BufferSubData)                               /* 273 */ \
-  OP(CheckFramebufferStatus)                      /* 274 */ \
-  OP(Clear)                                       /* 275 */ \
-  OP(ClearBufferfi)                               /* 276 */ \
-  OP(ClearBufferfvImmediate)                      /* 277 */ \
-  OP(ClearBufferivImmediate)                      /* 278 */ \
-  OP(ClearBufferuivImmediate)                     /* 279 */ \
-  OP(ClearColor)                                  /* 280 */ \
-  OP(ClearDepthf)                                 /* 281 */ \
-  OP(ClearStencil)                                /* 282 */ \
-  OP(ClientWaitSync)                              /* 283 */ \
-  OP(ColorMask)                                   /* 284 */ \
-  OP(CompileShader)                               /* 285 */ \
-  OP(CompressedTexImage2DBucket)                  /* 286 */ \
-  OP(CompressedTexImage2D)                        /* 287 */ \
-  OP(CompressedTexSubImage2DBucket)               /* 288 */ \
-  OP(CompressedTexSubImage2D)                     /* 289 */ \
-  OP(CompressedTexImage3DBucket)                  /* 290 */ \
-  OP(CompressedTexImage3D)                        /* 291 */ \
-  OP(CompressedTexSubImage3DBucket)               /* 292 */ \
-  OP(CompressedTexSubImage3D)                     /* 293 */ \
-  OP(CopyBufferSubData)                           /* 294 */ \
-  OP(CopyTexImage2D)                              /* 295 */ \
-  OP(CopyTexSubImage2D)                           /* 296 */ \
-  OP(CopyTexSubImage3D)                           /* 297 */ \
-  OP(CreateProgram)                               /* 298 */ \
-  OP(CreateShader)                                /* 299 */ \
-  OP(CullFace)                                    /* 300 */ \
-  OP(DeleteBuffersImmediate)                      /* 301 */ \
-  OP(DeleteFramebuffersImmediate)                 /* 302 */ \
-  OP(DeleteProgram)                               /* 303 */ \
-  OP(DeleteRenderbuffersImmediate)                /* 304 */ \
-  OP(DeleteSamplersImmediate)                     /* 305 */ \
-  OP(DeleteSync)                                  /* 306 */ \
-  OP(DeleteShader)                                /* 307 */ \
-  OP(DeleteTexturesImmediate)                     /* 308 */ \
-  OP(DeleteTransformFeedbacksImmediate)           /* 309 */ \
-  OP(DepthFunc)                                   /* 310 */ \
-  OP(DepthMask)                                   /* 311 */ \
-  OP(DepthRangef)                                 /* 312 */ \
-  OP(DetachShader)                                /* 313 */ \
-  OP(Disable)                                     /* 314 */ \
-  OP(DisableVertexAttribArray)                    /* 315 */ \
-  OP(DrawArrays)                                  /* 316 */ \
-  OP(DrawElements)                                /* 317 */ \
-  OP(Enable)                                      /* 318 */ \
-  OP(EnableVertexAttribArray)                     /* 319 */ \
-  OP(FenceSync)                                   /* 320 */ \
-  OP(Finish)                                      /* 321 */ \
-  OP(Flush)                                       /* 322 */ \
-  OP(FramebufferRenderbuffer)                     /* 323 */ \
-  OP(FramebufferTexture2D)                        /* 324 */ \
-  OP(FramebufferTextureLayer)                     /* 325 */ \
-  OP(FrontFace)                                   /* 326 */ \
-  OP(GenBuffersImmediate)                         /* 327 */ \
-  OP(GenerateMipmap)                              /* 328 */ \
-  OP(GenFramebuffersImmediate)                    /* 329 */ \
-  OP(GenRenderbuffersImmediate)                   /* 330 */ \
-  OP(GenSamplersImmediate)                        /* 331 */ \
-  OP(GenTexturesImmediate)                        /* 332 */ \
-  OP(GenTransformFeedbacksImmediate)              /* 333 */ \
-  OP(GetActiveAttrib)                             /* 334 */ \
-  OP(GetActiveUniform)                            /* 335 */ \
-  OP(GetActiveUniformBlockiv)                     /* 336 */ \
-  OP(GetActiveUniformBlockName)                   /* 337 */ \
-  OP(GetActiveUniformsiv)                         /* 338 */ \
-  OP(GetAttachedShaders)                          /* 339 */ \
-  OP(GetAttribLocation)                           /* 340 */ \
-  OP(GetBooleanv)                                 /* 341 */ \
-  OP(GetBufferParameteri64v)                      /* 342 */ \
-  OP(GetBufferParameteriv)                        /* 343 */ \
-  OP(GetError)                                    /* 344 */ \
-  OP(GetFloatv)                                   /* 345 */ \
-  OP(GetFragDataLocation)                         /* 346 */ \
-  OP(GetFramebufferAttachmentParameteriv)         /* 347 */ \
-  OP(GetInteger64v)                               /* 348 */ \
-  OP(GetIntegeri_v)                               /* 349 */ \
-  OP(GetInteger64i_v)                             /* 350 */ \
-  OP(GetIntegerv)                                 /* 351 */ \
-  OP(GetInternalformativ)                         /* 352 */ \
-  OP(GetProgramiv)                                /* 353 */ \
-  OP(GetProgramInfoLog)                           /* 354 */ \
-  OP(GetRenderbufferParameteriv)                  /* 355 */ \
-  OP(GetSamplerParameterfv)                       /* 356 */ \
-  OP(GetSamplerParameteriv)                       /* 357 */ \
-  OP(GetShaderiv)                                 /* 358 */ \
-  OP(GetShaderInfoLog)                            /* 359 */ \
-  OP(GetShaderPrecisionFormat)                    /* 360 */ \
-  OP(GetShaderSource)                             /* 361 */ \
-  OP(GetString)                                   /* 362 */ \
-  OP(GetSynciv)                                   /* 363 */ \
-  OP(GetTexParameterfv)                           /* 364 */ \
-  OP(GetTexParameteriv)                           /* 365 */ \
-  OP(GetTransformFeedbackVarying)                 /* 366 */ \
-  OP(GetUniformBlockIndex)                        /* 367 */ \
-  OP(GetUniformfv)                                /* 368 */ \
-  OP(GetUniformiv)                                /* 369 */ \
-  OP(GetUniformuiv)                               /* 370 */ \
-  OP(GetUniformIndices)                           /* 371 */ \
-  OP(GetUniformLocation)                          /* 372 */ \
-  OP(GetVertexAttribfv)                           /* 373 */ \
-  OP(GetVertexAttribiv)                           /* 374 */ \
-  OP(GetVertexAttribIiv)                          /* 375 */ \
-  OP(GetVertexAttribIuiv)                         /* 376 */ \
-  OP(GetVertexAttribPointerv)                     /* 377 */ \
-  OP(Hint)                                        /* 378 */ \
-  OP(InvalidateFramebufferImmediate)              /* 379 */ \
-  OP(InvalidateSubFramebufferImmediate)           /* 380 */ \
-  OP(IsBuffer)                                    /* 381 */ \
-  OP(IsEnabled)                                   /* 382 */ \
-  OP(IsFramebuffer)                               /* 383 */ \
-  OP(IsProgram)                                   /* 384 */ \
-  OP(IsRenderbuffer)                              /* 385 */ \
-  OP(IsSampler)                                   /* 386 */ \
-  OP(IsShader)                                    /* 387 */ \
-  OP(IsSync)                                      /* 388 */ \
-  OP(IsTexture)                                   /* 389 */ \
-  OP(IsTransformFeedback)                         /* 390 */ \
-  OP(LineWidth)                                   /* 391 */ \
-  OP(LinkProgram)                                 /* 392 */ \
-  OP(PauseTransformFeedback)                      /* 393 */ \
-  OP(PixelStorei)                                 /* 394 */ \
-  OP(PolygonOffset)                               /* 395 */ \
-  OP(ReadBuffer)                                  /* 396 */ \
-  OP(ReadPixels)                                  /* 397 */ \
-  OP(ReleaseShaderCompiler)                       /* 398 */ \
-  OP(RenderbufferStorage)                         /* 399 */ \
-  OP(ResumeTransformFeedback)                     /* 400 */ \
-  OP(SampleCoverage)                              /* 401 */ \
-  OP(SamplerParameterf)                           /* 402 */ \
-  OP(SamplerParameterfvImmediate)                 /* 403 */ \
-  OP(SamplerParameteri)                           /* 404 */ \
-  OP(SamplerParameterivImmediate)                 /* 405 */ \
-  OP(Scissor)                                     /* 406 */ \
-  OP(ShaderBinary)                                /* 407 */ \
-  OP(ShaderSourceBucket)                          /* 408 */ \
-  OP(StencilFunc)                                 /* 409 */ \
-  OP(StencilFuncSeparate)                         /* 410 */ \
-  OP(StencilMask)                                 /* 411 */ \
-  OP(StencilMaskSeparate)                         /* 412 */ \
-  OP(StencilOp)                                   /* 413 */ \
-  OP(StencilOpSeparate)                           /* 414 */ \
-  OP(TexImage2D)                                  /* 415 */ \
-  OP(TexImage3D)                                  /* 416 */ \
-  OP(TexParameterf)                               /* 417 */ \
-  OP(TexParameterfvImmediate)                     /* 418 */ \
-  OP(TexParameteri)                               /* 419 */ \
-  OP(TexParameterivImmediate)                     /* 420 */ \
-  OP(TexStorage3D)                                /* 421 */ \
-  OP(TexSubImage2D)                               /* 422 */ \
-  OP(TexSubImage3D)                               /* 423 */ \
-  OP(TransformFeedbackVaryingsBucket)             /* 424 */ \
-  OP(Uniform1f)                                   /* 425 */ \
-  OP(Uniform1fvImmediate)                         /* 426 */ \
-  OP(Uniform1i)                                   /* 427 */ \
-  OP(Uniform1ivImmediate)                         /* 428 */ \
-  OP(Uniform1ui)                                  /* 429 */ \
-  OP(Uniform1uivImmediate)                        /* 430 */ \
-  OP(Uniform2f)                                   /* 431 */ \
-  OP(Uniform2fvImmediate)                         /* 432 */ \
-  OP(Uniform2i)                                   /* 433 */ \
-  OP(Uniform2ivImmediate)                         /* 434 */ \
-  OP(Uniform2ui)                                  /* 435 */ \
-  OP(Uniform2uivImmediate)                        /* 436 */ \
-  OP(Uniform3f)                                   /* 437 */ \
-  OP(Uniform3fvImmediate)                         /* 438 */ \
-  OP(Uniform3i)                                   /* 439 */ \
-  OP(Uniform3ivImmediate)                         /* 440 */ \
-  OP(Uniform3ui)                                  /* 441 */ \
-  OP(Uniform3uivImmediate)                        /* 442 */ \
-  OP(Uniform4f)                                   /* 443 */ \
-  OP(Uniform4fvImmediate)                         /* 444 */ \
-  OP(Uniform4i)                                   /* 445 */ \
-  OP(Uniform4ivImmediate)                         /* 446 */ \
-  OP(Uniform4ui)                                  /* 447 */ \
-  OP(Uniform4uivImmediate)                        /* 448 */ \
-  OP(UniformBlockBinding)                         /* 449 */ \
-  OP(UniformMatrix2fvImmediate)                   /* 450 */ \
-  OP(UniformMatrix2x3fvImmediate)                 /* 451 */ \
-  OP(UniformMatrix2x4fvImmediate)                 /* 452 */ \
-  OP(UniformMatrix3fvImmediate)                   /* 453 */ \
-  OP(UniformMatrix3x2fvImmediate)                 /* 454 */ \
-  OP(UniformMatrix3x4fvImmediate)                 /* 455 */ \
-  OP(UniformMatrix4fvImmediate)                   /* 456 */ \
-  OP(UniformMatrix4x2fvImmediate)                 /* 457 */ \
-  OP(UniformMatrix4x3fvImmediate)                 /* 458 */ \
-  OP(UseProgram)                                  /* 459 */ \
-  OP(ValidateProgram)                             /* 460 */ \
-  OP(VertexAttrib1f)                              /* 461 */ \
-  OP(VertexAttrib1fvImmediate)                    /* 462 */ \
-  OP(VertexAttrib2f)                              /* 463 */ \
-  OP(VertexAttrib2fvImmediate)                    /* 464 */ \
-  OP(VertexAttrib3f)                              /* 465 */ \
-  OP(VertexAttrib3fvImmediate)                    /* 466 */ \
-  OP(VertexAttrib4f)                              /* 467 */ \
-  OP(VertexAttrib4fvImmediate)                    /* 468 */ \
-  OP(VertexAttribI4i)                             /* 469 */ \
-  OP(VertexAttribI4ivImmediate)                   /* 470 */ \
-  OP(VertexAttribI4ui)                            /* 471 */ \
-  OP(VertexAttribI4uivImmediate)                  /* 472 */ \
-  OP(VertexAttribIPointer)                        /* 473 */ \
-  OP(VertexAttribPointer)                         /* 474 */ \
-  OP(Viewport)                                    /* 475 */ \
-  OP(WaitSync)                                    /* 476 */ \
-  OP(BlitFramebufferCHROMIUM)                     /* 477 */ \
-  OP(RenderbufferStorageMultisampleCHROMIUM)      /* 478 */ \
-  OP(RenderbufferStorageMultisampleEXT)           /* 479 */ \
-  OP(FramebufferTexture2DMultisampleEXT)          /* 480 */ \
-  OP(TexStorage2DEXT)                             /* 481 */ \
-  OP(GenQueriesEXTImmediate)                      /* 482 */ \
-  OP(DeleteQueriesEXTImmediate)                   /* 483 */ \
-  OP(QueryCounterEXT)                             /* 484 */ \
-  OP(BeginQueryEXT)                               /* 485 */ \
-  OP(BeginTransformFeedback)                      /* 486 */ \
-  OP(EndQueryEXT)                                 /* 487 */ \
-  OP(EndTransformFeedback)                        /* 488 */ \
-  OP(SetDisjointValueSyncCHROMIUM)                /* 489 */ \
-  OP(InsertEventMarkerEXT)                        /* 490 */ \
-  OP(PushGroupMarkerEXT)                          /* 491 */ \
-  OP(PopGroupMarkerEXT)                           /* 492 */ \
-  OP(GenVertexArraysOESImmediate)                 /* 493 */ \
-  OP(DeleteVertexArraysOESImmediate)              /* 494 */ \
-  OP(IsVertexArrayOES)                            /* 495 */ \
-  OP(BindVertexArrayOES)                          /* 496 */ \
-  OP(SwapBuffers)                                 /* 497 */ \
-  OP(GetMaxValueInBufferCHROMIUM)                 /* 498 */ \
-  OP(EnableFeatureCHROMIUM)                       /* 499 */ \
-  OP(MapBufferRange)                              /* 500 */ \
-  OP(UnmapBuffer)                                 /* 501 */ \
-  OP(ResizeCHROMIUM)                              /* 502 */ \
-  OP(GetRequestableExtensionsCHROMIUM)            /* 503 */ \
-  OP(RequestExtensionCHROMIUM)                    /* 504 */ \
-  OP(GetProgramInfoCHROMIUM)                      /* 505 */ \
-  OP(GetUniformBlocksCHROMIUM)                    /* 506 */ \
-  OP(GetTransformFeedbackVaryingsCHROMIUM)        /* 507 */ \
-  OP(GetUniformsES3CHROMIUM)                      /* 508 */ \
-  OP(GetTranslatedShaderSourceANGLE)              /* 509 */ \
-  OP(PostSubBufferCHROMIUM)                       /* 510 */ \
-  OP(TexImageIOSurface2DCHROMIUM)                 /* 511 */ \
-  OP(CopyTextureCHROMIUM)                         /* 512 */ \
-  OP(CopySubTextureCHROMIUM)                      /* 513 */ \
-  OP(CompressedCopyTextureCHROMIUM)               /* 514 */ \
-  OP(DrawArraysInstancedANGLE)                    /* 515 */ \
-  OP(DrawElementsInstancedANGLE)                  /* 516 */ \
-  OP(VertexAttribDivisorANGLE)                    /* 517 */ \
-  OP(GenMailboxCHROMIUM)                          /* 518 */ \
-  OP(ProduceTextureCHROMIUMImmediate)             /* 519 */ \
-  OP(ProduceTextureDirectCHROMIUMImmediate)       /* 520 */ \
-  OP(ConsumeTextureCHROMIUMImmediate)             /* 521 */ \
-  OP(CreateAndConsumeTextureCHROMIUMImmediate)    /* 522 */ \
-  OP(BindUniformLocationCHROMIUMBucket)           /* 523 */ \
-  OP(GenValuebuffersCHROMIUMImmediate)            /* 524 */ \
-  OP(DeleteValuebuffersCHROMIUMImmediate)         /* 525 */ \
-  OP(IsValuebufferCHROMIUM)                       /* 526 */ \
-  OP(BindValuebufferCHROMIUM)                     /* 527 */ \
-  OP(SubscribeValueCHROMIUM)                      /* 528 */ \
-  OP(PopulateSubscribedValuesCHROMIUM)            /* 529 */ \
-  OP(UniformValuebufferCHROMIUM)                  /* 530 */ \
-  OP(BindTexImage2DCHROMIUM)                      /* 531 */ \
-  OP(ReleaseTexImage2DCHROMIUM)                   /* 532 */ \
-  OP(TraceBeginCHROMIUM)                          /* 533 */ \
-  OP(TraceEndCHROMIUM)                            /* 534 */ \
-  OP(DiscardFramebufferEXTImmediate)              /* 535 */ \
-  OP(LoseContextCHROMIUM)                         /* 536 */ \
-  OP(InsertFenceSyncCHROMIUM)                     /* 537 */ \
-  OP(GenSyncTokenCHROMIUMImmediate)               /* 538 */ \
-  OP(GenUnverifiedSyncTokenCHROMIUMImmediate)     /* 539 */ \
-  OP(VerifySyncTokensCHROMIUMImmediate)           /* 540 */ \
-  OP(WaitSyncTokenCHROMIUM)                       /* 541 */ \
-  OP(DrawBuffersEXTImmediate)                     /* 542 */ \
-  OP(DiscardBackbufferCHROMIUM)                   /* 543 */ \
-  OP(ScheduleOverlayPlaneCHROMIUM)                /* 544 */ \
-  OP(ScheduleCALayerCHROMIUM)                     /* 545 */ \
-  OP(CommitOverlayPlanesCHROMIUM)                 /* 546 */ \
-  OP(SwapInterval)                                /* 547 */ \
-  OP(FlushDriverCachesCHROMIUM)                   /* 548 */ \
-  OP(MatrixLoadfCHROMIUMImmediate)                /* 549 */ \
-  OP(MatrixLoadIdentityCHROMIUM)                  /* 550 */ \
-  OP(GenPathsCHROMIUM)                            /* 551 */ \
-  OP(DeletePathsCHROMIUM)                         /* 552 */ \
-  OP(IsPathCHROMIUM)                              /* 553 */ \
-  OP(PathCommandsCHROMIUM)                        /* 554 */ \
-  OP(PathParameterfCHROMIUM)                      /* 555 */ \
-  OP(PathParameteriCHROMIUM)                      /* 556 */ \
-  OP(PathStencilFuncCHROMIUM)                     /* 557 */ \
-  OP(StencilFillPathCHROMIUM)                     /* 558 */ \
-  OP(StencilStrokePathCHROMIUM)                   /* 559 */ \
-  OP(CoverFillPathCHROMIUM)                       /* 560 */ \
-  OP(CoverStrokePathCHROMIUM)                     /* 561 */ \
-  OP(StencilThenCoverFillPathCHROMIUM)            /* 562 */ \
-  OP(StencilThenCoverStrokePathCHROMIUM)          /* 563 */ \
-  OP(StencilFillPathInstancedCHROMIUM)            /* 564 */ \
-  OP(StencilStrokePathInstancedCHROMIUM)          /* 565 */ \
-  OP(CoverFillPathInstancedCHROMIUM)              /* 566 */ \
-  OP(CoverStrokePathInstancedCHROMIUM)            /* 567 */ \
-  OP(StencilThenCoverFillPathInstancedCHROMIUM)   /* 568 */ \
-  OP(StencilThenCoverStrokePathInstancedCHROMIUM) /* 569 */ \
-  OP(BindFragmentInputLocationCHROMIUMBucket)     /* 570 */ \
-  OP(ProgramPathFragmentInputGenCHROMIUM)         /* 571 */ \
-  OP(CoverageModulationCHROMIUM)                  /* 572 */ \
-  OP(BlendBarrierKHR)                             /* 573 */ \
-  OP(ApplyScreenSpaceAntialiasingCHROMIUM)        /* 574 */ \
-  OP(BindFragDataLocationIndexedEXTBucket)        /* 575 */ \
-  OP(BindFragDataLocationEXTBucket)               /* 576 */ \
-  OP(GetFragDataIndexEXT)                         /* 577 */
+#define GLES2_COMMAND_LIST(OP)                                       \
+  OP(ActiveTexture)                                        /* 256 */ \
+  OP(AttachShader)                                         /* 257 */ \
+  OP(BindAttribLocationBucket)                             /* 258 */ \
+  OP(BindBuffer)                                           /* 259 */ \
+  OP(BindBufferBase)                                       /* 260 */ \
+  OP(BindBufferRange)                                      /* 261 */ \
+  OP(BindFramebuffer)                                      /* 262 */ \
+  OP(BindRenderbuffer)                                     /* 263 */ \
+  OP(BindSampler)                                          /* 264 */ \
+  OP(BindTexture)                                          /* 265 */ \
+  OP(BindTransformFeedback)                                /* 266 */ \
+  OP(BlendColor)                                           /* 267 */ \
+  OP(BlendEquation)                                        /* 268 */ \
+  OP(BlendEquationSeparate)                                /* 269 */ \
+  OP(BlendFunc)                                            /* 270 */ \
+  OP(BlendFuncSeparate)                                    /* 271 */ \
+  OP(BufferData)                                           /* 272 */ \
+  OP(BufferSubData)                                        /* 273 */ \
+  OP(CheckFramebufferStatus)                               /* 274 */ \
+  OP(Clear)                                                /* 275 */ \
+  OP(ClearBufferfi)                                        /* 276 */ \
+  OP(ClearBufferfvImmediate)                               /* 277 */ \
+  OP(ClearBufferivImmediate)                               /* 278 */ \
+  OP(ClearBufferuivImmediate)                              /* 279 */ \
+  OP(ClearColor)                                           /* 280 */ \
+  OP(ClearDepthf)                                          /* 281 */ \
+  OP(ClearStencil)                                         /* 282 */ \
+  OP(ClientWaitSync)                                       /* 283 */ \
+  OP(ColorMask)                                            /* 284 */ \
+  OP(CompileShader)                                        /* 285 */ \
+  OP(CompressedTexImage2DBucket)                           /* 286 */ \
+  OP(CompressedTexImage2D)                                 /* 287 */ \
+  OP(CompressedTexSubImage2DBucket)                        /* 288 */ \
+  OP(CompressedTexSubImage2D)                              /* 289 */ \
+  OP(CompressedTexImage3DBucket)                           /* 290 */ \
+  OP(CompressedTexImage3D)                                 /* 291 */ \
+  OP(CompressedTexSubImage3DBucket)                        /* 292 */ \
+  OP(CompressedTexSubImage3D)                              /* 293 */ \
+  OP(CopyBufferSubData)                                    /* 294 */ \
+  OP(CopyTexImage2D)                                       /* 295 */ \
+  OP(CopyTexSubImage2D)                                    /* 296 */ \
+  OP(CopyTexSubImage3D)                                    /* 297 */ \
+  OP(CreateProgram)                                        /* 298 */ \
+  OP(CreateShader)                                         /* 299 */ \
+  OP(CullFace)                                             /* 300 */ \
+  OP(DeleteBuffersImmediate)                               /* 301 */ \
+  OP(DeleteFramebuffersImmediate)                          /* 302 */ \
+  OP(DeleteProgram)                                        /* 303 */ \
+  OP(DeleteRenderbuffersImmediate)                         /* 304 */ \
+  OP(DeleteSamplersImmediate)                              /* 305 */ \
+  OP(DeleteSync)                                           /* 306 */ \
+  OP(DeleteShader)                                         /* 307 */ \
+  OP(DeleteTexturesImmediate)                              /* 308 */ \
+  OP(DeleteTransformFeedbacksImmediate)                    /* 309 */ \
+  OP(DepthFunc)                                            /* 310 */ \
+  OP(DepthMask)                                            /* 311 */ \
+  OP(DepthRangef)                                          /* 312 */ \
+  OP(DetachShader)                                         /* 313 */ \
+  OP(Disable)                                              /* 314 */ \
+  OP(DisableVertexAttribArray)                             /* 315 */ \
+  OP(DrawArrays)                                           /* 316 */ \
+  OP(DrawElements)                                         /* 317 */ \
+  OP(Enable)                                               /* 318 */ \
+  OP(EnableVertexAttribArray)                              /* 319 */ \
+  OP(FenceSync)                                            /* 320 */ \
+  OP(Finish)                                               /* 321 */ \
+  OP(Flush)                                                /* 322 */ \
+  OP(FramebufferRenderbuffer)                              /* 323 */ \
+  OP(FramebufferTexture2D)                                 /* 324 */ \
+  OP(FramebufferTextureLayer)                              /* 325 */ \
+  OP(FrontFace)                                            /* 326 */ \
+  OP(GenBuffersImmediate)                                  /* 327 */ \
+  OP(GenerateMipmap)                                       /* 328 */ \
+  OP(GenFramebuffersImmediate)                             /* 329 */ \
+  OP(GenRenderbuffersImmediate)                            /* 330 */ \
+  OP(GenSamplersImmediate)                                 /* 331 */ \
+  OP(GenTexturesImmediate)                                 /* 332 */ \
+  OP(GenTransformFeedbacksImmediate)                       /* 333 */ \
+  OP(GetActiveAttrib)                                      /* 334 */ \
+  OP(GetActiveUniform)                                     /* 335 */ \
+  OP(GetActiveUniformBlockiv)                              /* 336 */ \
+  OP(GetActiveUniformBlockName)                            /* 337 */ \
+  OP(GetActiveUniformsiv)                                  /* 338 */ \
+  OP(GetAttachedShaders)                                   /* 339 */ \
+  OP(GetAttribLocation)                                    /* 340 */ \
+  OP(GetBooleanv)                                          /* 341 */ \
+  OP(GetBufferParameteri64v)                               /* 342 */ \
+  OP(GetBufferParameteriv)                                 /* 343 */ \
+  OP(GetError)                                             /* 344 */ \
+  OP(GetFloatv)                                            /* 345 */ \
+  OP(GetFragDataLocation)                                  /* 346 */ \
+  OP(GetFramebufferAttachmentParameteriv)                  /* 347 */ \
+  OP(GetInteger64v)                                        /* 348 */ \
+  OP(GetIntegeri_v)                                        /* 349 */ \
+  OP(GetInteger64i_v)                                      /* 350 */ \
+  OP(GetIntegerv)                                          /* 351 */ \
+  OP(GetInternalformativ)                                  /* 352 */ \
+  OP(GetProgramiv)                                         /* 353 */ \
+  OP(GetProgramInfoLog)                                    /* 354 */ \
+  OP(GetRenderbufferParameteriv)                           /* 355 */ \
+  OP(GetSamplerParameterfv)                                /* 356 */ \
+  OP(GetSamplerParameteriv)                                /* 357 */ \
+  OP(GetShaderiv)                                          /* 358 */ \
+  OP(GetShaderInfoLog)                                     /* 359 */ \
+  OP(GetShaderPrecisionFormat)                             /* 360 */ \
+  OP(GetShaderSource)                                      /* 361 */ \
+  OP(GetString)                                            /* 362 */ \
+  OP(GetSynciv)                                            /* 363 */ \
+  OP(GetTexParameterfv)                                    /* 364 */ \
+  OP(GetTexParameteriv)                                    /* 365 */ \
+  OP(GetTransformFeedbackVarying)                          /* 366 */ \
+  OP(GetUniformBlockIndex)                                 /* 367 */ \
+  OP(GetUniformfv)                                         /* 368 */ \
+  OP(GetUniformiv)                                         /* 369 */ \
+  OP(GetUniformuiv)                                        /* 370 */ \
+  OP(GetUniformIndices)                                    /* 371 */ \
+  OP(GetUniformLocation)                                   /* 372 */ \
+  OP(GetVertexAttribfv)                                    /* 373 */ \
+  OP(GetVertexAttribiv)                                    /* 374 */ \
+  OP(GetVertexAttribIiv)                                   /* 375 */ \
+  OP(GetVertexAttribIuiv)                                  /* 376 */ \
+  OP(GetVertexAttribPointerv)                              /* 377 */ \
+  OP(Hint)                                                 /* 378 */ \
+  OP(InvalidateFramebufferImmediate)                       /* 379 */ \
+  OP(InvalidateSubFramebufferImmediate)                    /* 380 */ \
+  OP(IsBuffer)                                             /* 381 */ \
+  OP(IsEnabled)                                            /* 382 */ \
+  OP(IsFramebuffer)                                        /* 383 */ \
+  OP(IsProgram)                                            /* 384 */ \
+  OP(IsRenderbuffer)                                       /* 385 */ \
+  OP(IsSampler)                                            /* 386 */ \
+  OP(IsShader)                                             /* 387 */ \
+  OP(IsSync)                                               /* 388 */ \
+  OP(IsTexture)                                            /* 389 */ \
+  OP(IsTransformFeedback)                                  /* 390 */ \
+  OP(LineWidth)                                            /* 391 */ \
+  OP(LinkProgram)                                          /* 392 */ \
+  OP(PauseTransformFeedback)                               /* 393 */ \
+  OP(PixelStorei)                                          /* 394 */ \
+  OP(PolygonOffset)                                        /* 395 */ \
+  OP(ReadBuffer)                                           /* 396 */ \
+  OP(ReadPixels)                                           /* 397 */ \
+  OP(ReleaseShaderCompiler)                                /* 398 */ \
+  OP(RenderbufferStorage)                                  /* 399 */ \
+  OP(ResumeTransformFeedback)                              /* 400 */ \
+  OP(SampleCoverage)                                       /* 401 */ \
+  OP(SamplerParameterf)                                    /* 402 */ \
+  OP(SamplerParameterfvImmediate)                          /* 403 */ \
+  OP(SamplerParameteri)                                    /* 404 */ \
+  OP(SamplerParameterivImmediate)                          /* 405 */ \
+  OP(Scissor)                                              /* 406 */ \
+  OP(ShaderBinary)                                         /* 407 */ \
+  OP(ShaderSourceBucket)                                   /* 408 */ \
+  OP(StencilFunc)                                          /* 409 */ \
+  OP(StencilFuncSeparate)                                  /* 410 */ \
+  OP(StencilMask)                                          /* 411 */ \
+  OP(StencilMaskSeparate)                                  /* 412 */ \
+  OP(StencilOp)                                            /* 413 */ \
+  OP(StencilOpSeparate)                                    /* 414 */ \
+  OP(TexImage2D)                                           /* 415 */ \
+  OP(TexImage3D)                                           /* 416 */ \
+  OP(TexParameterf)                                        /* 417 */ \
+  OP(TexParameterfvImmediate)                              /* 418 */ \
+  OP(TexParameteri)                                        /* 419 */ \
+  OP(TexParameterivImmediate)                              /* 420 */ \
+  OP(TexStorage3D)                                         /* 421 */ \
+  OP(TexSubImage2D)                                        /* 422 */ \
+  OP(TexSubImage3D)                                        /* 423 */ \
+  OP(TransformFeedbackVaryingsBucket)                      /* 424 */ \
+  OP(Uniform1f)                                            /* 425 */ \
+  OP(Uniform1fvImmediate)                                  /* 426 */ \
+  OP(Uniform1i)                                            /* 427 */ \
+  OP(Uniform1ivImmediate)                                  /* 428 */ \
+  OP(Uniform1ui)                                           /* 429 */ \
+  OP(Uniform1uivImmediate)                                 /* 430 */ \
+  OP(Uniform2f)                                            /* 431 */ \
+  OP(Uniform2fvImmediate)                                  /* 432 */ \
+  OP(Uniform2i)                                            /* 433 */ \
+  OP(Uniform2ivImmediate)                                  /* 434 */ \
+  OP(Uniform2ui)                                           /* 435 */ \
+  OP(Uniform2uivImmediate)                                 /* 436 */ \
+  OP(Uniform3f)                                            /* 437 */ \
+  OP(Uniform3fvImmediate)                                  /* 438 */ \
+  OP(Uniform3i)                                            /* 439 */ \
+  OP(Uniform3ivImmediate)                                  /* 440 */ \
+  OP(Uniform3ui)                                           /* 441 */ \
+  OP(Uniform3uivImmediate)                                 /* 442 */ \
+  OP(Uniform4f)                                            /* 443 */ \
+  OP(Uniform4fvImmediate)                                  /* 444 */ \
+  OP(Uniform4i)                                            /* 445 */ \
+  OP(Uniform4ivImmediate)                                  /* 446 */ \
+  OP(Uniform4ui)                                           /* 447 */ \
+  OP(Uniform4uivImmediate)                                 /* 448 */ \
+  OP(UniformBlockBinding)                                  /* 449 */ \
+  OP(UniformMatrix2fvImmediate)                            /* 450 */ \
+  OP(UniformMatrix2x3fvImmediate)                          /* 451 */ \
+  OP(UniformMatrix2x4fvImmediate)                          /* 452 */ \
+  OP(UniformMatrix3fvImmediate)                            /* 453 */ \
+  OP(UniformMatrix3x2fvImmediate)                          /* 454 */ \
+  OP(UniformMatrix3x4fvImmediate)                          /* 455 */ \
+  OP(UniformMatrix4fvImmediate)                            /* 456 */ \
+  OP(UniformMatrix4x2fvImmediate)                          /* 457 */ \
+  OP(UniformMatrix4x3fvImmediate)                          /* 458 */ \
+  OP(UseProgram)                                           /* 459 */ \
+  OP(ValidateProgram)                                      /* 460 */ \
+  OP(VertexAttrib1f)                                       /* 461 */ \
+  OP(VertexAttrib1fvImmediate)                             /* 462 */ \
+  OP(VertexAttrib2f)                                       /* 463 */ \
+  OP(VertexAttrib2fvImmediate)                             /* 464 */ \
+  OP(VertexAttrib3f)                                       /* 465 */ \
+  OP(VertexAttrib3fvImmediate)                             /* 466 */ \
+  OP(VertexAttrib4f)                                       /* 467 */ \
+  OP(VertexAttrib4fvImmediate)                             /* 468 */ \
+  OP(VertexAttribI4i)                                      /* 469 */ \
+  OP(VertexAttribI4ivImmediate)                            /* 470 */ \
+  OP(VertexAttribI4ui)                                     /* 471 */ \
+  OP(VertexAttribI4uivImmediate)                           /* 472 */ \
+  OP(VertexAttribIPointer)                                 /* 473 */ \
+  OP(VertexAttribPointer)                                  /* 474 */ \
+  OP(Viewport)                                             /* 475 */ \
+  OP(WaitSync)                                             /* 476 */ \
+  OP(BlitFramebufferCHROMIUM)                              /* 477 */ \
+  OP(RenderbufferStorageMultisampleCHROMIUM)               /* 478 */ \
+  OP(RenderbufferStorageMultisampleEXT)                    /* 479 */ \
+  OP(FramebufferTexture2DMultisampleEXT)                   /* 480 */ \
+  OP(TexStorage2DEXT)                                      /* 481 */ \
+  OP(GenQueriesEXTImmediate)                               /* 482 */ \
+  OP(DeleteQueriesEXTImmediate)                            /* 483 */ \
+  OP(QueryCounterEXT)                                      /* 484 */ \
+  OP(BeginQueryEXT)                                        /* 485 */ \
+  OP(BeginTransformFeedback)                               /* 486 */ \
+  OP(EndQueryEXT)                                          /* 487 */ \
+  OP(EndTransformFeedback)                                 /* 488 */ \
+  OP(SetDisjointValueSyncCHROMIUM)                         /* 489 */ \
+  OP(InsertEventMarkerEXT)                                 /* 490 */ \
+  OP(PushGroupMarkerEXT)                                   /* 491 */ \
+  OP(PopGroupMarkerEXT)                                    /* 492 */ \
+  OP(GenVertexArraysOESImmediate)                          /* 493 */ \
+  OP(DeleteVertexArraysOESImmediate)                       /* 494 */ \
+  OP(IsVertexArrayOES)                                     /* 495 */ \
+  OP(BindVertexArrayOES)                                   /* 496 */ \
+  OP(SwapBuffers)                                          /* 497 */ \
+  OP(GetMaxValueInBufferCHROMIUM)                          /* 498 */ \
+  OP(EnableFeatureCHROMIUM)                                /* 499 */ \
+  OP(MapBufferRange)                                       /* 500 */ \
+  OP(UnmapBuffer)                                          /* 501 */ \
+  OP(ResizeCHROMIUM)                                       /* 502 */ \
+  OP(GetRequestableExtensionsCHROMIUM)                     /* 503 */ \
+  OP(RequestExtensionCHROMIUM)                             /* 504 */ \
+  OP(GetProgramInfoCHROMIUM)                               /* 505 */ \
+  OP(GetUniformBlocksCHROMIUM)                             /* 506 */ \
+  OP(GetTransformFeedbackVaryingsCHROMIUM)                 /* 507 */ \
+  OP(GetUniformsES3CHROMIUM)                               /* 508 */ \
+  OP(GetTranslatedShaderSourceANGLE)                       /* 509 */ \
+  OP(PostSubBufferCHROMIUM)                                /* 510 */ \
+  OP(TexImageIOSurface2DCHROMIUM)                          /* 511 */ \
+  OP(CopyTextureCHROMIUM)                                  /* 512 */ \
+  OP(CopySubTextureCHROMIUM)                               /* 513 */ \
+  OP(CompressedCopyTextureCHROMIUM)                        /* 514 */ \
+  OP(DrawArraysInstancedANGLE)                             /* 515 */ \
+  OP(DrawElementsInstancedANGLE)                           /* 516 */ \
+  OP(VertexAttribDivisorANGLE)                             /* 517 */ \
+  OP(GenMailboxCHROMIUM)                                   /* 518 */ \
+  OP(ProduceTextureCHROMIUMImmediate)                      /* 519 */ \
+  OP(ProduceTextureDirectCHROMIUMImmediate)                /* 520 */ \
+  OP(ConsumeTextureCHROMIUMImmediate)                      /* 521 */ \
+  OP(CreateAndConsumeTextureCHROMIUMImmediate)             /* 522 */ \
+  OP(BindUniformLocationCHROMIUMBucket)                    /* 523 */ \
+  OP(GenValuebuffersCHROMIUMImmediate)                     /* 524 */ \
+  OP(DeleteValuebuffersCHROMIUMImmediate)                  /* 525 */ \
+  OP(IsValuebufferCHROMIUM)                                /* 526 */ \
+  OP(BindValuebufferCHROMIUM)                              /* 527 */ \
+  OP(SubscribeValueCHROMIUM)                               /* 528 */ \
+  OP(PopulateSubscribedValuesCHROMIUM)                     /* 529 */ \
+  OP(UniformValuebufferCHROMIUM)                           /* 530 */ \
+  OP(BindTexImage2DCHROMIUM)                               /* 531 */ \
+  OP(ReleaseTexImage2DCHROMIUM)                            /* 532 */ \
+  OP(TraceBeginCHROMIUM)                                   /* 533 */ \
+  OP(TraceEndCHROMIUM)                                     /* 534 */ \
+  OP(DiscardFramebufferEXTImmediate)                       /* 535 */ \
+  OP(LoseContextCHROMIUM)                                  /* 536 */ \
+  OP(InsertFenceSyncCHROMIUM)                              /* 537 */ \
+  OP(GenSyncTokenCHROMIUMImmediate)                        /* 538 */ \
+  OP(GenUnverifiedSyncTokenCHROMIUMImmediate)              /* 539 */ \
+  OP(VerifySyncTokensCHROMIUMImmediate)                    /* 540 */ \
+  OP(WaitSyncTokenCHROMIUM)                                /* 541 */ \
+  OP(DrawBuffersEXTImmediate)                              /* 542 */ \
+  OP(DiscardBackbufferCHROMIUM)                            /* 543 */ \
+  OP(ScheduleOverlayPlaneCHROMIUM)                         /* 544 */ \
+  OP(ScheduleCALayerCHROMIUM)                              /* 545 */ \
+  OP(CommitOverlayPlanesCHROMIUM)                          /* 546 */ \
+  OP(SwapInterval)                                         /* 547 */ \
+  OP(FlushDriverCachesCHROMIUM)                            /* 548 */ \
+  OP(MatrixLoadfCHROMIUMImmediate)                         /* 549 */ \
+  OP(MatrixLoadIdentityCHROMIUM)                           /* 550 */ \
+  OP(GenPathsCHROMIUM)                                     /* 551 */ \
+  OP(DeletePathsCHROMIUM)                                  /* 552 */ \
+  OP(IsPathCHROMIUM)                                       /* 553 */ \
+  OP(PathCommandsCHROMIUM)                                 /* 554 */ \
+  OP(PathParameterfCHROMIUM)                               /* 555 */ \
+  OP(PathParameteriCHROMIUM)                               /* 556 */ \
+  OP(PathStencilFuncCHROMIUM)                              /* 557 */ \
+  OP(StencilFillPathCHROMIUM)                              /* 558 */ \
+  OP(StencilStrokePathCHROMIUM)                            /* 559 */ \
+  OP(CoverFillPathCHROMIUM)                                /* 560 */ \
+  OP(CoverStrokePathCHROMIUM)                              /* 561 */ \
+  OP(StencilThenCoverFillPathCHROMIUM)                     /* 562 */ \
+  OP(StencilThenCoverStrokePathCHROMIUM)                   /* 563 */ \
+  OP(StencilFillPathInstancedCHROMIUM)                     /* 564 */ \
+  OP(StencilStrokePathInstancedCHROMIUM)                   /* 565 */ \
+  OP(CoverFillPathInstancedCHROMIUM)                       /* 566 */ \
+  OP(CoverStrokePathInstancedCHROMIUM)                     /* 567 */ \
+  OP(StencilThenCoverFillPathInstancedCHROMIUM)            /* 568 */ \
+  OP(StencilThenCoverStrokePathInstancedCHROMIUM)          /* 569 */ \
+  OP(BindFragmentInputLocationCHROMIUMBucket)              /* 570 */ \
+  OP(ProgramPathFragmentInputGenCHROMIUM)                  /* 571 */ \
+  OP(CoverageModulationCHROMIUM)                           /* 572 */ \
+  OP(BlendBarrierKHR)                                      /* 573 */ \
+  OP(ApplyScreenSpaceAntialiasingCHROMIUM)                 /* 574 */ \
+  OP(BindFragDataLocationIndexedEXTBucket)                 /* 575 */ \
+  OP(BindFragDataLocationEXTBucket)                        /* 576 */ \
+  OP(GetFragDataIndexEXT)                                  /* 577 */ \
+  OP(UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate) /* 578 */
 
 enum CommandId {
   kStartPoint = cmd::kLastCommonId,  // All GLES2 commands start after this.
diff --git a/gpu/command_buffer/service/gl_stream_texture_image.h b/gpu/command_buffer/service/gl_stream_texture_image.h
new file mode 100644
index 0000000..2cd710a
--- /dev/null
+++ b/gpu/command_buffer/service/gl_stream_texture_image.h
@@ -0,0 +1,33 @@
+// Copyright 2016 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 GPU_COMMAND_BUFFER_SERVICE_GL_STREAM_TEXTURE_IMAGE_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GL_STREAM_TEXTURE_IMAGE_H_
+
+#include "ui/gl/gl_image.h"
+
+namespace gpu {
+namespace gles2 {
+
+// Specialization of GLImage that allows us to support (stream) textures
+// that supply a texture matrix.
+class GPU_EXPORT GLStreamTextureImage : public gl::GLImage {
+ public:
+  GLStreamTextureImage() {}
+
+  // Get the matrix.
+  // Copy the texture matrix for this image into |matrix|.
+  virtual void GetTextureMatrix(float matrix[16]) = 0;
+
+ protected:
+  ~GLStreamTextureImage() override {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(GLStreamTextureImage);
+};
+
+}  // namespace gles2
+}  // namespace gpu
+
+#endif  // GPU_COMMAND_BUFFER_SERVICE_GL_STREAM_TEXTURE_IMAGE_H_
diff --git a/gpu/command_buffer/service/gl_surface_mock.h b/gpu/command_buffer/service/gl_surface_mock.h
index 68358e3f..058089c 100644
--- a/gpu/command_buffer/service/gl_surface_mock.h
+++ b/gpu/command_buffer/service/gl_surface_mock.h
@@ -34,7 +34,7 @@
   MOCK_METHOD0(GetShareHandle, void*());
   MOCK_METHOD0(GetDisplay, void*());
   MOCK_METHOD0(GetConfig, void*());
-  MOCK_METHOD0(GetFormat, unsigned());
+  MOCK_METHOD0(GetFormat, GLSurface::Format());
 
  protected:
   virtual ~GLSurfaceMock();
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 52118fb7..f69be1d 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -37,6 +37,7 @@
 #include "gpu/command_buffer/service/error_state.h"
 #include "gpu/command_buffer/service/feature_info.h"
 #include "gpu/command_buffer/service/framebuffer_manager.h"
+#include "gpu/command_buffer/service/gl_stream_texture_image.h"
 #include "gpu/command_buffer/service/gl_utils.h"
 #include "gpu/command_buffer/service/gles2_cmd_clear_framebuffer.h"
 #include "gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h"
@@ -1625,6 +1626,10 @@
   void DoUniformMatrix4fv(
       GLint fake_location, GLsizei count, GLboolean transpose,
       const GLfloat* value);
+  void DoUniformMatrix4fvStreamTextureMatrixCHROMIUM(
+      GLint fake_location,
+      GLboolean transpose,
+      const GLfloat* default_value);
   void DoUniformMatrix2x3fv(
       GLint fake_location, GLsizei count, GLboolean transpose,
       const GLfloat* value);
@@ -7486,6 +7491,46 @@
   glUniformMatrix4fv(real_location, count, transpose, value);
 }
 
+void GLES2DecoderImpl::DoUniformMatrix4fvStreamTextureMatrixCHROMIUM(
+    GLint fake_location,
+    GLboolean transpose,
+    const GLfloat* default_value) {
+  float gl_matrix[16];
+
+  // If we can't get a matrix from the texture, then use a default.
+  // TODO(liberato): remove |default_value| and replace with an identity matrix.
+  // It is only present as a transitionary step until StreamTexture supplies
+  // the matrix via GLImage.  Once that happens, GLRenderer can quit sending
+  // in a default.
+  memcpy(gl_matrix, default_value, sizeof(gl_matrix));
+
+  // This refers to the bound external texture on the active unit.
+  TextureUnit& unit = state_.texture_units[state_.active_texture_unit];
+  if (TextureRef* texture_ref = unit.bound_texture_external_oes.get()) {
+    if (GLStreamTextureImage* image =
+            texture_ref->texture()->GetLevelStreamTextureImage(
+                GL_TEXTURE_EXTERNAL_OES, 0)) {
+      image->GetTextureMatrix(gl_matrix);
+    }
+  } else {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION,
+                       "DoUniformMatrix4vStreamTextureMatrix",
+                       "no texture bound");
+    return;
+  }
+
+  GLenum type = 0;
+  GLint real_location = -1;
+  GLsizei count = 1;
+  if (!PrepForSetUniformByLocation(fake_location, "glUniformMatrix4fv",
+                                   Program::kUniformMatrix4f, &real_location,
+                                   &type, &count)) {
+    return;
+  }
+
+  glUniformMatrix4fv(real_location, count, transpose, gl_matrix);
+}
+
 void GLES2DecoderImpl::DoUniformMatrix2x3fv(
     GLint fake_location, GLsizei count, GLboolean transpose,
     const GLfloat* value) {
@@ -10244,7 +10289,7 @@
           nullptr, &padded_row_size)) {
     return false;
   }
-  const uint32_t kMaxZeroSize = 1048 * 1048 * 2;
+  const uint32_t kMaxZeroSize = 1024 * 1024 * 2;
   uint32_t buffer_size;
   std::vector<TexSubCoord3D> subs;
   if (size < kMaxZeroSize) {
@@ -10306,7 +10351,8 @@
     scoped_ptr<char[]> zero(new char[buffer_size]);
     memset(zero.get(), 0, buffer_size);
     // TODO(zmo): Consider glMapBufferRange instead.
-    glBufferData(GL_PIXEL_UNPACK_BUFFER, size, zero.get(), GL_STATIC_DRAW);
+    glBufferData(
+        GL_PIXEL_UNPACK_BUFFER, buffer_size, zero.get(), GL_STATIC_DRAW);
   }
 
   glBindTexture(texture->target(), texture->service_id());
@@ -10600,7 +10646,7 @@
     case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
     case GL_COMPRESSED_RGBA8_ETC2_EAC:
     case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
-      if (width <= 0 || height <= 0 || depth <= 0) {
+      if (width < 0 || height < 0 || depth < 0) {
         LOCAL_SET_GL_ERROR(
             GL_INVALID_OPERATION, function_name,
             "width, height, or depth invalid");
@@ -13310,7 +13356,7 @@
                            dest_internal_format == GL_RGBA ||
                            dest_internal_format == GL_BGRA_EXT;
   bool valid_source_format =
-      source_internal_format == GL_RED || source_internal_format == GL_ALPHA ||
+      source_internal_format == GL_R8 || source_internal_format == GL_ALPHA ||
       source_internal_format == GL_RGB || source_internal_format == GL_RGBA ||
       source_internal_format == GL_LUMINANCE ||
       source_internal_format == GL_LUMINANCE_ALPHA ||
@@ -13513,14 +13559,21 @@
   // before presenting.
   if (source_target == GL_TEXTURE_EXTERNAL_OES) {
     // TODO(hkuang): get the StreamTexture transform matrix in GPU process
-    // instead of using kIdentityMatrix crbug.com/226218.
+    // instead of using kIdentityMatrix crbug.com/226218.  AVDACodecImage does
+    // this correctly, but others (e.g., stream_texture_android.cc) don't.
+    // (crbug.com/371500, crbug.com/588837)
+    GLfloat transform_matrix[16];
+    memcpy(transform_matrix, kIdentityMatrix, sizeof(transform_matrix));
+    if (GLStreamTextureImage* image =
+            source_texture->GetLevelStreamTextureImage(GL_TEXTURE_EXTERNAL_OES,
+                                                       0)) {
+      image->GetTextureMatrix(transform_matrix);
+    }
     copy_texture_CHROMIUM_->DoCopyTextureWithTransform(
-        this, source_target, source_texture->service_id(),
-        dest_target, dest_texture->service_id(), source_width, source_height,
-        unpack_flip_y == GL_TRUE,
-        unpack_premultiply_alpha == GL_TRUE,
-        unpack_unmultiply_alpha == GL_TRUE,
-        kIdentityMatrix);
+        this, source_target, source_texture->service_id(), dest_target,
+        dest_texture->service_id(), source_width, source_height,
+        unpack_flip_y == GL_TRUE, unpack_premultiply_alpha == GL_TRUE,
+        unpack_unmultiply_alpha == GL_TRUE, transform_matrix);
   } else {
     copy_texture_CHROMIUM_->DoCopyTexture(
         this, source_target, source_texture->service_id(),
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
index a8f03ab..b56ae2cd 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -5013,6 +5013,34 @@
   return error::kNoError;
 }
 
+error::Error
+GLES2DecoderImpl::HandleUniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  const gles2::cmds::UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate& c =
+      *static_cast<const gles2::cmds::
+                       UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate*>(
+          cmd_data);
+  (void)c;
+  GLint location = static_cast<GLint>(c.location);
+  GLboolean transpose = static_cast<GLboolean>(c.transpose);
+  uint32_t data_size;
+  if (!ComputeDataSize(1, sizeof(GLfloat), 16, &data_size)) {
+    return error::kOutOfBounds;
+  }
+  if (data_size > immediate_data_size) {
+    return error::kOutOfBounds;
+  }
+  const GLfloat* default_value =
+      GetImmediateDataAs<const GLfloat*>(c, data_size, immediate_data_size);
+  if (default_value == NULL) {
+    return error::kOutOfBounds;
+  }
+  DoUniformMatrix4fvStreamTextureMatrixCHROMIUM(location, transpose,
+                                                default_value);
+  return error::kNoError;
+}
+
 bool GLES2DecoderImpl::SetCapabilityState(GLenum cap, bool enabled) {
   switch (cap) {
     case GL_BLEND:
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
index b91ceeb9..0962d43e 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
@@ -3381,11 +3381,189 @@
   const GLenum kFormat = GL_RGBA;
   const GLenum kType = GL_UNSIGNED_BYTE;
 
-  DoBindTexture(GL_TEXTURE_3D, client_texture_id_, kServiceTextureId);
+  DoBindTexture(kTarget, client_texture_id_, kServiceTextureId);
   DoTexImage3D(kTarget, kLevel, kInternalFormat, kWidth, kHeight, kDepth, 0,
                kFormat, kType, kSharedMemoryId, kSharedMemoryOffset);
 }
 
+TEST_P(GLES3DecoderTest, ClearLevel3DSingleCall) {
+  const GLenum kTarget = GL_TEXTURE_3D;
+  const GLint kLevel = 0;
+  const GLint kInternalFormat = GL_RGBA8;
+  const GLsizei kWidth = 2;
+  const GLsizei kHeight = 2;
+  const GLsizei kDepth = 2;
+  const GLenum kFormat = GL_RGBA;
+  const GLenum kType = GL_UNSIGNED_BYTE;
+  const uint32_t kBufferSize = kWidth * kHeight * kDepth * 4;
+
+  DoBindTexture(kTarget, client_texture_id_, kServiceTextureId);
+  DoTexImage3D(kTarget, kLevel, kInternalFormat, kWidth, kHeight, kDepth, 0,
+               kFormat, kType, 0, 0);
+  TextureRef* texture_ref =
+      group().texture_manager()->GetTexture(client_texture_id_);
+  ASSERT_TRUE(texture_ref != NULL);
+  Texture* texture = texture_ref->texture();
+
+  EXPECT_CALL(*gl_, GenBuffersARB(1, _))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, BindBuffer(GL_PIXEL_UNPACK_BUFFER, _))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, BufferData(GL_PIXEL_UNPACK_BUFFER,
+                               kBufferSize, _, GL_STATIC_DRAW))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, BindTexture(kTarget, kServiceTextureId))
+      .Times(1)
+      .RetiresOnSaturation();
+  {
+    // It takes 1 call to clear the entire 3D texture.
+    EXPECT_CALL(*gl_, TexSubImage3DNoData(kTarget, kLevel, 0, 0, 0,
+                                          kWidth, kHeight, kDepth,
+                                          kFormat, kType))
+        .Times(1)
+        .RetiresOnSaturation();
+  }
+  EXPECT_CALL(*gl_, BindBuffer(GL_PIXEL_UNPACK_BUFFER, _))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, DeleteBuffersARB(1, _))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, BindTexture(kTarget, _))
+      .Times(1)
+      .RetiresOnSaturation();
+
+  EXPECT_TRUE(decoder_->ClearLevel3D(
+      texture, kTarget, kLevel, kFormat, kType, kWidth, kHeight, kDepth));
+}
+
+TEST_P(GLES3DecoderTest, ClearLevel3DMultipleLayersPerCall) {
+  const GLenum kTarget = GL_TEXTURE_3D;
+  const GLint kLevel = 0;
+  const GLint kInternalFormat = GL_RGBA8;
+  const GLsizei kWidth = 512;
+  const GLsizei kHeight = 512;
+  const GLsizei kDepth = 7;
+  const GLenum kFormat = GL_RGBA;
+  const GLenum kType = GL_UNSIGNED_BYTE;
+  const uint32_t kBufferSize = 1024 * 1024 * 2;  // Max buffer size per call.
+
+  DoBindTexture(kTarget, client_texture_id_, kServiceTextureId);
+  DoTexImage3D(kTarget, kLevel, kInternalFormat, kWidth, kHeight, kDepth, 0,
+               kFormat, kType, 0, 0);
+  TextureRef* texture_ref =
+      group().texture_manager()->GetTexture(client_texture_id_);
+  ASSERT_TRUE(texture_ref != NULL);
+  Texture* texture = texture_ref->texture();
+
+  EXPECT_CALL(*gl_, GenBuffersARB(1, _))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, BindBuffer(GL_PIXEL_UNPACK_BUFFER, _))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, BufferData(GL_PIXEL_UNPACK_BUFFER,
+                               kBufferSize, _, GL_STATIC_DRAW))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, BindTexture(kTarget, kServiceTextureId))
+      .Times(1)
+      .RetiresOnSaturation();
+  {
+    // It takes 4 calls to clear the 3D texture, each clears 2/2/2/1 layers.
+    EXPECT_CALL(*gl_, TexSubImage3DNoData(kTarget, kLevel, 0, 0, 0,
+                                          kWidth, kHeight, 2, kFormat, kType))
+        .Times(1)
+        .RetiresOnSaturation();
+    EXPECT_CALL(*gl_, TexSubImage3DNoData(kTarget, kLevel, 0, 0, 2,
+                                          kWidth, kHeight, 2, kFormat, kType))
+        .Times(1)
+        .RetiresOnSaturation();
+    EXPECT_CALL(*gl_, TexSubImage3DNoData(kTarget, kLevel, 0, 0, 4,
+                                          kWidth, kHeight, 2, kFormat, kType))
+        .Times(1)
+        .RetiresOnSaturation();
+    EXPECT_CALL(*gl_, TexSubImage3DNoData(kTarget, kLevel, 0, 0, 6,
+                                          kWidth, kHeight, 1, kFormat, kType))
+        .Times(1)
+        .RetiresOnSaturation();
+  }
+  EXPECT_CALL(*gl_, BindBuffer(GL_PIXEL_UNPACK_BUFFER, _))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, DeleteBuffersARB(1, _))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, BindTexture(kTarget, _))
+      .Times(1)
+      .RetiresOnSaturation();
+
+  EXPECT_TRUE(decoder_->ClearLevel3D(
+      texture, kTarget, kLevel, kFormat, kType, kWidth, kHeight, kDepth));
+}
+
+TEST_P(GLES3DecoderTest, ClearLevel3DMultipleCallsPerLayer) {
+  const GLenum kTarget = GL_TEXTURE_3D;
+  const GLint kLevel = 0;
+  const GLint kInternalFormat = GL_RGBA8;
+  const GLsizei kWidth = 1024;
+  const GLsizei kHeight = 1000;
+  const GLsizei kDepth = 2;
+  const GLenum kFormat = GL_RGBA;
+  const GLenum kType = GL_UNSIGNED_BYTE;
+  const uint32_t kBufferSize = 1024 * 1024 * 2;  // Max buffer size per call.
+
+  DoBindTexture(kTarget, client_texture_id_, kServiceTextureId);
+  DoTexImage3D(kTarget, kLevel, kInternalFormat, kWidth, kHeight, kDepth, 0,
+               kFormat, kType, 0, 0);
+  TextureRef* texture_ref =
+      group().texture_manager()->GetTexture(client_texture_id_);
+  ASSERT_TRUE(texture_ref != NULL);
+  Texture* texture = texture_ref->texture();
+
+  EXPECT_CALL(*gl_, GenBuffersARB(1, _))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, BindBuffer(GL_PIXEL_UNPACK_BUFFER, _))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, BufferData(GL_PIXEL_UNPACK_BUFFER,
+                               kBufferSize, _, GL_STATIC_DRAW))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, BindTexture(kTarget, kServiceTextureId))
+      .Times(1)
+      .RetiresOnSaturation();
+  for (GLint zz = 0; zz < 2; ++zz) {
+    // It takes two calls to clear one layer of the 3D texture,
+    // each clears 512/488 rows.
+    // Layer 1.
+    EXPECT_CALL(*gl_, TexSubImage3DNoData(kTarget, kLevel, 0, 0, zz,
+                                          kWidth, 512, 1, kFormat, kType))
+        .Times(1)
+        .RetiresOnSaturation();
+    EXPECT_CALL(*gl_, TexSubImage3DNoData(kTarget, kLevel, 0, 512, zz,
+                                          kWidth, 488, 1, kFormat, kType))
+        .Times(1)
+        .RetiresOnSaturation();
+  }
+  EXPECT_CALL(*gl_, BindBuffer(GL_PIXEL_UNPACK_BUFFER, _))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, DeleteBuffersARB(1, _))
+      .Times(1)
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, BindTexture(kTarget, _))
+      .Times(1)
+      .RetiresOnSaturation();
+
+  EXPECT_TRUE(decoder_->ClearLevel3D(
+      texture, kTarget, kLevel, kFormat, kType, kWidth, kHeight, kDepth));
+}
+
 // TODO(gman): Complete this test.
 // TEST_P(GLES2DecoderTest, CompressedTexImage2DGLError) {
 // }
diff --git a/gpu/command_buffer/service/image_factory.cc b/gpu/command_buffer/service/image_factory.cc
index a96da9a..b60d644 100644
--- a/gpu/command_buffer/service/image_factory.cc
+++ b/gpu/command_buffer/service/image_factory.cc
@@ -19,7 +19,7 @@
 gfx::BufferFormat ImageFactory::DefaultBufferFormatForImageFormat(
     unsigned internalformat) {
   switch (internalformat) {
-    case GL_RED:
+    case GL_R8:
       return gfx::BufferFormat::R_8;
     case GL_RGB:
       return gfx::BufferFormat::BGRX_8888;
diff --git a/gpu/command_buffer/service/test_helper.h b/gpu/command_buffer/service/test_helper.h
index 272c9aaa..f285c2c 100644
--- a/gpu/command_buffer/service/test_helper.h
+++ b/gpu/command_buffer/service/test_helper.h
@@ -45,7 +45,7 @@
   static const GLint kMaxRenderbufferSize = 1024;
   static const GLint kMaxTextureSize = 2048;
   static const GLint kMaxCubeMapTextureSize = 256;
-  static const GLint kMax3DTextureSize = 256;
+  static const GLint kMax3DTextureSize = 1024;
   static const GLint kMaxRectangleTextureSize = 64;
   static const GLint kNumVertexAttribs = 16;
   static const GLint kNumTextureUnits = 8;
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc
index eaad260..e5430c15 100644
--- a/gpu/command_buffer/service/texture_manager.cc
+++ b/gpu/command_buffer/service/texture_manager.cc
@@ -22,6 +22,7 @@
 #include "gpu/command_buffer/service/error_state.h"
 #include "gpu/command_buffer/service/feature_info.h"
 #include "gpu/command_buffer/service/framebuffer_manager.h"
+#include "gpu/command_buffer/service/gl_stream_texture_image.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "gpu/command_buffer/service/mailbox_manager.h"
 #include "gpu/command_buffer/service/memory_tracking.h"
@@ -911,6 +912,7 @@
   info.format = format;
   info.type = type;
   info.image = 0;
+  info.stream_texture_image = 0;
   info.image_state = UNBOUND;
   info.internal_workaround = false;
 
@@ -1347,10 +1349,11 @@
   return true;
 }
 
-void Texture::SetLevelImage(GLenum target,
-                            GLint level,
-                            gl::GLImage* image,
-                            ImageState state) {
+void Texture::SetLevelImageInternal(GLenum target,
+                                    GLint level,
+                                    gl::GLImage* image,
+                                    GLStreamTextureImage* stream_texture_image,
+                                    ImageState state) {
   DCHECK_GE(level, 0);
   size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
   DCHECK_LT(static_cast<size_t>(face_index),
@@ -1362,15 +1365,29 @@
   DCHECK_EQ(info.target, target);
   DCHECK_EQ(info.level, level);
   info.image = image;
+  info.stream_texture_image = stream_texture_image;
   info.image_state = state;
 
   UpdateCanRenderCondition();
   UpdateHasImages();
 }
 
-gl::GLImage* Texture::GetLevelImage(GLint target,
-                                    GLint level,
-                                    ImageState* state) const {
+void Texture::SetLevelImage(GLenum target,
+                            GLint level,
+                            gl::GLImage* image,
+                            ImageState state) {
+  SetLevelImageInternal(target, level, image, nullptr, state);
+}
+
+void Texture::SetLevelStreamTextureImage(GLenum target,
+                                         GLint level,
+                                         GLStreamTextureImage* image,
+                                         ImageState state) {
+  SetLevelImageInternal(target, level, image, image, state);
+}
+
+const Texture::LevelInfo* Texture::GetLevelInfo(GLint target,
+                                                GLint level) const {
   if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES &&
       target != GL_TEXTURE_RECTANGLE_ARB) {
     return NULL;
@@ -1380,19 +1397,37 @@
   if (level >= 0 && face_index < face_infos_.size() &&
       static_cast<size_t>(level) < face_infos_[face_index].level_infos.size()) {
     const LevelInfo& info = face_infos_[face_index].level_infos[level];
-    if (info.target != 0) {
-      if (state)
-        *state = info.image_state;
-      return info.image.get();
-    }
+    if (info.target != 0)
+      return &info;
   }
   return NULL;
 }
 
+gl::GLImage* Texture::GetLevelImage(GLint target,
+                                    GLint level,
+                                    ImageState* state) const {
+  const LevelInfo* info = GetLevelInfo(target, level);
+  if (!info)
+    return nullptr;
+
+  if (state)
+    *state = info->image_state;
+  return info->image.get();
+}
+
 gl::GLImage* Texture::GetLevelImage(GLint target, GLint level) const {
   return GetLevelImage(target, level, nullptr);
 }
 
+GLStreamTextureImage* Texture::GetLevelStreamTextureImage(GLint target,
+                                                          GLint level) const {
+  const LevelInfo* info = GetLevelInfo(target, level);
+  if (!info)
+    return nullptr;
+
+  return info->stream_texture_image.get();
+}
+
 void Texture::DumpLevelMemory(base::trace_event::ProcessMemoryDump* pmd,
                               uint64_t client_tracing_id,
                               const std::string& dump_name) const {
@@ -1888,6 +1923,15 @@
   ref->texture()->SetLevelImage(target, level, image, state);
 }
 
+void TextureManager::SetLevelStreamTextureImage(TextureRef* ref,
+                                                GLenum target,
+                                                GLint level,
+                                                GLStreamTextureImage* image,
+                                                Texture::ImageState state) {
+  DCHECK(ref);
+  ref->texture()->SetLevelStreamTextureImage(target, level, image, state);
+}
+
 size_t TextureManager::GetSignatureSize() const {
   return sizeof(TextureTag) + sizeof(TextureSignature);
 }
diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h
index c57abec..50421ed 100644
--- a/gpu/command_buffer/service/texture_manager.h
+++ b/gpu/command_buffer/service/texture_manager.h
@@ -28,6 +28,7 @@
 namespace gles2 {
 
 class GLES2Decoder;
+class GLStreamTextureImage;
 struct ContextState;
 struct DecoderFramebufferState;
 class Display;
@@ -167,6 +168,14 @@
                      gl::GLImage* image,
                      ImageState state);
 
+  // Set the GLStreamTextureImage for a particular level.  This is identical
+  // to SetLevelImage, but it also permits GetLevelStreamTextureImage to return
+  // the image.
+  void SetLevelStreamTextureImage(GLenum target,
+                                  GLint level,
+                                  GLStreamTextureImage* image,
+                                  ImageState state);
+
   // Get the image associated with a particular level. Returns NULL if level
   // does not exist.
   gl::GLImage* GetLevelImage(GLint target,
@@ -174,6 +183,11 @@
                              ImageState* state) const;
   gl::GLImage* GetLevelImage(GLint target, GLint level) const;
 
+  // Like GetLevelImage, but will return NULL if the image wasn't set via
+  // a call to SetLevelStreamTextureImage.
+  GLStreamTextureImage* GetLevelStreamTextureImage(GLint target,
+                                                   GLint level) const;
+
   bool HasImages() const {
     return has_images_;
   }
@@ -278,6 +292,7 @@
     GLenum format;
     GLenum type;
     scoped_refptr<gl::GLImage> image;
+    scoped_refptr<GLStreamTextureImage> stream_texture_image;
     ImageState image_state;
     uint32_t estimated_size;
     bool internal_workaround;
@@ -293,6 +308,17 @@
     std::vector<LevelInfo> level_infos;
   };
 
+  // Helper for SetLevel*Image.  |stream_texture_image| may be null.
+  void SetLevelImageInternal(GLenum target,
+                             GLint level,
+                             gl::GLImage* image,
+                             GLStreamTextureImage* stream_texture_image,
+                             ImageState state);
+
+  // Helper for GetLevel*Image.  Returns the LevelInfo for |target| and |level|
+  // if it's set, else NULL.
+  const LevelInfo* GetLevelInfo(GLint target, GLint level) const;
+
   // Set the info for a particular level.
   void SetLevelInfo(GLenum target,
                     GLint level,
@@ -853,6 +879,12 @@
                      gl::GLImage* image,
                      Texture::ImageState state);
 
+  void SetLevelStreamTextureImage(TextureRef* ref,
+                                  GLenum target,
+                                  GLint level,
+                                  GLStreamTextureImage* image,
+                                  Texture::ImageState state);
+
   size_t GetSignatureSize() const;
 
   void AddToSignature(
diff --git a/gpu/command_buffer/service/texture_manager_unittest.cc b/gpu/command_buffer/service/texture_manager_unittest.cc
index b23441ca..80251b7 100644
--- a/gpu/command_buffer/service/texture_manager_unittest.cc
+++ b/gpu/command_buffer/service/texture_manager_unittest.cc
@@ -15,6 +15,7 @@
 #include "gpu/command_buffer/service/error_state_mock.h"
 #include "gpu/command_buffer/service/feature_info.h"
 #include "gpu/command_buffer/service/framebuffer_manager.h"
+#include "gpu/command_buffer/service/gl_stream_texture_image.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
 #include "gpu/command_buffer/service/gpu_service_test.h"
 #include "gpu/command_buffer/service/mailbox_manager.h"
@@ -139,6 +140,38 @@
 const GLint TextureManagerTest::kMax3dLevels;
 #endif
 
+class GLStreamTextureImageStub : public GLStreamTextureImage {
+ public:
+  GLStreamTextureImageStub() {}
+
+  // Overridden from GLImage:
+  void Destroy(bool have_context) override {}
+  gfx::Size GetSize() override { return gfx::Size(); }
+  unsigned GetInternalFormat() override { return 0; }
+  bool BindTexImage(unsigned target) override { return false; }
+  void ReleaseTexImage(unsigned target) override {}
+  bool CopyTexImage(unsigned target) override { return false; }
+  bool CopyTexSubImage(unsigned target,
+                       const gfx::Point& offset,
+                       const gfx::Rect& rect) override {
+    return false;
+  }
+  bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
+                            int z_order,
+                            gfx::OverlayTransform transform,
+                            const gfx::Rect& bounds_rect,
+                            const gfx::RectF& crop_rect) override {
+    return false;
+  }
+  void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
+                    uint64_t process_tracing_id,
+                    const std::string& dump_name) override {}
+  void GetTextureMatrix(float matrix[16]) override {}
+
+ protected:
+  ~GLStreamTextureImageStub() override {}
+};
+
 TEST_F(TextureManagerTest, Basic) {
   const GLuint kClient1Id = 1;
   const GLuint kService1Id = 11;
@@ -1508,6 +1541,7 @@
   manager_->SetLevelImage(texture_ref_.get(), GL_TEXTURE_2D, 1, image.get(),
                           Texture::BOUND);
   EXPECT_FALSE(texture->GetLevelImage(GL_TEXTURE_2D, 1) == NULL);
+  EXPECT_TRUE(texture->GetLevelStreamTextureImage(GL_TEXTURE_2D, 1) == NULL);
   // Remove it.
   manager_->SetLevelImage(texture_ref_.get(), GL_TEXTURE_2D, 1, nullptr,
                           Texture::UNBOUND);
@@ -1518,6 +1552,41 @@
   manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 1,
                          0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(2, 2));
   EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 1) == NULL);
+  EXPECT_TRUE(texture->GetLevelStreamTextureImage(GL_TEXTURE_2D, 1) == NULL);
+}
+
+TEST_F(TextureTest, GetLevelStreamTextureImage) {
+  manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_EXTERNAL_OES);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_EXTERNAL_OES, 0,
+                         GL_RGBA, 2, 2, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                         gfx::Rect(2, 2));
+  Texture* texture = texture_ref_->texture();
+
+  // Set image.
+  scoped_refptr<GLStreamTextureImage> image(new GLStreamTextureImageStub);
+  manager_->SetLevelStreamTextureImage(texture_ref_.get(),
+                                       GL_TEXTURE_EXTERNAL_OES, 0, image.get(),
+                                       Texture::BOUND);
+  EXPECT_FALSE(texture->GetLevelImage(GL_TEXTURE_EXTERNAL_OES, 0) == NULL);
+  EXPECT_FALSE(
+      texture->GetLevelStreamTextureImage(GL_TEXTURE_EXTERNAL_OES, 0) == NULL);
+  // Replace it as a normal image.
+  manager_->SetLevelImage(texture_ref_.get(), GL_TEXTURE_EXTERNAL_OES, 0,
+                          image.get(), Texture::BOUND);
+  EXPECT_FALSE(texture->GetLevelImage(GL_TEXTURE_EXTERNAL_OES, 0) == NULL);
+  EXPECT_TRUE(texture->GetLevelStreamTextureImage(GL_TEXTURE_EXTERNAL_OES, 0) ==
+              NULL);
+
+  // Image should be reset when SetLevelInfo is called.
+  manager_->SetLevelStreamTextureImage(texture_ref_.get(),
+                                       GL_TEXTURE_EXTERNAL_OES, 0, image.get(),
+                                       Texture::UNBOUND);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_EXTERNAL_OES, 0,
+                         GL_RGBA, 2, 2, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                         gfx::Rect(2, 2));
+  EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_EXTERNAL_OES, 0) == NULL);
+  EXPECT_TRUE(texture->GetLevelStreamTextureImage(GL_TEXTURE_EXTERNAL_OES, 0) ==
+              NULL);
 }
 
 namespace {
diff --git a/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittest.cc b/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittest.cc
index 5f1e1e0..a434df1 100644
--- a/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittest.cc
+++ b/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittest.cc
@@ -128,7 +128,7 @@
 GLenum InternalFormat(gfx::BufferFormat format) {
   switch (format) {
     case gfx::BufferFormat::R_8:
-      return GL_RED;
+      return GL_R8;
     case gfx::BufferFormat::RGBA_4444:
     case gfx::BufferFormat::RGBA_8888:
       return GL_RGBA;
diff --git a/infra/config/cq.cfg b/infra/config/cq.cfg
index 8ce6cbc..584bb1f 100644
--- a/infra/config/cq.cfg
+++ b/infra/config/cq.cfg
@@ -27,9 +27,6 @@
 # chrome-eng-review per
 # https://sites.google.com/a/chromium.org/dev/developers/testing/chromium-build-infrastructure/tour-of-the-chromium-buildbot?pli=1#TOC-Adding-new-build-configurations-and-tests-to-the-main-Chromium-waterfall-Commit-Queue
   try_job {
-    try_job_retry_config {
-      global_retry_quota: 1
-    }
     buckets {
       name: "tryserver.chromium.android"
       builders { name: "android_arm64_dbg_recipe" }
diff --git a/ios/DEPS b/ios/DEPS
index 2ee6925..8f13cb93e 100644
--- a/ios/DEPS
+++ b/ios/DEPS
@@ -3,6 +3,11 @@
   # directories in ios/ so we disallow all of them.
   "-ios",
 
+  # To avoid ODR violation, direct import of ios/third_party/ochamcrest
+  # is forbidden in ios/DEPS and code should instead use import as if
+  # OCHamcrest was in a framework (i.e. #import <OCHamcrest/OCHamcrest.h>).
+  "-ios/third_party/ochamcrest",
+
   # For unit tests.
   "+third_party/ocmock",
 ]
diff --git a/ios/chrome/app/strings/ios_chromium_strings.grd b/ios/chrome/app/strings/ios_chromium_strings.grd
index dab9acf..0126057 100644
--- a/ios/chrome/app/strings/ios_chromium_strings.grd
+++ b/ios/chrome/app/strings/ios_chromium_strings.grd
@@ -149,7 +149,7 @@
         Copied to Chrome
       </message>
       <message name="IDS_IOS_DISCONNECT_DIALOG_TITLE" desc="The title of the disconnect dialog [Length: 30em].">
-        Use Chromium without a Google Account.
+        Sign out of Chromium?
       </message>
       <message name="IDS_IOS_FIRSTRUN_TERMS_TITLE" desc="Title for the Terms of Service page shown to user on First Run. [Length: 30em]">
         Chromium Terms of Service
diff --git a/ios/chrome/app/strings/ios_google_chrome_strings.grd b/ios/chrome/app/strings/ios_google_chrome_strings.grd
index 03bf53b0..ec8aa7f6 100644
--- a/ios/chrome/app/strings/ios_google_chrome_strings.grd
+++ b/ios/chrome/app/strings/ios_google_chrome_strings.grd
@@ -149,7 +149,7 @@
         Copied to Chrome
       </message>
       <message name="IDS_IOS_DISCONNECT_DIALOG_TITLE" desc="The title of the disconnect dialog [Length: 30em].">
-        Use Chrome without a Google Account.
+        Sign out of Chrome?
       </message>
       <message name="IDS_IOS_FIRSTRUN_TERMS_TITLE" desc="Title for the Terms of Service page shown to user on First Run. [Length: 30em]">
         Google Chrome Terms of Service
diff --git a/ios/chrome/browser/autocomplete/autocomplete_scheme_classifier_impl.mm b/ios/chrome/browser/autocomplete/autocomplete_scheme_classifier_impl.mm
index 868a9eb..f65ed78 100644
--- a/ios/chrome/browser/autocomplete/autocomplete_scheme_classifier_impl.mm
+++ b/ios/chrome/browser/autocomplete/autocomplete_scheme_classifier_impl.mm
@@ -7,7 +7,6 @@
 #include "base/logging.h"
 #include "base/strings/string_util.h"
 #include "ios/chrome/browser/chrome_url_util.h"
-#include "net/base/net_util.h"
 #include "url/url_util.h"
 
 AutocompleteSchemeClassifierImpl::AutocompleteSchemeClassifierImpl() {}
diff --git a/ios/chrome/browser/autocomplete/in_memory_url_index_factory.cc b/ios/chrome/browser/autocomplete/in_memory_url_index_factory.cc
index 7e2da1ef..d7967cc 100644
--- a/ios/chrome/browser/autocomplete/in_memory_url_index_factory.cc
+++ b/ios/chrome/browser/autocomplete/in_memory_url_index_factory.cc
@@ -17,6 +17,7 @@
 #include "ios/chrome/browser/chrome_url_constants.h"
 #include "ios/chrome/browser/history/history_service_factory.h"
 #include "ios/chrome/browser/pref_names.h"
+#include "ios/chrome/browser/search_engines/template_url_service_factory.h"
 #include "ios/web/public/web_thread.h"
 
 namespace ios {
@@ -35,6 +36,7 @@
       ios::BookmarkModelFactory::GetForBrowserState(browser_state),
       ios::HistoryServiceFactory::GetForBrowserState(
           browser_state, ServiceAccessType::IMPLICIT_ACCESS),
+      ios::TemplateURLServiceFactory::GetForBrowserState(browser_state),
       web::WebThread::GetBlockingPool(), browser_state->GetStatePath(),
       browser_state->GetPrefs()->GetString(prefs::kAcceptLanguages),
       schemes_to_whilelist));
@@ -62,6 +64,7 @@
           BrowserStateDependencyManager::GetInstance()) {
   DependsOn(ios::BookmarkModelFactory::GetInstance());
   DependsOn(ios::HistoryServiceFactory::GetInstance());
+  DependsOn(ios::TemplateURLServiceFactory::GetInstance());
 }
 
 InMemoryURLIndexFactory::~InMemoryURLIndexFactory() {}
diff --git a/ios/chrome/browser/ios_chrome_io_thread.mm b/ios/chrome/browser/ios_chrome_io_thread.mm
index d29695a..61dfa99 100644
--- a/ios/chrome/browser/ios_chrome_io_thread.mm
+++ b/ios/chrome/browser/ios_chrome_io_thread.mm
@@ -43,7 +43,6 @@
 #include "ios/web/public/web_client.h"
 #include "ios/web/public/web_thread.h"
 #include "net/base/external_estimate_provider.h"
-#include "net/base/net_util.h"
 #include "net/base/network_quality_estimator.h"
 #include "net/base/sdch_manager.h"
 #include "net/cert/cert_verifier.h"
diff --git a/ios/chrome/browser/ntp_snippets/ios_chrome_ntp_snippets_service_factory.cc b/ios/chrome/browser/ntp_snippets/ios_chrome_ntp_snippets_service_factory.cc
index 4fa922e..0602d85 100644
--- a/ios/chrome/browser/ntp_snippets/ios_chrome_ntp_snippets_service_factory.cc
+++ b/ios/chrome/browser/ntp_snippets/ios_chrome_ntp_snippets_service_factory.cc
@@ -7,9 +7,17 @@
 #include "base/logging.h"
 #include "base/memory/singleton.h"
 #include "components/keyed_service/ios/browser_state_dependency_manager.h"
+#include "components/ntp_snippets/ntp_snippets_fetcher.h"
 #include "components/ntp_snippets/ntp_snippets_service.h"
+#include "components/signin/core/browser/profile_oauth2_token_service.h"
+#include "google_apis/gaia/oauth2_token_service.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/signin/oauth2_token_service_factory.h"
+#include "ios/chrome/browser/signin/signin_manager_factory.h"
+#include "ios/web/public/browser_state.h"
+#include "ios/web/public/web_thread.h"
+#include "net/url_request/url_request_context_getter.h"
 
 // static
 IOSChromeNTPSnippetsServiceFactory*
@@ -36,7 +44,24 @@
 scoped_ptr<KeyedService>
 IOSChromeNTPSnippetsServiceFactory::BuildServiceInstanceFor(
     web::BrowserState* browser_state) const {
+  ios::ChromeBrowserState* chrome_browser_state =
+      ios::ChromeBrowserState::FromBrowserState(browser_state);
   DCHECK(!browser_state->IsOffTheRecord());
+  SigninManager* signin_manager =
+      ios::SigninManagerFactory::GetForBrowserState(chrome_browser_state);
+  OAuth2TokenService* token_service =
+      OAuth2TokenServiceFactory::GetForBrowserState(chrome_browser_state);
+  scoped_refptr<net::URLRequestContextGetter> request_context =
+      browser_state->GetRequestContext();
+
+  scoped_refptr<base::SequencedTaskRunner> task_runner =
+      web::WebThread::GetBlockingPool()
+          ->GetSequencedTaskRunnerWithShutdownBehavior(
+              base::SequencedWorkerPool::GetSequenceToken(),
+              base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
   return make_scoped_ptr(new ntp_snippets::NTPSnippetsService(
-      GetApplicationContext()->GetApplicationLocale()));
+      task_runner, GetApplicationContext()->GetApplicationLocale(),
+      make_scoped_ptr(new ntp_snippets::NTPSnippetsFetcher(
+          task_runner, (SigninManagerBase*)signin_manager, token_service,
+          request_context, browser_state->GetStatePath()))));
 }
diff --git a/ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.mm b/ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.mm
index 5279db2db..6724251 100644
--- a/ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.mm
+++ b/ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.mm
@@ -99,7 +99,7 @@
 bool IOSChromeSavePasswordInfoBarDelegate::LinkClicked(
     WindowOpenDisposition disposition) {
   base::scoped_nsobject<OpenUrlCommand> command([[OpenUrlCommand alloc]
-       initWithURL:GURL(password_manager::kPasswordManagerAccountDashboardURL)
+       initWithURL:GURL(password_manager::kPasswordManagerHelpCenterSmartLock)
           referrer:web::Referrer()
         windowName:nil
        inIncognito:NO
diff --git a/ios/chrome/browser/reading_list/reading_list_model.cc b/ios/chrome/browser/reading_list/reading_list_model.cc
index bdc26516..073ec3b 100644
--- a/ios/chrome/browser/reading_list/reading_list_model.cc
+++ b/ios/chrome/browser/reading_list/reading_list_model.cc
@@ -4,7 +4,7 @@
 
 #include "ios/chrome/browser/reading_list/reading_list_model.h"
 
-ReadingListModel::ReadingListModel() {}
+ReadingListModel::ReadingListModel() : current_batch_updates_count_(0) {}
 ReadingListModel::~ReadingListModel() {}
 
 // Observer methods.
@@ -19,3 +19,30 @@
 void ReadingListModel::RemoveObserver(ReadingListModelObserver* observer) {
   observers_.RemoveObserver(observer);
 }
+
+// Batch update methods.
+bool ReadingListModel::IsPerformingBatchUpdates() const {
+  return current_batch_updates_count_ > 0;
+}
+
+std::unique_ptr<ReadingListModel::ScopedReadingListBatchUpdate>
+ReadingListModel::BeginBatchUpdates() {
+  std::unique_ptr<ReadingListModel::ScopedReadingListBatchUpdate> token(
+      new ReadingListModel::ScopedReadingListBatchUpdate(this));
+
+  ++current_batch_updates_count_;
+  if (current_batch_updates_count_ == 1) {
+    FOR_EACH_OBSERVER(ReadingListModelObserver, observers_,
+                      ReadingListModelBeganBatchUpdates(this));
+  }
+  return token;
+}
+
+void ReadingListModel::EndBatchUpdates() {
+  DCHECK(IsPerformingBatchUpdates());
+  --current_batch_updates_count_;
+  if (current_batch_updates_count_ == 0) {
+    FOR_EACH_OBSERVER(ReadingListModelObserver, observers_,
+                      ReadingListModelCompletedBatchUpdates(this));
+  }
+}
diff --git a/ios/chrome/browser/reading_list/reading_list_model.h b/ios/chrome/browser/reading_list/reading_list_model.h
index 196476e..dceb64d 100644
--- a/ios/chrome/browser/reading_list/reading_list_model.h
+++ b/ios/chrome/browser/reading_list/reading_list_model.h
@@ -25,11 +25,25 @@
 // (Usually the main thread). The observers callbacks are also sent on the main
 // thread.
 class ReadingListModel {
+ protected:
+  class ScopedReadingListBatchUpdate;
+
  public:
   // Returns true if the model finished loading. Until this returns true the
   // reading list is not ready for use.
   virtual bool loaded() const = 0;
 
+  // Returns true if the model is performing batch updates right now.
+  bool IsPerformingBatchUpdates() const;
+
+  // Tells model to prepare for batch updates.
+  // This method is reentrant, i.e. several batch updates may take place at the
+  // same time.
+  // Returns a scoped batch update object that should be retained while the
+  // batch update is performed. Deallocating this object will inform model that
+  // the batch update has completed.
+  std::unique_ptr<ScopedReadingListBatchUpdate> BeginBatchUpdates();
+
   // Returns the size of read and unread entries.
   virtual size_t unread_size() const = 0;
   virtual size_t read_size() const = 0;
@@ -70,6 +84,27 @@
   // The observers.
   base::ObserverList<ReadingListModelObserver> observers_;
 
+  // Tells model that batch updates have completed. Called from
+  // ReadingListBatchUpdateToken dtor.
+  void EndBatchUpdates();
+
+  // Helper class that is used to scope batch updates.
+  class ScopedReadingListBatchUpdate {
+   public:
+    explicit ScopedReadingListBatchUpdate(ReadingListModel* model)
+        : model_(model) {}
+
+    ~ScopedReadingListBatchUpdate() { model_->EndBatchUpdates(); }
+
+   private:
+    ReadingListModel* model_;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedReadingListBatchUpdate);
+  };
+
+ private:
+  unsigned int current_batch_updates_count_;
+
   DISALLOW_COPY_AND_ASSIGN(ReadingListModel);
 };
 
diff --git a/ios/chrome/browser/reading_list/reading_list_model_memory.h b/ios/chrome/browser/reading_list/reading_list_model_memory.h
index 1dda495..bec14c46 100644
--- a/ios/chrome/browser/reading_list/reading_list_model_memory.h
+++ b/ios/chrome/browser/reading_list/reading_list_model_memory.h
@@ -17,6 +17,7 @@
   void Shutdown() override;
 
   bool loaded() const override;
+
   size_t unread_size() const override;
   size_t read_size() const override;
 
diff --git a/ios/chrome/browser/reading_list/reading_list_model_observer.h b/ios/chrome/browser/reading_list/reading_list_model_observer.h
index 4881d3932..250e47b9 100644
--- a/ios/chrome/browser/reading_list/reading_list_model_observer.h
+++ b/ios/chrome/browser/reading_list/reading_list_model_observer.h
@@ -19,6 +19,17 @@
   // is unsafe to use the model.
   virtual void ReadingListModelLoaded(const ReadingListModel* model) = 0;
 
+  // Invoked when the batch updates are about to start. It will only be called
+  // once before ReadingListModelCompletedBatchUpdates, even if several updates
+  // are taking place at the same time.
+  virtual void ReadingListModelBeganBatchUpdates(
+      const ReadingListModel* model) {}
+
+  // Invoked when the batch updates have completed. This is called once all
+  // batch updates are completed.
+  virtual void ReadingListModelCompletedBatchUpdates(
+      const ReadingListModel* model) {}
+
   // Invoked from the destructor of the model. The model is no longer valid
   // after this call.
   virtual void ReadingListModelBeingDeleted(const ReadingListModel* model) {}
diff --git a/ios/chrome/browser/reading_list/reading_list_model_unittest.cc b/ios/chrome/browser/reading_list/reading_list_model_unittest.cc
index a863707..506c5eb3 100644
--- a/ios/chrome/browser/reading_list/reading_list_model_unittest.cc
+++ b/ios/chrome/browser/reading_list/reading_list_model_unittest.cc
@@ -17,12 +17,16 @@
   ~ReadingListModelTest() override {}
 
   void ClearCounts() {
-    observer_loaded_ = observer_deleted_ = observer_remove_unread_ =
-        observer_remove_read_ = observer_add_unread_ = observer_add_read_ =
-            observer_did_apply_ = 0;
+    observer_loaded_ = observer_started_batch_update_ =
+        observer_completed_batch_update_ = observer_deleted_ =
+            observer_remove_unread_ = observer_remove_read_ =
+                observer_add_unread_ = observer_add_read_ =
+                    observer_did_apply_ = 0;
   }
 
   void AssertObserverCount(int observer_loaded,
+                           int observer_started_batch_update,
+                           int observer_completed_batch_update,
                            int observer_deleted,
                            int observer_remove_unread,
                            int observer_remove_read,
@@ -30,6 +34,9 @@
                            int observer_add_read,
                            int observer_did_apply) {
     ASSERT_EQ(observer_loaded, observer_loaded_);
+    ASSERT_EQ(observer_started_batch_update, observer_started_batch_update_);
+    ASSERT_EQ(observer_completed_batch_update,
+              observer_completed_batch_update_);
     ASSERT_EQ(observer_deleted, observer_deleted_);
     ASSERT_EQ(observer_remove_unread, observer_remove_unread_);
     ASSERT_EQ(observer_remove_read, observer_remove_read_);
@@ -42,6 +49,14 @@
   void ReadingListModelLoaded(const ReadingListModel* model) override {
     observer_loaded_ += 1;
   }
+  void ReadingListModelBeganBatchUpdates(
+      const ReadingListModel* model) override {
+    observer_started_batch_update_ += 1;
+  }
+  void ReadingListModelCompletedBatchUpdates(
+      const ReadingListModel* model) override {
+    observer_completed_batch_update_ += 1;
+  }
   void ReadingListModelBeingDeleted(const ReadingListModel* model) override {
     observer_deleted_ += 1;
   }
@@ -67,6 +82,8 @@
 
  protected:
   int observer_loaded_;
+  int observer_started_batch_update_;
+  int observer_completed_batch_update_;
   int observer_deleted_;
   int observer_remove_unread_;
   int observer_remove_read_;
@@ -79,12 +96,12 @@
 
 TEST_F(ReadingListModelTest, EmptyLoaded) {
   EXPECT_TRUE(model_->loaded());
-  AssertObserverCount(1, 0, 0, 0, 0, 0, 0);
+  AssertObserverCount(1, 0, 0, 0, 0, 0, 0, 0, 0);
   EXPECT_EQ(0ul, model_->unread_size());
   EXPECT_EQ(0ul, model_->read_size());
   model_->Shutdown();
   EXPECT_FALSE(model_->loaded());
-  AssertObserverCount(1, 1, 0, 0, 0, 0, 0);
+  AssertObserverCount(1, 0, 0, 1, 0, 0, 0, 0, 0);
 }
 
 TEST_F(ReadingListModelTest, AddEntry) {
@@ -94,7 +111,7 @@
   EXPECT_EQ(GURL("http://example.com"), entry.url());
   EXPECT_EQ("sample", entry.title());
 
-  AssertObserverCount(0, 0, 0, 0, 1, 0, 1);
+  AssertObserverCount(0, 0, 0, 0, 0, 0, 1, 0, 1);
   EXPECT_EQ(1ul, model_->unread_size());
   EXPECT_EQ(0ul, model_->read_size());
   EXPECT_TRUE(model_->HasUnseenEntries());
@@ -110,7 +127,7 @@
 
   ClearCounts();
   model_->MarkReadByURL(GURL("http://example.com"));
-  AssertObserverCount(0, 0, 1, 0, 0, 1, 1);
+  AssertObserverCount(0, 0, 0, 0, 1, 0, 0, 1, 1);
   EXPECT_EQ(0ul, model_->unread_size());
   EXPECT_EQ(1ul, model_->read_size());
   EXPECT_FALSE(model_->HasUnseenEntries());
@@ -120,4 +137,45 @@
   EXPECT_EQ("sample", other_entry.title());
 }
 
+TEST_F(ReadingListModelTest, BatchUpdates) {
+  auto token = model_->BeginBatchUpdates();
+  AssertObserverCount(1, 1, 0, 0, 0, 0, 0, 0, 0);
+  EXPECT_TRUE(model_->IsPerformingBatchUpdates());
+
+  delete token.release();
+  AssertObserverCount(1, 1, 1, 0, 0, 0, 0, 0, 0);
+  EXPECT_FALSE(model_->IsPerformingBatchUpdates());
+}
+
+TEST_F(ReadingListModelTest, BatchUpdatesReentrant) {
+  // When two updates happen at the same time, the notification is only sent
+  // for beginning of first update and completion of last update.
+  EXPECT_FALSE(model_->IsPerformingBatchUpdates());
+
+  auto token = model_->BeginBatchUpdates();
+  AssertObserverCount(1, 1, 0, 0, 0, 0, 0, 0, 0);
+  EXPECT_TRUE(model_->IsPerformingBatchUpdates());
+
+  auto second_token = model_->BeginBatchUpdates();
+  AssertObserverCount(1, 1, 0, 0, 0, 0, 0, 0, 0);
+  EXPECT_TRUE(model_->IsPerformingBatchUpdates());
+
+  delete token.release();
+  AssertObserverCount(1, 1, 0, 0, 0, 0, 0, 0, 0);
+  EXPECT_TRUE(model_->IsPerformingBatchUpdates());
+
+  delete second_token.release();
+  AssertObserverCount(1, 1, 1, 0, 0, 0, 0, 0, 0);
+  EXPECT_FALSE(model_->IsPerformingBatchUpdates());
+
+  // Consequent updates send notifications.
+  auto third_token = model_->BeginBatchUpdates();
+  AssertObserverCount(1, 2, 1, 0, 0, 0, 0, 0, 0);
+  EXPECT_TRUE(model_->IsPerformingBatchUpdates());
+
+  delete third_token.release();
+  AssertObserverCount(1, 2, 2, 0, 0, 0, 0, 0, 0);
+  EXPECT_FALSE(model_->IsPerformingBatchUpdates());
+}
+
 }  // namespace
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.h b/ios/chrome/browser/sync/ios_chrome_sync_client.h
index d1535f86..a398c71d 100644
--- a/ios/chrome/browser/sync/ios_chrome_sync_client.h
+++ b/ios/chrome/browser/sync/ios_chrome_sync_client.h
@@ -38,8 +38,6 @@
   bookmarks::BookmarkModel* GetBookmarkModel() override;
   favicon::FaviconService* GetFaviconService() override;
   history::HistoryService* GetHistoryService() override;
-  sync_driver::ClearBrowsingDataCallback GetClearBrowsingDataCallback()
-      override;
   base::Closure GetPasswordStateChangedCallback() override;
   sync_driver::SyncApiComponentFactory::RegisterDataTypesMethod
   GetRegisterPlatformTypesCallback() override;
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
index dc5b80e..89007d3 100644
--- a/ios/chrome/browser/sync/ios_chrome_sync_client.mm
+++ b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
@@ -199,12 +199,6 @@
   return PersonalDataManagerFactory::GetForBrowserState(browser_state_);
 }
 
-sync_driver::ClearBrowsingDataCallback
-IOSChromeSyncClient::GetClearBrowsingDataCallback() {
-  return base::Bind(&IOSChromeSyncClient::ClearBrowsingData,
-                    base::Unretained(this));
-}
-
 base::Closure IOSChromeSyncClient::GetPasswordStateChangedCallback() {
   return base::Bind(
       &IOSChromePasswordStoreFactory::OnPasswordsSyncedStatePotentiallyChanged,
@@ -384,11 +378,6 @@
   return component_factory_.get();
 }
 
-void IOSChromeSyncClient::ClearBrowsingData(base::Time start, base::Time end) {
-  // This method should never be called on iOS.
-  NOTREACHED();
-}
-
 void IOSChromeSyncClient::SetSyncApiComponentFactoryForTesting(
     scoped_ptr<sync_driver::SyncApiComponentFactory> component_factory) {
   component_factory_ = std::move(component_factory);
diff --git a/ios/chrome/tools/build/ios_copy_files.py b/ios/chrome/tools/build/ios_copy_files.py
new file mode 100755
index 0000000..1a5074e
--- /dev/null
+++ b/ios/chrome/tools/build/ios_copy_files.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+# Copyright 2016 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 argparse
+import os
+import shutil
+import sys
+
+
+def DoMain(argv):
+  parser = argparse.ArgumentParser(description='Generate forwarding headers.')
+  parser.add_argument('-i', '--list-inputs', action='store_true',
+                      help='List input files and exit.')
+  parser.add_argument('-o', '--list-outputs', action='store_true',
+                      help='List output files and exit.')
+  parser.add_argument('-d', '--dest-dir', type=str,
+                      help=('Output directory for forwarding headers.'))
+  parser.add_argument('filenames', metavar='filename', type=str, nargs='+',
+                      help='Input filenames.')
+
+  args = parser.parse_args(argv)
+  if args.list_inputs:
+    return list_inputs(args.filenames)
+
+  if not args.dest_dir:
+    print '--dest-dir is required for this command.'
+    sys.exit(1)
+  if args.list_outputs:
+    return ' '.join(
+        os.path.join(args.dest_dir, os.path.basename(filename))
+        for filename in args.filenames)
+
+  if not os.path.isdir(args.dest_dir):
+    os.makedirs(args.dest_dir)
+  for filename in args.filenames:
+    target_filename = os.path.join(args.dest_dir, os.path.basename(filename))
+    if os.path.isfile(target_filename):
+      os.unlink(target_filename)
+    try:
+      os.link(filename, target_filename)
+    except OSError as e:
+      # Fallbacks to copy if hardlinking fails.
+      shutil.copy(filename, target_filename)
+
+
+if __name__ == '__main__':
+  results = DoMain(sys.argv[1:])
+  if results:
+    print results
diff --git a/ios/ios.gyp b/ios/ios.gyp
index 7d5fbf78..b29bdd2 100644
--- a/ios/ios.gyp
+++ b/ios/ios.gyp
@@ -23,6 +23,7 @@
         'provider/ios_provider_web.gyp:*',
         'testing/ios_testing.gyp:*',
         'third_party/fishhook/fishhook.gyp:*',
+        'third_party/ochamcrest/ochamcrest.gyp:*',
         'web/ios_web.gyp:*',
         'web/ios_web_inttests.gyp:*',
         'web/ios_web_shell.gyp:*',
diff --git a/ios/net/cookies/cookie_store_ios.h b/ios/net/cookies/cookie_store_ios.h
index 69da966..0e6a96fe 100644
--- a/ios/net/cookies/cookie_store_ios.h
+++ b/ios/net/cookies/cookie_store_ios.h
@@ -130,8 +130,10 @@
   void GetCookiesWithOptionsAsync(const GURL& url,
                                   const net::CookieOptions& options,
                                   const GetCookiesCallback& callback) override;
-  void GetAllCookiesForURLAsync(const GURL& url,
-                                const GetCookieListCallback& callback) override;
+  void GetCookieListWithOptionsAsync(
+      const GURL& url,
+      const net::CookieOptions& options,
+      const GetCookieListCallback& callback) override;
   void GetAllCookiesAsync(const GetCookieListCallback& callback) override;
   void DeleteCookieAsync(const GURL& url,
                          const std::string& cookie_name,
diff --git a/ios/net/cookies/cookie_store_ios.mm b/ios/net/cookies/cookie_store_ios.mm
index 70cff4f..1d957b21 100644
--- a/ios/net/cookies/cookie_store_ios.mm
+++ b/ios/net/cookies/cookie_store_ios.mm
@@ -221,8 +221,8 @@
 
 // Builds a cookie line (such as "key1=value1; key2=value2") from an array of
 // cookies.
-std::string BuildCookieLine(NSArray* cookies,
-                            const net::CookieOptions& options) {
+std::string BuildCookieLineWithOptions(NSArray* cookies,
+                                       const net::CookieOptions& options) {
   // The exclude_httponly() option would only be used by a javascript engine.
   DCHECK(!options.exclude_httponly());
 
@@ -520,35 +520,41 @@
       // engine.
       DCHECK(!options.exclude_httponly());
 
+      // TODO(mkwst): If/when iOS supports Same-Site cookies, we'll need to pass
+      // options in here as well. https://crbug.com/459154
       NSArray* cookies = GetCookiesForURL(system_store_,
                                           url, creation_time_manager_.get());
       if (!callback.is_null())
-        callback.Run(BuildCookieLine(cookies, options));
+        callback.Run(BuildCookieLineWithOptions(cookies, options));
       break;
   }
 }
 
-void CookieStoreIOS::GetAllCookiesForURLAsync(
+void CookieStoreIOS::GetCookieListWithOptionsAsync(
     const GURL& url,
+    const net::CookieOptions& options,
     const GetCookieListCallback& callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   switch (synchronization_state_) {
     case NOT_SYNCHRONIZED:
-      cookie_monster_->GetAllCookiesForURLAsync(url, callback);
+      cookie_monster_->GetCookieListWithOptionsAsync(url, options, callback);
       break;
     case SYNCHRONIZING:
-      tasks_pending_synchronization_.push_back(base::Bind(
-          &CookieStoreIOS::GetAllCookiesForURLAsync, this, url, callback));
+      tasks_pending_synchronization_.push_back(
+          base::Bind(&CookieStoreIOS::GetCookieListWithOptionsAsync, this, url,
+                     options, callback));
       break;
     case SYNCHRONIZED:
       if (!SystemCookiesAllowed()) {
         // If cookies are not allowed, the cookies are stashed in the
         // CookieMonster, so get them from there.
-        cookie_monster_->GetAllCookiesForURLAsync(url, callback);
+        cookie_monster_->GetCookieListWithOptionsAsync(url, options, callback);
         return;
       }
 
+      // TODO(mkwst): If/when iOS supports Same-Site cookies, we'll need to pass
+      // options in here as well. https://crbug.com/459154
       NSArray* cookies = GetCookiesForURL(system_store_,
                                           url, creation_time_manager_.get());
       net::CookieList cookie_list = CanonicalCookieListFromSystemCookies(
diff --git a/ios/net/cookies/cookie_store_ios_unittest.mm b/ios/net/cookies/cookie_store_ios_unittest.mm
index ac38dc7..2de2139 100644
--- a/ios/net/cookies/cookie_store_ios_unittest.mm
+++ b/ios/net/cookies/cookie_store_ios_unittest.mm
@@ -115,11 +115,12 @@
     store_->GetCookiesWithOptionsAsync(url, options, callback);
   }
 
-  void GetAllCookiesForURLAsync(
+  void GetCookieListWithOptionsAsync(
       const GURL& url,
+      const net::CookieOptions& options,
       const GetCookieListCallback& callback) override {
     RoundTrip();
-    store_->GetAllCookiesForURLAsync(url, callback);
+    store_->GetCookieListWithOptionsAsync(url, options, callback);
   }
 
   void GetAllCookiesAsync(const GetCookieListCallback& callback) override {
diff --git a/ios/net/crn_http_protocol_handler.mm b/ios/net/crn_http_protocol_handler.mm
index 155829da..477eb13 100644
--- a/ios/net/crn_http_protocol_handler.mm
+++ b/ios/net/crn_http_protocol_handler.mm
@@ -32,7 +32,6 @@
 #include "net/base/load_flags.h"
 #import "net/base/mac/url_conversions.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/upload_bytes_element_reader.h"
 #include "net/http/http_request_headers.h"
 #include "net/url_request/redirect_info.h"
diff --git a/ios/public/provider/chrome/browser/BUILD.gn b/ios/public/provider/chrome/browser/BUILD.gn
index f399afa5..e23994ad 100644
--- a/ios/public/provider/chrome/browser/BUILD.gn
+++ b/ios/public/provider/chrome/browser/BUILD.gn
@@ -14,8 +14,6 @@
     "signin/chrome_identity_service.mm",
     "signin/signin_error_provider.h",
     "signin/signin_error_provider.mm",
-    "string_provider.cc",
-    "string_provider.h",
     "ui/default_ios_web_view_factory.h",
     "ui/default_ios_web_view_factory.mm",
     "ui/infobar_view_delegate.h",
diff --git a/ios/third_party/fishhook/BUILD.gn b/ios/third_party/fishhook/BUILD.gn
new file mode 100644
index 0000000..00cdfaad
--- /dev/null
+++ b/ios/third_party/fishhook/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2016 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.
+
+config("fishhook_config") {
+  include_dirs = [ "src" ]
+  visibility = [ ":fishhook" ]
+}
+
+source_set("fishhook") {
+  testonly = true
+  sources = [
+    "src/fishhook.c",
+    "src/fishhook.h",
+  ]
+
+  public_configs = [ ":fishhook_config" ]
+  configs += [ ":fishhook_config" ]
+}
diff --git a/ios/third_party/fishhook/fishhook.gyp b/ios/third_party/fishhook/fishhook.gyp
index 5d32f755..968eb04 100644
--- a/ios/third_party/fishhook/fishhook.gyp
+++ b/ios/third_party/fishhook/fishhook.gyp
@@ -5,6 +5,7 @@
 {
   'targets': [
     {
+      # GN version: //ios/third_party/fishhook
       'target_name': 'fishhook',
       'type': 'static_library',
       'sources': [
diff --git a/ios/third_party/ochamcrest/BUILD.gn b/ios/third_party/ochamcrest/BUILD.gn
new file mode 100644
index 0000000..28c1795
--- /dev/null
+++ b/ios/third_party/ochamcrest/BUILD.gn
@@ -0,0 +1,205 @@
+# Copyright 2016 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.
+
+# OCHamcrest sources contains import rules using relative file names
+# ("HCAssertThat.h") and other using paths in an installed framework
+# (<OCHamcrest/HCMatcher.h>). In order to build, copy all the sources
+# to <(SHARED_INTERMEDIATE_DIR)/ios/third_party/ochmacrest/OCHamcrest
+# so that both type of import work (another option considered was to
+# build forwarding headers but this required duplicating the list of
+# files in GN build and was ruled out).
+#
+# To avoid ODR violation, direct import of ios/third_party/ochamcrest
+# is forbidden in ios/DEPS and code should instead use import as if
+# OCHamcrest was in a framework (i.e. #import <OCHamcrest/OCHamcrest.h>).
+copy("ochamcrest_copy_files") {
+  testonly = true
+  visibility = [ ":ochamcrest" ]
+  sources = [
+    "src/Source/Core/HCAssertThat.h",
+    "src/Source/Core/HCAssertThat.m",
+    "src/Source/Core/HCBaseDescription.h",
+    "src/Source/Core/HCBaseDescription.m",
+    "src/Source/Core/HCBaseMatcher.h",
+    "src/Source/Core/HCBaseMatcher.m",
+    "src/Source/Core/HCDescription.h",
+    "src/Source/Core/HCDiagnosingMatcher.h",
+    "src/Source/Core/HCDiagnosingMatcher.m",
+    "src/Source/Core/HCMatcher.h",
+    "src/Source/Core/HCSelfDescribing.h",
+    "src/Source/Core/HCStringDescription.h",
+    "src/Source/Core/HCStringDescription.m",
+    "src/Source/Core/Helpers/HCCollect.h",
+    "src/Source/Core/Helpers/HCCollect.m",
+    "src/Source/Core/Helpers/HCInvocationMatcher.h",
+    "src/Source/Core/Helpers/HCInvocationMatcher.m",
+    "src/Source/Core/Helpers/HCRequireNonNilObject.h",
+    "src/Source/Core/Helpers/HCRequireNonNilObject.m",
+    "src/Source/Core/Helpers/HCWrapInMatcher.h",
+    "src/Source/Core/Helpers/HCWrapInMatcher.m",
+    "src/Source/Core/Helpers/NSInvocation+OCHamcrest.h",
+    "src/Source/Core/Helpers/NSInvocation+OCHamcrest.m",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCBoolReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCBoolReturnGetter.m",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCCharReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCCharReturnGetter.m",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCDoubleReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCDoubleReturnGetter.m",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCFloatReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCFloatReturnGetter.m",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCIntReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCIntReturnGetter.m",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCLongLongReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCLongLongReturnGetter.m",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCLongReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCLongReturnGetter.m",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCObjectReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCObjectReturnGetter.m",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCReturnTypeHandlerChain.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCReturnTypeHandlerChain.m",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCReturnValueGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCReturnValueGetter.m",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCShortReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCShortReturnGetter.m",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedCharReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedCharReturnGetter.m",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedIntReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedIntReturnGetter.m",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedLongLongReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedLongLongReturnGetter.m",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedLongReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedLongReturnGetter.m",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedShortReturnGetter.h",
+    "src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedShortReturnGetter.m",
+    "src/Source/Core/Helpers/TestFailureReporters/HCGenericTestFailureReporter.h",
+    "src/Source/Core/Helpers/TestFailureReporters/HCGenericTestFailureReporter.m",
+    "src/Source/Core/Helpers/TestFailureReporters/HCSenTestFailureReporter.h",
+    "src/Source/Core/Helpers/TestFailureReporters/HCSenTestFailureReporter.m",
+    "src/Source/Core/Helpers/TestFailureReporters/HCTestFailure.h",
+    "src/Source/Core/Helpers/TestFailureReporters/HCTestFailure.m",
+    "src/Source/Core/Helpers/TestFailureReporters/HCTestFailureReporter.h",
+    "src/Source/Core/Helpers/TestFailureReporters/HCTestFailureReporter.m",
+    "src/Source/Core/Helpers/TestFailureReporters/HCTestFailureReporterChain.h",
+    "src/Source/Core/Helpers/TestFailureReporters/HCTestFailureReporterChain.m",
+    "src/Source/Core/Helpers/TestFailureReporters/HCXCTestFailureReporter.h",
+    "src/Source/Core/Helpers/TestFailureReporters/HCXCTestFailureReporter.m",
+    "src/Source/Library/Collection/HCEvery.h",
+    "src/Source/Library/Collection/HCEvery.m",
+    "src/Source/Library/Collection/HCHasCount.h",
+    "src/Source/Library/Collection/HCHasCount.m",
+    "src/Source/Library/Collection/HCIsCollectionContaining.h",
+    "src/Source/Library/Collection/HCIsCollectionContaining.m",
+    "src/Source/Library/Collection/HCIsCollectionContainingInAnyOrder.h",
+    "src/Source/Library/Collection/HCIsCollectionContainingInAnyOrder.m",
+    "src/Source/Library/Collection/HCIsCollectionContainingInOrder.h",
+    "src/Source/Library/Collection/HCIsCollectionContainingInOrder.m",
+    "src/Source/Library/Collection/HCIsCollectionContainingInRelativeOrder.h",
+    "src/Source/Library/Collection/HCIsCollectionContainingInRelativeOrder.m",
+    "src/Source/Library/Collection/HCIsCollectionOnlyContaining.h",
+    "src/Source/Library/Collection/HCIsCollectionOnlyContaining.m",
+    "src/Source/Library/Collection/HCIsDictionaryContaining.h",
+    "src/Source/Library/Collection/HCIsDictionaryContaining.m",
+    "src/Source/Library/Collection/HCIsDictionaryContainingEntries.h",
+    "src/Source/Library/Collection/HCIsDictionaryContainingEntries.m",
+    "src/Source/Library/Collection/HCIsDictionaryContainingKey.h",
+    "src/Source/Library/Collection/HCIsDictionaryContainingKey.m",
+    "src/Source/Library/Collection/HCIsDictionaryContainingValue.h",
+    "src/Source/Library/Collection/HCIsDictionaryContainingValue.m",
+    "src/Source/Library/Collection/HCIsEmptyCollection.h",
+    "src/Source/Library/Collection/HCIsEmptyCollection.m",
+    "src/Source/Library/Collection/HCIsIn.h",
+    "src/Source/Library/Collection/HCIsIn.m",
+    "src/Source/Library/Decorator/HCDescribedAs.h",
+    "src/Source/Library/Decorator/HCDescribedAs.m",
+    "src/Source/Library/Decorator/HCIs.h",
+    "src/Source/Library/Decorator/HCIs.m",
+    "src/Source/Library/Logical/HCAllOf.h",
+    "src/Source/Library/Logical/HCAllOf.m",
+    "src/Source/Library/Logical/HCAnyOf.h",
+    "src/Source/Library/Logical/HCAnyOf.m",
+    "src/Source/Library/Logical/HCIsAnything.h",
+    "src/Source/Library/Logical/HCIsAnything.m",
+    "src/Source/Library/Logical/HCIsNot.h",
+    "src/Source/Library/Logical/HCIsNot.m",
+    "src/Source/Library/Number/HCIsCloseTo.h",
+    "src/Source/Library/Number/HCIsCloseTo.m",
+    "src/Source/Library/Number/HCIsEqualToNumber.h",
+    "src/Source/Library/Number/HCIsEqualToNumber.m",
+    "src/Source/Library/Number/HCIsTrueFalse.h",
+    "src/Source/Library/Number/HCIsTrueFalse.m",
+    "src/Source/Library/Number/HCNumberAssert.h",
+    "src/Source/Library/Number/HCNumberAssert.m",
+    "src/Source/Library/Number/HCOrderingComparison.h",
+    "src/Source/Library/Number/HCOrderingComparison.m",
+    "src/Source/Library/Object/HCArgumentCaptor.h",
+    "src/Source/Library/Object/HCArgumentCaptor.m",
+    "src/Source/Library/Object/HCClassMatcher.h",
+    "src/Source/Library/Object/HCClassMatcher.m",
+    "src/Source/Library/Object/HCConformsToProtocol.h",
+    "src/Source/Library/Object/HCConformsToProtocol.m",
+    "src/Source/Library/Object/HCHasDescription.h",
+    "src/Source/Library/Object/HCHasDescription.m",
+    "src/Source/Library/Object/HCHasProperty.h",
+    "src/Source/Library/Object/HCHasProperty.m",
+    "src/Source/Library/Object/HCIsEqual.h",
+    "src/Source/Library/Object/HCIsEqual.m",
+    "src/Source/Library/Object/HCIsInstanceOf.h",
+    "src/Source/Library/Object/HCIsInstanceOf.m",
+    "src/Source/Library/Object/HCIsNil.h",
+    "src/Source/Library/Object/HCIsNil.m",
+    "src/Source/Library/Object/HCIsSame.h",
+    "src/Source/Library/Object/HCIsSame.m",
+    "src/Source/Library/Object/HCIsTypeOf.h",
+    "src/Source/Library/Object/HCIsTypeOf.m",
+    "src/Source/Library/Object/HCThrowsException.h",
+    "src/Source/Library/Object/HCThrowsException.m",
+    "src/Source/Library/Text/HCIsEqualIgnoringCase.h",
+    "src/Source/Library/Text/HCIsEqualIgnoringCase.m",
+    "src/Source/Library/Text/HCIsEqualIgnoringWhiteSpace.h",
+    "src/Source/Library/Text/HCIsEqualIgnoringWhiteSpace.m",
+    "src/Source/Library/Text/HCStringContains.h",
+    "src/Source/Library/Text/HCStringContains.m",
+    "src/Source/Library/Text/HCStringContainsInOrder.h",
+    "src/Source/Library/Text/HCStringContainsInOrder.m",
+    "src/Source/Library/Text/HCStringEndsWith.h",
+    "src/Source/Library/Text/HCStringEndsWith.m",
+    "src/Source/Library/Text/HCStringStartsWith.h",
+    "src/Source/Library/Text/HCStringStartsWith.m",
+    "src/Source/Library/Text/HCSubstringMatcher.h",
+    "src/Source/Library/Text/HCSubstringMatcher.m",
+    "src/Source/OCHamcrest.h",
+  ]
+  outputs = [
+    "$root_gen_dir/ios/third_party/ochamcrest/OCHamcrest/{{source_file_part}}",
+  ]
+}
+
+config("ochamcrest_config") {
+  visibility = [ ":ochamcrest" ]
+  libs = [ "XCTest.framework" ]
+  include_dirs = [ "$root_gen_dir/ios/third_party/ochamcrest" ]
+}
+
+config("ochamcrest_private_config") {
+  visibility = [ ":ochamcrest" ]
+
+  # TODO(crbug.com/589097): remove this once OCHamcrest source has been fixed
+  # by removing the semicolon in HCGenericTestFailureReporter.m.
+  cflags = [ "-Wno-semicolon-before-method-body" ]
+  cflags_objc = [ "-fobjc-arc" ]
+}
+
+source_set("ochamcrest") {
+  testonly = true
+  configs += [
+    ":ochamcrest_config",
+    ":ochamcrest_private_config",
+    "//build/config/compiler:no_chromium_code",
+  ]
+  public_configs = [ ":ochamcrest_config" ]
+  public_deps = [
+    ":ochamcrest_copy_files",
+  ]
+  sources = get_target_outputs(":ochamcrest_copy_files")
+}
diff --git a/ios/third_party/ochamcrest/LICENSE b/ios/third_party/ochamcrest/LICENSE
new file mode 100644
index 0000000..f6fcb1c4
--- /dev/null
+++ b/ios/third_party/ochamcrest/LICENSE
@@ -0,0 +1,13 @@
+OCHamcrest by Jon Reid, http://qualitycoding.org/about/
+Copyright 2016 hamcrest.org
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+Neither the name of Hamcrest nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+(BSD License)
diff --git a/ios/third_party/ochamcrest/OWNERS b/ios/third_party/ochamcrest/OWNERS
new file mode 100644
index 0000000..ff2123f
--- /dev/null
+++ b/ios/third_party/ochamcrest/OWNERS
@@ -0,0 +1,2 @@
+justincohen@chromium.org
+rohitrao@chromium.org
diff --git a/ios/third_party/ochamcrest/README.chromium b/ios/third_party/ochamcrest/README.chromium
new file mode 100644
index 0000000..a62a4df7
--- /dev/null
+++ b/ios/third_party/ochamcrest/README.chromium
@@ -0,0 +1,12 @@
+Name: OCHamcrest
+Short Name: OCHamcrest
+URL: https://github.com/hamcrest/OCHamcrest
+Version: 5.2.0
+License: BSD
+License File: NOT_SHIPPED
+Security Critical: no
+
+Description:
+OCHamcrest is the Objective-C implementation of Hamcrest, which
+provides the ability to create "matchers" which contain rules
+to verify that a given object matches those rules.
diff --git a/ios/third_party/ochamcrest/ochamcrest.gyp b/ios/third_party/ochamcrest/ochamcrest.gyp
new file mode 100644
index 0000000..993cee66
--- /dev/null
+++ b/ios/third_party/ochamcrest/ochamcrest.gyp
@@ -0,0 +1,238 @@
+# Copyright 2016 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.
+
+{
+  'chromium_sources': 0,
+  'variables': {
+    'ochamcrest_copy_dir': '<(SHARED_INTERMEDIATE_DIR)/ios/third_party/ochamcrest',
+    'ochamcrest_sources': [
+        'src/Source/Core/HCAssertThat.h',
+        'src/Source/Core/HCAssertThat.m',
+        'src/Source/Core/HCBaseDescription.h',
+        'src/Source/Core/HCBaseDescription.m',
+        'src/Source/Core/HCBaseMatcher.h',
+        'src/Source/Core/HCBaseMatcher.m',
+        'src/Source/Core/HCDescription.h',
+        'src/Source/Core/HCDiagnosingMatcher.h',
+        'src/Source/Core/HCDiagnosingMatcher.m',
+        'src/Source/Core/HCMatcher.h',
+        'src/Source/Core/HCSelfDescribing.h',
+        'src/Source/Core/HCStringDescription.h',
+        'src/Source/Core/HCStringDescription.m',
+        'src/Source/Core/Helpers/HCCollect.h',
+        'src/Source/Core/Helpers/HCCollect.m',
+        'src/Source/Core/Helpers/HCInvocationMatcher.h',
+        'src/Source/Core/Helpers/HCInvocationMatcher.m',
+        'src/Source/Core/Helpers/HCRequireNonNilObject.h',
+        'src/Source/Core/Helpers/HCRequireNonNilObject.m',
+        'src/Source/Core/Helpers/HCWrapInMatcher.h',
+        'src/Source/Core/Helpers/HCWrapInMatcher.m',
+        'src/Source/Core/Helpers/NSInvocation+OCHamcrest.h',
+        'src/Source/Core/Helpers/NSInvocation+OCHamcrest.m',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCBoolReturnGetter.h',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCBoolReturnGetter.m',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCCharReturnGetter.h',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCCharReturnGetter.m',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCDoubleReturnGetter.h',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCDoubleReturnGetter.m',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCFloatReturnGetter.h',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCFloatReturnGetter.m',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCIntReturnGetter.h',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCIntReturnGetter.m',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCLongLongReturnGetter.h',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCLongLongReturnGetter.m',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCLongReturnGetter.h',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCLongReturnGetter.m',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCObjectReturnGetter.h',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCObjectReturnGetter.m',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCReturnTypeHandlerChain.h',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCReturnTypeHandlerChain.m',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCReturnValueGetter.h',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCReturnValueGetter.m',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCShortReturnGetter.h',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCShortReturnGetter.m',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedCharReturnGetter.h',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedCharReturnGetter.m',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedIntReturnGetter.h',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedIntReturnGetter.m',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedLongLongReturnGetter.h',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedLongLongReturnGetter.m',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedLongReturnGetter.h',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedLongReturnGetter.m',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedShortReturnGetter.h',
+        'src/Source/Core/Helpers/ReturnValueGetters/HCUnsignedShortReturnGetter.m',
+        'src/Source/Core/Helpers/TestFailureReporters/HCGenericTestFailureReporter.h',
+        'src/Source/Core/Helpers/TestFailureReporters/HCGenericTestFailureReporter.m',
+        'src/Source/Core/Helpers/TestFailureReporters/HCSenTestFailureReporter.h',
+        'src/Source/Core/Helpers/TestFailureReporters/HCSenTestFailureReporter.m',
+        'src/Source/Core/Helpers/TestFailureReporters/HCTestFailure.h',
+        'src/Source/Core/Helpers/TestFailureReporters/HCTestFailure.m',
+        'src/Source/Core/Helpers/TestFailureReporters/HCTestFailureReporter.h',
+        'src/Source/Core/Helpers/TestFailureReporters/HCTestFailureReporter.m',
+        'src/Source/Core/Helpers/TestFailureReporters/HCTestFailureReporterChain.h',
+        'src/Source/Core/Helpers/TestFailureReporters/HCTestFailureReporterChain.m',
+        'src/Source/Core/Helpers/TestFailureReporters/HCXCTestFailureReporter.h',
+        'src/Source/Core/Helpers/TestFailureReporters/HCXCTestFailureReporter.m',
+        'src/Source/Library/Collection/HCEvery.h',
+        'src/Source/Library/Collection/HCEvery.m',
+        'src/Source/Library/Collection/HCHasCount.h',
+        'src/Source/Library/Collection/HCHasCount.m',
+        'src/Source/Library/Collection/HCIsCollectionContaining.h',
+        'src/Source/Library/Collection/HCIsCollectionContaining.m',
+        'src/Source/Library/Collection/HCIsCollectionContainingInAnyOrder.h',
+        'src/Source/Library/Collection/HCIsCollectionContainingInAnyOrder.m',
+        'src/Source/Library/Collection/HCIsCollectionContainingInOrder.h',
+        'src/Source/Library/Collection/HCIsCollectionContainingInOrder.m',
+        'src/Source/Library/Collection/HCIsCollectionContainingInRelativeOrder.h',
+        'src/Source/Library/Collection/HCIsCollectionContainingInRelativeOrder.m',
+        'src/Source/Library/Collection/HCIsCollectionOnlyContaining.h',
+        'src/Source/Library/Collection/HCIsCollectionOnlyContaining.m',
+        'src/Source/Library/Collection/HCIsDictionaryContaining.h',
+        'src/Source/Library/Collection/HCIsDictionaryContaining.m',
+        'src/Source/Library/Collection/HCIsDictionaryContainingEntries.h',
+        'src/Source/Library/Collection/HCIsDictionaryContainingEntries.m',
+        'src/Source/Library/Collection/HCIsDictionaryContainingKey.h',
+        'src/Source/Library/Collection/HCIsDictionaryContainingKey.m',
+        'src/Source/Library/Collection/HCIsDictionaryContainingValue.h',
+        'src/Source/Library/Collection/HCIsDictionaryContainingValue.m',
+        'src/Source/Library/Collection/HCIsEmptyCollection.h',
+        'src/Source/Library/Collection/HCIsEmptyCollection.m',
+        'src/Source/Library/Collection/HCIsIn.h',
+        'src/Source/Library/Collection/HCIsIn.m',
+        'src/Source/Library/Decorator/HCDescribedAs.h',
+        'src/Source/Library/Decorator/HCDescribedAs.m',
+        'src/Source/Library/Decorator/HCIs.h',
+        'src/Source/Library/Decorator/HCIs.m',
+        'src/Source/Library/Logical/HCAllOf.h',
+        'src/Source/Library/Logical/HCAllOf.m',
+        'src/Source/Library/Logical/HCAnyOf.h',
+        'src/Source/Library/Logical/HCAnyOf.m',
+        'src/Source/Library/Logical/HCIsAnything.h',
+        'src/Source/Library/Logical/HCIsAnything.m',
+        'src/Source/Library/Logical/HCIsNot.h',
+        'src/Source/Library/Logical/HCIsNot.m',
+        'src/Source/Library/Number/HCIsCloseTo.h',
+        'src/Source/Library/Number/HCIsCloseTo.m',
+        'src/Source/Library/Number/HCIsEqualToNumber.h',
+        'src/Source/Library/Number/HCIsEqualToNumber.m',
+        'src/Source/Library/Number/HCIsTrueFalse.h',
+        'src/Source/Library/Number/HCIsTrueFalse.m',
+        'src/Source/Library/Number/HCNumberAssert.h',
+        'src/Source/Library/Number/HCNumberAssert.m',
+        'src/Source/Library/Number/HCOrderingComparison.h',
+        'src/Source/Library/Number/HCOrderingComparison.m',
+        'src/Source/Library/Object/HCArgumentCaptor.h',
+        'src/Source/Library/Object/HCArgumentCaptor.m',
+        'src/Source/Library/Object/HCClassMatcher.h',
+        'src/Source/Library/Object/HCClassMatcher.m',
+        'src/Source/Library/Object/HCConformsToProtocol.h',
+        'src/Source/Library/Object/HCConformsToProtocol.m',
+        'src/Source/Library/Object/HCHasDescription.h',
+        'src/Source/Library/Object/HCHasDescription.m',
+        'src/Source/Library/Object/HCHasProperty.h',
+        'src/Source/Library/Object/HCHasProperty.m',
+        'src/Source/Library/Object/HCIsEqual.h',
+        'src/Source/Library/Object/HCIsEqual.m',
+        'src/Source/Library/Object/HCIsInstanceOf.h',
+        'src/Source/Library/Object/HCIsInstanceOf.m',
+        'src/Source/Library/Object/HCIsNil.h',
+        'src/Source/Library/Object/HCIsNil.m',
+        'src/Source/Library/Object/HCIsSame.h',
+        'src/Source/Library/Object/HCIsSame.m',
+        'src/Source/Library/Object/HCIsTypeOf.h',
+        'src/Source/Library/Object/HCIsTypeOf.m',
+        'src/Source/Library/Object/HCThrowsException.h',
+        'src/Source/Library/Object/HCThrowsException.m',
+        'src/Source/Library/Text/HCIsEqualIgnoringCase.h',
+        'src/Source/Library/Text/HCIsEqualIgnoringCase.m',
+        'src/Source/Library/Text/HCIsEqualIgnoringWhiteSpace.h',
+        'src/Source/Library/Text/HCIsEqualIgnoringWhiteSpace.m',
+        'src/Source/Library/Text/HCStringContains.h',
+        'src/Source/Library/Text/HCStringContains.m',
+        'src/Source/Library/Text/HCStringContainsInOrder.h',
+        'src/Source/Library/Text/HCStringContainsInOrder.m',
+        'src/Source/Library/Text/HCStringEndsWith.h',
+        'src/Source/Library/Text/HCStringEndsWith.m',
+        'src/Source/Library/Text/HCStringStartsWith.h',
+        'src/Source/Library/Text/HCStringStartsWith.m',
+        'src/Source/Library/Text/HCSubstringMatcher.h',
+        'src/Source/Library/Text/HCSubstringMatcher.m',
+        'src/Source/OCHamcrest.h',
+    ],
+  },
+  'targets': [
+    # OCHamcrest sources contains import rules using relative file names
+    # ("HCAssertThat.h") and other using paths in an installed framework
+    # (<OCHamcrest/HCMatcher.h>). In order to build, copy all the sources
+    # to <(SHARED_INTERMEDIATE_DIR)/ios/third_party/ochmacrest/OCHamcrest
+    # so that both type of import work (another option considered was to
+    # build forwarding headers but this required duplicating the list of
+    # files in GN build and was ruled out).
+    #
+    # To avoid ODR violation, direct import of ios/third_party/ochamcrest
+    # is forbidden in ios/DEPS and code should instead use import as if
+    # OCHamcrest was in a framework (i.e. #import <OCHamcrest/OCHamcrest.h>).
+    {
+      'target_name': 'ochamcrest_copy_sources',
+      'hard_dependency': 1,
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'copy_ochamcrest_sources',
+          'inputs': [
+            '../../chrome/tools/build/ios_copy_files.py',
+            '<@(ochamcrest_sources)',
+          ],
+          'outputs': [
+            '<!@pymod_do_main(ios_copy_files -o '
+                '--dest-dir <(ochamcrest_copy_dir)/OCHamcrest '
+                '<(ochamcrest_sources))',
+          ],
+          'action': [
+            'python',
+            '../../chrome/tools/build/ios_copy_files.py',
+            '--dest-dir',
+            '<(ochamcrest_copy_dir)/OCHamcrest/',
+            '<@(ochamcrest_sources)',
+          ],
+          'message': 'Copying OCHamcrest sources files',
+        },
+      ],
+    },
+    {
+      'target_name': 'ochamcrest',
+      'type': 'static_library',
+      'sources': [
+        '<!@pymod_do_main(ios_copy_files -o '
+            '--dest-dir <(ochamcrest_copy_dir)/OCHamcrest '
+            '<(ochamcrest_sources))',
+      ],
+      'include_dirs': [
+        '<(ochamcrest_copy_dir)',
+      ],
+      'xcode_settings': {
+        'CLANG_ENABLE_OBJC_ARC': 'YES',
+        # TODO(crbug.com/589097): remove this once OCHamcrest source has been
+        # fixed by removing the semicolon in HCGenericTestFailureReporter.m.
+       'WARNING_CFLAGS': [ '-Wno-semicolon-before-method-body' ]
+      },
+      'link_settings': {
+        'libraries': [
+          'XCTest.framework',
+        ],
+      },
+      'dependencies': [
+        'ochamcrest_copy_sources',
+      ],
+      'export_dependent_settings': [
+        'ochamcrest_copy_sources',
+      ],
+      'direct_dependent_settings': {
+        'include_dirs': [
+          '<(ochamcrest_copy_dir)',
+        ],
+      },
+    },
+  ],
+}
diff --git a/ios/web/public/origin_util.cc b/ios/web/public/origin_util.cc
index 43e002dd..28b39a9 100644
--- a/ios/web/public/origin_util.cc
+++ b/ios/web/public/origin_util.cc
@@ -4,7 +4,7 @@
 
 #include "ios/web/public/origin_util.h"
 
-#include "net/base/net_util.h"
+#include "net/base/url_util.h"
 #include "url/gurl.h"
 
 namespace web {
diff --git a/ios/web/public/web_controller_factory.h b/ios/web/public/web_controller_factory.h
index c0c7ab06..c6d1545 100644
--- a/ios/web/public/web_controller_factory.h
+++ b/ios/web/public/web_controller_factory.h
@@ -6,7 +6,6 @@
 #define IOS_WEB_PUBLIC_WEB_CONTROLLER_FACTORY_H_
 
 #include "base/memory/scoped_ptr.h"
-#include "ios/web/public/web_view_type.h"
 
 @class CRWWebController;
 
@@ -17,23 +16,6 @@
 
 // Returns a new instance of CRWWebViewController.
 // Note: Callers are responsible for releasing the returned web controller.
-// DEPRECATED: use CreateWebController(scoped_ptr<WebStateImpl>) instead.
-// TODO(crbug.com/588176): Remove this function.
-CRWWebController* CreateWebController(WebViewType web_view_type,
-                                      scoped_ptr<WebStateImpl> web_state);
-
-// Returns a new instance of CRWWebViewController.
-// Temporary factory method for use in components that require a web controller.
-// By requiring only the BrowserState, this eliminates the dependency on
-// WebStateImpl from components.
-// Note: Callers are responsible for releasing the returned web controller.
-// DEPRECATED: use CreateWebController(scoped_ptr<WebStateImpl>) instead.
-// TODO(crbug.com/588176): Remove this function.
-CRWWebController* CreateWebController(WebViewType web_view_type,
-                                      BrowserState* browser_state);
-
-// Returns a new instance of CRWWebViewController.
-// Note: Callers are responsible for releasing the returned web controller.
 CRWWebController* CreateWebController(scoped_ptr<WebStateImpl> web_state);
 
 // Returns a new instance of CRWWebViewController.
diff --git a/ios/web/public/web_controller_factory.mm b/ios/web/public/web_controller_factory.mm
index 85a6d01..e23e880 100644
--- a/ios/web/public/web_controller_factory.mm
+++ b/ios/web/public/web_controller_factory.mm
@@ -7,40 +7,21 @@
 #include <utility>
 
 #include "ios/web/public/browser_state.h"
-#import "ios/web/web_state/ui/crw_ui_web_view_web_controller.h"
 #import "ios/web/web_state/ui/crw_wk_web_view_web_controller.h"
 #include "ios/web/web_state/web_state_impl.h"
 
 namespace web {
 
-CRWWebController* CreateWebController(WebViewType web_view_type,
-                                      scoped_ptr<WebStateImpl> web_state) {
-  switch (web_view_type) {
-    case UI_WEB_VIEW_TYPE:
-      return [[CRWUIWebViewWebController alloc]
-          initWithWebState:std::move(web_state)];
-    case WK_WEB_VIEW_TYPE:
-      return [[CRWWKWebViewWebController alloc]
-          initWithWebState:std::move(web_state)];
-  }
-  NOTREACHED();
-  return nil;
-}
-
-CRWWebController* CreateWebController(WebViewType web_view_type,
-                                      BrowserState* browser_state) {
-  DCHECK(browser_state);
-  scoped_ptr<web::WebStateImpl> web_state(new web::WebStateImpl(browser_state));
-  web_state->GetNavigationManagerImpl().InitializeSession(nil, nil, NO, -1);
-  return CreateWebController(web_view_type, std::move(web_state));
-}
-
 CRWWebController* CreateWebController(scoped_ptr<WebStateImpl> web_state) {
-  return CreateWebController(WK_WEB_VIEW_TYPE, std::move(web_state));
+  return
+      [[CRWWKWebViewWebController alloc] initWithWebState:std::move(web_state)];
 }
 
 CRWWebController* CreateWebController(BrowserState* browser_state) {
-  return CreateWebController(WK_WEB_VIEW_TYPE, browser_state);
+  DCHECK(browser_state);
+  scoped_ptr<web::WebStateImpl> web_state(new web::WebStateImpl(browser_state));
+  web_state->GetNavigationManagerImpl().InitializeSession(nil, nil, NO, -1);
+  return CreateWebController(std::move(web_state));
 }
 
 }  // namespace web
diff --git a/ios/web/public/web_state/crw_web_view_proxy.h b/ios/web/public/web_state/crw_web_view_proxy.h
index 09da935..634b042 100644
--- a/ios/web/public/web_state/crw_web_view_proxy.h
+++ b/ios/web/public/web_state/crw_web_view_proxy.h
@@ -45,6 +45,11 @@
 // Retuns the type of the web view this proxy manages.
 @property(nonatomic, readonly) web::WebViewType webViewType;
 
+// Whether or not the content view should use the content inset when setting
+// |topContentPadding|. Implementations may or may not respect the setting
+// of this property.
+@property(nonatomic, assign) BOOL shouldUseInsetForTopPadding;
+
 // Register the given insets for the given caller.
 - (void)registerInsets:(UIEdgeInsets)insets forCaller:(id)caller;
 
diff --git a/ios/web/public/web_state/ui/crw_content_view.h b/ios/web/public/web_state/ui/crw_content_view.h
index bc39db33..fb04b6c 100644
--- a/ios/web/public/web_state/ui/crw_content_view.h
+++ b/ios/web/public/web_state/ui/crw_content_view.h
@@ -26,6 +26,12 @@
 // TODO(stuartmorgan): See if this can be removed from the public interface.
 - (BOOL)isViewAlive;
 
+@optional
+
+// Whether or not the content view should use the content inset when setting
+// |topContentPadding|.
+@property(nonatomic, assign) BOOL shouldUseInsetForTopPadding;
+
 @end
 
 // Convenience type for content views.
diff --git a/ios/web/web_state/crw_web_view_proxy_impl.mm b/ios/web/web_state/crw_web_view_proxy_impl.mm
index 47f0337..b405332 100644
--- a/ios/web/web_state/crw_web_view_proxy_impl.mm
+++ b/ios/web/web_state/crw_web_view_proxy_impl.mm
@@ -113,6 +113,19 @@
   return [_webController webViewType];
 }
 
+- (BOOL)shouldUseInsetForTopPadding {
+  SEL shouldUseInsetSelector = @selector(shouldUseInsetForTopPadding);
+  return [_contentView respondsToSelector:shouldUseInsetSelector] &&
+         [_contentView shouldUseInsetForTopPadding];
+}
+
+- (void)setShouldUseInsetForTopPadding:(BOOL)shouldUseInsetForTopPadding {
+  if ([_contentView
+          respondsToSelector:@selector(setShouldUseInsetForTopPadding:)]) {
+    [_contentView setShouldUseInsetForTopPadding:shouldUseInsetForTopPadding];
+  }
+}
+
 - (void)registerInsets:(UIEdgeInsets)insets forCaller:(id)caller {
   NSValue* callerValue = [NSValue valueWithNonretainedObject:caller];
   if ([_registeredInsets objectForKey:callerValue])
diff --git a/ios/web/web_state/ui/crw_web_view_content_view.mm b/ios/web/web_state/ui/crw_web_view_content_view.mm
index 986973d6..060916e 100644
--- a/ios/web/web_state/ui/crw_web_view_content_view.mm
+++ b/ios/web/web_state/ui/crw_web_view_content_view.mm
@@ -38,6 +38,7 @@
 @implementation CRWWebViewContentView
 
 @synthesize webViewType = _webViewType;
+@synthesize shouldUseInsetForTopPadding = _shouldUseInsetForTopPadding;
 
 - (instancetype)initWithWebView:(UIView*)webView
                      scrollView:(UIScrollView*)scrollView {
@@ -122,14 +123,22 @@
 }
 
 - (CGFloat)topContentPadding {
-  return self.webViewType == web::WK_WEB_VIEW_TYPE
-             ? _topContentPadding
-             : [_scrollView contentInset].top;
+  BOOL isSettingWebViewFrame = self.webViewType == web::WK_WEB_VIEW_TYPE &&
+                               !self.shouldUseInsetForTopPadding;
+  return isSettingWebViewFrame ? _topContentPadding
+                               : [_scrollView contentInset].top;
 }
 
 - (void)setTopContentPadding:(CGFloat)newTopPadding {
-  if (self.webViewType == web::WK_WEB_VIEW_TYPE) {
+  if (self.webViewType == web::WK_WEB_VIEW_TYPE &&
+      !self.shouldUseInsetForTopPadding) {
     if (_topContentPadding != newTopPadding) {
+      // Update the content offset of the scroll view to match the padding
+      // that will be included in the frame.
+      CGFloat paddingChange = newTopPadding - _topContentPadding;
+      CGPoint contentOffset = [_scrollView contentOffset];
+      contentOffset.y += paddingChange;
+      [_scrollView setContentOffset:contentOffset];
       _topContentPadding = newTopPadding;
       // Update web view frame immediately to make |topContentPadding|
       // animatable.
@@ -142,6 +151,15 @@
   }
 }
 
+- (void)setShouldUseInsetForTopPadding:(BOOL)shouldUseInsetForTopPadding {
+  if (_shouldUseInsetForTopPadding != shouldUseInsetForTopPadding) {
+    CGFloat oldTopContentPadding = self.topContentPadding;
+    self.topContentPadding = 0.0f;
+    _shouldUseInsetForTopPadding = shouldUseInsetForTopPadding;
+    self.topContentPadding = oldTopContentPadding;
+  }
+}
+
 #pragma mark Private methods
 
 - (void)updateWebViewFrame {
diff --git a/ipc/attachment_broker.cc b/ipc/attachment_broker.cc
index b35c397..45fe120 100644
--- a/ipc/attachment_broker.cc
+++ b/ipc/attachment_broker.cc
@@ -138,6 +138,8 @@
 }
 
 AttachmentBroker::ObserverInfo::ObserverInfo() {}
+AttachmentBroker::ObserverInfo::ObserverInfo(const ObserverInfo& other) =
+    default;
 AttachmentBroker::ObserverInfo::~ObserverInfo() {}
 
 }  // namespace IPC
diff --git a/ipc/attachment_broker.h b/ipc/attachment_broker.h
index d936f44..9bca157 100644
--- a/ipc/attachment_broker.h
+++ b/ipc/attachment_broker.h
@@ -142,6 +142,7 @@
 
   struct ObserverInfo {
     ObserverInfo();
+    ObserverInfo(const ObserverInfo& other);
     ~ObserverInfo();
 
     Observer* observer;
diff --git a/jingle/glue/chrome_async_socket.cc b/jingle/glue/chrome_async_socket.cc
index 52b35b52..38bca588 100644
--- a/jingle/glue/chrome_async_socket.cc
+++ b/jingle/glue/chrome_async_socket.cc
@@ -18,7 +18,6 @@
 #include "net/base/address_list.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/io_buffer.h"
-#include "net/base/net_util.h"
 #include "net/socket/client_socket_handle.h"
 #include "net/socket/ssl_client_socket.h"
 #include "net/socket/tcp_client_socket.h"
diff --git a/jingle/glue/chrome_async_socket_unittest.cc b/jingle/glue/chrome_async_socket_unittest.cc
index fd8193da..0a9fd31 100644
--- a/jingle/glue/chrome_async_socket_unittest.cc
+++ b/jingle/glue/chrome_async_socket_unittest.cc
@@ -17,7 +17,6 @@
 #include "jingle/glue/resolving_client_socket_factory.h"
 #include "net/base/address_list.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/cert/mock_cert_verifier.h"
 #include "net/http/transport_security_state.h"
 #include "net/socket/socket_test_util.h"
diff --git a/jingle/glue/utils.cc b/jingle/glue/utils.cc
index 618ac5ca..d74c6bc 100644
--- a/jingle/glue/utils.cc
+++ b/jingle/glue/utils.cc
@@ -12,7 +12,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/values.h"
 #include "net/base/ip_endpoint.h"
-#include "net/base/net_util.h"
 #include "third_party/webrtc/base/byteorder.h"
 #include "third_party/webrtc/base/socketaddress.h"
 #include "third_party/webrtc/p2p/base/candidate.h"
diff --git a/mash/browser_driver/browser_driver_application_delegate.cc b/mash/browser_driver/browser_driver_application_delegate.cc
index 3bc7ede..674be254 100644
--- a/mash/browser_driver/browser_driver_application_delegate.cc
+++ b/mash/browser_driver/browser_driver_application_delegate.cc
@@ -52,7 +52,8 @@
 
 void BrowserDriverApplicationDelegate::Initialize(mojo::Shell* shell,
                                                   const std::string& url,
-                                                  uint32_t id) {
+                                                  uint32_t id,
+                                                  uint32_t user_id) {
   shell_ = shell;
   AddAccelerators();
 }
diff --git a/mash/browser_driver/browser_driver_application_delegate.h b/mash/browser_driver/browser_driver_application_delegate.h
index 2c1f981..ff2aa9a 100644
--- a/mash/browser_driver/browser_driver_application_delegate.h
+++ b/mash/browser_driver/browser_driver_application_delegate.h
@@ -28,7 +28,7 @@
  private:
   // mojo::ShellClient:
   void Initialize(mojo::Shell* shell, const std::string& url,
-                  uint32_t id) override;
+                  uint32_t id, uint32_t user_id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
   // mus::mojom::AcceleratorHandler:
diff --git a/mash/example/views_examples/views_examples_application_delegate.cc b/mash/example/views_examples/views_examples_application_delegate.cc
index ccdb1afc..9be2175e 100644
--- a/mash/example/views_examples/views_examples_application_delegate.cc
+++ b/mash/example/views_examples/views_examples_application_delegate.cc
@@ -18,7 +18,8 @@
 
 void ViewsExamplesApplicationDelegate::Initialize(mojo::Shell* shell,
                                                   const std::string& url,
-                                                  uint32_t id) {
+                                                  uint32_t id,
+                                                  uint32_t user_id) {
   tracing_.Initialize(shell, url);
   aura_init_.reset(new views::AuraInit(shell, "views_mus_resources.pak"));
 
diff --git a/mash/example/views_examples/views_examples_application_delegate.h b/mash/example/views_examples/views_examples_application_delegate.h
index a8d9a4f..90f28ce 100644
--- a/mash/example/views_examples/views_examples_application_delegate.h
+++ b/mash/example/views_examples/views_examples_application_delegate.h
@@ -22,7 +22,7 @@
  private:
   // mojo::ShellClient:
   void Initialize(mojo::Shell* shell, const std::string& url,
-                  uint32_t id) override;
+                  uint32_t id, uint32_t user_id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
   mojo::TracingImpl tracing_;
diff --git a/mash/example/window_type_launcher/main.cc b/mash/example/window_type_launcher/main.cc
index f41e6bc..3932a37 100644
--- a/mash/example/window_type_launcher/main.cc
+++ b/mash/example/window_type_launcher/main.cc
@@ -61,7 +61,7 @@
 
     mojo::edk::InitIPCSupport(&process_delegate, io_thread.task_runner().get());
 
-    mojo::ShellClientRequest request;
+    mojo::shell::mojom::ShellClientRequest request;
     scoped_ptr<mojo::shell::RunnerConnection> connection(
         mojo::shell::RunnerConnection::ConnectToRunner(
             &request, mojo::ScopedMessagePipeHandle()));
diff --git a/mash/example/window_type_launcher/window_type_launcher.cc b/mash/example/window_type_launcher/window_type_launcher.cc
index b8dcbb6..a5dacd0 100644
--- a/mash/example/window_type_launcher/window_type_launcher.cc
+++ b/mash/example/window_type_launcher/window_type_launcher.cc
@@ -356,7 +356,7 @@
 WindowTypeLauncher::~WindowTypeLauncher() {}
 
 void WindowTypeLauncher::Initialize(mojo::Shell* shell, const std::string& url,
-                                    uint32_t id) {
+                                    uint32_t id, uint32_t user_id) {
   aura_init_.reset(new views::AuraInit(shell, "views_mus_resources.pak"));
 
   views::WindowManagerConnection::Create(shell);
diff --git a/mash/example/window_type_launcher/window_type_launcher.h b/mash/example/window_type_launcher/window_type_launcher.h
index e1d9c6e..610c528 100644
--- a/mash/example/window_type_launcher/window_type_launcher.h
+++ b/mash/example/window_type_launcher/window_type_launcher.h
@@ -21,7 +21,7 @@
  private:
   // mojo::ShellClient:
   void Initialize(mojo::Shell* shell, const std::string& url,
-                  uint32_t id) override;
+                  uint32_t id, uint32_t user_id) override;
 
   scoped_ptr<views::AuraInit> aura_init_;
 
diff --git a/mash/quick_launch/quick_launch_application.cc b/mash/quick_launch/quick_launch_application.cc
index dc7f82a..8753f50 100644
--- a/mash/quick_launch/quick_launch_application.cc
+++ b/mash/quick_launch/quick_launch_application.cc
@@ -90,7 +90,8 @@
 
 void QuickLaunchApplication::Initialize(mojo::Shell* shell,
                                         const std::string& url,
-                                        uint32_t id) {
+                                        uint32_t id,
+                                        uint32_t user_id) {
   tracing_.Initialize(shell, url);
 
   aura_init_.reset(new views::AuraInit(shell, "views_mus_resources.pak"));
diff --git a/mash/quick_launch/quick_launch_application.h b/mash/quick_launch/quick_launch_application.h
index 70db23a2..07a6eba 100644
--- a/mash/quick_launch/quick_launch_application.h
+++ b/mash/quick_launch/quick_launch_application.h
@@ -26,7 +26,8 @@
   // mojo::ShellClient:
   void Initialize(mojo::Shell* shell,
                   const std::string& url,
-                  uint32_t id) override;
+                  uint32_t id,
+                  uint32_t user_id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
   mojo::TracingImpl tracing_;
diff --git a/mash/screenlock/screenlock.cc b/mash/screenlock/screenlock.cc
index 86f3bd4..e525664 100644
--- a/mash/screenlock/screenlock.cc
+++ b/mash/screenlock/screenlock.cc
@@ -76,7 +76,7 @@
 Screenlock::~Screenlock() {}
 
 void Screenlock::Initialize(mojo::Shell* shell, const std::string& url,
-                            uint32_t id) {
+                            uint32_t id, uint32_t user_id) {
   shell_ = shell;
   tracing_.Initialize(shell, url);
 
diff --git a/mash/screenlock/screenlock.h b/mash/screenlock/screenlock.h
index 60c8999..07f9de5 100644
--- a/mash/screenlock/screenlock.h
+++ b/mash/screenlock/screenlock.h
@@ -30,7 +30,7 @@
  private:
   // mojo::ShellClient:
   void Initialize(mojo::Shell* shell, const std::string& url,
-                  uint32_t id) override;
+                  uint32_t id, uint32_t user_id) override;
 
   // mash::shell::mojom::ScreenlockStateListener:
   void ScreenlockStateChanged(bool locked) override;
diff --git a/mash/shell/BUILD.gn b/mash/shell/BUILD.gn
index b4dbc89..3f52946f 100644
--- a/mash/shell/BUILD.gn
+++ b/mash/shell/BUILD.gn
@@ -8,17 +8,13 @@
 import("//mojo/public/tools/bindings/mojom.gni")
 import("//tools/grit/repack.gni")
 
-mojo_native_application("shell") {
-  output_name = "mash_shell"
-
+source_set("lib") {
   sources = [
-    "main.cc",
     "shell_application_delegate.cc",
     "shell_application_delegate.h",
   ]
 
   deps = [
-    ":manifest",
     "//base",
     "//mash/shell/public/interfaces",
     "//mojo/common",
@@ -35,6 +31,25 @@
   ]
 }
 
+mojo_native_application("shell") {
+  output_name = "mash_shell"
+
+  sources = [
+    "main.cc",
+  ]
+
+  deps = [
+    ":lib",
+    ":manifest",
+    "//base",
+    "//mash/shell/public/interfaces",
+    "//mojo/common",
+    "//mojo/public/cpp/bindings",
+    "//mojo/shell/public/cpp",
+    "//mojo/shell/public/cpp:sources",
+  ]
+}
+
 mojo_application_manifest("manifest") {
   application_name = "mash_shell"
   source = "manifest.json"
diff --git a/mash/shell/shell_application_delegate.cc b/mash/shell/shell_application_delegate.cc
index c538b73..9972514 100644
--- a/mash/shell/shell_application_delegate.cc
+++ b/mash/shell/shell_application_delegate.cc
@@ -19,7 +19,8 @@
 
 void ShellApplicationDelegate::Initialize(mojo::Shell* shell,
                                           const std::string& url,
-                                          uint32_t id) {
+                                          uint32_t id,
+                                          uint32_t user_id) {
   shell_ = shell;
   StartBrowserDriver();
   StartWindowManager();
diff --git a/mash/shell/shell_application_delegate.h b/mash/shell/shell_application_delegate.h
index 1047d3f..60a1d69b 100644
--- a/mash/shell/shell_application_delegate.h
+++ b/mash/shell/shell_application_delegate.h
@@ -34,7 +34,7 @@
  private:
   // mojo::ShellClient:
   void Initialize(mojo::Shell* shell, const std::string& url,
-                  uint32_t id) override;
+                  uint32_t id, uint32_t user_id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
   // mash::shell::mojom::Shell:
diff --git a/mash/task_viewer/task_viewer.cc b/mash/task_viewer/task_viewer.cc
index a099a3d1..552104f 100644
--- a/mash/task_viewer/task_viewer.cc
+++ b/mash/task_viewer/task_viewer.cc
@@ -266,7 +266,7 @@
 TaskViewer::~TaskViewer() {}
 
 void TaskViewer::Initialize(mojo::Shell* shell, const std::string& url,
-                            uint32_t id) {
+                            uint32_t id, uint32_t user_id) {
   tracing_.Initialize(shell, url);
 
   aura_init_.reset(new views::AuraInit(shell, "views_mus_resources.pak"));
diff --git a/mash/task_viewer/task_viewer.h b/mash/task_viewer/task_viewer.h
index 6c737da..0af60ef 100644
--- a/mash/task_viewer/task_viewer.h
+++ b/mash/task_viewer/task_viewer.h
@@ -28,7 +28,7 @@
  private:
   // mojo::ShellClient:
   void Initialize(mojo::Shell* shell, const std::string& url,
-                  uint32_t id) override;
+                  uint32_t id, uint32_t user_id) override;
 
   mojo::TracingImpl tracing_;
   scoped_ptr<views::AuraInit> aura_init_;
diff --git a/mash/wm/window_manager_application.cc b/mash/wm/window_manager_application.cc
index 0650c44..f02f613 100644
--- a/mash/wm/window_manager_application.cc
+++ b/mash/wm/window_manager_application.cc
@@ -105,7 +105,8 @@
 
 void WindowManagerApplication::Initialize(mojo::Shell* shell,
                                           const std::string& url,
-                                          uint32_t id) {
+                                          uint32_t id,
+                                          uint32_t user_id) {
   shell_ = shell;
   tracing_.Initialize(shell, url);
 
diff --git a/mash/wm/window_manager_application.h b/mash/wm/window_manager_application.h
index d8356f7..7699b9f 100644
--- a/mash/wm/window_manager_application.h
+++ b/mash/wm/window_manager_application.h
@@ -79,7 +79,7 @@
 
   // mojo::ShellClient:
   void Initialize(mojo::Shell* shell, const std::string& url,
-                  uint32_t id) override;
+                  uint32_t id, uint32_t user_id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
   // InterfaceFactory<mash::wm::mojom::UserWindowController>:
diff --git a/media/BUILD.gn b/media/BUILD.gn
index 02a4917f..18e1830f 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -115,6 +115,8 @@
     "capture/content/thread_safe_capture_oracle.h",
     "capture/content/video_capture_oracle.cc",
     "capture/content/video_capture_oracle.h",
+    "capture/device_monitor_mac.h",
+    "capture/device_monitor_mac.mm",
     "capture/video/android/video_capture_device_android.cc",
     "capture/video/android/video_capture_device_android.h",
     "capture/video/android/video_capture_device_factory_android.cc",
diff --git a/media/audio/mac/audio_low_latency_input_mac.cc b/media/audio/mac/audio_low_latency_input_mac.cc
index 4157c22..b945d7f 100644
--- a/media/audio/mac/audio_low_latency_input_mac.cc
+++ b/media/audio/mac/audio_low_latency_input_mac.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "media/audio/mac/audio_low_latency_input_mac.h"
-
 #include <CoreServices/CoreServices.h>
 
 #include "base/logging.h"
@@ -36,16 +35,22 @@
   return !(format_flags & kAudioFormatFlagIsNonInterleaved);
 }
 
+// Converts the 32-bit non-terminated 4 byte string into an std::string.
+// Example: code=1735354734 <=> 'goin' <=> kAudioDevicePropertyDeviceIsRunning.
+static std::string FourCharFormatCodeToString(UInt32 code) {
+  char code_string[5];
+  // Converts a 32-bit integer from the host’s native byte order to big-endian.
+  UInt32 code_id = CFSwapInt32HostToBig(code);
+  bcopy(&code_id, code_string, 4);
+  code_string[4] = '\0';
+  return std::string(code_string);
+}
+
 static std::ostream& operator<<(std::ostream& os,
                                 const AudioStreamBasicDescription& format) {
-  // The 32-bit integer format.mFormatID is actually a non-terminated 4 byte
-  // string. Example: kAudioFormatLinearPCM = 'lpcm'.
-  char format_id_string[5];
-  // Converts a 32-bit integer from the host’s native byte order to big-endian.
-  UInt32 format_id = CFSwapInt32HostToBig(format.mFormatID);
-  bcopy(&format_id, format_id_string, 4);
+  std::string format_string = FourCharFormatCodeToString(format.mFormatID);
   os << "sample rate       : " << format.mSampleRate << std::endl
-     << "format ID         : " << format_id_string << std::endl
+     << "format ID         : " << format_string << std::endl
      << "format flags      : " << format.mFormatFlags << std::endl
      << "bytes per packet  : " << format.mBytesPerPacket << std::endl
      << "frames per packet : " << format.mFramesPerPacket << std::endl
@@ -58,6 +63,47 @@
   return os;
 }
 
+// Property address to monitor device changes. Use wildcards to match any and
+// all values for their associated type. Filtering for device-specific
+// notifications will take place in the callback.
+const AudioObjectPropertyAddress
+    AUAudioInputStream::kDeviceChangePropertyAddress = {
+        kAudioObjectPropertySelectorWildcard, kAudioObjectPropertyScopeWildcard,
+        kAudioObjectPropertyElementWildcard};
+
+// Maps internal enumerator values (e.g. kAudioDevicePropertyDeviceHasChanged)
+// into local values that are suitable for UMA stats.
+// See AudioObjectPropertySelector in CoreAudio/AudioHardware.h for details.
+enum AudioDevicePropertyResult {
+  PROPERTY_OTHER = 0,  // Use for all non-supported property changes
+  PROPERTY_DEVICE_HAS_CHANGED = 1,
+  PROPERTY_IO_STOPPED_ABNORMALLY = 2,
+  PROPERTY_HOG_MODE = 3,
+  PROPERTY_BUFFER_FRAME_SIZE = 4,
+  PROPERTY_BUFFER_FRAME_SIZE_RANGE = 5,
+  PROPERTY_STREAM_CONFIGURATION = 6,
+  PROPERTY_ACTUAL_SAMPLE_RATE = 7,
+  PROPERTY_NOMINAL_SAMPLE_RATE = 8,
+  PROPERTY_DEVICE_IS_RUNNING_SOMEWHERE = 9,
+  PROPERTY_DEVICE_IS_RUNNING = 10,
+  PROPERTY_DEVICE_IS_ALIVE = 11,
+  PROPERTY_STREAM_PHYSICAL_FORMAT = 12,
+  PROPERTY_MAX = PROPERTY_STREAM_PHYSICAL_FORMAT
+};
+
+// Add the provided value in |result| to a UMA histogram.
+static void LogDevicePropertyChange(bool startup_failed,
+                                    AudioDevicePropertyResult result) {
+  if (startup_failed) {
+    UMA_HISTOGRAM_ENUMERATION(
+        "Media.Audio.InputDevicePropertyChangedStartupFailedMac", result,
+        PROPERTY_MAX + 1);
+  } else {
+    UMA_HISTOGRAM_ENUMERATION("Media.Audio.InputDevicePropertyChangedMac",
+                              result, PROPERTY_MAX + 1);
+  }
+}
+
 static OSStatus GetInputDeviceStreamFormat(
     AudioUnit audio_unit,
     AudioStreamBasicDescription* format) {
@@ -93,7 +139,8 @@
       input_callback_is_active_(false),
       start_was_deferred_(false),
       buffer_size_was_changed_(false),
-      audio_unit_render_has_worked_(false) {
+      audio_unit_render_has_worked_(false),
+      device_listener_is_active_(false) {
   DCHECK(manager_);
 
   // Set up the desired (output) format specified by the client.
@@ -135,6 +182,7 @@
 
 AUAudioInputStream::~AUAudioInputStream() {
   DVLOG(1) << "~dtor";
+  DCHECK(!device_listener_is_active_);
 }
 
 // Obtain and open the AUHAL AudioOutputUnit for recording.
@@ -151,6 +199,9 @@
     return false;
   }
 
+  // Start listening for changes in device properties.
+  RegisterDeviceChangeListener();
+
   // The requested sample-rate must match the hardware sample-rate.
   int sample_rate =
       AudioManagerMac::HardwareSampleRateForDevice(input_device_id_);
@@ -427,7 +478,14 @@
   if (IsRunning()) {
     Stop();
   }
+  // Uninitialize and dispose the audio unit.
   CloseAudioUnit();
+  // Disable the listener for device property changes.
+  DeRegisterDeviceChangeListener();
+  // Check if any device property changes are added by filtering out a selected
+  // set of the |device_property_changes_map_| map. Add UMA stats if valuable
+  // data is found.
+  AddDevicePropertyChangesToUMA(false);
   // Inform the audio manager that we have been closed. This will cause our
   // destruction.
   manager_->ReleaseInputStream(this);
@@ -750,22 +808,76 @@
   return noErr;
 }
 
+OSStatus AUAudioInputStream::OnDevicePropertyChanged(
+    AudioObjectID object_id,
+    UInt32 num_addresses,
+    const AudioObjectPropertyAddress addresses[],
+    void* context) {
+  AUAudioInputStream* self = static_cast<AUAudioInputStream*>(context);
+  return self->DevicePropertyChanged(object_id, num_addresses, addresses);
+}
+
+OSStatus AUAudioInputStream::DevicePropertyChanged(
+    AudioObjectID object_id,
+    UInt32 num_addresses,
+    const AudioObjectPropertyAddress addresses[]) {
+  if (object_id != input_device_id_)
+    return noErr;
+
+  // Listeners will be called when possibly many properties have changed.
+  // Consequently, the implementation of a listener must go through the array of
+  // addresses to see what exactly has changed.
+  for (UInt32 i = 0; i < num_addresses; ++i) {
+    const UInt32 property = addresses[i].mSelector;
+    // Use selector as key to a map and increase its value. We are not
+    // interested in all property changes but store all here anyhow.
+    // Filtering will be done later in AddDevicePropertyChangesToUMA();
+    ++device_property_changes_map_[property];
+  }
+  return noErr;
+}
+
+void AUAudioInputStream::RegisterDeviceChangeListener() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(!device_listener_is_active_);
+  DVLOG(1) << "RegisterDeviceChangeListener";
+  if (input_device_id_ == kAudioObjectUnknown)
+    return;
+  device_property_changes_map_.clear();
+  OSStatus result = AudioObjectAddPropertyListener(
+      input_device_id_, &kDeviceChangePropertyAddress,
+      &AUAudioInputStream::OnDevicePropertyChanged, this);
+  OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
+      << "AudioObjectAddPropertyListener() failed!";
+  device_listener_is_active_ = (result == noErr);
+}
+
+void AUAudioInputStream::DeRegisterDeviceChangeListener() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  if (!device_listener_is_active_)
+    return;
+  DVLOG(1) << "DeRegisterDeviceChangeListener";
+  if (input_device_id_ == kAudioObjectUnknown)
+    return;
+  device_listener_is_active_ = false;
+  OSStatus result = AudioObjectRemovePropertyListener(
+      input_device_id_, &kDeviceChangePropertyAddress,
+      &AUAudioInputStream::OnDevicePropertyChanged, this);
+  OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
+      << "AudioObjectRemovePropertyListener() failed!";
+}
+
 int AUAudioInputStream::HardwareSampleRate() {
   // Determine the default input device's sample-rate.
   AudioDeviceID device_id = kAudioObjectUnknown;
   UInt32 info_size = sizeof(device_id);
 
   AudioObjectPropertyAddress default_input_device_address = {
-    kAudioHardwarePropertyDefaultInputDevice,
-    kAudioObjectPropertyScopeGlobal,
-    kAudioObjectPropertyElementMaster
-  };
+      kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal,
+      kAudioObjectPropertyElementMaster};
   OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
-                                               &default_input_device_address,
-                                               0,
-                                               0,
-                                               &info_size,
-                                               &device_id);
+                                               &default_input_device_address, 0,
+                                               0, &info_size, &device_id);
   if (result != noErr)
     return 0.0;
 
@@ -773,16 +885,10 @@
   info_size = sizeof(nominal_sample_rate);
 
   AudioObjectPropertyAddress nominal_sample_rate_address = {
-    kAudioDevicePropertyNominalSampleRate,
-    kAudioObjectPropertyScopeGlobal,
-    kAudioObjectPropertyElementMaster
-  };
-  result = AudioObjectGetPropertyData(device_id,
-                                      &nominal_sample_rate_address,
-                                      0,
-                                      0,
-                                      &info_size,
-                                      &nominal_sample_rate);
+      kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal,
+      kAudioObjectPropertyElementMaster};
+  result = AudioObjectGetPropertyData(device_id, &nominal_sample_rate_address,
+                                      0, 0, &info_size, &nominal_sample_rate);
   if (result != noErr)
     return 0.0;
 
@@ -798,40 +904,35 @@
   // Get audio unit latency.
   Float64 audio_unit_latency_sec = 0.0;
   UInt32 size = sizeof(audio_unit_latency_sec);
-  OSStatus result = AudioUnitGetProperty(audio_unit_,
-                                         kAudioUnitProperty_Latency,
-                                         kAudioUnitScope_Global,
-                                         0,
-                                         &audio_unit_latency_sec,
-                                         &size);
+  OSStatus result = AudioUnitGetProperty(
+      audio_unit_, kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0,
+      &audio_unit_latency_sec, &size);
   OSSTATUS_DLOG_IF(WARNING, result != noErr, result)
       << "Could not get audio unit latency";
 
   // Get input audio device latency.
   AudioObjectPropertyAddress property_address = {
-    kAudioDevicePropertyLatency,
-    kAudioDevicePropertyScopeInput,
-    kAudioObjectPropertyElementMaster
-  };
+      kAudioDevicePropertyLatency, kAudioDevicePropertyScopeInput,
+      kAudioObjectPropertyElementMaster};
   UInt32 device_latency_frames = 0;
   size = sizeof(device_latency_frames);
   result = AudioObjectGetPropertyData(input_device_id_, &property_address, 0,
                                       nullptr, &size, &device_latency_frames);
   DLOG_IF(WARNING, result != noErr) << "Could not get audio device latency.";
 
-  return static_cast<double>((audio_unit_latency_sec *
-      format_.mSampleRate) + device_latency_frames);
+  return static_cast<double>((audio_unit_latency_sec * format_.mSampleRate) +
+                             device_latency_frames);
 }
 
 double AUAudioInputStream::GetCaptureLatency(
     const AudioTimeStamp* input_time_stamp) {
   // Get the delay between between the actual recording instant and the time
   // when the data packet is provided as a callback.
-  UInt64 capture_time_ns = AudioConvertHostTimeToNanos(
-      input_time_stamp->mHostTime);
+  UInt64 capture_time_ns =
+      AudioConvertHostTimeToNanos(input_time_stamp->mHostTime);
   UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
-  double delay_frames = static_cast<double>
-      (1e-9 * (now_ns - capture_time_ns) * format_.mSampleRate);
+  double delay_frames = static_cast<double>(1e-9 * (now_ns - capture_time_ns) *
+                                            format_.mSampleRate);
 
   // Total latency is composed by the dynamic latency and the fixed
   // hardware latency.
@@ -841,10 +942,8 @@
 int AUAudioInputStream::GetNumberOfChannelsFromStream() {
   // Get the stream format, to be able to read the number of channels.
   AudioObjectPropertyAddress property_address = {
-    kAudioDevicePropertyStreamFormat,
-    kAudioDevicePropertyScopeInput,
-    kAudioObjectPropertyElementMaster
-  };
+      kAudioDevicePropertyStreamFormat, kAudioDevicePropertyScopeInput,
+      kAudioObjectPropertyElementMaster};
   AudioStreamBasicDescription stream_format;
   UInt32 size = sizeof(stream_format);
   OSStatus result = AudioObjectGetPropertyData(
@@ -877,8 +976,8 @@
   // carries one extra level of information.
   UMA_HISTOGRAM_SPARSE_SLOWLY("Media.InputErrorMac",
                               GetInputCallbackIsActive() ? err : (err * -1));
-  NOTREACHED() << "error " << GetMacOSStatusErrorString(err)
-               << " (" << err << ")";
+  NOTREACHED() << "error " << GetMacOSStatusErrorString(err) << " (" << err
+               << ")";
   if (sink_)
     sink_->OnError(this);
 }
@@ -886,13 +985,10 @@
 bool AUAudioInputStream::IsVolumeSettableOnChannel(int channel) {
   Boolean is_settable = false;
   AudioObjectPropertyAddress property_address = {
-    kAudioDevicePropertyVolumeScalar,
-    kAudioDevicePropertyScopeInput,
-    static_cast<UInt32>(channel)
-  };
-  OSStatus result = AudioObjectIsPropertySettable(input_device_id_,
-                                                  &property_address,
-                                                  &is_settable);
+      kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeInput,
+      static_cast<UInt32>(channel)};
+  OSStatus result = AudioObjectIsPropertySettable(
+      input_device_id_, &property_address, &is_settable);
   return (result == noErr) ? is_settable : false;
 }
 
@@ -950,25 +1046,105 @@
                             manager_->low_latency_input_streams());
   UMA_HISTOGRAM_COUNTS_1000("Media.Audio.NumberOfBasicInputStreamsMac",
                             manager_->basic_input_streams());
-  // |number_of_frames_| is set at construction and corresponds to the requested
-  // (by the client) number of audio frames per I/O buffer connected to the
-  // selected input device. Ideally, this size will be the same as the native
-  // I/O buffer size given by |io_buffer_frame_size_|.
+  // |number_of_frames_| is set at construction and corresponds to the
+  // requested (by the client) number of audio frames per I/O buffer connected
+  // to the selected input device. Ideally, this size will be the same as the
+  // native I/O buffer size given by |io_buffer_frame_size_|.
   UMA_HISTOGRAM_SPARSE_SLOWLY("Media.Audio.RequestedInputBufferFrameSizeMac",
                               number_of_frames_);
   DVLOG(1) << "number_of_frames_: " << number_of_frames_;
-  // This value indicates the number of frames in the IO buffers connected to
-  // the selected input device. It has been set by the audio manger in Open()
-  // and can be the same as |number_of_frames_|, which is the desired buffer
-  // size. These two values might differ if other streams are using the same
-  // device and any of these streams have asked for a smaller buffer size.
+  // This value indicates the number of frames in the IO buffers connected
+  // to the selected input device. It has been set by the audio manger in
+  // Open() and can be the same as |number_of_frames_|, which is the desired
+  // buffer size. These two values might differ if other streams are using the
+  // same device and any of these streams have asked for a smaller buffer size.
   UMA_HISTOGRAM_SPARSE_SLOWLY("Media.Audio.ActualInputBufferFrameSizeMac",
                               io_buffer_frame_size_);
   DVLOG(1) << "io_buffer_frame_size_: " << io_buffer_frame_size_;
-  // TODO(henrika): this value will currently always report true. It should be
-  // fixed when we understand the problem better.
+  // TODO(henrika): this value will currently always report true. It should
+  // be fixed when we understand the problem better.
   UMA_HISTOGRAM_BOOLEAN("Media.Audio.AutomaticGainControlMac",
                         GetAutomaticGainControl());
+  // Disable the listener for device property changes. Ensures that we don't
+  // need a lock when reading the map.
+  DeRegisterDeviceChangeListener();
+  // Check if any device property changes are added by filtering out a selected
+  // set of the |device_property_changes_map_| map. Add UMA stats if valuable
+  // data is found.
+  AddDevicePropertyChangesToUMA(true);
+}
+
+void AUAudioInputStream::AddDevicePropertyChangesToUMA(bool startup_failed) {
+  DVLOG(1) << "AddDevicePropertyChangesToUMA";
+  DCHECK(!device_listener_is_active_);
+  // Scan the map of all available property changes (notification types) and
+  // filter out some that make sense to add to UMA stats.
+  // TODO(henrika): figure out if the set of stats is sufficient or not.
+  for (auto it = device_property_changes_map_.begin();
+       it != device_property_changes_map_.end(); ++it) {
+    UInt32 device_property = it->first;
+    int change_count = it->second;
+    AudioDevicePropertyResult uma_result = PROPERTY_OTHER;
+    switch (device_property) {
+      case kAudioDevicePropertyDeviceHasChanged:
+        uma_result = PROPERTY_DEVICE_HAS_CHANGED;
+        DVLOG(1) << "kAudioDevicePropertyDeviceHasChanged";
+        break;
+      case kAudioDevicePropertyIOStoppedAbnormally:
+        uma_result = PROPERTY_IO_STOPPED_ABNORMALLY;
+        DVLOG(1) << "kAudioDevicePropertyIOStoppedAbnormally";
+        break;
+      case kAudioDevicePropertyHogMode:
+        uma_result = PROPERTY_HOG_MODE;
+        DVLOG(1) << "kAudioDevicePropertyHogMode";
+        break;
+      case kAudioDevicePropertyBufferFrameSize:
+        uma_result = PROPERTY_BUFFER_FRAME_SIZE;
+        DVLOG(1) << "kAudioDevicePropertyBufferFrameSize";
+        break;
+      case kAudioDevicePropertyBufferFrameSizeRange:
+        uma_result = PROPERTY_BUFFER_FRAME_SIZE_RANGE;
+        DVLOG(1) << "kAudioDevicePropertyBufferFrameSizeRange";
+        break;
+      case kAudioDevicePropertyStreamConfiguration:
+        uma_result = PROPERTY_STREAM_CONFIGURATION;
+        DVLOG(1) << "kAudioDevicePropertyStreamConfiguration";
+        break;
+      case kAudioDevicePropertyActualSampleRate:
+        uma_result = PROPERTY_ACTUAL_SAMPLE_RATE;
+        DVLOG(1) << "kAudioDevicePropertyActualSampleRate";
+        break;
+      case kAudioDevicePropertyNominalSampleRate:
+        uma_result = PROPERTY_NOMINAL_SAMPLE_RATE;
+        DVLOG(1) << "kAudioDevicePropertyNominalSampleRate";
+        break;
+      case kAudioDevicePropertyDeviceIsRunningSomewhere:
+        uma_result = PROPERTY_DEVICE_IS_RUNNING_SOMEWHERE;
+        DVLOG(1) << "kAudioDevicePropertyDeviceIsRunningSomewhere";
+        break;
+      case kAudioDevicePropertyDeviceIsRunning:
+        uma_result = PROPERTY_DEVICE_IS_RUNNING;
+        DVLOG(1) << "kAudioDevicePropertyDeviceIsRunning";
+        break;
+      case kAudioDevicePropertyDeviceIsAlive:
+        uma_result = PROPERTY_DEVICE_IS_ALIVE;
+        DVLOG(1) << "kAudioDevicePropertyDeviceIsAlive";
+        break;
+      case kAudioStreamPropertyPhysicalFormat:
+        uma_result = PROPERTY_STREAM_PHYSICAL_FORMAT;
+        DVLOG(1) << "kAudioStreamPropertyPhysicalFormat";
+        break;
+      default:
+        uma_result = PROPERTY_OTHER;
+        DVLOG(1) << "Property change is ignored";
+        break;
+    }
+    DVLOG(1) << "property: " << device_property << " ("
+             << FourCharFormatCodeToString(device_property) << ")"
+             << " changed: " << change_count;
+    LogDevicePropertyChange(startup_failed, uma_result);
+  }
+  device_property_changes_map_.clear();
 }
 
 }  // namespace media
diff --git a/media/audio/mac/audio_low_latency_input_mac.h b/media/audio/mac/audio_low_latency_input_mac.h
index 6d2d8f5..c66c8143 100644
--- a/media/audio/mac/audio_low_latency_input_mac.h
+++ b/media/audio/mac/audio_low_latency_input_mac.h
@@ -38,14 +38,12 @@
 
 #include <AudioUnit/AudioUnit.h>
 #include <CoreAudio/CoreAudio.h>
-#include <stddef.h>
-#include <stdint.h>
+#include <map>
 
 #include "base/atomicops.h"
 #include "base/cancelable_callback.h"
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
@@ -94,6 +92,8 @@
   size_t requested_buffer_size() const { return number_of_frames_; }
 
  private:
+  static const AudioObjectPropertyAddress kDeviceChangePropertyAddress;
+
   // Callback functions called on a real-time priority I/O thread from the audio
   // unit. These methods are called when recorded audio is available.
   static OSStatus DataIsAvailable(void* context,
@@ -111,6 +111,23 @@
   OSStatus Provide(UInt32 number_of_frames, AudioBufferList* io_data,
                    const AudioTimeStamp* time_stamp);
 
+  // Callback functions called on different system threads from the Core Audio
+  // framework. These methods are called when device properties are changed.
+  static OSStatus OnDevicePropertyChanged(
+      AudioObjectID object_id,
+      UInt32 num_addresses,
+      const AudioObjectPropertyAddress addresses[],
+      void* context);
+  OSStatus DevicePropertyChanged(AudioObjectID object_id,
+                                 UInt32 num_addresses,
+                                 const AudioObjectPropertyAddress addresses[]);
+
+  // Registers OnDevicePropertyChanged() to receive notifications when device
+  // properties changes.
+  void RegisterDeviceChangeListener();
+  // Stop listening for changes in device properties.
+  void DeRegisterDeviceChangeListener();
+
   // Gets the fixed capture hardware latency and store it during initialization.
   // Returns 0 if not available.
   double GetHardwareLatency();
@@ -143,6 +160,10 @@
   // Adds extra UMA stats when it has been detected that startup failed.
   void AddHistogramsForFailedStartup();
 
+  // Scans the map of all available property changes (notification types) and
+  // filters out some that make sense to add to UMA stats.
+  void AddDevicePropertyChangesToUMA(bool startup_failed);
+
   // Verifies that Open(), Start(), Stop() and Close() are all called on the
   // creating thread which is the main browser thread (CrBrowserMain) on Mac.
   base::ThreadChecker thread_checker_;
@@ -218,6 +239,21 @@
   // Set to true once when AudioUnitRender() succeeds for the first time.
   bool audio_unit_render_has_worked_;
 
+  // Maps unique representations of device property notification types and
+  // number of times we have been notified about a change in such a type.
+  // While the notifier is active, this member is modified by several different
+  // internal thread. My guess is that a serial dispatch queue is used under
+  // the hood and it executes one task at a time in the order in which they are
+  // added to the queue. The currently executing task runs on a distinct thread
+  // (which can vary from task to task) that is managed by the dispatch queue.
+  // The map is always read on the creating thread but only while the notifier
+  // is disabled, hence no lock is required.
+  std::map<UInt32, int> device_property_changes_map_;
+
+  // Set to true when we are listening for changes in device properties.
+  // Only touched on the creating thread.
+  bool device_listener_is_active_;
+
   DISALLOW_COPY_AND_ASSIGN(AUAudioInputStream);
 };
 
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn
index ae207e1..adb1541 100644
--- a/media/base/BUILD.gn
+++ b/media/base/BUILD.gn
@@ -39,6 +39,8 @@
     "audio_hash.h",
     "audio_pull_fifo.cc",
     "audio_pull_fifo.h",
+    "audio_push_fifo.cc",
+    "audio_push_fifo.h",
     "audio_renderer.cc",
     "audio_renderer.h",
     "audio_renderer_mixer.cc",
@@ -139,8 +141,9 @@
     "null_video_sink.cc",
     "null_video_sink.h",
     "output_device.h",
-    "pipeline.cc",
     "pipeline.h",
+    "pipeline_impl.cc",
+    "pipeline_impl.h",
     "pipeline_status.h",
     "player_tracker.cc",
     "player_tracker.h",
@@ -383,6 +386,7 @@
     "audio_hardware_config_unittest.cc",
     "audio_hash_unittest.cc",
     "audio_pull_fifo_unittest.cc",
+    "audio_push_fifo_unittest.cc",
     "audio_renderer_mixer_input_unittest.cc",
     "audio_renderer_mixer_unittest.cc",
     "audio_shifter_unittest.cc",
@@ -406,7 +410,7 @@
     "moving_average_unittest.cc",
     "multi_channel_resampler_unittest.cc",
     "null_video_sink_unittest.cc",
-    "pipeline_unittest.cc",
+    "pipeline_impl_unittest.cc",
     "ranges_unittest.cc",
     "run_all_unittests.cc",
     "seekable_buffer_unittest.cc",
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
index adc7f774..8af3111 100644
--- a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
+++ b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
@@ -410,9 +410,9 @@
 
     @CalledByNative
     private boolean configureVideo(MediaFormat format, Surface surface, MediaCrypto crypto,
-            int flags) {
+            int flags, boolean allowAdaptivePlayback) {
         try {
-            if (mAdaptivePlaybackSupported) {
+            if (mAdaptivePlaybackSupported && allowAdaptivePlayback) {
                 format.setInteger(MediaFormat.KEY_MAX_WIDTH, MAX_ADAPTIVE_PLAYBACK_WIDTH);
                 format.setInteger(MediaFormat.KEY_MAX_HEIGHT, MAX_ADAPTIVE_PLAYBACK_HEIGHT);
             }
diff --git a/media/base/android/sdk_media_codec_bridge.cc b/media/base/android/sdk_media_codec_bridge.cc
index 1e767c82..6278216 100644
--- a/media/base/android/sdk_media_codec_bridge.cc
+++ b/media/base/android/sdk_media_codec_bridge.cc
@@ -560,11 +560,13 @@
 }
 
 // static
-VideoCodecBridge* VideoCodecBridge::CreateDecoder(const VideoCodec& codec,
-                                                  bool is_secure,
-                                                  const gfx::Size& size,
-                                                  jobject surface,
-                                                  jobject media_crypto) {
+VideoCodecBridge* VideoCodecBridge::CreateDecoder(
+    const VideoCodec& codec,
+    bool is_secure,
+    const gfx::Size& size,
+    jobject surface,
+    jobject media_crypto,
+    bool allow_adaptive_playback) {
   if (!MediaCodecUtil::IsMediaCodecAvailable())
     return nullptr;
 
@@ -583,9 +585,9 @@
       Java_MediaCodecBridge_createVideoDecoderFormat(
           env, j_mime.obj(), size.width(), size.height()));
   DCHECK(!j_format.is_null());
-  if (!Java_MediaCodecBridge_configureVideo(env, bridge->media_codec(),
-                                            j_format.obj(), surface,
-                                            media_crypto, 0)) {
+  if (!Java_MediaCodecBridge_configureVideo(
+          env, bridge->media_codec(), j_format.obj(), surface, media_crypto, 0,
+          allow_adaptive_playback)) {
     return nullptr;
   }
 
@@ -620,7 +622,7 @@
   DCHECK(!j_format.is_null());
   if (!Java_MediaCodecBridge_configureVideo(env, bridge->media_codec(),
                                             j_format.obj(), nullptr, nullptr,
-                                            kConfigureFlagEncode)) {
+                                            kConfigureFlagEncode, true)) {
     return nullptr;
   }
 
diff --git a/media/base/android/sdk_media_codec_bridge.h b/media/base/android/sdk_media_codec_bridge.h
index b729eab..bf072b41 100644
--- a/media/base/android/sdk_media_codec_bridge.h
+++ b/media/base/android/sdk_media_codec_bridge.h
@@ -162,10 +162,12 @@
   // Create, start, and return a VideoCodecBridge decoder or NULL on failure.
   static VideoCodecBridge* CreateDecoder(
       const VideoCodec& codec,  // e.g. media::kCodecVP8
-      bool is_secure,
-      const gfx::Size& size,  // Output frame size.
-      jobject surface,        // Output surface, optional.
-      jobject media_crypto);  // MediaCrypto object, optional.
+      bool is_secure,           // Will be used with encrypted content.
+      const gfx::Size& size,    // Output frame size.
+      jobject surface,          // Output surface, optional.
+      jobject media_crypto,     // MediaCrypto object, optional.
+      bool allow_adaptive_playback =
+          true);  // Should adaptive playback be allowed if supported.
 
   // Create, start, and return a VideoCodecBridge encoder or NULL on failure.
   static VideoCodecBridge* CreateEncoder(
diff --git a/media/base/audio_push_fifo.cc b/media/base/audio_push_fifo.cc
new file mode 100644
index 0000000..5e75967
--- /dev/null
+++ b/media/base/audio_push_fifo.cc
@@ -0,0 +1,86 @@
+// Copyright 2016 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 "media/base/audio_push_fifo.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+
+namespace media {
+
+AudioPushFifo::AudioPushFifo(const OutputCallback& callback)
+    : callback_(callback), frames_per_buffer_(0) {
+  DCHECK(!callback_.is_null());
+}
+
+AudioPushFifo::~AudioPushFifo() {}
+
+void AudioPushFifo::Reset(int frames_per_buffer) {
+  DCHECK_GT(frames_per_buffer, 0);
+
+  audio_queue_.reset();
+  queued_frames_ = 0;
+
+  frames_per_buffer_ = frames_per_buffer;
+}
+
+void AudioPushFifo::Push(const AudioBus& input_bus) {
+  DCHECK_GT(frames_per_buffer_, 0);
+
+  // Fast path: No buffering required.
+  if ((queued_frames_ == 0) && (input_bus.frames() == frames_per_buffer_)) {
+    callback_.Run(input_bus, 0);
+    return;
+  }
+
+  // Lazy-create the |audio_queue_| if needed.
+  if (!audio_queue_ || audio_queue_->channels() != input_bus.channels())
+    audio_queue_ = AudioBus::Create(input_bus.channels(), frames_per_buffer_);
+
+  // Start with a frame offset that refers to the position of the first sample
+  // in |audio_queue_| relative to the first sample in |input_bus|.
+  int frame_delay = -queued_frames_;
+
+  // Repeatedly fill up |audio_queue_| with more sample frames from |input_bus|
+  // and deliver batches until all sample frames in |input_bus| have been
+  // consumed.
+  int input_offset = 0;
+  do {
+    // Attempt to fill |audio_queue_| completely.
+    const int frames_to_enqueue =
+        std::min(static_cast<int>(input_bus.frames() - input_offset),
+                 frames_per_buffer_ - queued_frames_);
+    if (frames_to_enqueue > 0) {
+      DVLOG(2) << "Enqueuing " << frames_to_enqueue << " frames.";
+      input_bus.CopyPartialFramesTo(input_offset, frames_to_enqueue,
+                                    queued_frames_, audio_queue_.get());
+      queued_frames_ += frames_to_enqueue;
+      input_offset += frames_to_enqueue;
+    }
+
+    // If |audio_queue_| has been filled completely, deliver the re-buffered
+    // audio to the consumer.
+    if (queued_frames_ == frames_per_buffer_) {
+      DVLOG(2) << "Delivering another " << queued_frames_ << " frames.";
+      callback_.Run(*audio_queue_, frame_delay);
+      frame_delay += frames_per_buffer_;
+      queued_frames_ = 0;
+    } else {
+      // Not enough frames queued-up yet to deliver more frames.
+    }
+  } while (input_offset < input_bus.frames());
+}
+
+void AudioPushFifo::Flush() {
+  if (queued_frames_ == 0)
+    return;
+
+  audio_queue_->ZeroFramesPartial(queued_frames_,
+                                  audio_queue_->frames() - queued_frames_);
+  callback_.Run(*audio_queue_, -queued_frames_);
+  queued_frames_ = 0;
+}
+
+}  // namespace media
diff --git a/media/base/audio_push_fifo.h b/media/base/audio_push_fifo.h
new file mode 100644
index 0000000..8512cd1
--- /dev/null
+++ b/media/base/audio_push_fifo.h
@@ -0,0 +1,73 @@
+// Copyright 2016 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 MEDIA_BASE_AUDIO_PUSH_FIFO_H_
+#define MEDIA_BASE_AUDIO_PUSH_FIFO_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "media/base/audio_bus.h"
+#include "media/base/media_export.h"
+
+namespace media {
+
+// Yet another FIFO for audio data that re-buffers audio to a desired buffer
+// size.  Unlike AudioFifo and AudioBlockFifo, this FIFO cannot overflow: The
+// client is required to provide a callback that is called synchronously during
+// a push whenever enough data becomes available.  This implementation
+// eliminates redundant memory copies when the input buffer size always matches
+// the desired buffer size.
+class MEDIA_EXPORT AudioPushFifo final {
+ public:
+  // Called synchronously zero, one, or multiple times during a call to Push()
+  // to deliver re-buffered audio.  |frame_delay| refers to the position of the
+  // first frame in |output| relative to the first frame in the Push() call.  If
+  // negative, this indicates the output contains some data from a prior call to
+  // Push().  If zero or positive, the output contains data from the current
+  // call to Push().  Clients can use this to adjust timestamps.
+  using OutputCallback =
+      base::Callback<void(const AudioBus& output_bus, int frame_delay)>;
+
+  // Creates a new AudioPushFifo which delivers re-buffered audio by running
+  // |callback|.
+  explicit AudioPushFifo(const OutputCallback& callback);
+
+  ~AudioPushFifo();
+
+  // Returns the number of frames in each AudioBus delivered to the
+  // OutputCallback.
+  int frames_per_buffer() const { return frames_per_buffer_; }
+
+  // Must be called at least once before the first call to Push().  May be
+  // called later (e.g., to support an audio format change).
+  void Reset(int frames_per_buffer);
+
+  // Pushes all audio channel data from |input_bus| through the FIFO.  This will
+  // result in zero, one, or multiple synchronous calls to the OutputCallback
+  // provided in the constructor.  If the |input_bus| has a different number of
+  // channels than the prior Push() call, any currently-queued frames will be
+  // dropped.
+  void Push(const AudioBus& input_bus);
+
+  // Flushes any enqueued frames by invoking the OutputCallback with those
+  // frames plus padded zero samples.  If there are no frames currently
+  // enqueued, OutputCallback is not run.
+  void Flush();
+
+ private:
+  const OutputCallback callback_;
+
+  int frames_per_buffer_;
+
+  // Queue of frames pending for delivery.
+  scoped_ptr<AudioBus> audio_queue_;
+  int queued_frames_;
+
+  DISALLOW_COPY_AND_ASSIGN(AudioPushFifo);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_BASE_AUDIO_PUSH_FIFO_H_
diff --git a/media/base/audio_push_fifo_unittest.cc b/media/base/audio_push_fifo_unittest.cc
new file mode 100644
index 0000000..8d815fd
--- /dev/null
+++ b/media/base/audio_push_fifo_unittest.cc
@@ -0,0 +1,256 @@
+// Copyright 2016 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 <limits>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/macros.h"
+#include "media/base/audio_bus.h"
+#include "media/base/audio_push_fifo.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+namespace {
+
+class AudioPushFifoTest : public testing::TestWithParam<int> {
+ public:
+  AudioPushFifoTest() {}
+  ~AudioPushFifoTest() override {}
+
+  int output_chunk_size() const { return GetParam(); }
+
+  void SetUp() final {
+    fifo_.reset(new AudioPushFifo(base::Bind(
+        &AudioPushFifoTest::ReceiveAndCheckNextChunk, base::Unretained(this))));
+    fifo_->Reset(output_chunk_size());
+    ASSERT_EQ(output_chunk_size(), fifo_->frames_per_buffer());
+  }
+
+ protected:
+  struct OutputChunkResult {
+    int num_frames;
+    float first_sample_value;
+    float last_sample_value;
+    int frame_delay;
+  };
+
+  // Returns the number of output chunks that should have been emitted given the
+  // number of input frames pushed so far.
+  size_t GetExpectedOutputChunks(int frames_pushed) const {
+    return static_cast<size_t>(frames_pushed / output_chunk_size());
+  }
+
+  // Returns the number of Push() calls to make in order to get at least 3
+  // output chunks.
+  int GetNumPushTestIterations(int input_chunk_size) const {
+    return 3 * std::max(1, output_chunk_size() / input_chunk_size);
+  }
+
+  // Repeatedly pushes constant-sized batches of input samples and checks that
+  // the input data is re-chunked correctly.
+  void RunSimpleRechunkTest(int input_chunk_size) {
+    const int num_iterations = GetNumPushTestIterations(input_chunk_size);
+
+    int sample_value = 0;
+    const scoped_ptr<AudioBus> audio_bus =
+        AudioBus::Create(1, input_chunk_size);
+
+    for (int i = 0; i < num_iterations; ++i) {
+      EXPECT_EQ(GetExpectedOutputChunks(i * input_chunk_size), results_.size());
+
+      // Fill audio data with predictable values.
+      for (int j = 0; j < audio_bus->frames(); ++j)
+        audio_bus->channel(0)[j] = static_cast<float>(sample_value++);
+
+      fifo_->Push(*audio_bus);
+      // Note: AudioPushFifo has just called ReceiveAndCheckNextChunk() zero or
+      // more times.
+    }
+    EXPECT_EQ(GetExpectedOutputChunks(num_iterations * input_chunk_size),
+              results_.size());
+
+    // Confirm first and last sample values that have been output are the
+    // expected ones.
+    ASSERT_FALSE(results_.empty());
+    EXPECT_EQ(0.0f, results_.front().first_sample_value);
+    const float last_value_in_last_chunk = static_cast<float>(
+        GetExpectedOutputChunks(num_iterations * input_chunk_size) *
+            output_chunk_size() -
+        1);
+    EXPECT_EQ(last_value_in_last_chunk, results_.back().last_sample_value);
+
+    // Confirm the expected frame delays for the first output chunk (or two).
+    if (input_chunk_size < output_chunk_size()) {
+      const int num_queued_before_first_output =
+          ((output_chunk_size() - 1) / input_chunk_size) * input_chunk_size;
+      EXPECT_EQ(-num_queued_before_first_output, results_.front().frame_delay);
+    } else if (input_chunk_size >= output_chunk_size()) {
+      EXPECT_EQ(0, results_[0].frame_delay);
+      if (input_chunk_size >= 2 * output_chunk_size()) {
+        EXPECT_EQ(output_chunk_size(), results_[1].frame_delay);
+      } else {
+        const int num_remaining_after_first_output =
+            input_chunk_size - output_chunk_size();
+        EXPECT_EQ(-num_remaining_after_first_output, results_[1].frame_delay);
+      }
+    }
+
+    const size_t num_results_before_flush = results_.size();
+    fifo_->Flush();
+    const size_t num_results_after_flush = results_.size();
+    if (num_results_after_flush > num_results_before_flush) {
+      EXPECT_NE(0, results_.back().frame_delay);
+      EXPECT_LT(-output_chunk_size(), results_.back().frame_delay);
+    }
+  }
+
+  // Returns a "random" integer in the range [begin,end).
+  int GetRandomInRange(int begin, int end) {
+    const int len = end - begin;
+    const int rand_offset = (len == 0) ? 0 : (NextRandomInt() % (end - begin));
+    return begin + rand_offset;
+  }
+
+  scoped_ptr<AudioPushFifo> fifo_;
+  std::vector<OutputChunkResult> results_;
+
+ private:
+  // Called by |fifo_| to deliver another chunk of audio.  Sanity checks
+  // the sample values are as expected, and without any dropped/duplicated, and
+  // adds a result to |results_|.
+  void ReceiveAndCheckNextChunk(const AudioBus& audio_bus, int frame_delay) {
+    OutputChunkResult result;
+    result.num_frames = audio_bus.frames();
+    result.first_sample_value = audio_bus.channel(0)[0];
+    result.last_sample_value = audio_bus.channel(0)[audio_bus.frames() - 1];
+    result.frame_delay = frame_delay;
+
+    // Check that each sample value is the previous sample value plus one.
+    for (int i = 1; i < audio_bus.frames(); ++i) {
+      const float expected_value = result.first_sample_value + i;
+      const float actual_value = audio_bus.channel(0)[i];
+      if (actual_value != expected_value) {
+        if (actual_value == 0.0f) {
+          // This chunk is probably being emitted by a Flush().  If that's true
+          // then the frame_delay will be negative and the rest of the
+          // |audio_bus| should be all zeroes.
+          ASSERT_GT(0, frame_delay);
+          for (int j = i + 1; j < audio_bus.frames(); ++j)
+            ASSERT_EQ(0.0f, audio_bus.channel(0)[j]);
+          break;
+        } else {
+          ASSERT_EQ(expected_value, actual_value) << "Sample at offset " << i
+                                                  << " is incorrect.";
+        }
+      }
+    }
+
+    results_.push_back(result);
+  }
+
+  // Note: Not using base::RandInt() because it is horribly slow on debug
+  // builds.  The following is a very simple, deterministic LCG:
+  int NextRandomInt() {
+    rand_seed_ = (1103515245 * rand_seed_ + 12345) % (1 << 31);
+    return static_cast<int>(rand_seed_);
+  }
+
+  uint32_t rand_seed_ = 0x7e110;
+
+  DISALLOW_COPY_AND_ASSIGN(AudioPushFifoTest);
+};
+
+// Tests an atypical edge case: Push()ing one frame at a time.
+TEST_P(AudioPushFifoTest, PushOneFrameAtATime) {
+  RunSimpleRechunkTest(1);
+}
+
+// Tests that re-chunking the audio from common platform input chunk sizes
+// works.
+TEST_P(AudioPushFifoTest, Push128FramesAtATime) {
+  RunSimpleRechunkTest(128);
+}
+TEST_P(AudioPushFifoTest, Push512FramesAtATime) {
+  RunSimpleRechunkTest(512);
+}
+
+// Tests that re-chunking the audio from common "10 ms" input chunk sizes
+// works (44100 Hz * 10 ms = 441, and 48000 Hz * 10 ms = 480).
+TEST_P(AudioPushFifoTest, Push441FramesAtATime) {
+  RunSimpleRechunkTest(441);
+}
+TEST_P(AudioPushFifoTest, Push480FramesAtATime) {
+  RunSimpleRechunkTest(480);
+}
+
+// Tests that re-chunking when input audio is provided in varying chunk sizes
+// works.
+TEST_P(AudioPushFifoTest, PushArbitraryNumbersOfFramesAtATime) {
+  // The loop below will run until both: 1) kMinNumIterations loops have
+  // occurred; and 2) there are at least 3 entries in |results_|.
+  const int kMinNumIterations = 30;
+
+  int sample_value = 0;
+  int frames_pushed_so_far = 0;
+  for (int i = 0; i < kMinNumIterations || results_.size() < 3; ++i) {
+    EXPECT_EQ(GetExpectedOutputChunks(frames_pushed_so_far), results_.size());
+
+    // Create an AudioBus of a random length, populated with sample values.
+    const int input_chunk_size = GetRandomInRange(1, 1920);
+    const scoped_ptr<AudioBus> audio_bus =
+        AudioBus::Create(1, input_chunk_size);
+    for (int j = 0; j < audio_bus->frames(); ++j)
+      audio_bus->channel(0)[j] = static_cast<float>(sample_value++);
+
+    fifo_->Push(*audio_bus);
+    // Note: AudioPushFifo has just called ReceiveAndCheckNextChunk() zero or
+    // more times.
+
+    frames_pushed_so_far += input_chunk_size;
+  }
+  EXPECT_EQ(GetExpectedOutputChunks(frames_pushed_so_far), results_.size());
+
+  ASSERT_FALSE(results_.empty());
+  EXPECT_EQ(0.0f, results_.front().first_sample_value);
+  const float last_value_in_last_chunk = static_cast<float>(
+      GetExpectedOutputChunks(frames_pushed_so_far) * output_chunk_size() - 1);
+  EXPECT_EQ(last_value_in_last_chunk, results_.back().last_sample_value);
+
+  const size_t num_results_before_flush = results_.size();
+  fifo_->Flush();
+  const size_t num_results_after_flush = results_.size();
+  if (num_results_after_flush > num_results_before_flush) {
+    EXPECT_NE(0, results_.back().frame_delay);
+    EXPECT_LT(-output_chunk_size(), results_.back().frame_delay);
+  }
+}
+
+INSTANTIATE_TEST_CASE_P(,
+                        AudioPushFifoTest,
+                        ::testing::Values(
+                            // 1 ms output chunks at common sample rates.
+                            16,  // 16000 Hz
+                            22,  // 22050 Hz
+                            44,  // 44100 Hz
+                            48,  // 48000 Hz
+
+                            // 10 ms output chunks at common sample rates.
+                            160,  // 16000 Hz
+                            220,  // 22050 Hz
+                            441,  // 44100 Hz
+                            480,  // 48000 Hz
+
+                            // 60 ms output chunks at common sample rates.
+                            960,   // 16000 Hz
+                            1323,  // 22050 Hz
+                            2646,  // 44100 Hz
+                            2880   // 48000 Hz
+                            ));
+
+}  // namespace
+
+}  // namespace media
diff --git a/media/base/cdm_context.h b/media/base/cdm_context.h
index c64f276e..7d89760 100644
--- a/media/base/cdm_context.h
+++ b/media/base/cdm_context.h
@@ -68,19 +68,6 @@
 // A dummy implementation of CdmAttachedCB.
 MEDIA_EXPORT void IgnoreCdmAttached(bool success);
 
-// Callback to notify that a CDM is ready. CdmAttachedCB is called when the CDM
-// has been completely attached to the media pipeline.
-typedef base::Callback<void(CdmContext*, const CdmAttachedCB&)> CdmReadyCB;
-
-// Callback to set/cancel a CdmReadyCB.
-// Calling this callback with a non-null callback registers CDM ready
-// notification. When the CDM is ready, notification will be sent
-// through the provided callback.
-// Calling this callback with a null callback cancels previously registered CDM
-// ready notification. Any previously provided callback will be fired
-// immediately with NULL.
-typedef base::Callback<void(const CdmReadyCB&)> SetCdmReadyCB;
-
 }  // namespace media
 
 #endif  // MEDIA_BASE_CDM_CONTEXT_H_
diff --git a/media/base/media_log.cc b/media/base/media_log.cc
index 916021a..ed43742 100644
--- a/media/base/media_log.cc
+++ b/media/base/media_log.cc
@@ -195,10 +195,11 @@
 }
 
 scoped_ptr<MediaLogEvent> MediaLog::CreatePipelineStateChangedEvent(
-    Pipeline::State state) {
+    PipelineImpl::State state) {
   scoped_ptr<MediaLogEvent> event(
       CreateEvent(MediaLogEvent::PIPELINE_STATE_CHANGED));
-  event->params.SetString("pipeline_state", Pipeline::GetStateString(state));
+  event->params.SetString("pipeline_state",
+                          PipelineImpl::GetStateString(state));
   return event;
 }
 
diff --git a/media/base/media_log.h b/media/base/media_log.h
index c547ef7..2286119 100644
--- a/media/base/media_log.h
+++ b/media/base/media_log.h
@@ -17,7 +17,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "media/base/media_export.h"
 #include "media/base/media_log_event.h"
-#include "media/base/pipeline.h"
+#include "media/base/pipeline_impl.h"
 #include "media/base/pipeline_status.h"
 
 namespace media {
@@ -57,7 +57,7 @@
   scoped_ptr<MediaLogEvent> CreateLoadEvent(const std::string& url);
   scoped_ptr<MediaLogEvent> CreateSeekEvent(float seconds);
   scoped_ptr<MediaLogEvent> CreatePipelineStateChangedEvent(
-      Pipeline::State state);
+      PipelineImpl::State state);
   scoped_ptr<MediaLogEvent> CreatePipelineErrorEvent(PipelineStatus error);
   scoped_ptr<MediaLogEvent> CreateVideoSizeSetEvent(
       size_t width, size_t height);
diff --git a/media/base/pipeline.h b/media/base/pipeline.h
index 5eae2e09..db326c2 100644
--- a/media/base/pipeline.h
+++ b/media/base/pipeline.h
@@ -5,36 +5,21 @@
 #ifndef MEDIA_BASE_PIPELINE_H_
 #define MEDIA_BASE_PIPELINE_H_
 
-#include "base/gtest_prod_util.h"
-#include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/synchronization/lock.h"
-#include "base/threading/thread_checker.h"
-#include "base/time/default_tick_clock.h"
+#include "base/time/time.h"
 #include "media/base/buffering_state.h"
 #include "media/base/cdm_context.h"
-#include "media/base/demuxer.h"
 #include "media/base/media_export.h"
 #include "media/base/pipeline_status.h"
 #include "media/base/ranges.h"
-#include "media/base/serial_runner.h"
 #include "media/base/text_track.h"
 #include "media/base/video_rotation.h"
 #include "ui/gfx/geometry/size.h"
 
-namespace base {
-class SingleThreadTaskRunner;
-class TimeDelta;
-}
-
 namespace media {
 
-class MediaLog;
+class Demuxer;
 class Renderer;
-class TextRenderer;
-class TextTrackConfig;
-class TimeDeltaInterpolator;
 class VideoFrame;
 
 // Metadata describing a pipeline once it has been initialized.
@@ -51,56 +36,11 @@
 
 typedef base::Callback<void(PipelineMetadata)> PipelineMetadataCB;
 
-// Pipeline runs the media pipeline.  Filters are created and called on the
-// task runner injected into this object. Pipeline works like a state
-// machine to perform asynchronous initialization, pausing, seeking and playing.
-//
-// Here's a state diagram that describes the lifetime of this object.
-//
-//   [ *Created ]                       [ Any State ]
-//         | Start()                         | Stop() / SetError()
-//         V                                 V
-//   [ InitXXX (for each filter) ]      [ Stopping ]
-//         |                                 |
-//         V                                 V
-//   [ Playing ] <---------.            [ Stopped ]
-//     |     | Seek()      |
-//     |     V             |
-//     |   [ Seeking ] ----'
-//     |                   ^
-//     | Suspend()         |
-//     V                   |
-//   [ Suspending ]        |
-//     |                   |
-//     V                   |
-//   [ Suspended ]         |
-//     | Resume()          |
-//     V                   |
-//   [ Resuming ] ---------'
-//
-// Initialization is a series of state transitions from "Created" through each
-// filter initialization state.  When all filter initialization states have
-// completed, we simulate a Seek() to the beginning of the media to give filters
-// a chance to preroll. From then on the normal Seek() transitions are carried
-// out and we start playing the media.
-//
-// If any error ever happens, this object will transition to the "Error" state
-// from any state. If Stop() is ever called, this object will transition to
-// "Stopped" state.
-//
-// TODO(sandersd): It should be possible to pass through Suspended when going
-// from InitDemuxer to InitRenderer, thereby eliminating the Resuming state.
-// Some annoying differences between the two paths need to be removed first.
-class MEDIA_EXPORT Pipeline : public DemuxerHost {
+class MEDIA_EXPORT Pipeline {
  public:
   // Used to paint VideoFrame.
   typedef base::Callback<void(const scoped_refptr<VideoFrame>&)> PaintCB;
 
-  // Constructs a media pipeline that will execute on |task_runner|.
-  Pipeline(const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
-           MediaLog* media_log);
-  ~Pipeline() override;
-
   // Build a pipeline to using the given |demuxer| and |renderer| to construct
   // a filter chain, executing |seek_cb| when the initial seek has completed.
   //
@@ -120,16 +60,16 @@
   //   |waiting_for_decryption_key_cb| will be executed whenever the key needed
   //                                   to decrypt the stream is not available.
   // It is an error to call this method after the pipeline has already started.
-  void Start(Demuxer* demuxer,
-             scoped_ptr<Renderer> renderer,
-             const base::Closure& ended_cb,
-             const PipelineStatusCB& error_cb,
-             const PipelineStatusCB& seek_cb,
-             const PipelineMetadataCB& metadata_cb,
-             const BufferingStateCB& buffering_state_cb,
-             const base::Closure& duration_change_cb,
-             const AddTextTrackCB& add_text_track_cb,
-             const base::Closure& waiting_for_decryption_key_cb);
+  virtual void Start(Demuxer* demuxer,
+                     scoped_ptr<Renderer> renderer,
+                     const base::Closure& ended_cb,
+                     const PipelineStatusCB& error_cb,
+                     const PipelineStatusCB& seek_cb,
+                     const PipelineMetadataCB& metadata_cb,
+                     const BufferingStateCB& buffering_state_cb,
+                     const base::Closure& duration_change_cb,
+                     const AddTextTrackCB& add_text_track_cb,
+                     const base::Closure& waiting_for_decryption_key_cb) = 0;
 
   // Asynchronously stops the pipeline, executing |stop_cb| when the pipeline
   // teardown has completed.
@@ -138,7 +78,7 @@
   // call Stop() at any point during the lifetime of the pipeline.
   //
   // It is safe to delete the pipeline during the execution of |stop_cb|.
-  void Stop(const base::Closure& stop_cb);
+  virtual void Stop(const base::Closure& stop_cb) = 0;
 
   // Attempt to seek to the position specified by time.  |seek_cb| will be
   // executed when the all filters in the pipeline have processed the seek.
@@ -147,291 +87,74 @@
   // succeeded.
   //
   // It is an error to call this method if the pipeline has not started or
-  // is suspended.
-  void Seek(base::TimeDelta time, const PipelineStatusCB& seek_cb);
+  // has been suspended.
+  virtual void Seek(base::TimeDelta time, const PipelineStatusCB& seek_cb) = 0;
 
-  // Returns true if the pipeline has been started via Start().  If IsRunning()
-  // returns true, it is expected that Stop() will be called before destroying
-  // the pipeline.
-  bool IsRunning() const;
-
-  // Gets the current playback rate of the pipeline.  When the pipeline is
-  // started, the playback rate will be 0.0.  A rate of 1.0 indicates
-  // that the pipeline is rendering the media at the standard rate.  Valid
-  // values for playback rate are >= 0.0.
-  double GetPlaybackRate() const;
-
-  // Attempt to adjust the playback rate. Setting a playback rate of 0.0 pauses
-  // all rendering of the media.  A rate of 1.0 indicates a normal playback
-  // rate.  Values for the playback rate must be greater than or equal to 0.0.
-  //
-  // TODO(scherkus): What about maximum rate?  Does HTML5 specify a max?
-  void SetPlaybackRate(double playback_rate);
-
-  // Suspend the pipeline, discarding the current renderer.
+  // Suspends the pipeline, discarding the current renderer.
   //
   // While suspended, GetMediaTime() returns the presentation timestamp of the
   // last rendered frame.
   //
   // It is an error to call this method if the pipeline has not started or is
   // seeking.
-  void Suspend(const PipelineStatusCB& suspend_cb);
+  virtual void Suspend(const PipelineStatusCB& suspend_cb) = 0;
 
   // Resume the pipeline with a new renderer, and initialize it with a seek.
-  void Resume(scoped_ptr<Renderer> renderer,
-              base::TimeDelta timestamp,
-              const PipelineStatusCB& seek_cb);
+  //
+  // It is an error to call this method if the pipeline has not finished
+  // suspending.
+  virtual void Resume(scoped_ptr<Renderer> renderer,
+                      base::TimeDelta timestamp,
+                      const PipelineStatusCB& seek_cb) = 0;
+
+  // Returns true if the pipeline has been started via Start().  If IsRunning()
+  // returns true, it is expected that Stop() will be called before destroying
+  // the pipeline.
+  virtual bool IsRunning() const = 0;
+
+  // Gets the current playback rate of the pipeline.  When the pipeline is
+  // started, the playback rate will be 0.0.  A rate of 1.0 indicates
+  // that the pipeline is rendering the media at the standard rate.  Valid
+  // values for playback rate are >= 0.0.
+  virtual double GetPlaybackRate() const = 0;
+
+  // Attempt to adjust the playback rate. Setting a playback rate of 0.0 pauses
+  // all rendering of the media.  A rate of 1.0 indicates a normal playback
+  // rate.  Values for the playback rate must be greater than or equal to 0.0.
+  //
+  // TODO(scherkus): What about maximum rate?  Does HTML5 specify a max?
+  virtual void SetPlaybackRate(double playback_rate) = 0;
 
   // Gets the current volume setting being used by the audio renderer.  When
   // the pipeline is started, this value will be 1.0f.  Valid values range
   // from 0.0f to 1.0f.
-  float GetVolume() const;
+  virtual float GetVolume() const = 0;
 
   // Attempt to set the volume of the audio renderer.  Valid values for volume
   // range from 0.0f (muted) to 1.0f (full volume).  This value affects all
   // channels proportionately for multi-channel audio streams.
-  void SetVolume(float volume);
+  virtual void SetVolume(float volume) = 0;
 
   // Returns the current media playback time, which progresses from 0 until
   // GetMediaDuration().
-  base::TimeDelta GetMediaTime() const;
+  virtual base::TimeDelta GetMediaTime() const = 0;
 
   // Get approximate time ranges of buffered media.
-  Ranges<base::TimeDelta> GetBufferedTimeRanges() const;
+  virtual Ranges<base::TimeDelta> GetBufferedTimeRanges() const = 0;
 
   // Get the duration of the media in microseconds.  If the duration has not
   // been determined yet, then returns 0.
-  base::TimeDelta GetMediaDuration() const;
+  virtual base::TimeDelta GetMediaDuration() const = 0;
 
   // Return true if loading progress has been made since the last time this
   // method was called.
-  bool DidLoadingProgress();
+  virtual bool DidLoadingProgress() = 0;
 
   // Gets the current pipeline statistics.
-  PipelineStatistics GetStatistics() const;
+  virtual PipelineStatistics GetStatistics() const = 0;
 
-  void SetCdm(CdmContext* cdm_context, const CdmAttachedCB& cdm_attached_cb);
-
-  void SetErrorForTesting(PipelineStatus status);
-  bool HasWeakPtrsForTesting() const;
-
- private:
-  FRIEND_TEST_ALL_PREFIXES(PipelineTest, GetBufferedTimeRanges);
-  FRIEND_TEST_ALL_PREFIXES(PipelineTest, EndedCallback);
-  FRIEND_TEST_ALL_PREFIXES(PipelineTest, AudioStreamShorterThanVideo);
-  friend class MediaLog;
-
-  // Pipeline states, as described above.
-  enum State {
-    kCreated,
-    kInitDemuxer,
-    kInitRenderer,
-    kSeeking,
-    kPlaying,
-    kStopping,
-    kStopped,
-    kSuspending,
-    kSuspended,
-    kResuming,
-  };
-
-  // Updates |state_|. All state transitions should use this call.
-  void SetState(State next_state);
-
-  static const char* GetStateString(State state);
-  State GetNextState() const;
-
-  // Helper method that runs & resets |seek_cb_| and resets |seek_timestamp_|
-  // and |seek_pending_|.
-  void FinishSeek();
-
-  // DemuxerHost implementaion.
-  void OnBufferedTimeRangesChanged(
-      const Ranges<base::TimeDelta>& ranges) override;
-  void SetDuration(base::TimeDelta duration) override;
-  void OnDemuxerError(PipelineStatus error) override;
-  void AddTextStream(DemuxerStream* text_stream,
-                     const TextTrackConfig& config) override;
-  void RemoveTextStream(DemuxerStream* text_stream) override;
-
-  // Callback executed when a rendering error happened, initiating the teardown
-  // sequence.
-  void OnError(PipelineStatus error);
-
-  // Callback executed by filters to update statistics.
-  void OnUpdateStatistics(const PipelineStatistics& stats_delta);
-
-  // The following "task" methods correspond to the public methods, but these
-  // methods are run as the result of posting a task to the Pipeline's
-  // task runner.
-  void StartTask();
-
-  // Suspends the pipeline, discarding the current renderer.
-  void SuspendTask(const PipelineStatusCB& suspend_cb);
-
-  // Resumes the pipeline with a new renderer, and initializes it with a seek.
-  void ResumeTask(scoped_ptr<Renderer> renderer,
-                  base::TimeDelta timestamp,
-                  const PipelineStatusCB& seek_sb);
-
-  // Stops and destroys all filters, placing the pipeline in the kStopped state.
-  void StopTask(const base::Closure& stop_cb);
-
-  // Carries out stopping and destroying all filters, placing the pipeline in
-  // the kStopped state.
-  void ErrorChangedTask(PipelineStatus error);
-
-  // Carries out notifying filters that the playback rate has changed.
-  void PlaybackRateChangedTask(double playback_rate);
-
-  // Carries out notifying filters that the volume has changed.
-  void VolumeChangedTask(float volume);
-
-  // Carries out notifying filters that we are seeking to a new timestamp.
-  void SeekTask(base::TimeDelta time, const PipelineStatusCB& seek_cb);
-
-  // Carries out setting the |cdm_context| in |renderer_|, and then fires
-  // |cdm_attached_cb| with the result. If |renderer_| is null,
-  // |cdm_attached_cb| will be fired immediately with true, and |cdm_context|
-  // will be set in |renderer_| later when |renderer_| is created.
-  void SetCdmTask(CdmContext* cdm_context,
-                  const CdmAttachedCB& cdm_attached_cb);
-
-  // Callbacks executed when a renderer has ended.
-  void OnRendererEnded();
-  void OnTextRendererEnded();
-  void RunEndedCallbackIfNeeded();
-
-  scoped_ptr<TextRenderer> CreateTextRenderer();
-
-  // Carries out adding a new text stream to the text renderer.
-  void AddTextStreamTask(DemuxerStream* text_stream,
-                         const TextTrackConfig& config);
-
-  // Carries out removing a text stream from the text renderer.
-  void RemoveTextStreamTask(DemuxerStream* text_stream);
-
-  // Callbacks executed when a text track is added.
-  void OnAddTextTrack(const TextTrackConfig& config,
-                      const AddTextTrackDoneCB& done_cb);
-
-  // Kicks off initialization for each media object, executing |done_cb| with
-  // the result when completed.
-  void InitializeDemuxer(const PipelineStatusCB& done_cb);
-  void InitializeRenderer(const PipelineStatusCB& done_cb);
-
-  void StateTransitionTask(PipelineStatus status);
-
-  // Initiates an asynchronous pause-flush-seek-preroll call sequence
-  // executing |done_cb| with the final status when completed.
-  void DoSeek(base::TimeDelta seek_timestamp, const PipelineStatusCB& done_cb);
-
-  // Initiates an asynchronous pause-flush-stop call sequence executing
-  // |done_cb| when completed.
-  void DoStop(const PipelineStatusCB& done_cb);
-  void OnStopCompleted(PipelineStatus status);
-
-  void ReportMetadata();
-
-  void BufferingStateChanged(BufferingState new_buffering_state);
-
-  // Task runner used to execute pipeline tasks.
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-
-  // MediaLog to which to log events.
-  scoped_refptr<MediaLog> media_log_;
-
-  // Lock used to serialize access for the following data members.
-  mutable base::Lock lock_;
-
-  // Whether or not the pipeline is running.
-  bool running_;
-
-  // Amount of available buffered data as reported by |demuxer_|.
-  Ranges<base::TimeDelta> buffered_time_ranges_;
-
-  // True when OnBufferedTimeRangesChanged() has been called more recently than
-  // DidLoadingProgress().
-  bool did_loading_progress_;
-
-  // Current volume level (from 0.0f to 1.0f).  This value is set immediately
-  // via SetVolume() and a task is dispatched on the task runner to notify the
-  // filters.
-  float volume_;
-
-  // Current playback rate (>= 0.0).  This value is set immediately via
-  // SetPlaybackRate() and a task is dispatched on the task runner to notify
-  // the filters.
-  double playback_rate_;
-
-  // Current duration as reported by |demuxer_|.
-  base::TimeDelta duration_;
-
-  // Status of the pipeline.  Initialized to PIPELINE_OK which indicates that
-  // the pipeline is operating correctly. Any other value indicates that the
-  // pipeline is stopped or is stopping.  Clients can call the Stop() method to
-  // reset the pipeline state, and restore this to PIPELINE_OK.
-  PipelineStatus status_;
-
-  // The following data members are only accessed by tasks posted to
-  // |task_runner_|.
-
-  // Member that tracks the current state.
-  State state_;
-
-  // The timestamp to start playback from after starting/seeking/resuming has
-  // completed.
-  base::TimeDelta start_timestamp_;
-
-  // The media timestamp to return while the pipeline is suspended. Otherwise
-  // set to kNoTimestamp().
-  base::TimeDelta suspend_timestamp_;
-
-  // Whether we've received the audio/video/text ended events.
-  bool renderer_ended_;
-  bool text_renderer_ended_;
-
-  // Temporary callback used for Start(), Seek(), and Resume().
-  PipelineStatusCB seek_cb_;
-
-  // Temporary callback used for Stop().
-  base::Closure stop_cb_;
-
-  // Temporary callback used for Suspend().
-  PipelineStatusCB suspend_cb_;
-
-  // Permanent callbacks passed in via Start().
-  base::Closure ended_cb_;
-  PipelineStatusCB error_cb_;
-  PipelineMetadataCB metadata_cb_;
-  BufferingStateCB buffering_state_cb_;
-  base::Closure duration_change_cb_;
-  AddTextTrackCB add_text_track_cb_;
-  base::Closure waiting_for_decryption_key_cb_;
-
-  // Holds the initialized demuxer. Used for seeking. Owned by client.
-  Demuxer* demuxer_;
-
-  // Holds the initialized renderers. Used for setting the volume,
-  // playback rate, and determining when playback has finished.
-  scoped_ptr<Renderer> renderer_;
-  scoped_ptr<TextRenderer> text_renderer_;
-
-  PipelineStatistics statistics_;
-
-  scoped_ptr<SerialRunner> pending_callbacks_;
-
-  // CdmContext to be used to decrypt (and decode) encrypted stream in this
-  // pipeline. Non-null only when SetCdm() is called and the pipeline has not
-  // been started. Then during Start(), this value will be set on |renderer_|.
-  CdmContext* pending_cdm_context_;
-
-  base::ThreadChecker thread_checker_;
-
-  // NOTE: Weak pointers must be invalidated before all other member variables.
-  base::WeakPtrFactory<Pipeline> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(Pipeline);
+  virtual void SetCdm(CdmContext* cdm_context,
+                      const CdmAttachedCB& cdm_attached_cb) = 0;
 };
 
 }  // namespace media
diff --git a/media/base/pipeline.cc b/media/base/pipeline_impl.cc
similarity index 71%
rename from media/base/pipeline.cc
rename to media/base/pipeline_impl.cc
index a548b64..a9ee4f0 100644
--- a/media/base/pipeline.cc
+++ b/media/base/pipeline_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "media/base/pipeline.h"
+#include "media/base/pipeline_impl.h"
 
 #include <algorithm>
 #include <utility>
@@ -32,7 +32,7 @@
 
 namespace media {
 
-Pipeline::Pipeline(
+PipelineImpl::PipelineImpl(
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
     MediaLog* media_log)
     : task_runner_(task_runner),
@@ -52,7 +52,7 @@
   media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated));
 }
 
-Pipeline::~Pipeline() {
+PipelineImpl::~PipelineImpl() {
   DCHECK(thread_checker_.CalledOnValidThread())
       << "Pipeline must be destroyed on same thread that created it";
   DCHECK(!running_) << "Stop() must complete before destroying object";
@@ -60,16 +60,16 @@
   DCHECK(seek_cb_.is_null());
 }
 
-void Pipeline::Start(Demuxer* demuxer,
-                     scoped_ptr<Renderer> renderer,
-                     const base::Closure& ended_cb,
-                     const PipelineStatusCB& error_cb,
-                     const PipelineStatusCB& seek_cb,
-                     const PipelineMetadataCB& metadata_cb,
-                     const BufferingStateCB& buffering_state_cb,
-                     const base::Closure& duration_change_cb,
-                     const AddTextTrackCB& add_text_track_cb,
-                     const base::Closure& waiting_for_decryption_key_cb) {
+void PipelineImpl::Start(Demuxer* demuxer,
+                         scoped_ptr<Renderer> renderer,
+                         const base::Closure& ended_cb,
+                         const PipelineStatusCB& error_cb,
+                         const PipelineStatusCB& seek_cb,
+                         const PipelineMetadataCB& metadata_cb,
+                         const BufferingStateCB& buffering_state_cb,
+                         const base::Closure& duration_change_cb,
+                         const AddTextTrackCB& add_text_track_cb,
+                         const base::Closure& waiting_for_decryption_key_cb) {
   DCHECK(!ended_cb.is_null());
   DCHECK(!error_cb.is_null());
   DCHECK(!seek_cb.is_null());
@@ -91,18 +91,18 @@
   add_text_track_cb_ = add_text_track_cb;
   waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb;
 
-  task_runner_->PostTask(
-      FROM_HERE, base::Bind(&Pipeline::StartTask, weak_factory_.GetWeakPtr()));
+  task_runner_->PostTask(FROM_HERE, base::Bind(&PipelineImpl::StartTask,
+                                               weak_factory_.GetWeakPtr()));
 }
 
-void Pipeline::Stop(const base::Closure& stop_cb) {
+void PipelineImpl::Stop(const base::Closure& stop_cb) {
   DVLOG(2) << __FUNCTION__;
   task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&Pipeline::StopTask, weak_factory_.GetWeakPtr(), stop_cb));
+      base::Bind(&PipelineImpl::StopTask, weak_factory_.GetWeakPtr(), stop_cb));
 }
 
-void Pipeline::Seek(TimeDelta time, const PipelineStatusCB& seek_cb) {
+void PipelineImpl::Seek(TimeDelta time, const PipelineStatusCB& seek_cb) {
   base::AutoLock auto_lock(lock_);
   if (!running_) {
     DLOG(ERROR) << "Media pipeline isn't running. Ignoring Seek().";
@@ -110,70 +110,67 @@
   }
 
   task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(
-          &Pipeline::SeekTask, weak_factory_.GetWeakPtr(), time, seek_cb));
+      FROM_HERE, base::Bind(&PipelineImpl::SeekTask, weak_factory_.GetWeakPtr(),
+                            time, seek_cb));
 }
 
-bool Pipeline::IsRunning() const {
+bool PipelineImpl::IsRunning() const {
   base::AutoLock auto_lock(lock_);
   return running_;
 }
 
-double Pipeline::GetPlaybackRate() const {
+double PipelineImpl::GetPlaybackRate() const {
   base::AutoLock auto_lock(lock_);
   return playback_rate_;
 }
 
-void Pipeline::SetPlaybackRate(double playback_rate) {
+void PipelineImpl::SetPlaybackRate(double playback_rate) {
   if (playback_rate < 0.0)
     return;
 
   base::AutoLock auto_lock(lock_);
   playback_rate_ = playback_rate;
   if (running_) {
-    task_runner_->PostTask(FROM_HERE,
-                           base::Bind(&Pipeline::PlaybackRateChangedTask,
-                                      weak_factory_.GetWeakPtr(),
-                                      playback_rate));
+    task_runner_->PostTask(
+        FROM_HERE, base::Bind(&PipelineImpl::PlaybackRateChangedTask,
+                              weak_factory_.GetWeakPtr(), playback_rate));
   }
 }
 
-void Pipeline::Suspend(const PipelineStatusCB& suspend_cb) {
-  task_runner_->PostTask(
-      FROM_HERE, base::Bind(&Pipeline::SuspendTask, weak_factory_.GetWeakPtr(),
-                            suspend_cb));
+void PipelineImpl::Suspend(const PipelineStatusCB& suspend_cb) {
+  task_runner_->PostTask(FROM_HERE,
+                         base::Bind(&PipelineImpl::SuspendTask,
+                                    weak_factory_.GetWeakPtr(), suspend_cb));
 }
 
-void Pipeline::Resume(scoped_ptr<Renderer> renderer,
-                      base::TimeDelta timestamp,
-                      const PipelineStatusCB& seek_cb) {
+void PipelineImpl::Resume(scoped_ptr<Renderer> renderer,
+                          base::TimeDelta timestamp,
+                          const PipelineStatusCB& seek_cb) {
   task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&Pipeline::ResumeTask, weak_factory_.GetWeakPtr(),
-                 base::Passed(std::move(renderer)), timestamp, seek_cb));
+      base::Bind(&PipelineImpl::ResumeTask, weak_factory_.GetWeakPtr(),
+                 base::Passed(&renderer), timestamp, seek_cb));
 }
 
-float Pipeline::GetVolume() const {
+float PipelineImpl::GetVolume() const {
   base::AutoLock auto_lock(lock_);
   return volume_;
 }
 
-void Pipeline::SetVolume(float volume) {
+void PipelineImpl::SetVolume(float volume) {
   if (volume < 0.0f || volume > 1.0f)
     return;
 
   base::AutoLock auto_lock(lock_);
   volume_ = volume;
   if (running_) {
-    task_runner_->PostTask(
-        FROM_HERE,
-        base::Bind(
-            &Pipeline::VolumeChangedTask, weak_factory_.GetWeakPtr(), volume));
+    task_runner_->PostTask(FROM_HERE,
+                           base::Bind(&PipelineImpl::VolumeChangedTask,
+                                      weak_factory_.GetWeakPtr(), volume));
   }
 }
 
-TimeDelta Pipeline::GetMediaTime() const {
+TimeDelta PipelineImpl::GetMediaTime() const {
   base::AutoLock auto_lock(lock_);
   if (suspend_timestamp_ != kNoTimestamp())
     return suspend_timestamp_;
@@ -181,54 +178,56 @@
                    : TimeDelta();
 }
 
-Ranges<TimeDelta> Pipeline::GetBufferedTimeRanges() const {
+Ranges<TimeDelta> PipelineImpl::GetBufferedTimeRanges() const {
   base::AutoLock auto_lock(lock_);
   return buffered_time_ranges_;
 }
 
-TimeDelta Pipeline::GetMediaDuration() const {
+TimeDelta PipelineImpl::GetMediaDuration() const {
   base::AutoLock auto_lock(lock_);
   return duration_;
 }
 
-bool Pipeline::DidLoadingProgress() {
+bool PipelineImpl::DidLoadingProgress() {
   base::AutoLock auto_lock(lock_);
   bool ret = did_loading_progress_;
   did_loading_progress_ = false;
   return ret;
 }
 
-PipelineStatistics Pipeline::GetStatistics() const {
+PipelineStatistics PipelineImpl::GetStatistics() const {
   base::AutoLock auto_lock(lock_);
   return statistics_;
 }
 
-void Pipeline::SetCdm(CdmContext* cdm_context,
-                      const CdmAttachedCB& cdm_attached_cb) {
-  task_runner_->PostTask(
-      FROM_HERE, base::Bind(&Pipeline::SetCdmTask, weak_factory_.GetWeakPtr(),
-                            cdm_context, cdm_attached_cb));
+void PipelineImpl::SetCdm(CdmContext* cdm_context,
+                          const CdmAttachedCB& cdm_attached_cb) {
+  task_runner_->PostTask(FROM_HERE, base::Bind(&PipelineImpl::SetCdmTask,
+                                               weak_factory_.GetWeakPtr(),
+                                               cdm_context, cdm_attached_cb));
 }
 
-void Pipeline::SetErrorForTesting(PipelineStatus status) {
+void PipelineImpl::SetErrorForTesting(PipelineStatus status) {
   OnError(status);
 }
 
-bool Pipeline::HasWeakPtrsForTesting() const {
+bool PipelineImpl::HasWeakPtrsForTesting() const {
   DCHECK(task_runner_->BelongsToCurrentThread());
   return weak_factory_.HasWeakPtrs();
 }
 
-void Pipeline::SetState(State next_state) {
+void PipelineImpl::SetState(State next_state) {
   DVLOG(1) << GetStateString(state_) << " -> " << GetStateString(next_state);
 
   state_ = next_state;
   media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(next_state));
 }
 
-#define RETURN_STRING(state) case state: return #state;
+#define RETURN_STRING(state) \
+  case state:                \
+    return #state;
 
-const char* Pipeline::GetStateString(State state) {
+const char* PipelineImpl::GetStateString(State state) {
   switch (state) {
     RETURN_STRING(kCreated);
     RETURN_STRING(kInitDemuxer);
@@ -247,10 +246,9 @@
 
 #undef RETURN_STRING
 
-Pipeline::State Pipeline::GetNextState() const {
+PipelineImpl::State PipelineImpl::GetNextState() const {
   DCHECK(task_runner_->BelongsToCurrentThread());
-  DCHECK(stop_cb_.is_null())
-      << "State transitions don't happen when stopping";
+  DCHECK(stop_cb_.is_null()) << "State transitions don't happen when stopping";
   DCHECK_EQ(status_, PIPELINE_OK)
       << "State transitions don't happen when there's an error: " << status_;
 
@@ -283,44 +281,40 @@
   return state_;
 }
 
-void Pipeline::OnDemuxerError(PipelineStatus error) {
+void PipelineImpl::OnDemuxerError(PipelineStatus error) {
   task_runner_->PostTask(FROM_HERE,
-                         base::Bind(&Pipeline::ErrorChangedTask,
-                                    weak_factory_.GetWeakPtr(),
-                                    error));
+                         base::Bind(&PipelineImpl::ErrorChangedTask,
+                                    weak_factory_.GetWeakPtr(), error));
 }
 
-void Pipeline::AddTextStream(DemuxerStream* text_stream,
-                             const TextTrackConfig& config) {
-  task_runner_->PostTask(FROM_HERE,
-                         base::Bind(&Pipeline::AddTextStreamTask,
-                                    weak_factory_.GetWeakPtr(),
-                                    text_stream,
-                                    config));
+void PipelineImpl::AddTextStream(DemuxerStream* text_stream,
+                                 const TextTrackConfig& config) {
+  task_runner_->PostTask(
+      FROM_HERE, base::Bind(&PipelineImpl::AddTextStreamTask,
+                            weak_factory_.GetWeakPtr(), text_stream, config));
 }
 
-void Pipeline::RemoveTextStream(DemuxerStream* text_stream) {
+void PipelineImpl::RemoveTextStream(DemuxerStream* text_stream) {
   task_runner_->PostTask(FROM_HERE,
-                         base::Bind(&Pipeline::RemoveTextStreamTask,
-                                    weak_factory_.GetWeakPtr(),
-                                    text_stream));
+                         base::Bind(&PipelineImpl::RemoveTextStreamTask,
+                                    weak_factory_.GetWeakPtr(), text_stream));
 }
 
-void Pipeline::OnError(PipelineStatus error) {
+void PipelineImpl::OnError(PipelineStatus error) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK(IsRunning());
   DCHECK_NE(PIPELINE_OK, error);
   VLOG(1) << "Media pipeline error: " << error;
 
-  task_runner_->PostTask(FROM_HERE, base::Bind(
-      &Pipeline::ErrorChangedTask, weak_factory_.GetWeakPtr(), error));
+  task_runner_->PostTask(FROM_HERE,
+                         base::Bind(&PipelineImpl::ErrorChangedTask,
+                                    weak_factory_.GetWeakPtr(), error));
 }
 
-void Pipeline::SetDuration(TimeDelta duration) {
+void PipelineImpl::SetDuration(TimeDelta duration) {
   DCHECK(IsRunning());
-  media_log_->AddEvent(
-      media_log_->CreateTimeEvent(
-          MediaLogEvent::DURATION_SET, "duration", duration));
+  media_log_->AddEvent(media_log_->CreateTimeEvent(MediaLogEvent::DURATION_SET,
+                                                   "duration", duration));
   UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration);
 
   base::AutoLock auto_lock(lock_);
@@ -329,7 +323,7 @@
     duration_change_cb_.Run();
 }
 
-void Pipeline::StateTransitionTask(PipelineStatus status) {
+void PipelineImpl::StateTransitionTask(PipelineStatus status) {
   DCHECK(task_runner_->BelongsToCurrentThread());
 
   // No-op any state transitions if we're stopping.
@@ -352,8 +346,8 @@
 
   pending_callbacks_.reset();
 
-  PipelineStatusCB done_cb =
-      base::Bind(&Pipeline::StateTransitionTask, weak_factory_.GetWeakPtr());
+  PipelineStatusCB done_cb = base::Bind(&PipelineImpl::StateTransitionTask,
+                                        weak_factory_.GetWeakPtr());
 
   // Switch states, performing any entrance actions for the new state as well.
   SetState(GetNextState());
@@ -410,8 +404,8 @@
 //
 // That being said, deleting the renderers while keeping |pending_callbacks_|
 // running on the media thread would result in crashes.
-void Pipeline::DoSeek(TimeDelta seek_timestamp,
-                      const PipelineStatusCB& done_cb) {
+void PipelineImpl::DoSeek(TimeDelta seek_timestamp,
+                          const PipelineStatusCB& done_cb) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK(!pending_callbacks_.get());
   DCHECK_EQ(state_, kSeeking);
@@ -419,8 +413,8 @@
 
   // Pause.
   if (text_renderer_) {
-    bound_fns.Push(base::Bind(
-        &TextRenderer::Pause, base::Unretained(text_renderer_.get())));
+    bound_fns.Push(base::Bind(&TextRenderer::Pause,
+                              base::Unretained(text_renderer_.get())));
   }
 
   // Flush.
@@ -429,18 +423,18 @@
       base::Bind(&Renderer::Flush, base::Unretained(renderer_.get())));
 
   if (text_renderer_) {
-    bound_fns.Push(base::Bind(
-        &TextRenderer::Flush, base::Unretained(text_renderer_.get())));
+    bound_fns.Push(base::Bind(&TextRenderer::Flush,
+                              base::Unretained(text_renderer_.get())));
   }
 
   // Seek demuxer.
-  bound_fns.Push(base::Bind(
-      &Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp));
+  bound_fns.Push(
+      base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp));
 
   pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb);
 }
 
-void Pipeline::DoStop(const PipelineStatusCB& done_cb) {
+void PipelineImpl::DoStop(const PipelineStatusCB& done_cb) {
   DVLOG(2) << __FUNCTION__;
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK(!pending_callbacks_.get());
@@ -463,7 +457,7 @@
   task_runner_->PostTask(FROM_HERE, base::Bind(done_cb, PIPELINE_OK));
 }
 
-void Pipeline::OnStopCompleted(PipelineStatus status) {
+void PipelineImpl::OnStopCompleted(PipelineStatus status) {
   DVLOG(2) << __FUNCTION__;
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK_EQ(state_, kStopping);
@@ -507,7 +501,7 @@
   }
 }
 
-void Pipeline::OnBufferedTimeRangesChanged(
+void PipelineImpl::OnBufferedTimeRangesChanged(
     const Ranges<base::TimeDelta>& ranges) {
   DCHECK(IsRunning());
   base::AutoLock auto_lock(lock_);
@@ -516,7 +510,7 @@
 }
 
 // Called from any thread.
-void Pipeline::OnUpdateStatistics(const PipelineStatistics& stats_delta) {
+void PipelineImpl::OnUpdateStatistics(const PipelineStatistics& stats_delta) {
   base::AutoLock auto_lock(lock_);
   statistics_.audio_bytes_decoded += stats_delta.audio_bytes_decoded;
   statistics_.video_bytes_decoded += stats_delta.video_bytes_decoded;
@@ -526,7 +520,7 @@
   statistics_.video_memory_usage += stats_delta.video_memory_usage;
 }
 
-void Pipeline::StartTask() {
+void PipelineImpl::StartTask() {
   DCHECK(task_runner_->BelongsToCurrentThread());
 
   CHECK_EQ(kCreated, state_)
@@ -534,8 +528,8 @@
 
   text_renderer_ = CreateTextRenderer();
   if (text_renderer_) {
-    text_renderer_->Initialize(
-        base::Bind(&Pipeline::OnTextRendererEnded, weak_factory_.GetWeakPtr()));
+    text_renderer_->Initialize(base::Bind(&PipelineImpl::OnTextRendererEnded,
+                                          weak_factory_.GetWeakPtr()));
   }
 
   // Set CDM early to avoid unnecessary delay in Renderer::Initialize().
@@ -547,7 +541,7 @@
   StateTransitionTask(PIPELINE_OK);
 }
 
-void Pipeline::StopTask(const base::Closure& stop_cb) {
+void PipelineImpl::StopTask(const base::Closure& stop_cb) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK(stop_cb_.is_null());
 
@@ -581,10 +575,11 @@
 
   SetState(kStopping);
   pending_callbacks_.reset();
-  DoStop(base::Bind(&Pipeline::OnStopCompleted, weak_factory_.GetWeakPtr()));
+  DoStop(
+      base::Bind(&PipelineImpl::OnStopCompleted, weak_factory_.GetWeakPtr()));
 }
 
-void Pipeline::ErrorChangedTask(PipelineStatus error) {
+void PipelineImpl::ErrorChangedTask(PipelineStatus error) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK_NE(PIPELINE_OK, error) << "PIPELINE_OK isn't an error!";
 
@@ -597,10 +592,11 @@
   pending_callbacks_.reset();
   status_ = error;
 
-  DoStop(base::Bind(&Pipeline::OnStopCompleted, weak_factory_.GetWeakPtr()));
+  DoStop(
+      base::Bind(&PipelineImpl::OnStopCompleted, weak_factory_.GetWeakPtr()));
 }
 
-void Pipeline::PlaybackRateChangedTask(double playback_rate) {
+void PipelineImpl::PlaybackRateChangedTask(double playback_rate) {
   DCHECK(task_runner_->BelongsToCurrentThread());
 
   // Playback rate changes are only carried out while playing.
@@ -610,7 +606,7 @@
   renderer_->SetPlaybackRate(playback_rate);
 }
 
-void Pipeline::VolumeChangedTask(float volume) {
+void PipelineImpl::VolumeChangedTask(float volume) {
   DCHECK(task_runner_->BelongsToCurrentThread());
 
   // Volume changes are only carried out while playing.
@@ -620,7 +616,7 @@
   renderer_->SetVolume(volume);
 }
 
-void Pipeline::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) {
+void PipelineImpl::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK(stop_cb_.is_null());
 
@@ -643,11 +639,11 @@
   text_renderer_ended_ = false;
   start_timestamp_ = seek_timestamp;
 
-  DoSeek(seek_timestamp, base::Bind(&Pipeline::StateTransitionTask,
+  DoSeek(seek_timestamp, base::Bind(&PipelineImpl::StateTransitionTask,
                                     weak_factory_.GetWeakPtr()));
 }
 
-void Pipeline::SuspendTask(const PipelineStatusCB& suspend_cb) {
+void PipelineImpl::SuspendTask(const PipelineStatusCB& suspend_cb) {
   DCHECK(task_runner_->BelongsToCurrentThread());
 
   // Suppress suspending if we're not playing.
@@ -689,14 +685,14 @@
                         base::Unretained(text_renderer_.get())));
   }
 
-  pending_callbacks_ = SerialRunner::Run(
-      fns,
-      base::Bind(&Pipeline::StateTransitionTask, weak_factory_.GetWeakPtr()));
+  pending_callbacks_ =
+      SerialRunner::Run(fns, base::Bind(&PipelineImpl::StateTransitionTask,
+                                        weak_factory_.GetWeakPtr()));
 }
 
-void Pipeline::ResumeTask(scoped_ptr<Renderer> renderer,
-                          base::TimeDelta timestamp,
-                          const PipelineStatusCB& seek_cb) {
+void PipelineImpl::ResumeTask(scoped_ptr<Renderer> renderer,
+                              base::TimeDelta timestamp,
+                              const PipelineStatusCB& seek_cb) {
   DCHECK(task_runner_->BelongsToCurrentThread());
 
   // Suppress resuming if we're not suspended.
@@ -724,19 +720,19 @@
   // kInitDemuxer, and even if we did the current code would seek to the start
   // instead of |timestamp|).
   SerialRunner::Queue fns;
-  base::WeakPtr<Pipeline> weak_this = weak_factory_.GetWeakPtr();
+  base::WeakPtr<PipelineImpl> weak_this = weak_factory_.GetWeakPtr();
 
   fns.Push(
       base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), start_timestamp_));
 
-  fns.Push(base::Bind(&Pipeline::InitializeRenderer, weak_this));
+  fns.Push(base::Bind(&PipelineImpl::InitializeRenderer, weak_this));
 
   pending_callbacks_ = SerialRunner::Run(
-      fns, base::Bind(&Pipeline::StateTransitionTask, weak_this));
+      fns, base::Bind(&PipelineImpl::StateTransitionTask, weak_this));
 }
 
-void Pipeline::SetCdmTask(CdmContext* cdm_context,
-                          const CdmAttachedCB& cdm_attached_cb) {
+void PipelineImpl::SetCdmTask(CdmContext* cdm_context,
+                              const CdmAttachedCB& cdm_attached_cb) {
   base::AutoLock auto_lock(lock_);
   if (!renderer_) {
     pending_cdm_context_ = cdm_context;
@@ -747,7 +743,7 @@
   renderer_->SetCdm(cdm_context, cdm_attached_cb);
 }
 
-void Pipeline::OnRendererEnded() {
+void PipelineImpl::OnRendererEnded() {
   DCHECK(task_runner_->BelongsToCurrentThread());
   media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::ENDED));
 
@@ -760,7 +756,7 @@
   RunEndedCallbackIfNeeded();
 }
 
-void Pipeline::OnTextRendererEnded() {
+void PipelineImpl::OnTextRendererEnded() {
   DCHECK(task_runner_->BelongsToCurrentThread());
   media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::TEXT_ENDED));
 
@@ -773,7 +769,7 @@
   RunEndedCallbackIfNeeded();
 }
 
-void Pipeline::RunEndedCallbackIfNeeded() {
+void PipelineImpl::RunEndedCallbackIfNeeded() {
   DCHECK(task_runner_->BelongsToCurrentThread());
 
   if (renderer_ && !renderer_ended_)
@@ -786,7 +782,7 @@
   ended_cb_.Run();
 }
 
-scoped_ptr<TextRenderer> Pipeline::CreateTextRenderer() {
+scoped_ptr<TextRenderer> PipelineImpl::CreateTextRenderer() {
   DCHECK(task_runner_->BelongsToCurrentThread());
 
   const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
@@ -795,11 +791,11 @@
 
   return scoped_ptr<media::TextRenderer>(new media::TextRenderer(
       task_runner_,
-      base::Bind(&Pipeline::OnAddTextTrack, weak_factory_.GetWeakPtr())));
+      base::Bind(&PipelineImpl::OnAddTextTrack, weak_factory_.GetWeakPtr())));
 }
 
-void Pipeline::AddTextStreamTask(DemuxerStream* text_stream,
-                                 const TextTrackConfig& config) {
+void PipelineImpl::AddTextStreamTask(DemuxerStream* text_stream,
+                                     const TextTrackConfig& config) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   // TODO(matthewjheaney): fix up text_ended_ when text stream
   // is added (http://crbug.com/321446).
@@ -807,24 +803,24 @@
     text_renderer_->AddTextStream(text_stream, config);
 }
 
-void Pipeline::RemoveTextStreamTask(DemuxerStream* text_stream) {
+void PipelineImpl::RemoveTextStreamTask(DemuxerStream* text_stream) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   if (text_renderer_)
     text_renderer_->RemoveTextStream(text_stream);
 }
 
-void Pipeline::OnAddTextTrack(const TextTrackConfig& config,
-                              const AddTextTrackDoneCB& done_cb) {
+void PipelineImpl::OnAddTextTrack(const TextTrackConfig& config,
+                                  const AddTextTrackDoneCB& done_cb) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   add_text_track_cb_.Run(config, done_cb);
 }
 
-void Pipeline::InitializeDemuxer(const PipelineStatusCB& done_cb) {
+void PipelineImpl::InitializeDemuxer(const PipelineStatusCB& done_cb) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   demuxer_->Initialize(this, done_cb, !!text_renderer_);
 }
 
-void Pipeline::InitializeRenderer(const PipelineStatusCB& done_cb) {
+void PipelineImpl::InitializeRenderer(const PipelineStatusCB& done_cb) {
   DCHECK(task_runner_->BelongsToCurrentThread());
 
   if (!demuxer_->GetStream(DemuxerStream::AUDIO) &&
@@ -837,18 +833,17 @@
     return;
   }
 
-  base::WeakPtr<Pipeline> weak_this = weak_factory_.GetWeakPtr();
+  base::WeakPtr<PipelineImpl> weak_this = weak_factory_.GetWeakPtr();
   renderer_->Initialize(
-      demuxer_,
-      done_cb,
-      base::Bind(&Pipeline::OnUpdateStatistics, weak_this),
-      base::Bind(&Pipeline::BufferingStateChanged, weak_this),
-      base::Bind(&Pipeline::OnRendererEnded, weak_this),
-      base::Bind(&Pipeline::OnError, weak_this),
+      demuxer_, done_cb,
+      base::Bind(&PipelineImpl::OnUpdateStatistics, weak_this),
+      base::Bind(&PipelineImpl::BufferingStateChanged, weak_this),
+      base::Bind(&PipelineImpl::OnRendererEnded, weak_this),
+      base::Bind(&PipelineImpl::OnError, weak_this),
       waiting_for_decryption_key_cb_);
 }
 
-void Pipeline::ReportMetadata() {
+void PipelineImpl::ReportMetadata() {
   DCHECK(task_runner_->BelongsToCurrentThread());
   PipelineMetadata metadata;
   metadata.timeline_offset = demuxer_->GetTimelineOffset();
@@ -864,7 +859,7 @@
   metadata_cb_.Run(metadata);
 }
 
-void Pipeline::BufferingStateChanged(BufferingState new_buffering_state) {
+void PipelineImpl::BufferingStateChanged(BufferingState new_buffering_state) {
   DVLOG(1) << __FUNCTION__ << "(" << new_buffering_state << ") ";
   DCHECK(task_runner_->BelongsToCurrentThread());
   buffering_state_cb_.Run(new_buffering_state);
diff --git a/media/base/pipeline_impl.h b/media/base/pipeline_impl.h
new file mode 100644
index 0000000..a4a4757
--- /dev/null
+++ b/media/base/pipeline_impl.h
@@ -0,0 +1,336 @@
+// Copyright (c) 2016 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 MEDIA_BASE_PIPELINE_IMPL_H_
+#define MEDIA_BASE_PIPELINE_IMPL_H_
+
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/time.h"
+#include "media/base/buffering_state.h"
+#include "media/base/cdm_context.h"
+#include "media/base/demuxer.h"
+#include "media/base/media_export.h"
+#include "media/base/pipeline.h"
+#include "media/base/pipeline_status.h"
+#include "media/base/ranges.h"
+#include "media/base/serial_runner.h"
+#include "media/base/text_track.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+namespace media {
+
+class MediaLog;
+class Renderer;
+class TextRenderer;
+
+// Pipeline runs the media pipeline.  Filters are created and called on the
+// task runner injected into this object. Pipeline works like a state
+// machine to perform asynchronous initialization, pausing, seeking and playing.
+//
+// Here's a state diagram that describes the lifetime of this object.
+//
+//   [ *Created ]                       [ Any State ]
+//         | Start()                         | Stop() / SetError()
+//         V                                 V
+//   [ InitXXX (for each filter) ]      [ Stopping ]
+//         |                                 |
+//         V                                 V
+//   [ Playing ] <---------.            [ Stopped ]
+//     |     | Seek()      |
+//     |     V             |
+//     |   [ Seeking ] ----'
+//     |                   ^
+//     | Suspend()         |
+//     V                   |
+//   [ Suspending ]        |
+//     |                   |
+//     V                   |
+//   [ Suspended ]         |
+//     | Resume()          |
+//     V                   |
+//   [ Resuming ] ---------'
+//
+// Initialization is a series of state transitions from "Created" through each
+// filter initialization state.  When all filter initialization states have
+// completed, we simulate a Seek() to the beginning of the media to give filters
+// a chance to preroll. From then on the normal Seek() transitions are carried
+// out and we start playing the media.
+//
+// If any error ever happens, this object will transition to the "Error" state
+// from any state. If Stop() is ever called, this object will transition to
+// "Stopped" state.
+//
+// TODO(sandersd): It should be possible to pass through Suspended when going
+// from InitDemuxer to InitRenderer, thereby eliminating the Resuming state.
+// Some annoying differences between the two paths need to be removed first.
+class MEDIA_EXPORT PipelineImpl : public Pipeline, public DemuxerHost {
+ public:
+  // Constructs a media pipeline that will execute on |task_runner|.
+  PipelineImpl(const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+               MediaLog* media_log);
+  ~PipelineImpl() override;
+
+  void SetErrorForTesting(PipelineStatus status);
+  bool HasWeakPtrsForTesting() const;
+
+  // Pipeline implementation.
+  void Start(Demuxer* demuxer,
+             scoped_ptr<Renderer> renderer,
+             const base::Closure& ended_cb,
+             const PipelineStatusCB& error_cb,
+             const PipelineStatusCB& seek_cb,
+             const PipelineMetadataCB& metadata_cb,
+             const BufferingStateCB& buffering_state_cb,
+             const base::Closure& duration_change_cb,
+             const AddTextTrackCB& add_text_track_cb,
+             const base::Closure& waiting_for_decryption_key_cb) override;
+  void Stop(const base::Closure& stop_cb) override;
+  void Seek(base::TimeDelta time, const PipelineStatusCB& seek_cb) override;
+  bool IsRunning() const override;
+  double GetPlaybackRate() const override;
+  void SetPlaybackRate(double playback_rate) override;
+  void Suspend(const PipelineStatusCB& suspend_cb) override;
+  void Resume(scoped_ptr<Renderer> renderer,
+              base::TimeDelta timestamp,
+              const PipelineStatusCB& seek_cb) override;
+  float GetVolume() const override;
+  void SetVolume(float volume) override;
+  base::TimeDelta GetMediaTime() const override;
+  Ranges<base::TimeDelta> GetBufferedTimeRanges() const override;
+  base::TimeDelta GetMediaDuration() const override;
+  bool DidLoadingProgress() override;
+  PipelineStatistics GetStatistics() const override;
+  void SetCdm(CdmContext* cdm_context,
+              const CdmAttachedCB& cdm_attached_cb) override;
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(PipelineImplTest, GetBufferedTimeRanges);
+  FRIEND_TEST_ALL_PREFIXES(PipelineImplTest, EndedCallback);
+  FRIEND_TEST_ALL_PREFIXES(PipelineImplTest, AudioStreamShorterThanVideo);
+  friend class MediaLog;
+
+  // Pipeline states, as described above.
+  enum State {
+    kCreated,
+    kInitDemuxer,
+    kInitRenderer,
+    kSeeking,
+    kPlaying,
+    kStopping,
+    kStopped,
+    kSuspending,
+    kSuspended,
+    kResuming,
+  };
+
+  // Updates |state_|. All state transitions should use this call.
+  void SetState(State next_state);
+
+  static const char* GetStateString(State state);
+  State GetNextState() const;
+
+  // Helper method that runs & resets |seek_cb_| and resets |seek_timestamp_|
+  // and |seek_pending_|.
+  void FinishSeek();
+
+  // DemuxerHost implementaion.
+  void OnBufferedTimeRangesChanged(
+      const Ranges<base::TimeDelta>& ranges) override;
+  void SetDuration(base::TimeDelta duration) override;
+  void OnDemuxerError(PipelineStatus error) override;
+  void AddTextStream(DemuxerStream* text_stream,
+                     const TextTrackConfig& config) override;
+  void RemoveTextStream(DemuxerStream* text_stream) override;
+
+  // Callback executed when a rendering error happened, initiating the teardown
+  // sequence.
+  void OnError(PipelineStatus error);
+
+  // Callback executed by filters to update statistics.
+  void OnUpdateStatistics(const PipelineStatistics& stats_delta);
+
+  // The following "task" methods correspond to the public methods, but these
+  // methods are run as the result of posting a task to the Pipeline's
+  // task runner.
+  void StartTask();
+
+  // Suspends the pipeline, discarding the current renderer.
+  void SuspendTask(const PipelineStatusCB& suspend_cb);
+
+  // Resumes the pipeline with a new renderer, and initializes it with a seek.
+  void ResumeTask(scoped_ptr<Renderer> renderer,
+                  base::TimeDelta timestamp,
+                  const PipelineStatusCB& seek_sb);
+
+  // Stops and destroys all filters, placing the pipeline in the kStopped state.
+  void StopTask(const base::Closure& stop_cb);
+
+  // Carries out stopping and destroying all filters, placing the pipeline in
+  // the kStopped state.
+  void ErrorChangedTask(PipelineStatus error);
+
+  // Carries out notifying filters that the playback rate has changed.
+  void PlaybackRateChangedTask(double playback_rate);
+
+  // Carries out notifying filters that the volume has changed.
+  void VolumeChangedTask(float volume);
+
+  // Carries out notifying filters that we are seeking to a new timestamp.
+  void SeekTask(base::TimeDelta time, const PipelineStatusCB& seek_cb);
+
+  // Carries out setting the |cdm_context| in |renderer_|, and then fires
+  // |cdm_attached_cb| with the result. If |renderer_| is null,
+  // |cdm_attached_cb| will be fired immediately with true, and |cdm_context|
+  // will be set in |renderer_| later when |renderer_| is created.
+  void SetCdmTask(CdmContext* cdm_context,
+                  const CdmAttachedCB& cdm_attached_cb);
+
+  // Callbacks executed when a renderer has ended.
+  void OnRendererEnded();
+  void OnTextRendererEnded();
+  void RunEndedCallbackIfNeeded();
+
+  scoped_ptr<TextRenderer> CreateTextRenderer();
+
+  // Carries out adding a new text stream to the text renderer.
+  void AddTextStreamTask(DemuxerStream* text_stream,
+                         const TextTrackConfig& config);
+
+  // Carries out removing a text stream from the text renderer.
+  void RemoveTextStreamTask(DemuxerStream* text_stream);
+
+  // Callbacks executed when a text track is added.
+  void OnAddTextTrack(const TextTrackConfig& config,
+                      const AddTextTrackDoneCB& done_cb);
+
+  // Kicks off initialization for each media object, executing |done_cb| with
+  // the result when completed.
+  void InitializeDemuxer(const PipelineStatusCB& done_cb);
+  void InitializeRenderer(const PipelineStatusCB& done_cb);
+
+  void StateTransitionTask(PipelineStatus status);
+
+  // Initiates an asynchronous pause-flush-seek-preroll call sequence
+  // executing |done_cb| with the final status when completed.
+  void DoSeek(base::TimeDelta seek_timestamp, const PipelineStatusCB& done_cb);
+
+  // Initiates an asynchronous pause-flush-stop call sequence executing
+  // |done_cb| when completed.
+  void DoStop(const PipelineStatusCB& done_cb);
+  void OnStopCompleted(PipelineStatus status);
+
+  void ReportMetadata();
+
+  void BufferingStateChanged(BufferingState new_buffering_state);
+
+  // Task runner used to execute pipeline tasks.
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+  // MediaLog to which to log events.
+  scoped_refptr<MediaLog> media_log_;
+
+  // Lock used to serialize access for the following data members.
+  mutable base::Lock lock_;
+
+  // Whether or not the pipeline is running.
+  bool running_;
+
+  // Amount of available buffered data as reported by |demuxer_|.
+  Ranges<base::TimeDelta> buffered_time_ranges_;
+
+  // True when OnBufferedTimeRangesChanged() has been called more recently than
+  // DidLoadingProgress().
+  bool did_loading_progress_;
+
+  // Current volume level (from 0.0f to 1.0f).  This value is set immediately
+  // via SetVolume() and a task is dispatched on the task runner to notify the
+  // filters.
+  float volume_;
+
+  // Current playback rate (>= 0.0).  This value is set immediately via
+  // SetPlaybackRate() and a task is dispatched on the task runner to notify
+  // the filters.
+  double playback_rate_;
+
+  // Current duration as reported by |demuxer_|.
+  base::TimeDelta duration_;
+
+  // Status of the pipeline.  Initialized to PIPELINE_OK which indicates that
+  // the pipeline is operating correctly. Any other value indicates that the
+  // pipeline is stopped or is stopping.  Clients can call the Stop() method to
+  // reset the pipeline state, and restore this to PIPELINE_OK.
+  PipelineStatus status_;
+
+  // The following data members are only accessed by tasks posted to
+  // |task_runner_|.
+
+  // Member that tracks the current state.
+  State state_;
+
+  // The timestamp to start playback from after starting/seeking/resuming has
+  // completed.
+  base::TimeDelta start_timestamp_;
+
+  // The media timestamp to return while the pipeline is suspended. Otherwise
+  // set to kNoTimestamp().
+  base::TimeDelta suspend_timestamp_;
+
+  // Whether we've received the audio/video/text ended events.
+  bool renderer_ended_;
+  bool text_renderer_ended_;
+
+  // Temporary callback used for Start(), Seek(), and Resume().
+  PipelineStatusCB seek_cb_;
+
+  // Temporary callback used for Stop().
+  base::Closure stop_cb_;
+
+  // Temporary callback used for Suspend().
+  PipelineStatusCB suspend_cb_;
+
+  // Permanent callbacks passed in via Start().
+  base::Closure ended_cb_;
+  PipelineStatusCB error_cb_;
+  PipelineMetadataCB metadata_cb_;
+  BufferingStateCB buffering_state_cb_;
+  base::Closure duration_change_cb_;
+  AddTextTrackCB add_text_track_cb_;
+  base::Closure waiting_for_decryption_key_cb_;
+
+  // Holds the initialized demuxer. Used for seeking. Owned by client.
+  Demuxer* demuxer_;
+
+  // Holds the initialized renderers. Used for setting the volume,
+  // playback rate, and determining when playback has finished.
+  scoped_ptr<Renderer> renderer_;
+  scoped_ptr<TextRenderer> text_renderer_;
+
+  PipelineStatistics statistics_;
+
+  scoped_ptr<SerialRunner> pending_callbacks_;
+
+  // CdmContext to be used to decrypt (and decode) encrypted stream in this
+  // pipeline. Non-null only when SetCdm() is called and the pipeline has not
+  // been started. Then during Start(), this value will be set on |renderer_|.
+  CdmContext* pending_cdm_context_;
+
+  base::ThreadChecker thread_checker_;
+
+  // NOTE: Weak pointers must be invalidated before all other member variables.
+  base::WeakPtrFactory<PipelineImpl> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(PipelineImpl);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_BASE_PIPELINE_IMPL_H_
diff --git a/media/base/pipeline_unittest.cc b/media/base/pipeline_impl_unittest.cc
similarity index 85%
rename from media/base/pipeline_unittest.cc
rename to media/base/pipeline_impl_unittest.cc
index 8f43d60..1f735105 100644
--- a/media/base/pipeline_unittest.cc
+++ b/media/base/pipeline_impl_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "media/base/pipeline.h"
+#include "media/base/pipeline_impl.h"
 
 #include <stddef.h>
 #include <utility>
@@ -72,7 +72,7 @@
 // InitializationComplete(), which keeps the pipeline humming along.  If
 // either filters don't call InitializationComplete() immediately or filter
 // initialization is moved to a separate thread this test will become flaky.
-class PipelineTest : public ::testing::Test {
+class PipelineImplTest : public ::testing::Test {
  public:
   // Used for setting expectations on pipeline callbacks.  Using a StrictMock
   // also lets us test for missing callbacks.
@@ -96,17 +96,16 @@
     DISALLOW_COPY_AND_ASSIGN(CallbackHelper);
   };
 
-  PipelineTest()
-      : pipeline_(new Pipeline(message_loop_.task_runner(),
-                               new MediaLog())),
+  PipelineImplTest()
+      : pipeline_(
+            new PipelineImpl(message_loop_.task_runner(), new MediaLog())),
         demuxer_(new StrictMock<MockDemuxer>()),
         scoped_renderer_(new StrictMock<MockRenderer>()),
         renderer_(scoped_renderer_.get()) {
     // SetDemuxerExpectations() adds overriding expectations for expected
     // non-NULL streams.
     DemuxerStream* null_pointer = NULL;
-    EXPECT_CALL(*demuxer_, GetStream(_))
-        .WillRepeatedly(Return(null_pointer));
+    EXPECT_CALL(*demuxer_, GetStream(_)).WillRepeatedly(Return(null_pointer));
 
     EXPECT_CALL(*demuxer_, GetTimelineOffset())
         .WillRepeatedly(Return(base::Time()));
@@ -117,7 +116,7 @@
     EXPECT_CALL(*demuxer_, GetStartTime()).WillRepeatedly(Return(start_time_));
   }
 
-  virtual ~PipelineTest() {
+  virtual ~PipelineImplTest() {
     if (!pipeline_ || !pipeline_->IsRunning())
       return;
 
@@ -132,8 +131,8 @@
 
     // Expect a stop callback if we were started.
     ExpectPipelineStopAndDestroyPipeline();
-    pipeline_->Stop(base::Bind(&CallbackHelper::OnStop,
-                               base::Unretained(&callbacks_)));
+    pipeline_->Stop(
+        base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
     message_loop_.RunUntilIdle();
   }
 
@@ -166,9 +165,9 @@
     SetDemuxerExpectations(streams, base::TimeDelta::FromSeconds(10));
   }
 
-  scoped_ptr<StrictMock<MockDemuxerStream> > CreateStream(
+  scoped_ptr<StrictMock<MockDemuxerStream>> CreateStream(
       DemuxerStream::Type type) {
-    scoped_ptr<StrictMock<MockDemuxerStream> > stream(
+    scoped_ptr<StrictMock<MockDemuxerStream>> stream(
         new StrictMock<MockDemuxerStream>(type));
     return stream;
   }
@@ -177,17 +176,17 @@
   void SetRendererExpectations() {
     EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _))
         .WillOnce(DoAll(SaveArg<3>(&buffering_state_cb_),
-                        SaveArg<4>(&ended_cb_),
-                        PostCallback<1>(PIPELINE_OK)));
+                        SaveArg<4>(&ended_cb_), PostCallback<1>(PIPELINE_OK)));
     EXPECT_CALL(*renderer_, HasAudio()).WillRepeatedly(Return(audio_stream()));
     EXPECT_CALL(*renderer_, HasVideo()).WillRepeatedly(Return(video_stream()));
   }
 
   void AddTextStream() {
-    EXPECT_CALL(*this, OnAddTextTrack(_,_))
-        .WillOnce(Invoke(this, &PipelineTest::DoOnAddTextTrack));
-    static_cast<DemuxerHost*>(pipeline_.get())->AddTextStream(text_stream(),
-                              TextTrackConfig(kTextSubtitles, "", "", ""));
+    EXPECT_CALL(*this, OnAddTextTrack(_, _))
+        .WillOnce(Invoke(this, &PipelineImplTest::DoOnAddTextTrack));
+    static_cast<DemuxerHost*>(pipeline_.get())
+        ->AddTextStream(text_stream(),
+                        TextTrackConfig(kTextSubtitles, "", "", ""));
     message_loop_.RunUntilIdle();
   }
 
@@ -203,8 +202,8 @@
                    base::Unretained(&callbacks_)),
         base::Bind(&CallbackHelper::OnDurationChange,
                    base::Unretained(&callbacks_)),
-        base::Bind(&PipelineTest::OnAddTextTrack, base::Unretained(this)),
-        base::Bind(&PipelineTest::OnWaitingForDecryptionKey,
+        base::Bind(&PipelineImplTest::OnAddTextTrack, base::Unretained(this)),
+        base::Bind(&PipelineImplTest::OnWaitingForDecryptionKey,
                    base::Unretained(this)));
   }
 
@@ -218,8 +217,8 @@
       EXPECT_CALL(*renderer_, SetPlaybackRate(0.0));
       EXPECT_CALL(*renderer_, SetVolume(1.0f));
       EXPECT_CALL(*renderer_, StartPlayingFrom(start_time_))
-          .WillOnce(SetBufferingState(&buffering_state_cb_,
-                                      BUFFERING_HAVE_ENOUGH));
+          .WillOnce(
+              SetBufferingState(&buffering_state_cb_, BUFFERING_HAVE_ENOUGH));
       EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH));
     }
 
@@ -242,31 +241,25 @@
     text_stream_ = std::move(text_stream);
   }
 
-  MockDemuxerStream* audio_stream() {
-    return audio_stream_.get();
-  }
+  MockDemuxerStream* audio_stream() { return audio_stream_.get(); }
 
-  MockDemuxerStream* video_stream() {
-    return video_stream_.get();
-  }
+  MockDemuxerStream* video_stream() { return video_stream_.get(); }
 
-  FakeTextTrackStream* text_stream() {
-    return text_stream_.get();
-  }
+  FakeTextTrackStream* text_stream() { return text_stream_.get(); }
 
   void ExpectSeek(const base::TimeDelta& seek_time, bool underflowed) {
     EXPECT_CALL(*demuxer_, Seek(seek_time, _))
         .WillOnce(RunCallback<1>(PIPELINE_OK));
 
     EXPECT_CALL(*renderer_, Flush(_))
-        .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_,
-                                          BUFFERING_HAVE_NOTHING),
-                        RunClosure<0>()));
+        .WillOnce(DoAll(
+            SetBufferingState(&buffering_state_cb_, BUFFERING_HAVE_NOTHING),
+            RunClosure<0>()));
     EXPECT_CALL(*renderer_, SetPlaybackRate(_));
     EXPECT_CALL(*renderer_, SetVolume(_));
     EXPECT_CALL(*renderer_, StartPlayingFrom(seek_time))
-        .WillOnce(SetBufferingState(&buffering_state_cb_,
-                                    BUFFERING_HAVE_ENOUGH));
+        .WillOnce(
+            SetBufferingState(&buffering_state_cb_, BUFFERING_HAVE_ENOUGH));
     EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
 
     // We expect a successful seek callback followed by a buffering update.
@@ -275,9 +268,8 @@
   }
 
   void DoSeek(const base::TimeDelta& seek_time) {
-    pipeline_->Seek(seek_time,
-                    base::Bind(&CallbackHelper::OnSeek,
-                               base::Unretained(&callbacks_)));
+    pipeline_->Seek(seek_time, base::Bind(&CallbackHelper::OnSeek,
+                                          base::Unretained(&callbacks_)));
     message_loop_.RunUntilIdle();
   }
 
@@ -337,11 +329,11 @@
     // After the Pipeline is stopped, it could be destroyed any time. Always
     // destroy the pipeline immediately after OnStop() to test this.
     EXPECT_CALL(callbacks_, OnStop())
-        .WillOnce(Invoke(this, &PipelineTest::DestroyPipeline));
+        .WillOnce(Invoke(this, &PipelineImplTest::DestroyPipeline));
   }
 
-  MOCK_METHOD2(OnAddTextTrack, void(const TextTrackConfig&,
-                                    const AddTextTrackDoneCB&));
+  MOCK_METHOD2(OnAddTextTrack,
+               void(const TextTrackConfig&, const AddTextTrackDoneCB&));
   MOCK_METHOD0(OnWaitingForDecryptionKey, void(void));
 
   void DoOnAddTextTrack(const TextTrackConfig& config,
@@ -354,15 +346,15 @@
   StrictMock<CallbackHelper> callbacks_;
   base::SimpleTestTickClock test_tick_clock_;
   base::MessageLoop message_loop_;
-  scoped_ptr<Pipeline> pipeline_;
+  scoped_ptr<PipelineImpl> pipeline_;
 
-  scoped_ptr<StrictMock<MockDemuxer> > demuxer_;
-  scoped_ptr<StrictMock<MockRenderer> > scoped_renderer_;
+  scoped_ptr<StrictMock<MockDemuxer>> demuxer_;
+  scoped_ptr<StrictMock<MockRenderer>> scoped_renderer_;
   StrictMock<MockRenderer>* renderer_;
   StrictMock<CallbackHelper> text_renderer_callbacks_;
   TextRenderer* text_renderer_;
-  scoped_ptr<StrictMock<MockDemuxerStream> > audio_stream_;
-  scoped_ptr<StrictMock<MockDemuxerStream> > video_stream_;
+  scoped_ptr<StrictMock<MockDemuxerStream>> audio_stream_;
+  scoped_ptr<StrictMock<MockDemuxerStream>> video_stream_;
   scoped_ptr<FakeTextTrackStream> text_stream_;
   BufferingStateCB buffering_state_cb_;
   base::Closure ended_cb_;
@@ -371,12 +363,12 @@
   base::TimeDelta start_time_;
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(PipelineTest);
+  DISALLOW_COPY_AND_ASSIGN(PipelineImplTest);
 };
 
 // Test that playback controls methods no-op when the pipeline hasn't been
 // started.
-TEST_F(PipelineTest, NotStarted) {
+TEST_F(PipelineImplTest, NotStarted) {
   const base::TimeDelta kZero;
 
   EXPECT_FALSE(pipeline_->IsRunning());
@@ -400,7 +392,7 @@
   EXPECT_TRUE(kZero == pipeline_->GetMediaDuration());
 }
 
-TEST_F(PipelineTest, NeverInitializes) {
+TEST_F(PipelineImplTest, NeverInitializes) {
   // Don't execute the callback passed into Initialize().
   EXPECT_CALL(*demuxer_, Initialize(_, _, _));
 
@@ -417,14 +409,14 @@
   EXPECT_CALL(callbacks_, OnStart(PIPELINE_OK));
 }
 
-TEST_F(PipelineTest, StopWithoutStart) {
+TEST_F(PipelineImplTest, StopWithoutStart) {
   ExpectPipelineStopAndDestroyPipeline();
   pipeline_->Stop(
       base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
   message_loop_.RunUntilIdle();
 }
 
-TEST_F(PipelineTest, StartThenStopImmediately) {
+TEST_F(PipelineImplTest, StartThenStopImmediately) {
   EXPECT_CALL(*demuxer_, Initialize(_, _, _))
       .WillOnce(PostCallback<1>(PIPELINE_OK));
   EXPECT_CALL(*demuxer_, Stop());
@@ -439,7 +431,7 @@
   message_loop_.RunUntilIdle();
 }
 
-TEST_F(PipelineTest, DemuxerErrorDuringStop) {
+TEST_F(PipelineImplTest, DemuxerErrorDuringStop) {
   CreateAudioStream();
   MockDemuxerStreamVector streams;
   streams.push_back(audio_stream());
@@ -450,7 +442,7 @@
   StartPipelineAndExpect(PIPELINE_OK);
 
   EXPECT_CALL(*demuxer_, Stop())
-      .WillOnce(InvokeWithoutArgs(this, &PipelineTest::OnDemuxerError));
+      .WillOnce(InvokeWithoutArgs(this, &PipelineImplTest::OnDemuxerError));
   ExpectPipelineStopAndDestroyPipeline();
 
   pipeline_->Stop(
@@ -458,7 +450,7 @@
   message_loop_.RunUntilIdle();
 }
 
-TEST_F(PipelineTest, URLNotFound) {
+TEST_F(PipelineImplTest, URLNotFound) {
   EXPECT_CALL(*demuxer_, Initialize(_, _, _))
       .WillOnce(PostCallback<1>(PIPELINE_ERROR_URL_NOT_FOUND));
   EXPECT_CALL(*demuxer_, Stop());
@@ -466,7 +458,7 @@
   StartPipelineAndExpect(PIPELINE_ERROR_URL_NOT_FOUND);
 }
 
-TEST_F(PipelineTest, NoStreams) {
+TEST_F(PipelineImplTest, NoStreams) {
   EXPECT_CALL(*demuxer_, Initialize(_, _, _))
       .WillOnce(PostCallback<1>(PIPELINE_OK));
   EXPECT_CALL(*demuxer_, Stop());
@@ -475,7 +467,7 @@
   StartPipelineAndExpect(PIPELINE_ERROR_COULD_NOT_RENDER);
 }
 
-TEST_F(PipelineTest, AudioStream) {
+TEST_F(PipelineImplTest, AudioStream) {
   CreateAudioStream();
   MockDemuxerStreamVector streams;
   streams.push_back(audio_stream());
@@ -488,7 +480,7 @@
   EXPECT_FALSE(metadata_.has_video);
 }
 
-TEST_F(PipelineTest, VideoStream) {
+TEST_F(PipelineImplTest, VideoStream) {
   CreateVideoStream();
   MockDemuxerStreamVector streams;
   streams.push_back(video_stream());
@@ -501,7 +493,7 @@
   EXPECT_TRUE(metadata_.has_video);
 }
 
-TEST_F(PipelineTest, AudioVideoStream) {
+TEST_F(PipelineImplTest, AudioVideoStream) {
   CreateAudioStream();
   CreateVideoStream();
   MockDemuxerStreamVector streams;
@@ -516,7 +508,7 @@
   EXPECT_TRUE(metadata_.has_video);
 }
 
-TEST_F(PipelineTest, VideoTextStream) {
+TEST_F(PipelineImplTest, VideoTextStream) {
   CreateVideoStream();
   CreateTextStream();
   MockDemuxerStreamVector streams;
@@ -532,7 +524,7 @@
   AddTextStream();
 }
 
-TEST_F(PipelineTest, VideoAudioTextStream) {
+TEST_F(PipelineImplTest, VideoAudioTextStream) {
   CreateVideoStream();
   CreateAudioStream();
   CreateTextStream();
@@ -550,7 +542,7 @@
   AddTextStream();
 }
 
-TEST_F(PipelineTest, Seek) {
+TEST_F(PipelineImplTest, Seek) {
   CreateAudioStream();
   CreateVideoStream();
   CreateTextStream();
@@ -570,7 +562,7 @@
   DoSeek(expected);
 }
 
-TEST_F(PipelineTest, SeekAfterError) {
+TEST_F(PipelineImplTest, SeekAfterError) {
   CreateAudioStream();
   MockDemuxerStreamVector streams;
   streams.push_back(audio_stream());
@@ -594,7 +586,7 @@
   message_loop_.RunUntilIdle();
 }
 
-TEST_F(PipelineTest, SuspendResume) {
+TEST_F(PipelineImplTest, SuspendResume) {
   CreateAudioStream();
   CreateVideoStream();
   CreateTextStream();
@@ -615,7 +607,7 @@
   DoResume(expected);
 }
 
-TEST_F(PipelineTest, SetVolume) {
+TEST_F(PipelineImplTest, SetVolume) {
   CreateAudioStream();
   MockDemuxerStreamVector streams;
   streams.push_back(audio_stream());
@@ -632,7 +624,7 @@
   pipeline_->SetVolume(expected);
 }
 
-TEST_F(PipelineTest, Properties) {
+TEST_F(PipelineImplTest, Properties) {
   CreateVideoStream();
   MockDemuxerStreamVector streams;
   streams.push_back(video_stream());
@@ -647,7 +639,7 @@
   EXPECT_FALSE(pipeline_->DidLoadingProgress());
 }
 
-TEST_F(PipelineTest, GetBufferedTimeRanges) {
+TEST_F(PipelineImplTest, GetBufferedTimeRanges) {
   CreateVideoStream();
   MockDemuxerStreamVector streams;
   streams.push_back(video_stream());
@@ -677,7 +669,7 @@
   EXPECT_FALSE(pipeline_->DidLoadingProgress());
 }
 
-TEST_F(PipelineTest, EndedCallback) {
+TEST_F(PipelineImplTest, EndedCallback) {
   CreateAudioStream();
   CreateVideoStream();
   CreateTextStream();
@@ -700,7 +692,7 @@
   message_loop_.RunUntilIdle();
 }
 
-TEST_F(PipelineTest, ErrorDuringSeek) {
+TEST_F(PipelineImplTest, ErrorDuringSeek) {
   CreateAudioStream();
   MockDemuxerStreamVector streams;
   streams.push_back(audio_stream());
@@ -718,9 +710,9 @@
 
   EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
   EXPECT_CALL(*renderer_, Flush(_))
-      .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_,
-                                        BUFFERING_HAVE_NOTHING),
-                      RunClosure<0>()));
+      .WillOnce(
+          DoAll(SetBufferingState(&buffering_state_cb_, BUFFERING_HAVE_NOTHING),
+                RunClosure<0>()));
 
   EXPECT_CALL(*demuxer_, Seek(seek_time, _))
       .WillOnce(RunCallback<1>(PIPELINE_ERROR_READ));
@@ -734,9 +726,9 @@
 
 // Invoked function OnError. This asserts that the pipeline does not enqueue
 // non-teardown related tasks while tearing down.
-static void TestNoCallsAfterError(
-    Pipeline* pipeline, base::MessageLoop* message_loop,
-    PipelineStatus /* status */) {
+static void TestNoCallsAfterError(PipelineImpl* pipeline,
+                                  base::MessageLoop* message_loop,
+                                  PipelineStatus /* status */) {
   CHECK(pipeline);
   CHECK(message_loop);
 
@@ -751,7 +743,7 @@
   EXPECT_TRUE(message_loop->IsIdleForTesting());
 }
 
-TEST_F(PipelineTest, NoMessageDuringTearDownFromError) {
+TEST_F(PipelineImplTest, NoMessageDuringTearDownFromError) {
   CreateAudioStream();
   MockDemuxerStreamVector streams;
   streams.push_back(audio_stream());
@@ -761,8 +753,8 @@
   StartPipelineAndExpect(PIPELINE_OK);
 
   // Trigger additional requests on the pipeline during tear down from error.
-  base::Callback<void(PipelineStatus)> cb = base::Bind(
-      &TestNoCallsAfterError, pipeline_.get(), &message_loop_);
+  base::Callback<void(PipelineStatus)> cb =
+      base::Bind(&TestNoCallsAfterError, pipeline_.get(), &message_loop_);
   ON_CALL(callbacks_, OnError(_))
       .WillByDefault(Invoke(&cb, &base::Callback<void(PipelineStatus)>::Run));
 
@@ -770,9 +762,9 @@
 
   // Seek() isn't called as the demuxer errors out first.
   EXPECT_CALL(*renderer_, Flush(_))
-      .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_,
-                                        BUFFERING_HAVE_NOTHING),
-                      RunClosure<0>()));
+      .WillOnce(
+          DoAll(SetBufferingState(&buffering_state_cb_, BUFFERING_HAVE_NOTHING),
+                RunClosure<0>()));
   EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
 
   EXPECT_CALL(*demuxer_, Seek(seek_time, _))
@@ -785,7 +777,7 @@
   message_loop_.RunUntilIdle();
 }
 
-TEST_F(PipelineTest, DestroyAfterStop) {
+TEST_F(PipelineImplTest, DestroyAfterStop) {
   CreateAudioStream();
   MockDemuxerStreamVector streams;
   streams.push_back(audio_stream());
@@ -801,7 +793,7 @@
   message_loop_.RunUntilIdle();
 }
 
-TEST_F(PipelineTest, Underflow) {
+TEST_F(PipelineImplTest, Underflow) {
   CreateAudioStream();
   CreateVideoStream();
   MockDemuxerStreamVector streams;
@@ -822,7 +814,7 @@
   DoSeek(expected);
 }
 
-TEST_F(PipelineTest, PositiveStartTime) {
+TEST_F(PipelineImplTest, PositiveStartTime) {
   start_time_ = base::TimeDelta::FromSeconds(1);
   EXPECT_CALL(*demuxer_, GetStartTime()).WillRepeatedly(Return(start_time_));
   CreateAudioStream();
@@ -838,7 +830,7 @@
   message_loop_.RunUntilIdle();
 }
 
-class PipelineTeardownTest : public PipelineTest {
+class PipelineTeardownTest : public PipelineImplTest {
  public:
   enum TeardownState {
     kInitDemuxer,
@@ -903,8 +895,8 @@
   PipelineStatus SetInitializeExpectations(TeardownState state,
                                            StopOrError stop_or_error) {
     PipelineStatus status = PIPELINE_OK;
-    base::Closure stop_cb = base::Bind(
-        &CallbackHelper::OnStop, base::Unretained(&callbacks_));
+    base::Closure stop_cb =
+        base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_));
 
     if (state == kInitDemuxer) {
       if (stop_or_error == kStop) {
@@ -959,8 +951,8 @@
     EXPECT_CALL(*renderer_, SetPlaybackRate(0.0));
     EXPECT_CALL(*renderer_, SetVolume(1.0f));
     EXPECT_CALL(*renderer_, StartPlayingFrom(base::TimeDelta()))
-        .WillOnce(SetBufferingState(&buffering_state_cb_,
-                                    BUFFERING_HAVE_ENOUGH));
+        .WillOnce(
+            SetBufferingState(&buffering_state_cb_, BUFFERING_HAVE_ENOUGH));
 
     if (status == PIPELINE_OK)
       EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH));
@@ -979,32 +971,33 @@
       ExpectPipelineStopAndDestroyPipeline();
     }
 
-    pipeline_->Seek(base::TimeDelta::FromSeconds(10), base::Bind(
-        &CallbackHelper::OnSeek, base::Unretained(&callbacks_)));
+    pipeline_->Seek(
+        base::TimeDelta::FromSeconds(10),
+        base::Bind(&CallbackHelper::OnSeek, base::Unretained(&callbacks_)));
     message_loop_.RunUntilIdle();
   }
 
   PipelineStatus SetSeekExpectations(TeardownState state,
                                      StopOrError stop_or_error) {
     PipelineStatus status = PIPELINE_OK;
-    base::Closure stop_cb = base::Bind(
-        &CallbackHelper::OnStop, base::Unretained(&callbacks_));
+    base::Closure stop_cb =
+        base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_));
 
     if (state == kFlushing) {
       if (stop_or_error == kStop) {
         EXPECT_CALL(*renderer_, Flush(_))
-            .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
-                            SetBufferingState(&buffering_state_cb_,
-                                              BUFFERING_HAVE_NOTHING),
-                            RunClosure<0>()));
+            .WillOnce(DoAll(
+                Stop(pipeline_.get(), stop_cb),
+                SetBufferingState(&buffering_state_cb_, BUFFERING_HAVE_NOTHING),
+                RunClosure<0>()));
         EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
       } else {
         status = PIPELINE_ERROR_READ;
         EXPECT_CALL(*renderer_, Flush(_))
-            .WillOnce(DoAll(SetError(pipeline_.get(), status),
-                            SetBufferingState(&buffering_state_cb_,
-                                              BUFFERING_HAVE_NOTHING),
-                            RunClosure<0>()));
+            .WillOnce(DoAll(
+                SetError(pipeline_.get(), status),
+                SetBufferingState(&buffering_state_cb_, BUFFERING_HAVE_NOTHING),
+                RunClosure<0>()));
         EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
       }
 
@@ -1012,9 +1005,9 @@
     }
 
     EXPECT_CALL(*renderer_, Flush(_))
-        .WillOnce(DoAll(SetBufferingState(&buffering_state_cb_,
-                                          BUFFERING_HAVE_NOTHING),
-                        RunClosure<0>()));
+        .WillOnce(DoAll(
+            SetBufferingState(&buffering_state_cb_, BUFFERING_HAVE_NOTHING),
+            RunClosure<0>()));
     EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
 
     if (state == kSeeking) {
@@ -1024,8 +1017,7 @@
                             RunCallback<1>(PIPELINE_OK)));
       } else {
         status = PIPELINE_ERROR_READ;
-        EXPECT_CALL(*demuxer_, Seek(_, _))
-            .WillOnce(RunCallback<1>(status));
+        EXPECT_CALL(*demuxer_, Seek(_, _)).WillOnce(RunCallback<1>(status));
       }
 
       return status;
@@ -1046,12 +1038,12 @@
       }
     }
 
-    PipelineTest::DoSuspend();
+    PipelineImplTest::DoSuspend();
 
     if (state == kSuspended) {
       DoStopOrError(stop_or_error);
     } else if (state == kResuming) {
-      PipelineTest::DoResume(base::TimeDelta());
+      PipelineImplTest::DoResume(base::TimeDelta());
     }
   }
 
@@ -1112,8 +1104,8 @@
     switch (stop_or_error) {
       case kStop:
         ExpectPipelineStopAndDestroyPipeline();
-        pipeline_->Stop(base::Bind(
-            &CallbackHelper::OnStop, base::Unretained(&callbacks_)));
+        pipeline_->Stop(
+            base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
         break;
 
       case kError:
@@ -1126,8 +1118,8 @@
         ExpectPipelineStopAndDestroyPipeline();
         pipeline_->SetErrorForTesting(PIPELINE_ERROR_READ);
         message_loop_.RunUntilIdle();
-        pipeline_->Stop(base::Bind(
-            &CallbackHelper::OnStop, base::Unretained(&callbacks_)));
+        pipeline_->Stop(
+            base::Bind(&CallbackHelper::OnStop, base::Unretained(&callbacks_)));
         break;
     }
 
@@ -1137,10 +1129,10 @@
   DISALLOW_COPY_AND_ASSIGN(PipelineTeardownTest);
 };
 
-#define INSTANTIATE_TEARDOWN_TEST(stop_or_error, state) \
-    TEST_F(PipelineTeardownTest, stop_or_error##_##state) { \
-      RunTest(k##state, k##stop_or_error); \
-    }
+#define INSTANTIATE_TEARDOWN_TEST(stop_or_error, state)   \
+  TEST_F(PipelineTeardownTest, stop_or_error##_##state) { \
+    RunTest(k##state, k##stop_or_error);                  \
+  }
 
 INSTANTIATE_TEARDOWN_TEST(Stop, InitDemuxer);
 INSTANTIATE_TEARDOWN_TEST(Stop, InitRenderer);
diff --git a/media/blink/multibuffer_data_source.cc b/media/blink/multibuffer_data_source.cc
index 1ecebcc..67a6136 100644
--- a/media/blink/multibuffer_data_source.cc
+++ b/media/blink/multibuffer_data_source.cc
@@ -356,8 +356,13 @@
 }
 
 bool MultibufferDataSource::GetSize(int64_t* size_out) {
-  *size_out = url_data_->length();
-  return *size_out != kPositionNotSpecified;
+  base::AutoLock auto_lock(lock_);
+  if (total_bytes_ != kPositionNotSpecified) {
+    *size_out = total_bytes_;
+    return true;
+  }
+  *size_out = 0;
+  return false;
 }
 
 bool MultibufferDataSource::IsStreaming() {
@@ -445,7 +450,10 @@
                   url_data_->length() != kPositionNotSpecified);
 
   if (success) {
-    total_bytes_ = url_data_->length();
+    {
+      base::AutoLock auto_lock(lock_);
+      total_bytes_ = url_data_->length();
+    }
     streaming_ =
         !assume_fully_buffered() && (total_bytes_ == kPositionNotSpecified ||
                                      !url_data_->range_supported());
diff --git a/media/blink/multibuffer_data_source.h b/media/blink/multibuffer_data_source.h
index edf02c85..749cdeda2 100644
--- a/media/blink/multibuffer_data_source.h
+++ b/media/blink/multibuffer_data_source.h
@@ -190,7 +190,7 @@
   class ReadOperation;
   scoped_ptr<ReadOperation> read_op_;
 
-  // Protects |stop_signal_received_| and |read_op_|.
+  // Protects |stop_signal_received_|, |read_op_| and |total_bytes_|.
   base::Lock lock_;
 
   // Whether we've been told to stop via Abort() or Stop().
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index 3749bf2f..4f966eb 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -835,7 +835,7 @@
     return;
   }
 
-  // TODO(xhwang): Update this UMA name.
+  // TODO(xhwang): Update this UMA name. https://crbug.com/589251
   UMA_HISTOGRAM_COUNTS("Media.EME.NeedKey", 1);
 
   encrypted_client_->encrypted(
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h
index cfdc7907..73a1ce9e 100644
--- a/media/blink/webmediaplayer_impl.h
+++ b/media/blink/webmediaplayer_impl.h
@@ -18,7 +18,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread.h"
 #include "build/build_config.h"
-#include "media/base/pipeline.h"
+#include "media/base/pipeline_impl.h"
 #include "media/base/renderer_factory.h"
 #include "media/base/surface_manager.h"
 #include "media/base/text_track.h"
@@ -308,7 +308,7 @@
   scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
   scoped_refptr<base::TaskRunner> worker_task_runner_;
   scoped_refptr<MediaLog> media_log_;
-  Pipeline pipeline_;
+  PipelineImpl pipeline_;
 
   // The LoadType passed in the |load_type| parameter of the load() call.
   LoadType load_type_;
diff --git a/content/browser/device_monitor_mac.h b/media/capture/device_monitor_mac.h
similarity index 83%
rename from content/browser/device_monitor_mac.h
rename to media/capture/device_monitor_mac.h
index 05eab158..1b70bd9 100644
--- a/content/browser/device_monitor_mac.h
+++ b/media/capture/device_monitor_mac.h
@@ -2,23 +2,24 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_DEVICE_MONITOR_MAC_H_
-#define CONTENT_BROWSER_DEVICE_MONITOR_MAC_H_
+#ifndef MEDIA_CAPTURE_DEVICE_MONITOR_MAC_H_
+#define MEDIA_CAPTURE_DEVICE_MONITOR_MAC_H_
 
 #include "base/macros.h"
 #include "base/system_monitor/system_monitor.h"
 #include "base/threading/thread_checker.h"
+#include "media/base/media_export.h"
 
 namespace {
 class DeviceMonitorMacImpl;
 }
 
-namespace content {
+namespace media {
 
 // Class to track audio/video devices removal or addition via callback to
 // base::SystemMonitor ProcessDevicesChanged(). A single object of this class
 // is created from the browser main process and lives as long as this one.
-class DeviceMonitorMac {
+class MEDIA_EXPORT DeviceMonitorMac {
  public:
   DeviceMonitorMac();
   ~DeviceMonitorMac();
@@ -28,7 +29,7 @@
   // OS supports it. The |device_task_runner| argument represents the thread on
   // which device enumeration will occur.
   void StartMonitoring(
-    const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner);
+      const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner);
 
   // Method called by the internal DeviceMonitorMacImpl object
   // |device_monitor_impl_| when a device of type |type| has been added to or
@@ -48,4 +49,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_DEVICE_MONITOR_MAC_H_
+#endif  // MEDIA_CAPTURE_DEVICE_MONITOR_MAC_H_
diff --git a/content/browser/device_monitor_mac.mm b/media/capture/device_monitor_mac.mm
similarity index 80%
rename from content/browser/device_monitor_mac.mm
rename to media/capture/device_monitor_mac.mm
index 248b99d..aab9884 100644
--- a/content/browser/device_monitor_mac.mm
+++ b/media/capture/device_monitor_mac.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/device_monitor_mac.h"
+#include "media/capture/device_monitor_mac.h"
 
 #import <QTKit/QTKit.h>
 
@@ -14,24 +14,16 @@
 #include "base/mac/scoped_nsobject.h"
 #include "base/macros.h"
 #include "base/profiler/scoped_tracker.h"
+#include "base/task_runner_util.h"
 #include "base/threading/thread_checker.h"
-#include "content/public/browser/browser_thread.h"
 #import "media/base/mac/avfoundation_glue.h"
 
-using content::BrowserThread;
-
 namespace {
 
 // This class is used to keep track of system devices names and their types.
 class DeviceInfo {
  public:
-  enum DeviceType {
-    kAudio,
-    kVideo,
-    kMuxed,
-    kUnknown,
-    kInvalid
-  };
+  enum DeviceType { kAudio, kVideo, kMuxed, kUnknown, kInvalid };
 
   DeviceInfo(const std::string& unique_id, DeviceType type)
       : unique_id_(unique_id), type_(type) {}
@@ -56,7 +48,7 @@
 // or an AVFoundation implementation of events and notifications.
 class DeviceMonitorMacImpl {
  public:
-  explicit DeviceMonitorMacImpl(content::DeviceMonitorMac* monitor)
+  explicit DeviceMonitorMacImpl(media::DeviceMonitorMac* monitor)
       : monitor_(monitor),
         cached_devices_(),
         device_arrival_(nil),
@@ -80,7 +72,7 @@
       const std::vector<DeviceInfo>& snapshot_devices);
 
  protected:
-  content::DeviceMonitorMac* monitor_;
+  media::DeviceMonitorMac* monitor_;
   std::vector<DeviceInfo> cached_devices_;
 
   // Handles to NSNotificationCenter block observers.
@@ -137,7 +129,7 @@
 
 class QTKitMonitorImpl : public DeviceMonitorMacImpl {
  public:
-  explicit QTKitMonitorImpl(content::DeviceMonitorMac* monitor);
+  explicit QTKitMonitorImpl(media::DeviceMonitorMac* monitor);
   ~QTKitMonitorImpl() override;
 
   void OnDeviceChanged() override;
@@ -149,7 +141,7 @@
   id device_change_;
 };
 
-QTKitMonitorImpl::QTKitMonitorImpl(content::DeviceMonitorMac* monitor)
+QTKitMonitorImpl::QTKitMonitorImpl(media::DeviceMonitorMac* monitor)
     : DeviceMonitorMacImpl(monitor) {
   NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
   device_arrival_ =
@@ -157,19 +149,22 @@
                       object:nil
                        queue:nil
                   usingBlock:^(NSNotification* notification) {
-                      OnDeviceChanged();}];
+                    OnDeviceChanged();
+                  }];
   device_removal_ =
       [nc addObserverForName:QTCaptureDeviceWasDisconnectedNotification
                       object:nil
                        queue:nil
                   usingBlock:^(NSNotification* notification) {
-                      OnDeviceChanged();}];
+                    OnDeviceChanged();
+                  }];
   device_change_ =
       [nc addObserverForName:QTCaptureDeviceAttributeDidChangeNotification
                       object:nil
                        queue:nil
                   usingBlock:^(NSNotification* notification) {
-                      OnAttributeChanged(notification);}];
+                    OnAttributeChanged(notification);
+                  }];
 }
 
 QTKitMonitorImpl::~QTKitMonitorImpl() {
@@ -179,11 +174,9 @@
   [nc removeObserver:device_change_];
 }
 
-void QTKitMonitorImpl::OnAttributeChanged(
-    NSNotification* notification) {
-  if ([[[notification userInfo]
-         objectForKey:QTCaptureDeviceChangedAttributeKey]
-      isEqualToString:QTCaptureDeviceSuspendedAttribute]) {
+void QTKitMonitorImpl::OnAttributeChanged(NSNotification* notification) {
+  if ([[[notification userInfo] objectForKey:QTCaptureDeviceChangedAttributeKey]
+          isEqualToString:QTCaptureDeviceSuspendedAttribute]) {
     OnDeviceChanged();
   }
 }
@@ -198,15 +191,15 @@
     // example, a laptop's internal webcam is suspended when the lid is closed.
     if ([device hasMediaType:QTMediaTypeVideo] &&
         ![[device attributeForKey:QTCaptureDeviceSuspendedAttribute]
-        boolValue]) {
+            boolValue]) {
       device_type = DeviceInfo::kVideo;
     } else if ([device hasMediaType:QTMediaTypeMuxed] &&
-        ![[device attributeForKey:QTCaptureDeviceSuspendedAttribute]
-        boolValue]) {
+               ![[device attributeForKey:QTCaptureDeviceSuspendedAttribute]
+                   boolValue]) {
       device_type = DeviceInfo::kMuxed;
     } else if ([device hasMediaType:QTMediaTypeSound] &&
-        ![[device attributeForKey:QTCaptureDeviceSuspendedAttribute]
-        boolValue]) {
+               ![[device attributeForKey:QTCaptureDeviceSuspendedAttribute]
+                   boolValue]) {
       device_type = DeviceInfo::kAudio;
     }
     snapshot_devices.push_back(
@@ -229,7 +222,10 @@
   base::Closure onDeviceChangedCallback_;
 
   // Member to keep track of the devices we are already monitoring.
-  std::set<base::scoped_nsobject<CrAVCaptureDevice> > monitoredDevices_;
+  std::set<base::scoped_nsobject<CrAVCaptureDevice>> monitoredDevices_;
+
+  // Pegged to the "main" thread -- usually content::BrowserThread::UI.
+  base::ThreadChecker mainThreadChecker_;
 }
 
 - (id)initWithOnChangedCallback:(const base::Closure&)callback;
@@ -242,11 +238,11 @@
 namespace {
 
 // This class owns and manages the lifetime of a CrAVFoundationDeviceObserver.
-// It is created and destroyed in UI thread by AVFoundationMonitorImpl, and it
-// operates on this thread except for the expensive device enumerations which
-// are run on Device Thread.
-class SuspendObserverDelegate :
-    public base::RefCountedThreadSafe<SuspendObserverDelegate> {
+// It is created and destroyed on AVFoundationMonitorImpl's main thread (usually
+// browser's UI thread), and it operates on this thread except for the expensive
+// device enumerations which are run on Device Thread.
+class SuspendObserverDelegate
+    : public base::RefCountedThreadSafe<SuspendObserverDelegate> {
  public:
   explicit SuspendObserverDelegate(DeviceMonitorMacImpl* monitor);
 
@@ -280,20 +276,22 @@
 
   base::scoped_nsobject<CrAVFoundationDeviceObserver> suspend_observer_;
   DeviceMonitorMacImpl* avfoundation_monitor_impl_;
+
+  // Pegged to the "main" thread -- usually content::BrowserThread::UI.
+  base::ThreadChecker main_thread_checker_;
 };
 
 SuspendObserverDelegate::SuspendObserverDelegate(DeviceMonitorMacImpl* monitor)
     : avfoundation_monitor_impl_(monitor) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(main_thread_checker_.CalledOnValidThread());
 }
 
 void SuspendObserverDelegate::StartObserver(
-      const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) {
+  DCHECK(main_thread_checker_.CalledOnValidThread());
 
-  base::Closure on_device_changed_callback =
-      base::Bind(&SuspendObserverDelegate::OnDeviceChanged,
-                 this, device_thread);
+  base::Closure on_device_changed_callback = base::Bind(
+      &SuspendObserverDelegate::OnDeviceChanged, this, device_thread);
   suspend_observer_.reset([[CrAVFoundationDeviceObserver alloc]
       initWithOnChangedCallback:on_device_changed_callback]);
 
@@ -301,37 +299,37 @@
   // done on UI thread. The devices array is retained in |device_thread| and
   // released in DoStartObserver().
   base::PostTaskAndReplyWithResult(
-      device_thread.get(),
-      FROM_HERE,
-      base::BindBlock(^{ return [[AVCaptureDeviceGlue devices] retain]; }),
+      device_thread.get(), FROM_HERE, base::BindBlock(^{
+        return [[AVCaptureDeviceGlue devices] retain];
+      }),
       base::Bind(&SuspendObserverDelegate::DoStartObserver, this));
 }
 
 void SuspendObserverDelegate::OnDeviceChanged(
-      const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    const scoped_refptr<base::SingleThreadTaskRunner>& device_thread) {
+  DCHECK(main_thread_checker_.CalledOnValidThread());
   // Enumerate the devices in Device thread and post the consolidation of the
-  // new devices and the old ones to be done on UI thread. The devices array
+  // new devices and the old ones to be done on main thread. The devices array
   // is retained in |device_thread| and released in DoOnDeviceChanged().
   PostTaskAndReplyWithResult(
-      device_thread.get(),
-      FROM_HERE,
-      base::BindBlock(^{ return [[AVCaptureDeviceGlue devices] retain]; }),
+      device_thread.get(), FROM_HERE, base::BindBlock(^{
+        return [[AVCaptureDeviceGlue devices] retain];
+      }),
       base::Bind(&SuspendObserverDelegate::DoOnDeviceChanged, this));
 }
 
 void SuspendObserverDelegate::ResetDeviceMonitor() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(main_thread_checker_.CalledOnValidThread());
   avfoundation_monitor_impl_ = NULL;
   [suspend_observer_ clearOnDeviceChangedCallback];
 }
 
 SuspendObserverDelegate::~SuspendObserverDelegate() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(main_thread_checker_.CalledOnValidThread());
 }
 
 void SuspendObserverDelegate::DoStartObserver(NSArray* devices) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(main_thread_checker_.CalledOnValidThread());
   base::scoped_nsobject<NSArray> auto_release(devices);
   for (CrAVCaptureDevice* device in devices) {
     base::scoped_nsobject<CrAVCaptureDevice> device_ptr([device retain]);
@@ -340,7 +338,7 @@
 }
 
 void SuspendObserverDelegate::DoOnDeviceChanged(NSArray* devices) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(main_thread_checker_.CalledOnValidThread());
   base::scoped_nsobject<NSArray> auto_release(devices);
   std::vector<DeviceInfo> snapshot_devices;
   for (CrAVCaptureDevice* device in devices) {
@@ -348,7 +346,7 @@
     [suspend_observer_ startObserving:device_ptr];
 
     BOOL suspended = [device respondsToSelector:@selector(isSuspended)] &&
-        [device isSuspended];
+                     [device isSuspended];
     DeviceInfo::DeviceType device_type = DeviceInfo::kUnknown;
     if ([device hasMediaType:AVFoundationGlue::AVMediaTypeVideo()]) {
       if (suspended)
@@ -359,8 +357,8 @@
     } else if ([device hasMediaType:AVFoundationGlue::AVMediaTypeAudio()]) {
       device_type = DeviceInfo::kAudio;
     }
-    snapshot_devices.push_back(DeviceInfo([[device uniqueID] UTF8String],
-                                          device_type));
+    snapshot_devices.push_back(
+        DeviceInfo([[device uniqueID] UTF8String], device_type));
   }
   // Make sure no references are held to |devices| when
   // ConsolidateDevicesListAndNotify is called since the VideoCaptureManager
@@ -377,12 +375,13 @@
 
 // AVFoundation implementation of the Mac Device Monitor, registers as a global
 // device connect/disconnect observer and plugs suspend/wake up device observers
-// per device. This class is created and lives in UI thread. Owns a
-// SuspendObserverDelegate that notifies when a device is suspended/resumed.
+// per device. This class is created and lives on the main Application thread
+// (UI for content). Owns a SuspendObserverDelegate that notifies when a device
+// is suspended/resumed.
 class AVFoundationMonitorImpl : public DeviceMonitorMacImpl {
  public:
   AVFoundationMonitorImpl(
-      content::DeviceMonitorMac* monitor,
+      media::DeviceMonitorMac* monitor,
       const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner);
   ~AVFoundationMonitorImpl() override;
 
@@ -390,42 +389,46 @@
 
  private:
   // {Video,AudioInput}DeviceManager's "Device" thread task runner used for
-  // posting tasks to |suspend_observer_delegate_|; valid after
-  // MediaStreamManager calls StartMonitoring().
+  // posting tasks to |suspend_observer_delegate_|;
   const scoped_refptr<base::SingleThreadTaskRunner> device_task_runner_;
 
+  // Pegged to the "main" thread -- usually content::BrowserThread::UI.
+  base::ThreadChecker main_thread_checker_;
+
   scoped_refptr<SuspendObserverDelegate> suspend_observer_delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(AVFoundationMonitorImpl);
 };
 
 AVFoundationMonitorImpl::AVFoundationMonitorImpl(
-    content::DeviceMonitorMac* monitor,
+    media::DeviceMonitorMac* monitor,
     const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner)
     : DeviceMonitorMacImpl(monitor),
       device_task_runner_(device_task_runner),
       suspend_observer_delegate_(new SuspendObserverDelegate(this)) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(main_thread_checker_.CalledOnValidThread());
   NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
   device_arrival_ =
       [nc addObserverForName:AVFoundationGlue::
-          AVCaptureDeviceWasConnectedNotification()
+                                 AVCaptureDeviceWasConnectedNotification()
                       object:nil
                        queue:nil
                   usingBlock:^(NSNotification* notification) {
-                      OnDeviceChanged();}];
+                    OnDeviceChanged();
+                  }];
   device_removal_ =
       [nc addObserverForName:AVFoundationGlue::
-          AVCaptureDeviceWasDisconnectedNotification()
+                                 AVCaptureDeviceWasDisconnectedNotification()
                       object:nil
                        queue:nil
                   usingBlock:^(NSNotification* notification) {
-                      OnDeviceChanged();}];
+                    OnDeviceChanged();
+                  }];
   suspend_observer_delegate_->StartObserver(device_task_runner_);
 }
 
 AVFoundationMonitorImpl::~AVFoundationMonitorImpl() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(main_thread_checker_.CalledOnValidThread());
   suspend_observer_delegate_->ResetDeviceMonitor();
   NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
   [nc removeObserver:device_arrival_];
@@ -433,7 +436,7 @@
 }
 
 void AVFoundationMonitorImpl::OnDeviceChanged() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(main_thread_checker_.CalledOnValidThread());
   suspend_observer_delegate_->OnDeviceChanged(device_task_runner_);
 }
 
@@ -442,7 +445,7 @@
 @implementation CrAVFoundationDeviceObserver
 
 - (id)initWithOnChangedCallback:(const base::Closure&)callback {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(mainThreadChecker_.CalledOnValidThread());
   if ((self = [super init])) {
     DCHECK(!callback.is_null());
     onDeviceChangedCallback_ = callback;
@@ -451,8 +454,8 @@
 }
 
 - (void)dealloc {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  std::set<base::scoped_nsobject<CrAVCaptureDevice> >::iterator it =
+  DCHECK(mainThreadChecker_.CalledOnValidThread());
+  std::set<base::scoped_nsobject<CrAVCaptureDevice>>::iterator it =
       monitoredDevices_.begin();
   while (it != monitoredDevices_.end())
     [self removeObservers:*(it++)];
@@ -460,7 +463,7 @@
 }
 
 - (void)startObserving:(base::scoped_nsobject<CrAVCaptureDevice>)device {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(mainThreadChecker_.CalledOnValidThread());
   DCHECK(device != nil);
   // Skip this device if there are already observers connected to it.
   if (std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device) !=
@@ -479,10 +482,10 @@
 }
 
 - (void)stopObserving:(CrAVCaptureDevice*)device {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(mainThreadChecker_.CalledOnValidThread());
   DCHECK(device != nil);
 
-  std::set<base::scoped_nsobject<CrAVCaptureDevice> >::iterator found =
+  std::set<base::scoped_nsobject<CrAVCaptureDevice>>::iterator found =
       std::find(monitoredDevices_.begin(), monitoredDevices_.end(), device);
   DCHECK(found != monitoredDevices_.end());
   [self removeObservers:*found];
@@ -490,12 +493,12 @@
 }
 
 - (void)clearOnDeviceChangedCallback {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(mainThreadChecker_.CalledOnValidThread());
   onDeviceChangedCallback_.Reset();
 }
 
 - (void)removeObservers:(CrAVCaptureDevice*)device {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(mainThreadChecker_.CalledOnValidThread());
   // Check sanity of |device| via its -observationInfo. http://crbug.com/371271.
   if ([device observationInfo]) {
     [device removeObserver:self
@@ -509,7 +512,7 @@
                       ofObject:(id)object
                         change:(NSDictionary*)change
                        context:(void*)context {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(mainThreadChecker_.CalledOnValidThread());
   if ([keyPath isEqual:@"suspended"])
     onDeviceChangedCallback_.Run();
   if ([keyPath isEqual:@"connected"])
@@ -518,7 +521,7 @@
 
 @end  // @implementation CrAVFoundationDeviceObserver
 
-namespace content {
+namespace media {
 
 DeviceMonitorMac::DeviceMonitorMac() {
   // Both QTKit and AVFoundation do not need to be fired up until the user
@@ -545,8 +548,8 @@
         FROM_HERE_WITH_EXPLICIT_FUNCTION(
             "458404 DeviceMonitorMac::StartMonitoring::AVFoundation"));
     DVLOG(1) << "Monitoring via AVFoundation";
-    device_monitor_impl_.reset(new AVFoundationMonitorImpl(this,
-                                                           device_task_runner));
+    device_monitor_impl_.reset(
+        new AVFoundationMonitorImpl(this, device_task_runner));
   } else {
     // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/458404
     // is fixed.
@@ -565,4 +568,4 @@
   base::SystemMonitor::Get()->ProcessDevicesChanged(type);
 }
 
-}  // namespace content
+}  // namespace media
diff --git a/media/cast/net/cast_transport_config.h b/media/cast/net/cast_transport_config.h
index 82823ad..dc63bee 100644
--- a/media/cast/net/cast_transport_config.h
+++ b/media/cast/net/cast_transport_config.h
@@ -126,6 +126,8 @@
 typedef base::Callback<bool(scoped_ptr<Packet> packet)>
     PacketReceiverCallbackWithStatus;
 
+// TODO(xjz): Rename PacketSender as it also deals with receiving packets.
+// http://crbug.com/589157.
 class PacketSender {
  public:
   // Send a packet to the network. Returns false if the network is blocked
@@ -138,6 +140,13 @@
   // Returns the number of bytes ever sent.
   virtual int64_t GetBytesSent() = 0;
 
+  // Start receiving packets. Pakets are submitted to |packet_receiver|.
+  virtual void StartReceiving(
+      const PacketReceiverCallbackWithStatus& packet_receiver) = 0;
+
+  // Stop receiving packets.
+  virtual void StopReceiving() = 0;
+
   virtual ~PacketSender() {}
 };
 
diff --git a/media/cast/net/cast_transport_sender.h b/media/cast/net/cast_transport_sender.h
index 0ff76e1..3272f74 100644
--- a/media/cast/net/cast_transport_sender.h
+++ b/media/cast/net/cast_transport_sender.h
@@ -25,6 +25,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/non_thread_safe.h"
 #include "base/time/tick_clock.h"
+#include "base/values.h"
 #include "media/cast/logging/logging_defines.h"
 #include "media/cast/net/cast_transport_config.h"
 #include "media/cast/net/cast_transport_defines.h"
@@ -42,6 +43,7 @@
 
 namespace media {
 namespace cast {
+
 struct RtpReceiverStatistics;
 struct RtcpTimeData;
 
@@ -54,19 +56,36 @@
                             scoped_ptr<std::vector<PacketEvent>>)>
     BulkRawEventsCallback;
 
+// TODO(xjz): Rename CastTransportSender as it also deals with receiving
+// packets. http://crbug.com/589157.
 // The application should only trigger this class from the transport thread.
 class CastTransportSender : public base::NonThreadSafe {
  public:
+  // Interface used for receiving status updates, raw events, and RTP packets
+  // from CastTransportSender.
+  class Client {
+   public:
+    virtual ~Client(){};
+
+    // Audio and Video transport status change is reported on this callback.
+    virtual void OnStatusChanged(CastTransportStatus status) = 0;
+
+    // Raw events will be invoked on this callback periodically, according to
+    // the configured logging flush interval passed to
+    // CastTransportSender::Create().
+    virtual void OnLoggingEventsReceived(
+        scoped_ptr<std::vector<FrameEvent>> frame_events,
+        scoped_ptr<std::vector<PacketEvent>> packet_events) = 0;
+
+    // Called to pass RTP packets to the Client.
+    virtual void ProcessRtpPacket(scoped_ptr<Packet> packet) = 0;
+  };
+
   static scoped_ptr<CastTransportSender> Create(
-      net::NetLog* net_log,
-      base::TickClock* clock,
-      const net::IPEndPoint& local_end_point,
-      const net::IPEndPoint& remote_end_point,
-      scoped_ptr<base::DictionaryValue> options,
-      const CastTransportStatusCallback& status_callback,
-      const BulkRawEventsCallback& raw_events_callback,
-      base::TimeDelta raw_events_callback_interval,
-      const PacketReceiverCallback& packet_callback,
+      base::TickClock* clock,  // Owned by the caller.
+      base::TimeDelta logging_flush_interval,
+      scoped_ptr<Client> client,
+      scoped_ptr<PacketSender> transport,
       const scoped_refptr<base::SingleThreadTaskRunner>& transport_task_runner);
 
   virtual ~CastTransportSender() {}
@@ -122,6 +141,9 @@
       base::TimeDelta target_delay,
       const ReceiverRtcpEventSubscriber::RtcpEvents* rtcp_events,
       const RtpReceiverStatistics* rtp_receiver_statistics) = 0;
+
+  // Set options for the PacedSender and Wifi.
+  virtual void SetOptions(const base::DictionaryValue& options) = 0;
 };
 
 }  // namespace cast
diff --git a/media/cast/net/cast_transport_sender_impl.cc b/media/cast/net/cast_transport_sender_impl.cc
index c1b700df..2962967 100644
--- a/media/cast/net/cast_transport_sender_impl.cc
+++ b/media/cast/net/cast_transport_sender_impl.cc
@@ -10,28 +10,22 @@
 #include <utility>
 
 #include "base/single_thread_task_runner.h"
-#include "base/values.h"
 #include "build/build_config.h"
 #include "media/cast/net/cast_transport_defines.h"
 #include "media/cast/net/rtcp/receiver_rtcp_session.h"
 #include "media/cast/net/rtcp/sender_rtcp_session.h"
-#include "media/cast/net/udp_transport.h"
 #include "net/base/net_errors.h"
-#include "net/base/network_interfaces.h"
 
 namespace media {
 namespace cast {
 
 namespace {
 
-// See header file for what these mean.
-const char kOptionDscp[] = "DSCP";
-#if defined(OS_WIN)
-const char kOptionDisableNonBlockingIO[] = "disable_non_blocking_io";
-#endif
-const char kOptionPacerTargetBurstSize[] = "pacer_target_burst_size";
+// Options for PaceSender.
 const char kOptionPacerMaxBurstSize[] = "pacer_max_burst_size";
-const char kOptionSendBufferMinSize[] = "send_buffer_min_size";
+const char kOptionPacerTargetBurstSize[] = "pacer_target_burst_size";
+
+// Wifi options.
 const char kOptionWifiDisableScan[] = "disable_wifi_scan";
 const char kOptionWifiMediaStreamingMode[] = "media_streaming_mode";
 
@@ -46,35 +40,17 @@
   }
 }
 
-int32_t GetTransportSendBufferSize(const base::DictionaryValue& options) {
-  // Socket send buffer size needs to be at least greater than one burst
-  // size.
-  int32_t max_burst_size =
-      LookupOptionWithDefault(options, kOptionPacerMaxBurstSize,
-                              kMaxBurstSize) *
-      kMaxIpPacketSize;
-  int32_t min_send_buffer_size =
-      LookupOptionWithDefault(options, kOptionSendBufferMinSize, 0);
-  return std::max(max_burst_size, min_send_buffer_size);
-}
-
 }  // namespace
 
 scoped_ptr<CastTransportSender> CastTransportSender::Create(
-    net::NetLog* net_log,
-    base::TickClock* clock,
-    const net::IPEndPoint& local_end_point,
-    const net::IPEndPoint& remote_end_point,
-    scoped_ptr<base::DictionaryValue> options,
-    const CastTransportStatusCallback& status_callback,
-    const BulkRawEventsCallback& raw_events_callback,
-    base::TimeDelta raw_events_callback_interval,
-    const PacketReceiverCallback& packet_callback,
+    base::TickClock* clock,  // Owned by the caller.
+    base::TimeDelta logging_flush_interval,
+    scoped_ptr<Client> client,
+    scoped_ptr<PacketSender> transport,
     const scoped_refptr<base::SingleThreadTaskRunner>& transport_task_runner) {
   return scoped_ptr<CastTransportSender>(new CastTransportSenderImpl(
-      net_log, clock, local_end_point, remote_end_point, std::move(options),
-      status_callback, raw_events_callback, raw_events_callback_interval,
-      transport_task_runner.get(), packet_callback, NULL));
+      clock, logging_flush_interval, std::move(client), std::move(transport),
+      transport_task_runner.get()));
 }
 
 PacketReceiverCallback CastTransportSender::PacketReceiverForTesting() {
@@ -82,83 +58,41 @@
 }
 
 CastTransportSenderImpl::CastTransportSenderImpl(
-    net::NetLog* net_log,
     base::TickClock* clock,
-    const net::IPEndPoint& local_end_point,
-    const net::IPEndPoint& remote_end_point,
-    scoped_ptr<base::DictionaryValue> options,
-    const CastTransportStatusCallback& status_callback,
-    const BulkRawEventsCallback& raw_events_callback,
-    base::TimeDelta raw_events_callback_interval,
-    const scoped_refptr<base::SingleThreadTaskRunner>& transport_task_runner,
-    const PacketReceiverCallback& packet_callback,
-    PacketSender* external_transport)
+    base::TimeDelta logging_flush_interval,
+    scoped_ptr<Client> client,
+    scoped_ptr<PacketSender> transport,
+    const scoped_refptr<base::SingleThreadTaskRunner>& transport_task_runner)
     : clock_(clock),
-      status_callback_(status_callback),
+      logging_flush_interval_(logging_flush_interval),
+      transport_client_(std::move(client)),
+      transport_(std::move(transport)),
       transport_task_runner_(transport_task_runner),
-      transport_(external_transport
-                     ? nullptr
-                     : new UdpTransport(net_log,
-                                        transport_task_runner,
-                                        local_end_point,
-                                        remote_end_point,
-                                        GetTransportSendBufferSize(*options),
-                                        status_callback)),
-      pacer_(LookupOptionWithDefault(*options,
-                                     kOptionPacerTargetBurstSize,
-                                     kTargetBurstSize),
-             LookupOptionWithDefault(*options,
-                                     kOptionPacerMaxBurstSize,
-                                     kMaxBurstSize),
+      pacer_(kTargetBurstSize,
+             kMaxBurstSize,
              clock,
-             raw_events_callback.is_null() ? nullptr : &recent_packet_events_,
-             external_transport ? external_transport : transport_.get(),
+             logging_flush_interval > base::TimeDelta() ? &recent_packet_events_
+                                                        : nullptr,
+             transport_.get(),
              transport_task_runner),
-      raw_events_callback_(raw_events_callback),
-      raw_events_callback_interval_(raw_events_callback_interval),
       last_byte_acked_for_audio_(0),
-      packet_callback_(packet_callback),
       weak_factory_(this) {
-  DCHECK(clock_);
-  if (!raw_events_callback_.is_null()) {
-    DCHECK(raw_events_callback_interval > base::TimeDelta());
-    transport_task_runner->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&CastTransportSenderImpl::SendRawEvents,
-                   weak_factory_.GetWeakPtr()),
-        raw_events_callback_interval);
+  DCHECK(clock);
+  DCHECK(transport_client_);
+  DCHECK(transport_);
+  DCHECK(transport_task_runner_);
+  if (logging_flush_interval_ > base::TimeDelta()) {
+    transport_task_runner_->PostDelayedTask(
+        FROM_HERE, base::Bind(&CastTransportSenderImpl::SendRawEvents,
+                              weak_factory_.GetWeakPtr()),
+        logging_flush_interval_);
   }
-  if (transport_) {
-    if (options->HasKey(kOptionDscp)) {
-      // The default DSCP value for cast is AF41. Which gives it a higher
-      // priority over other traffic.
-      transport_->SetDscp(net::DSCP_AF41);
-    }
-#if defined(OS_WIN)
-    if (!options->HasKey(kOptionDisableNonBlockingIO)) {
-      transport_->UseNonBlockingIO();
-    }
-#endif
-    transport_->StartReceiving(
-        base::Bind(&CastTransportSenderImpl::OnReceivedPacket,
-                   base::Unretained(this)));
-    int wifi_options = 0;
-    if (options->HasKey(kOptionWifiDisableScan)) {
-      wifi_options |= net::WIFI_OPTIONS_DISABLE_SCAN;
-    }
-    if (options->HasKey(kOptionWifiMediaStreamingMode)) {
-      wifi_options |= net::WIFI_OPTIONS_MEDIA_STREAMING_MODE;
-    }
-    if (wifi_options) {
-      wifi_options_autoreset_ = net::SetWifiOptions(wifi_options);
-    }
-  }
+  transport_->StartReceiving(base::Bind(
+      &CastTransportSenderImpl::OnReceivedPacket, base::Unretained(this)));
 }
 
 CastTransportSenderImpl::~CastTransportSenderImpl() {
-  if (transport_) {
-    transport_->StopReceiving();
-  }
+  transport_->StopReceiving();
 }
 
 void CastTransportSenderImpl::InitializeAudio(
@@ -168,7 +102,7 @@
   LOG_IF(WARNING, config.aes_key.empty() || config.aes_iv_mask.empty())
       << "Unsafe to send audio with encryption DISABLED.";
   if (!audio_encryptor_.Initialize(config.aes_key, config.aes_iv_mask)) {
-    status_callback_.Run(TRANSPORT_AUDIO_UNINITIALIZED);
+    transport_client_->OnStatusChanged(TRANSPORT_AUDIO_UNINITIALIZED);
     return;
   }
 
@@ -177,10 +111,10 @@
     // Audio packets have a higher priority.
     pacer_.RegisterAudioSsrc(config.ssrc);
     pacer_.RegisterPrioritySsrc(config.ssrc);
-    status_callback_.Run(TRANSPORT_AUDIO_INITIALIZED);
+    transport_client_->OnStatusChanged(TRANSPORT_AUDIO_INITIALIZED);
   } else {
     audio_sender_.reset();
-    status_callback_.Run(TRANSPORT_AUDIO_UNINITIALIZED);
+    transport_client_->OnStatusChanged(TRANSPORT_AUDIO_UNINITIALIZED);
     return;
   }
 
@@ -192,7 +126,7 @@
       clock_, &pacer_, config.ssrc, config.feedback_ssrc));
   pacer_.RegisterAudioSsrc(config.ssrc);
   AddValidSsrc(config.feedback_ssrc);
-  status_callback_.Run(TRANSPORT_AUDIO_INITIALIZED);
+  transport_client_->OnStatusChanged(TRANSPORT_AUDIO_INITIALIZED);
 }
 
 void CastTransportSenderImpl::InitializeVideo(
@@ -202,14 +136,14 @@
   LOG_IF(WARNING, config.aes_key.empty() || config.aes_iv_mask.empty())
       << "Unsafe to send video with encryption DISABLED.";
   if (!video_encryptor_.Initialize(config.aes_key, config.aes_iv_mask)) {
-    status_callback_.Run(TRANSPORT_VIDEO_UNINITIALIZED);
+    transport_client_->OnStatusChanged(TRANSPORT_VIDEO_UNINITIALIZED);
     return;
   }
 
   video_sender_.reset(new RtpSender(transport_task_runner_, &pacer_));
   if (!video_sender_->Initialize(config)) {
     video_sender_.reset();
-    status_callback_.Run(TRANSPORT_VIDEO_UNINITIALIZED);
+    transport_client_->OnStatusChanged(TRANSPORT_VIDEO_UNINITIALIZED);
     return;
   }
 
@@ -221,7 +155,7 @@
       clock_, &pacer_, config.ssrc, config.feedback_ssrc));
   pacer_.RegisterVideoSsrc(config.ssrc);
   AddValidSsrc(config.feedback_ssrc);
-  status_callback_.Run(TRANSPORT_VIDEO_INITIALIZED);
+  transport_client_->OnStatusChanged(TRANSPORT_VIDEO_INITIALIZED);
 }
 
 namespace {
@@ -327,7 +261,7 @@
 }
 
 void CastTransportSenderImpl::SendRawEvents() {
-  DCHECK(!raw_events_callback_.is_null());
+  DCHECK(logging_flush_interval_ > base::TimeDelta());
 
   if (!recent_frame_events_.empty() || !recent_packet_events_.empty()) {
     scoped_ptr<std::vector<FrameEvent>> frame_events(
@@ -336,14 +270,14 @@
     scoped_ptr<std::vector<PacketEvent>> packet_events(
         new std::vector<PacketEvent>());
     packet_events->swap(recent_packet_events_);
-    raw_events_callback_.Run(std::move(frame_events), std::move(packet_events));
+    transport_client_->OnLoggingEventsReceived(std::move(frame_events),
+                                               std::move(packet_events));
   }
 
   transport_task_runner_->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&CastTransportSenderImpl::SendRawEvents,
-                 weak_factory_.GetWeakPtr()),
-      raw_events_callback_interval_);
+      FROM_HERE, base::Bind(&CastTransportSenderImpl::SendRawEvents,
+                            weak_factory_.GetWeakPtr()),
+      logging_flush_interval_);
 }
 
 bool CastTransportSenderImpl::OnReceivedPacket(scoped_ptr<Packet> packet) {
@@ -369,18 +303,14 @@
       video_rtcp_session_->IncomingRtcpPacket(data, length)) {
     return true;
   }
-  if (packet_callback_.is_null()) {
-    VLOG(1) << "Stale packet received.";
-    return false;
-  }
-  packet_callback_.Run(std::move(packet));
+  transport_client_->ProcessRtpPacket(std::move(packet));
   return true;
 }
 
 void CastTransportSenderImpl::OnReceivedLogMessage(
     EventMediaType media_type,
     const RtcpReceiverLogMessage& log) {
-  if (raw_events_callback_.is_null())
+  if (logging_flush_interval_ <= base::TimeDelta())
     return;
 
   // Add received log messages into our log system.
@@ -460,6 +390,29 @@
   valid_ssrcs_.insert(ssrc);
 }
 
+void CastTransportSenderImpl::SetOptions(const base::DictionaryValue& options) {
+  // Set PacedSender options.
+  int burst_size = LookupOptionWithDefault(options, kOptionPacerTargetBurstSize,
+                                           media::cast::kTargetBurstSize);
+  if (burst_size != media::cast::kTargetBurstSize)
+    pacer_.SetTargetBurstSize(burst_size);
+  burst_size = LookupOptionWithDefault(options, kOptionPacerMaxBurstSize,
+                                       media::cast::kMaxBurstSize);
+  if (burst_size != media::cast::kMaxBurstSize)
+    pacer_.SetMaxBurstSize(burst_size);
+
+  // Set Wifi options.
+  int wifi_options = 0;
+  if (options.HasKey(kOptionWifiDisableScan)) {
+    wifi_options |= net::WIFI_OPTIONS_DISABLE_SCAN;
+  }
+  if (options.HasKey(kOptionWifiMediaStreamingMode)) {
+    wifi_options |= net::WIFI_OPTIONS_MEDIA_STREAMING_MODE;
+  }
+  if (wifi_options)
+    wifi_options_autoreset_ = net::SetWifiOptions(wifi_options);
+}
+
 // TODO(isheriff): This interface needs clean up.
 // https://crbug.com/569259
 void CastTransportSenderImpl::SendRtcpFromRtpReceiver(
diff --git a/media/cast/net/cast_transport_sender_impl.h b/media/cast/net/cast_transport_sender_impl.h
index 53f8694d..18b2db1 100644
--- a/media/cast/net/cast_transport_sender_impl.h
+++ b/media/cast/net/cast_transport_sender_impl.h
@@ -54,44 +54,12 @@
 
 class CastTransportSenderImpl : public CastTransportSender {
  public:
-  // |external_transport| is only used for testing.
-  // |raw_events_callback|: Raw events will be returned on this callback
-  // which will be invoked every |raw_events_callback_interval|.
-  // This can be a null callback, i.e. if user is not interested in raw events.
-  // |raw_events_callback_interval|: This can be |base::TimeDelta()| if
-  // |raw_events_callback| is a null callback.
-  // |options| contains optional settings for the transport, possible
-  // keys are:
-  //   "DSCP" (value ignored)
-  //       - Turns DSCP on (higher IP Precedence and Type of Service).
-  //   "disable_non_blocking_io" (value ignored)
-  //       - Windows only.  Turns off non-blocking IO for the socket.
-  //         Note: Non-blocking IO is, by default, enabled on all platforms.
-  //   "pacer_target_burst_size": int
-  //        - Specifies how many packets to send per 10 ms ideally.
-  //   "pacer_max_burst_size": int
-  //        - Specifies how many pakcets to send per 10 ms, maximum.
-  //   "send_buffer_min_size": int
-  //        - Specifies the minimum socket send buffer size.
-  //   "disable_wifi_scan" (value ignored)
-  //        - Disable wifi scans while streaming.
-  //   "media_streaming_mode" (value ignored)
-  //        - Turn media streaming mode on.
-  // Note, these options may be ignored on some platforms.
-  // TODO(hubbe): Too many callbacks, replace with an interface.
-  // http://crbug.com/557477
   CastTransportSenderImpl(
-      net::NetLog* net_log,
-      base::TickClock* clock,
-      const net::IPEndPoint& local_end_point,
-      const net::IPEndPoint& remote_end_point,
-      scoped_ptr<base::DictionaryValue> options,
-      const CastTransportStatusCallback& status_callback,
-      const BulkRawEventsCallback& raw_events_callback,
-      base::TimeDelta raw_events_callback_interval,
-      const scoped_refptr<base::SingleThreadTaskRunner>& transport_task_runner,
-      const PacketReceiverCallback& packet_callback,
-      PacketSender* external_transport);
+      base::TickClock* clock,  // Owned by the caller.
+      base::TimeDelta logging_flush_interval,
+      scoped_ptr<Client> client,
+      scoped_ptr<PacketSender> transport,
+      const scoped_refptr<base::SingleThreadTaskRunner>& transport_task_runner);
 
   ~CastTransportSenderImpl() final;
 
@@ -115,6 +83,20 @@
 
   PacketReceiverCallback PacketReceiverForTesting() final;
 
+  // Possible keys of |options| handled here are:
+  //   "pacer_target_burst_size": int
+  //        - Specifies how many packets to send per 10 ms ideally.
+  //   "pacer_max_burst_size": int
+  //        - Specifies how many pakcets to send per 10 ms, maximum.
+  //   "send_buffer_min_size": int
+  //        - Specifies the minimum socket send buffer size.
+  //   "disable_wifi_scan" (value ignored)
+  //        - Disable wifi scans while streaming.
+  //   "media_streaming_mode" (value ignored)
+  //        - Turn media streaming mode on.
+  // Note, these options may be ignored on some platforms.
+  void SetOptions(const base::DictionaryValue& options) final;
+
   // CastTransportReceiver implementation.
   void AddValidSsrc(uint32_t ssrc) final;
 
@@ -143,8 +125,8 @@
                      bool cancel_rtx_if_not_in_list,
                      const DedupInfo& dedup_info);
 
-  // If |raw_events_callback_| is non-null, calls it with events collected
-  // in |recent_frame_events_| and |recent_packet_events_| since last call.
+  // If |logging_flush_interval| is set, this is called at approximate periodic
+  // intervals.
   void SendRawEvents();
 
   // Called when a packet is received.
@@ -159,18 +141,18 @@
                              const RtcpCastMessageCallback& cast_message_cb,
                              const RtcpCastMessage& cast_message);
 
-  base::TickClock* clock_;  // Not owned by this class.
-  CastTransportStatusCallback status_callback_;
-  scoped_refptr<base::SingleThreadTaskRunner> transport_task_runner_;
+  base::TickClock* const clock_;  // Not owned by this class.
+  const base::TimeDelta logging_flush_interval_;
+  const scoped_ptr<Client> transport_client_;
+  const scoped_ptr<PacketSender> transport_;
+  const scoped_refptr<base::SingleThreadTaskRunner> transport_task_runner_;
 
-  // FrameEvents and PacketEvents pending delivery via |raw_events_callback_|.
-  // Do not add elements to these when |raw_events_callback_.is_null()|.
+  // FrameEvents and PacketEvents pending delivery via raw events callback.
+  // Do not add elements to these when |logging_flush_interval| is
+  // |base::TimeDelta()|.
   std::vector<FrameEvent> recent_frame_events_;
   std::vector<PacketEvent> recent_packet_events_;
 
-  // Interface to a UDP socket.
-  scoped_ptr<UdpTransport> transport_;
-
   // Packet sender that performs pacing.
   PacedSender pacer_;
 
@@ -189,9 +171,6 @@
   TransportEncryptionHandler audio_encryptor_;
   TransportEncryptionHandler video_encryptor_;
 
-  BulkRawEventsCallback raw_events_callback_;
-  base::TimeDelta raw_events_callback_interval_;
-
   // Right after a frame is sent we record the number of bytes sent to the
   // socket. We record the corresponding bytes sent for the most recent ACKed
   // audio packet.
@@ -200,10 +179,9 @@
   // Packets that don't match these ssrcs are ignored.
   std::set<uint32_t> valid_ssrcs_;
 
-  // Called with incoming packets. (Unless they match the
-  // channels created by Initialize{Audio,Video}.
-  PacketReceiverCallback packet_callback_;
-
+  // While non-null, global WiFi behavior modifications are in effect. This is
+  // used, for example, to turn off WiFi scanning that tends to interfere with
+  // the reliability of UDP packet transmission.
   scoped_ptr<net::ScopedWifiOptions> wifi_options_autoreset_;
 
   base::WeakPtrFactory<CastTransportSenderImpl> weak_factory_;
diff --git a/media/cast/net/cast_transport_sender_impl_unittest.cc b/media/cast/net/cast_transport_sender_impl_unittest.cc
index db6c5df..f2e9d5c 100644
--- a/media/cast/net/cast_transport_sender_impl_unittest.cc
+++ b/media/cast/net/cast_transport_sender_impl_unittest.cc
@@ -23,9 +23,11 @@
 namespace cast {
 
 namespace {
+
 const int64_t kStartMillisecond = INT64_C(12345678900000);
 const uint32_t kVideoSsrc = 1;
 const uint32_t kAudioSsrc = 2;
+
 }  // namespace
 
 class FakePacketSender : public PacketSender {
@@ -46,6 +48,11 @@
 
   int64_t GetBytesSent() final { return bytes_sent_; }
 
+  void StartReceiving(
+      const PacketReceiverCallbackWithStatus& packet_receiver) final {}
+
+  void StopReceiving() final {}
+
   void SetPaused(bool paused) {
     paused_ = paused;
     if (!paused && stored_packet_.get()) {
@@ -67,6 +74,9 @@
 };
 
 class CastTransportSenderImplTest : public ::testing::Test {
+ public:
+  void ReceivedLoggingEvents() { num_times_logging_callback_called_++; }
+
  protected:
   CastTransportSenderImplTest() : num_times_logging_callback_called_(0) {
     testing_clock_.Advance(
@@ -76,62 +86,16 @@
 
   ~CastTransportSenderImplTest() override {}
 
-  void InitWithoutLogging() {
-    transport_sender_.reset(
-        new CastTransportSenderImpl(NULL,
-                                    &testing_clock_,
-                                    net::IPEndPoint(),
-                                    net::IPEndPoint(),
-                                    make_scoped_ptr(new base::DictionaryValue),
-                                    base::Bind(&UpdateCastTransportStatus),
-                                    BulkRawEventsCallback(),
-                                    base::TimeDelta(),
-                                    task_runner_,
-                                    PacketReceiverCallback(),
-                                    &transport_));
-    task_runner_->RunTasks();
-  }
-
-  void InitWithOptions() {
-    scoped_ptr<base::DictionaryValue> options(
-        new base::DictionaryValue);
-    options->SetBoolean("DHCP", true);
-    options->SetBoolean("disable_wifi_scan", true);
-    options->SetBoolean("media_streaming_mode", true);
-    options->SetInteger("pacer_target_burst_size", 20);
-    options->SetInteger("pacer_max_burst_size", 100);
-    transport_sender_.reset(new CastTransportSenderImpl(
-        NULL, &testing_clock_, net::IPEndPoint(), net::IPEndPoint(),
-        std::move(options), base::Bind(&UpdateCastTransportStatus),
-        BulkRawEventsCallback(), base::TimeDelta(), task_runner_,
-        PacketReceiverCallback(), &transport_));
-    task_runner_->RunTasks();
-  }
-
-  void InitWithLogging() {
-    transport_sender_.reset(new CastTransportSenderImpl(
-        NULL,
-        &testing_clock_,
-        net::IPEndPoint(),
-        net::IPEndPoint(),
-        make_scoped_ptr(new base::DictionaryValue),
-        base::Bind(&UpdateCastTransportStatus),
-        base::Bind(&CastTransportSenderImplTest::LogRawEvents,
-                   base::Unretained(this)),
-        base::TimeDelta::FromMilliseconds(10),
-        task_runner_,
-        PacketReceiverCallback(),
-        &transport_));
-    task_runner_->RunTasks();
-  }
+  void InitWithoutLogging();
+  void InitWithOptions();
+  void InitWithLogging();
 
   void InitializeVideo() {
     CastTransportRtpConfig rtp_config;
     rtp_config.ssrc = kVideoSsrc;
     rtp_config.feedback_ssrc = 2;
     rtp_config.rtp_payload_type = 3;
-    transport_sender_->InitializeVideo(rtp_config,
-                                       RtcpCastMessageCallback(),
+    transport_sender_->InitializeVideo(rtp_config, RtcpCastMessageCallback(),
                                        RtcpRttCallback());
   }
 
@@ -140,26 +104,75 @@
     rtp_config.ssrc = kAudioSsrc;
     rtp_config.feedback_ssrc = 3;
     rtp_config.rtp_payload_type = 4;
-    transport_sender_->InitializeAudio(rtp_config,
-                                       RtcpCastMessageCallback(),
+    transport_sender_->InitializeAudio(rtp_config, RtcpCastMessageCallback(),
                                        RtcpRttCallback());
   }
 
-  void LogRawEvents(scoped_ptr<std::vector<FrameEvent>> frame_events,
-                    scoped_ptr<std::vector<PacketEvent>> packet_events) {
-    num_times_logging_callback_called_++;
-  }
-
-  static void UpdateCastTransportStatus(CastTransportStatus status) {
-  }
-
   base::SimpleTestTickClock testing_clock_;
   scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_;
   scoped_ptr<CastTransportSenderImpl> transport_sender_;
-  FakePacketSender transport_;
+  FakePacketSender* transport_;  // Owned by CastTransportSender.
   int num_times_logging_callback_called_;
 };
 
+namespace {
+
+class TransportClient : public CastTransportSender::Client {
+ public:
+  explicit TransportClient(
+      CastTransportSenderImplTest* cast_transport_sender_impl_test)
+      : cast_transport_sender_impl_test_(cast_transport_sender_impl_test) {}
+
+  void OnStatusChanged(CastTransportStatus status) final{};
+  void OnLoggingEventsReceived(
+      scoped_ptr<std::vector<FrameEvent>> frame_events,
+      scoped_ptr<std::vector<PacketEvent>> packet_events) final {
+    CHECK(cast_transport_sender_impl_test_);
+    cast_transport_sender_impl_test_->ReceivedLoggingEvents();
+  };
+  void ProcessRtpPacket(scoped_ptr<Packet> packet) final{};
+
+ private:
+  CastTransportSenderImplTest* const cast_transport_sender_impl_test_;
+
+  DISALLOW_COPY_AND_ASSIGN(TransportClient);
+};
+
+}  // namespace
+
+void CastTransportSenderImplTest::InitWithoutLogging() {
+  transport_ = new FakePacketSender();
+  transport_sender_.reset(
+      new CastTransportSenderImpl(&testing_clock_, base::TimeDelta(),
+                                  make_scoped_ptr(new TransportClient(nullptr)),
+                                  make_scoped_ptr(transport_), task_runner_));
+  task_runner_->RunTasks();
+}
+
+void CastTransportSenderImplTest::InitWithOptions() {
+  scoped_ptr<base::DictionaryValue> options(new base::DictionaryValue);
+  options->SetBoolean("disable_wifi_scan", true);
+  options->SetBoolean("media_streaming_mode", true);
+  options->SetInteger("pacer_target_burst_size", 20);
+  options->SetInteger("pacer_max_burst_size", 100);
+  transport_ = new FakePacketSender();
+  transport_sender_.reset(
+      new CastTransportSenderImpl(&testing_clock_, base::TimeDelta(),
+                                  make_scoped_ptr(new TransportClient(nullptr)),
+                                  make_scoped_ptr(transport_), task_runner_));
+  transport_sender_->SetOptions(*options);
+  task_runner_->RunTasks();
+}
+
+void CastTransportSenderImplTest::InitWithLogging() {
+  transport_ = new FakePacketSender();
+  transport_sender_.reset(new CastTransportSenderImpl(
+      &testing_clock_, base::TimeDelta::FromMilliseconds(10),
+      make_scoped_ptr(new TransportClient(this)), make_scoped_ptr(transport_),
+      task_runner_));
+  task_runner_->RunTasks();
+}
+
 TEST_F(CastTransportSenderImplTest, InitWithoutLogging) {
   InitWithoutLogging();
   task_runner_->Sleep(base::TimeDelta::FromMilliseconds(50));
@@ -187,7 +200,7 @@
 
   transport_sender_->InsertFrame(kVideoSsrc, fake_frame);
   task_runner_->Sleep(base::TimeDelta::FromMilliseconds(10));
-  EXPECT_EQ(4, transport_.packets_sent());
+  EXPECT_EQ(4, transport_->packets_sent());
   EXPECT_EQ(1, num_times_logging_callback_called_);
 
   // Resend packet 0.
@@ -196,7 +209,7 @@
   missing_packets[1].insert(1);
   missing_packets[1].insert(2);
 
-  transport_.SetPaused(true);
+  transport_->SetPaused(true);
   DedupInfo dedup_info;
   dedup_info.resend_interval = base::TimeDelta::FromMilliseconds(10);
   transport_sender_->ResendPackets(
@@ -212,13 +225,13 @@
   transport_sender_->OnReceivedCastMessage(kVideoSsrc,
                                            RtcpCastMessageCallback(),
                                            cast_message);
-  transport_.SetPaused(false);
+  transport_->SetPaused(false);
   task_runner_->Sleep(base::TimeDelta::FromMilliseconds(10));
   EXPECT_EQ(3, num_times_logging_callback_called_);
 
   // Resend one packet in the socket when unpaused.
   // Resend one more packet from NACK.
-  EXPECT_EQ(6, transport_.packets_sent());
+  EXPECT_EQ(6, transport_->packets_sent());
 }
 
 TEST_F(CastTransportSenderImplTest, CancelRetransmits) {
@@ -236,14 +249,14 @@
 
   transport_sender_->InsertFrame(kVideoSsrc, fake_frame);
   task_runner_->Sleep(base::TimeDelta::FromMilliseconds(10));
-  EXPECT_EQ(4, transport_.packets_sent());
+  EXPECT_EQ(4, transport_->packets_sent());
   EXPECT_EQ(1, num_times_logging_callback_called_);
 
   // Resend all packets for frame 1.
   MissingFramesAndPacketsMap missing_packets;
   missing_packets[1].insert(kRtcpCastAllPacketsLost);
 
-  transport_.SetPaused(true);
+  transport_->SetPaused(true);
   DedupInfo dedup_info;
   dedup_info.resend_interval = base::TimeDelta::FromMilliseconds(10);
   transport_sender_->ResendPackets(
@@ -256,12 +269,12 @@
   cancel_sending_frames.push_back(1);
   transport_sender_->CancelSendingFrames(kVideoSsrc,
                                          cancel_sending_frames);
-  transport_.SetPaused(false);
+  transport_->SetPaused(false);
   task_runner_->Sleep(base::TimeDelta::FromMilliseconds(10));
   EXPECT_EQ(2, num_times_logging_callback_called_);
 
   // Resend one packet in the socket when unpaused.
-  EXPECT_EQ(5, transport_.packets_sent());
+  EXPECT_EQ(5, transport_->packets_sent());
 }
 
 TEST_F(CastTransportSenderImplTest, Kickstart) {
@@ -277,12 +290,12 @@
   fake_frame.dependency = EncodedFrame::KEY;
   fake_frame.data.resize(5000, ' ');
 
-  transport_.SetPaused(true);
+  transport_->SetPaused(true);
   transport_sender_->InsertFrame(kVideoSsrc, fake_frame);
   transport_sender_->ResendFrameForKickstart(kVideoSsrc, 1);
-  transport_.SetPaused(false);
+  transport_->SetPaused(false);
   task_runner_->Sleep(base::TimeDelta::FromMilliseconds(10));
-  EXPECT_EQ(4, transport_.packets_sent());
+  EXPECT_EQ(4, transport_->packets_sent());
   EXPECT_EQ(1, num_times_logging_callback_called_);
 
   // Resend 2 packets for frame 1.
@@ -290,19 +303,19 @@
   missing_packets[1].insert(0);
   missing_packets[1].insert(1);
 
-  transport_.SetPaused(true);
+  transport_->SetPaused(true);
   DedupInfo dedup_info;
   dedup_info.resend_interval = base::TimeDelta::FromMilliseconds(10);
   transport_sender_->ResendPackets(
       kVideoSsrc, missing_packets, true, dedup_info);
   transport_sender_->ResendFrameForKickstart(kVideoSsrc, 1);
-  transport_.SetPaused(false);
+  transport_->SetPaused(false);
   task_runner_->Sleep(base::TimeDelta::FromMilliseconds(10));
   EXPECT_EQ(2, num_times_logging_callback_called_);
 
   // Resend one packet in the socket when unpaused.
   // Two more retransmission packets sent.
-  EXPECT_EQ(7, transport_.packets_sent());
+  EXPECT_EQ(7, transport_->packets_sent());
 }
 
 TEST_F(CastTransportSenderImplTest, DedupRetransmissionWithAudio) {
@@ -324,7 +337,7 @@
   fake_audio.reference_time = testing_clock_.NowTicks();
   transport_sender_->InsertFrame(kAudioSsrc, fake_audio);
   task_runner_->Sleep(base::TimeDelta::FromMilliseconds(2));
-  EXPECT_EQ(2, transport_.packets_sent());
+  EXPECT_EQ(2, transport_->packets_sent());
 
   // Ack the first audio frame.
   RtcpCastMessage cast_message;
@@ -334,7 +347,7 @@
                                            RtcpCastMessageCallback(),
                                            cast_message);
   task_runner_->RunTasks();
-  EXPECT_EQ(2, transport_.packets_sent());
+  EXPECT_EQ(2, transport_->packets_sent());
   EXPECT_EQ(0, num_times_logging_callback_called_);  // Only 4 ms since last.
 
   // Send a fake video frame that will be decomposed into 4 packets.
@@ -344,7 +357,7 @@
   fake_video.data.resize(5000, ' ');
   transport_sender_->InsertFrame(kVideoSsrc, fake_video);
   task_runner_->RunTasks();
-  EXPECT_EQ(6, transport_.packets_sent());
+  EXPECT_EQ(6, transport_->packets_sent());
   EXPECT_EQ(0, num_times_logging_callback_called_);  // Only 4 ms since last.
 
   // Retransmission is reject because audio is not acked yet.
@@ -356,7 +369,7 @@
                                            RtcpCastMessageCallback(),
                                            cast_message);
   task_runner_->RunTasks();
-  EXPECT_EQ(6, transport_.packets_sent());
+  EXPECT_EQ(6, transport_->packets_sent());
   EXPECT_EQ(1, num_times_logging_callback_called_);
 
   // Ack the second audio frame.
@@ -368,7 +381,7 @@
                                            RtcpCastMessageCallback(),
                                            cast_message);
   task_runner_->RunTasks();
-  EXPECT_EQ(6, transport_.packets_sent());
+  EXPECT_EQ(6, transport_->packets_sent());
   EXPECT_EQ(1, num_times_logging_callback_called_);  // Only 6 ms since last.
 
   // Retransmission of video packet now accepted.
@@ -380,7 +393,7 @@
                                            RtcpCastMessageCallback(),
                                            cast_message);
   task_runner_->RunTasks();
-  EXPECT_EQ(7, transport_.packets_sent());
+  EXPECT_EQ(7, transport_->packets_sent());
   EXPECT_EQ(1, num_times_logging_callback_called_);  // Only 8 ms since last.
 
   task_runner_->Sleep(base::TimeDelta::FromMilliseconds(2));
diff --git a/media/cast/net/mock_cast_transport_sender.h b/media/cast/net/mock_cast_transport_sender.h
index 371b4192..bf1dfc0d 100644
--- a/media/cast/net/mock_cast_transport_sender.h
+++ b/media/cast/net/mock_cast_transport_sender.h
@@ -45,6 +45,7 @@
                     base::TimeDelta target_delay,
                     const ReceiverRtcpEventSubscriber::RtcpEvents* rtcp_events,
                     const RtpReceiverStatistics* rtp_receiver_statistics));
+  MOCK_METHOD1(SetOptions, void(const base::DictionaryValue& options));
 };
 
 }  // namespace cast
diff --git a/media/cast/net/pacing/paced_sender.h b/media/cast/net/pacing/paced_sender.h
index 714fe9d..8d45cc43 100644
--- a/media/cast/net/pacing/paced_sender.h
+++ b/media/cast/net/pacing/paced_sender.h
@@ -131,6 +131,13 @@
   bool SendRtcpPacket(uint32_t ssrc, PacketRef packet) final;
   void CancelSendingPacket(const PacketKey& packet_key) final;
 
+  void SetTargetBurstSize(int burst_size) {
+    target_burst_size_ = current_max_burst_size_ = next_max_burst_size_ =
+        next_next_max_burst_size_ = burst_size;
+  }
+
+  void SetMaxBurstSize(int burst_size) { max_burst_size_ = burst_size; }
+
  private:
   // Actually sends the packets to the transport.
   void SendStoredPackets();
diff --git a/media/cast/net/pacing/paced_sender_unittest.cc b/media/cast/net/pacing/paced_sender_unittest.cc
index fec5c5f..89c341f 100644
--- a/media/cast/net/pacing/paced_sender_unittest.cc
+++ b/media/cast/net/pacing/paced_sender_unittest.cc
@@ -47,6 +47,11 @@
 
   int64_t GetBytesSent() final { return bytes_sent_; }
 
+  void StartReceiving(
+      const PacketReceiverCallbackWithStatus& packet_receiver) final {}
+
+  void StopReceiving() final {}
+
   void AddExpectedSize(int expected_packet_size, int repeat_count) {
     for (int i = 0; i < repeat_count; ++i) {
       expected_packet_size_.push_back(expected_packet_size);
diff --git a/media/cast/net/rtp/rtp_packetizer_unittest.cc b/media/cast/net/rtp/rtp_packetizer_unittest.cc
index 5c58125..76aa2323 100644
--- a/media/cast/net/rtp/rtp_packetizer_unittest.cc
+++ b/media/cast/net/rtp/rtp_packetizer_unittest.cc
@@ -80,6 +80,11 @@
 
   int64_t GetBytesSent() final { return 0; }
 
+  void StartReceiving(
+      const PacketReceiverCallbackWithStatus& packet_receiver) final {}
+
+  void StopReceiving() final {}
+
   size_t number_of_packets_received() const { return packets_sent_; }
 
   void set_expected_number_of_packets(size_t expected_number_of_packets) {
diff --git a/media/cast/net/udp_transport.cc b/media/cast/net/udp_transport.cc
index 2560b459..bf126bc 100644
--- a/media/cast/net/udp_transport.cc
+++ b/media/cast/net/udp_transport.cc
@@ -21,7 +21,13 @@
 namespace cast {
 
 namespace {
-const int kMaxPacketSize = 1500;
+
+const char kOptionDscp[] = "DSCP";
+#if defined(OS_WIN)
+const char kOptionDisableNonBlockingIO[] = "disable_non_blocking_io";
+#endif
+const char kOptionSendBufferMinSize[] = "send_buffer_min_size";
+const char kOptionPacerMaxBurstSize[] = "pacer_max_burst_size";
 
 bool IsEmpty(const net::IPEndPoint& addr) {
   net::IPAddressNumber empty_addr(addr.address().size());
@@ -30,6 +36,29 @@
          !addr.port();
 }
 
+int LookupOptionWithDefault(const base::DictionaryValue& options,
+                            const std::string& path,
+                            int default_value) {
+  int ret;
+  if (options.GetInteger(path, &ret)) {
+    return ret;
+  } else {
+    return default_value;
+  }
+}
+
+int32_t GetTransportSendBufferSize(const base::DictionaryValue& options) {
+  // Socket send buffer size needs to be at least greater than one burst
+  // size.
+  int32_t max_burst_size =
+      LookupOptionWithDefault(options, kOptionPacerMaxBurstSize,
+                              media::cast::kMaxBurstSize) *
+      media::cast::kMaxIpPacketSize;
+  int32_t min_send_buffer_size =
+      LookupOptionWithDefault(options, kOptionSendBufferMinSize, 0);
+  return std::max(max_burst_size, min_send_buffer_size);
+}
+
 }  // namespace
 
 UdpTransport::UdpTransport(
@@ -37,7 +66,6 @@
     const scoped_refptr<base::SingleThreadTaskRunner>& io_thread_proxy,
     const net::IPEndPoint& local_end_point,
     const net::IPEndPoint& remote_end_point,
-    int32_t send_buffer_size,
     const CastTransportStatusCallback& status_callback)
     : io_thread_proxy_(io_thread_proxy),
       local_addr_(local_end_point),
@@ -50,7 +78,8 @@
       receive_pending_(false),
       client_connected_(false),
       next_dscp_value_(net::DSCP_NO_CHANGE),
-      send_buffer_size_(send_buffer_size),
+      send_buffer_size_(media::cast::kMaxBurstSize *
+                        media::cast::kMaxIpPacketSize),
       status_callback_(status_callback),
       bytes_sent_(0),
       weak_factory_(this) {
@@ -145,15 +174,13 @@
   // the future when a packet is ready.
   while (true) {
     if (length_or_status == net::ERR_IO_PENDING) {
-      next_packet_.reset(new Packet(kMaxPacketSize));
+      next_packet_.reset(new Packet(media::cast::kMaxIpPacketSize));
       recv_buf_ = new net::WrappedIOBuffer(
           reinterpret_cast<char*>(&next_packet_->front()));
-      length_or_status =
-          udp_socket_->RecvFrom(recv_buf_.get(),
-                                kMaxPacketSize,
-                                &recv_addr_,
-                                base::Bind(&UdpTransport::ReceiveNextPacket,
-                                           weak_factory_.GetWeakPtr()));
+      length_or_status = udp_socket_->RecvFrom(
+          recv_buf_.get(), media::cast::kMaxIpPacketSize, &recv_addr_,
+          base::Bind(&UdpTransport::ReceiveNextPacket,
+                     weak_factory_.GetWeakPtr()));
       if (length_or_status == net::ERR_IO_PENDING) {
         receive_pending_ = true;
         return;
@@ -275,5 +302,23 @@
   }
 }
 
+void UdpTransport::SetUdpOptions(const base::DictionaryValue& options) {
+  SetSendBufferSize(GetTransportSendBufferSize(options));
+  if (options.HasKey(kOptionDscp)) {
+    // The default DSCP value for cast is AF41. Which gives it a higher
+    // priority over other traffic.
+    SetDscp(net::DSCP_AF41);
+  }
+#if defined(OS_WIN)
+  if (!options.HasKey(kOptionDisableNonBlockingIO)) {
+    UseNonBlockingIO();
+  }
+#endif
+}
+
+void UdpTransport::SetSendBufferSize(int32_t send_buffer_size) {
+  send_buffer_size_ = send_buffer_size;
+}
+
 }  // namespace cast
 }  // namespace media
diff --git a/media/cast/net/udp_transport.h b/media/cast/net/udp_transport.h
index 6da6ae3a..c098a58 100644
--- a/media/cast/net/udp_transport.h
+++ b/media/cast/net/udp_transport.h
@@ -11,10 +11,12 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/values.h"
 #include "build/build_config.h"
 #include "media/cast/cast_environment.h"
 #include "media/cast/net/cast_transport_config.h"
 #include "media/cast/net/cast_transport_sender.h"
+#include "media/cast/net/pacing/paced_sender.h"
 #include "net/base/io_buffer.h"
 #include "net/base/ip_endpoint.h"
 #include "net/udp/diff_serv_code_point.h"
@@ -44,18 +46,35 @@
       const scoped_refptr<base::SingleThreadTaskRunner>& io_thread_proxy,
       const net::IPEndPoint& local_end_point,
       const net::IPEndPoint& remote_end_point,
-      int32_t send_buffer_size,
       const CastTransportStatusCallback& status_callback);
   ~UdpTransport() final;
 
   // Start receiving packets. Packets are submitted to |packet_receiver|.
-  void StartReceiving(const PacketReceiverCallbackWithStatus& packet_receiver);
-  void StopReceiving();
+  void StartReceiving(
+      const PacketReceiverCallbackWithStatus& packet_receiver) final;
+  void StopReceiving() final;
 
   // Set a new DSCP value to the socket. The value will be set right before
   // the next send.
   void SetDscp(net::DiffServCodePoint dscp);
 
+  // Set UdpTransport options.
+  // Possible keys are:
+  //   "pacer_max_burst_size": int
+  //        - Specifies how many pakcets to send per 10 ms, maximum.
+  //   "send_buffer_min_size": int
+  //        - Specifies the minimum socket send buffer size.
+  //   "DSCP" (value ignored)
+  //       - Turns DSCP on (higher IP Precedence and Type of Service).
+  //   "disable_non_blocking_io" (value ignored)
+  //       - Windows only.  Turns off non-blocking IO for the socket.
+  //         Note: Non-blocking IO is, by default, enabled on all platforms.
+  void SetUdpOptions(const base::DictionaryValue& options);
+
+  // This has to be called before |StartReceiving()| to change the
+  // |send_buffer_size_|. Calling |SetUdpOptions()| will automatically call it.
+  void SetSendBufferSize(int32_t send_buffer_size);
+
 #if defined(OS_WIN)
   // Switch to use non-blocking IO. Must be called before StartReceiving().
   void UseNonBlockingIO();
diff --git a/media/cast/net/udp_transport_unittest.cc b/media/cast/net/udp_transport_unittest.cc
index 63f1043..b73c683 100644
--- a/media/cast/net/udp_transport_unittest.cc
+++ b/media/cast/net/udp_transport_unittest.cc
@@ -15,7 +15,6 @@
 #include "base/run_loop.h"
 #include "media/cast/net/cast_transport_config.h"
 #include "media/cast/test/utility/net_utility.h"
-#include "net/base/net_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace media {
@@ -67,14 +66,14 @@
                               message_loop.task_runner(),
                               free_local_port1,
                               free_local_port2,
-                              65536,
                               base::Bind(&UpdateCastTransportStatus));
+  send_transport.SetSendBufferSize(65536);
   UdpTransport recv_transport(NULL,
                               message_loop.task_runner(),
                               free_local_port2,
                               net::IPEndPoint(empty_addr_number, 0),
-                              65536,
                               base::Bind(&UpdateCastTransportStatus));
+  recv_transport.SetSendBufferSize(65536);
 
   Packet packet;
   packet.push_back('t');
diff --git a/media/cast/sender/audio_sender_unittest.cc b/media/cast/sender/audio_sender_unittest.cc
index af6b9c4..bfe2383e 100644
--- a/media/cast/sender/audio_sender_unittest.cc
+++ b/media/cast/sender/audio_sender_unittest.cc
@@ -35,6 +35,21 @@
   *out_status = in_status;
 }
 
+class TransportClient : public CastTransportSender::Client {
+ public:
+  TransportClient() {}
+
+  void OnStatusChanged(CastTransportStatus status) final {
+    EXPECT_EQ(TRANSPORT_AUDIO_INITIALIZED, status);
+  };
+  void OnLoggingEventsReceived(
+      scoped_ptr<std::vector<FrameEvent>> frame_events,
+      scoped_ptr<std::vector<PacketEvent>> packet_events) final{};
+  void ProcessRtpPacket(scoped_ptr<Packet> packet) final{};
+
+  DISALLOW_COPY_AND_ASSIGN(TransportClient);
+};
+
 }  // namespace
 
 class TestPacketSender : public PacketSender {
@@ -58,6 +73,11 @@
 
   int64_t GetBytesSent() final { return 0; }
 
+  void StartReceiving(
+      const PacketReceiverCallbackWithStatus& packet_receiver) final {}
+
+  void StopReceiving() final {}
+
   int number_of_rtp_packets() const { return number_of_rtp_packets_; }
 
   int number_of_rtcp_packets() const { return number_of_rtcp_packets_; }
@@ -86,20 +106,11 @@
     audio_config_.bitrate = kDefaultAudioEncoderBitrate;
     audio_config_.rtp_payload_type = 127;
 
-    net::IPEndPoint dummy_endpoint;
-
-    transport_sender_.reset(new CastTransportSenderImpl(
-        NULL,
-        testing_clock_,
-        net::IPEndPoint(),
-        dummy_endpoint,
-        make_scoped_ptr(new base::DictionaryValue),
-        base::Bind(&UpdateCastTransportStatus),
-        BulkRawEventsCallback(),
-        base::TimeDelta(),
-        task_runner_,
-        PacketReceiverCallback(),
-        &transport_));
+    transport_ = new TestPacketSender();
+    transport_sender_.reset(
+        new CastTransportSenderImpl(testing_clock_, base::TimeDelta(),
+                                    make_scoped_ptr(new TransportClient()),
+                                    make_scoped_ptr(transport_), task_runner_));
     OperationalStatus operational_status = STATUS_UNINITIALIZED;
     audio_sender_.reset(new AudioSender(
         cast_environment_,
@@ -112,12 +123,8 @@
 
   ~AudioSenderTest() override {}
 
-  static void UpdateCastTransportStatus(CastTransportStatus status) {
-    EXPECT_EQ(TRANSPORT_AUDIO_INITIALIZED, status);
-  }
-
   base::SimpleTestTickClock* testing_clock_;  // Owned by CastEnvironment.
-  TestPacketSender transport_;
+  TestPacketSender* transport_;               // Owned by CastTransportSender.
   scoped_ptr<CastTransportSenderImpl> transport_sender_;
   scoped_refptr<test::FakeSingleThreadTaskRunner> task_runner_;
   scoped_ptr<AudioSender> audio_sender_;
@@ -135,8 +142,8 @@
 
   audio_sender_->InsertAudio(std::move(bus), testing_clock_->NowTicks());
   task_runner_->RunTasks();
-  EXPECT_LE(1, transport_.number_of_rtp_packets());
-  EXPECT_LE(1, transport_.number_of_rtcp_packets());
+  EXPECT_LE(1, transport_->number_of_rtp_packets());
+  EXPECT_LE(1, transport_->number_of_rtcp_packets());
 }
 
 TEST_F(AudioSenderTest, RtcpTimer) {
@@ -155,8 +162,8 @@
       base::TimeDelta::FromMilliseconds(1 + kRtcpReportIntervalMs * 3 / 2);
   testing_clock_->Advance(max_rtcp_timeout);
   task_runner_->RunTasks();
-  EXPECT_LE(1, transport_.number_of_rtp_packets());
-  EXPECT_LE(1, transport_.number_of_rtcp_packets());
+  EXPECT_LE(1, transport_->number_of_rtp_packets());
+  EXPECT_LE(1, transport_->number_of_rtcp_packets());
 }
 
 }  // namespace cast
diff --git a/media/cast/sender/video_sender_unittest.cc b/media/cast/sender/video_sender_unittest.cc
index 9c5d9c4..3d315ea 100644
--- a/media/cast/sender/video_sender_unittest.cc
+++ b/media/cast/sender/video_sender_unittest.cc
@@ -77,6 +77,11 @@
 
   int64_t GetBytesSent() final { return 0; }
 
+  void StartReceiving(
+      const PacketReceiverCallbackWithStatus& packet_receiver) final {}
+
+  void StopReceiving() final {}
+
   int number_of_rtp_packets() const { return number_of_rtp_packets_; }
 
   int number_of_rtcp_packets() const { return number_of_rtcp_packets_; }
@@ -121,6 +126,21 @@
   using VideoSender::OnReceivedCastFeedback;
 };
 
+class TransportClient : public CastTransportSender::Client {
+ public:
+  TransportClient() {}
+
+  void OnStatusChanged(CastTransportStatus status) final {
+    EXPECT_EQ(TRANSPORT_VIDEO_INITIALIZED, status);
+  };
+  void OnLoggingEventsReceived(
+      scoped_ptr<std::vector<FrameEvent>> frame_events,
+      scoped_ptr<std::vector<PacketEvent>> packet_events) final{};
+  void ProcessRtpPacket(scoped_ptr<Packet> packet) final{};
+
+  DISALLOW_COPY_AND_ASSIGN(TransportClient);
+};
+
 }  // namespace
 
 class VideoSenderTest : public ::testing::Test {
@@ -138,19 +158,11 @@
     testing_clock_->Advance(base::TimeTicks::Now() - base::TimeTicks());
     vea_factory_.SetAutoRespond(true);
     last_pixel_value_ = kPixelValue;
-    net::IPEndPoint dummy_endpoint;
-    transport_sender_.reset(new CastTransportSenderImpl(
-        NULL,
-        testing_clock_,
-        dummy_endpoint,
-        dummy_endpoint,
-        make_scoped_ptr(new base::DictionaryValue),
-        base::Bind(&UpdateCastTransportStatus),
-        BulkRawEventsCallback(),
-        base::TimeDelta(),
-        task_runner_,
-        PacketReceiverCallback(),
-        &transport_));
+    transport_ = new TestPacketSender();
+    transport_sender_.reset(
+        new CastTransportSenderImpl(testing_clock_, base::TimeDelta(),
+                                    make_scoped_ptr(new TransportClient()),
+                                    make_scoped_ptr(transport_), task_runner_));
   }
 
   ~VideoSenderTest() override {}
@@ -160,10 +172,6 @@
     task_runner_->RunTasks();
   }
 
-  static void UpdateCastTransportStatus(CastTransportStatus status) {
-    EXPECT_EQ(TRANSPORT_VIDEO_INITIALIZED, status);
-  }
-
   // If |external| is true then external video encoder (VEA) is used.
   // |expect_init_success| is true if initialization is expected to succeed.
   void InitEncoder(bool external, bool expect_init_success) {
@@ -229,7 +237,7 @@
   const scoped_refptr<CastEnvironment> cast_environment_;
   OperationalStatus operational_status_;
   FakeVideoEncodeAcceleratorFactory vea_factory_;
-  TestPacketSender transport_;
+  TestPacketSender* transport_;  // Owned by CastTransportSender.
   scoped_ptr<CastTransportSenderImpl> transport_sender_;
   scoped_ptr<PeerVideoSender> video_sender_;
   int last_pixel_value_;
@@ -249,8 +257,8 @@
   video_sender_->InsertRawVideoFrame(video_frame, reference_time);
 
   task_runner_->RunTasks();
-  EXPECT_LE(1, transport_.number_of_rtp_packets());
-  EXPECT_LE(1, transport_.number_of_rtcp_packets());
+  EXPECT_LE(1, transport_->number_of_rtp_packets());
+  EXPECT_LE(1, transport_->number_of_rtcp_packets());
 }
 
 TEST_F(VideoSenderTest, ExternalEncoder) {
@@ -324,15 +332,15 @@
       base::TimeDelta::FromMilliseconds(1 + kRtcpReportIntervalMs * 3 / 2);
 
   RunTasks(max_rtcp_timeout.InMilliseconds());
-  EXPECT_LE(1, transport_.number_of_rtp_packets());
-  EXPECT_LE(1, transport_.number_of_rtcp_packets());
+  EXPECT_LE(1, transport_->number_of_rtp_packets());
+  EXPECT_LE(1, transport_->number_of_rtcp_packets());
   // Build Cast msg and expect RTCP packet.
   RtcpCastMessage cast_feedback(1);
   cast_feedback.media_ssrc = 2;
   cast_feedback.ack_frame_id = 0;
   video_sender_->OnReceivedCastFeedback(cast_feedback);
   RunTasks(max_rtcp_timeout.InMilliseconds());
-  EXPECT_LE(1, transport_.number_of_rtcp_packets());
+  EXPECT_LE(1, transport_->number_of_rtcp_packets());
 }
 
 TEST_F(VideoSenderTest, ResendTimer) {
@@ -359,9 +367,8 @@
   // Make sure that we do a re-send.
   RunTasks(max_resend_timeout.InMilliseconds());
   // Should have sent at least 3 packets.
-  EXPECT_LE(
-      3,
-      transport_.number_of_rtp_packets() + transport_.number_of_rtcp_packets());
+  EXPECT_LE(3, transport_->number_of_rtp_packets() +
+                   transport_->number_of_rtcp_packets());
 }
 
 TEST_F(VideoSenderTest, LogAckReceivedEvent) {
@@ -414,7 +421,7 @@
     video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
     RunTasks(33);
   }
-  const int number_of_packets_sent = transport_.number_of_rtp_packets();
+  const int number_of_packets_sent = transport_->number_of_rtp_packets();
 
   // Send 3 more frames - they should not be encoded, as we have not received
   // any acks.
@@ -426,24 +433,21 @@
 
   // We expect a frame to be retransmitted because of duplicated ACKs.
   // Only one packet of the frame is re-transmitted.
-  EXPECT_EQ(number_of_packets_sent + 1,
-            transport_.number_of_rtp_packets());
+  EXPECT_EQ(number_of_packets_sent + 1, transport_->number_of_rtp_packets());
 
   // Start acking and make sure we're back to steady-state.
   RtcpCastMessage cast_feedback(1);
   cast_feedback.media_ssrc = 2;
   cast_feedback.ack_frame_id = 0;
   video_sender_->OnReceivedCastFeedback(cast_feedback);
-  EXPECT_LE(
-      4,
-      transport_.number_of_rtp_packets() + transport_.number_of_rtcp_packets());
+  EXPECT_LE(4, transport_->number_of_rtp_packets() +
+                   transport_->number_of_rtcp_packets());
 
   // Empty the pipeline.
   RunTasks(100);
   // Should have sent at least 7 packets.
-  EXPECT_LE(
-      7,
-      transport_.number_of_rtp_packets() + transport_.number_of_rtcp_packets());
+  EXPECT_LE(7, transport_->number_of_rtp_packets() +
+                   transport_->number_of_rtcp_packets());
 }
 
 TEST_F(VideoSenderTest, DuplicateAckRetransmit) {
@@ -463,7 +467,7 @@
     video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
     RunTasks(33);
   }
-  const int number_of_packets_sent = transport_.number_of_rtp_packets();
+  const int number_of_packets_sent = transport_->number_of_rtp_packets();
 
   // Send duplicated ACKs and mix some invalid NACKs.
   for (int i = 0; i < 10; ++i) {
@@ -476,7 +480,7 @@
     video_sender_->OnReceivedCastFeedback(ack_feedback);
     video_sender_->OnReceivedCastFeedback(nack_feedback);
   }
-  EXPECT_EQ(number_of_packets_sent, transport_.number_of_rtp_packets());
+  EXPECT_EQ(number_of_packets_sent, transport_->number_of_rtp_packets());
 
   // Re-transmit one packet because of duplicated ACKs.
   for (int i = 0; i < 3; ++i) {
@@ -485,7 +489,7 @@
     ack_feedback.ack_frame_id = 0;
     video_sender_->OnReceivedCastFeedback(ack_feedback);
   }
-  EXPECT_EQ(number_of_packets_sent + 1, transport_.number_of_rtp_packets());
+  EXPECT_EQ(number_of_packets_sent + 1, transport_->number_of_rtp_packets());
 }
 
 TEST_F(VideoSenderTest, DuplicateAckRetransmitDoesNotCancelRetransmits) {
@@ -506,14 +510,14 @@
     RunTasks(33);
   }
   // Pause the transport
-  transport_.SetPause(true);
+  transport_->SetPause(true);
 
   // Insert one more video frame.
   video_frame = GetLargeNewVideoFrame();
   video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
   RunTasks(33);
 
-  const int number_of_packets_sent = transport_.number_of_rtp_packets();
+  const int number_of_packets_sent = transport_->number_of_rtp_packets();
 
   // Send duplicated ACKs and mix some invalid NACKs.
   for (int i = 0; i < 10; ++i) {
@@ -526,7 +530,7 @@
     video_sender_->OnReceivedCastFeedback(ack_feedback);
     video_sender_->OnReceivedCastFeedback(nack_feedback);
   }
-  EXPECT_EQ(number_of_packets_sent, transport_.number_of_rtp_packets());
+  EXPECT_EQ(number_of_packets_sent, transport_->number_of_rtp_packets());
 
   // Re-transmit one packet because of duplicated ACKs.
   for (int i = 0; i < 3; ++i) {
@@ -536,16 +540,16 @@
     video_sender_->OnReceivedCastFeedback(ack_feedback);
   }
 
-  transport_.SetPause(false);
+  transport_->SetPause(false);
   RunTasks(100);
-  EXPECT_LT(number_of_packets_sent + 1, transport_.number_of_rtp_packets());
+  EXPECT_LT(number_of_packets_sent + 1, transport_->number_of_rtp_packets());
 }
 
 TEST_F(VideoSenderTest, AcksCancelRetransmits) {
   InitEncoder(false, true);
   ASSERT_EQ(STATUS_INITIALIZED, operational_status_);
 
-  transport_.SetPause(true);
+  transport_->SetPause(true);
   scoped_refptr<media::VideoFrame> video_frame = GetLargeNewVideoFrame();
   video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
   RunTasks(33);
@@ -556,9 +560,9 @@
   cast_feedback.ack_frame_id = 0;
   video_sender_->OnReceivedCastFeedback(cast_feedback);
 
-  transport_.SetPause(false);
+  transport_->SetPause(false);
   RunTasks(33);
-  EXPECT_EQ(0, transport_.number_of_rtp_packets());
+  EXPECT_EQ(0, transport_->number_of_rtp_packets());
 }
 
 TEST_F(VideoSenderTest, CheckVideoFrameFactoryIsNull) {
diff --git a/media/cast/test/cast_benchmarks.cc b/media/cast/test/cast_benchmarks.cc
index 29e2d41..3d3950e5 100644
--- a/media/cast/test/cast_benchmarks.cc
+++ b/media/cast/test/cast_benchmarks.cc
@@ -71,12 +71,6 @@
 static const int64_t kStartMillisecond = INT64_C(1245);
 static const int kTargetPlayoutDelayMs = 400;
 
-void UpdateCastTransportStatus(CastTransportStatus status) {
-  bool result = (status == TRANSPORT_AUDIO_INITIALIZED ||
-                 status == TRANSPORT_VIDEO_INITIALIZED);
-  EXPECT_TRUE(result);
-}
-
 void ExpectVideoSuccess(OperationalStatus status) {
   EXPECT_EQ(STATUS_INITIALIZED, status);
 }
@@ -85,9 +79,6 @@
   EXPECT_EQ(STATUS_INITIALIZED, status);
 }
 
-void IgnoreRawEvents(scoped_ptr<std::vector<FrameEvent>> frame_events,
-                     scoped_ptr<std::vector<PacketEvent>> packet_events) {}
-
 }  // namespace
 
 // Wraps a CastTransportSender and records some statistics about
@@ -168,6 +159,8 @@
                                                rtp_receiver_statistics);
   }
 
+  void SetOptions(const base::DictionaryValue& options) final {}
+
  private:
   scoped_ptr<CastTransportSender> transport_;
   uint32_t audio_ssrc_, video_ssrc_;
@@ -220,8 +213,6 @@
             task_runner_receiver_,
             task_runner_receiver_,
             task_runner_receiver_)),
-        receiver_to_sender_(cast_environment_receiver_),
-        sender_to_receiver_(cast_environment_sender_),
         video_bytes_encoded_(0),
         audio_bytes_encoded_(0),
         frames_sent_(0) {
@@ -269,64 +260,7 @@
     task_runner_receiver_->SetSkew(1.0 / skew);
   }
 
-  void Create(const MeasuringPoint& p) {
-    net::IPEndPoint dummy_endpoint;
-    transport_sender_.Init(
-        new CastTransportSenderImpl(
-            NULL,
-            testing_clock_sender_,
-            dummy_endpoint,
-            dummy_endpoint,
-            make_scoped_ptr(new base::DictionaryValue),
-            base::Bind(&UpdateCastTransportStatus),
-            base::Bind(&IgnoreRawEvents),
-            base::TimeDelta::FromSeconds(1),
-            task_runner_sender_,
-            PacketReceiverCallback(),
-            &sender_to_receiver_),
-        &video_bytes_encoded_,
-        &audio_bytes_encoded_);
-
-    transport_receiver_.reset(
-        new CastTransportSenderImpl(
-            NULL,
-            testing_clock_receiver_,
-            dummy_endpoint,
-            dummy_endpoint,
-            make_scoped_ptr(new base::DictionaryValue),
-            base::Bind(&UpdateCastTransportStatus),
-            base::Bind(&IgnoreRawEvents),
-            base::TimeDelta::FromSeconds(1),
-            task_runner_receiver_,
-            base::Bind(&RunOneBenchmark::ReceivePacket, base::Unretained(this)),
-            &receiver_to_sender_));
-
-    cast_receiver_ = CastReceiver::Create(cast_environment_receiver_,
-                                          audio_receiver_config_,
-                                          video_receiver_config_,
-                                          transport_receiver_.get());
-
-    cast_sender_ =
-        CastSender::Create(cast_environment_sender_, &transport_sender_);
-
-    cast_sender_->InitializeAudio(
-        audio_sender_config_,
-        base::Bind(&ExpectAudioSuccess));
-    cast_sender_->InitializeVideo(
-        video_sender_config_,
-        base::Bind(&ExpectVideoSuccess),
-        CreateDefaultVideoEncodeAcceleratorCallback(),
-        CreateDefaultVideoEncodeMemoryCallback());
-
-    receiver_to_sender_.Initialize(CreateSimplePipe(p),
-                                   transport_sender_.PacketReceiverForTesting(),
-                                   task_runner_, &testing_clock_);
-    sender_to_receiver_.Initialize(
-        CreateSimplePipe(p), transport_receiver_->PacketReceiverForTesting(),
-        task_runner_, &testing_clock_);
-
-    task_runner_->RunTasks();
-  }
+  void Create(const MeasuringPoint& p);
 
   void ReceivePacket(scoped_ptr<Packet> packet) {
     cast_receiver_->ReceivePacket(std::move(packet));
@@ -484,8 +418,8 @@
   scoped_refptr<CastEnvironment> cast_environment_sender_;
   scoped_refptr<CastEnvironment> cast_environment_receiver_;
 
-  LoopBackTransport receiver_to_sender_;
-  LoopBackTransport sender_to_receiver_;
+  LoopBackTransport* receiver_to_sender_;  // Owned by CastTransportSenderImpl.
+  LoopBackTransport* sender_to_receiver_;  // Owned by CastTransportSenderImpl.
   CastTransportSenderWrapper transport_sender_;
   scoped_ptr<CastTransportSender> transport_receiver_;
   uint64_t video_bytes_encoded_;
@@ -501,6 +435,73 @@
   std::vector<std::pair<base::TimeTicks, base::TimeTicks> > video_ticks_;
 };
 
+namespace {
+
+class TransportClient : public CastTransportSender::Client {
+ public:
+  explicit TransportClient(RunOneBenchmark* run_one_benchmark)
+      : run_one_benchmark_(run_one_benchmark) {}
+
+  void OnStatusChanged(CastTransportStatus status) final {
+    bool result = (status == TRANSPORT_AUDIO_INITIALIZED ||
+                   status == TRANSPORT_VIDEO_INITIALIZED);
+    EXPECT_TRUE(result);
+  };
+  void OnLoggingEventsReceived(
+      scoped_ptr<std::vector<FrameEvent>> frame_events,
+      scoped_ptr<std::vector<PacketEvent>> packet_events) final{};
+  void ProcessRtpPacket(scoped_ptr<Packet> packet) final {
+    if (run_one_benchmark_)
+      run_one_benchmark_->ReceivePacket(std::move(packet));
+  };
+
+ private:
+  RunOneBenchmark* const run_one_benchmark_;
+
+  DISALLOW_COPY_AND_ASSIGN(TransportClient);
+};
+
+}  // namepspace
+
+void RunOneBenchmark::Create(const MeasuringPoint& p) {
+  sender_to_receiver_ = new LoopBackTransport(cast_environment_sender_);
+  transport_sender_.Init(
+      new CastTransportSenderImpl(
+          testing_clock_sender_, base::TimeDelta::FromSeconds(1),
+          make_scoped_ptr(new TransportClient(nullptr)),
+          make_scoped_ptr(sender_to_receiver_), task_runner_sender_),
+      &video_bytes_encoded_, &audio_bytes_encoded_);
+
+  receiver_to_sender_ = new LoopBackTransport(cast_environment_receiver_);
+  transport_receiver_.reset(new CastTransportSenderImpl(
+      testing_clock_receiver_, base::TimeDelta::FromSeconds(1),
+      make_scoped_ptr(new TransportClient(this)),
+      make_scoped_ptr(receiver_to_sender_), task_runner_receiver_));
+
+  cast_receiver_ =
+      CastReceiver::Create(cast_environment_receiver_, audio_receiver_config_,
+                           video_receiver_config_, transport_receiver_.get());
+
+  cast_sender_ =
+      CastSender::Create(cast_environment_sender_, &transport_sender_);
+
+  cast_sender_->InitializeAudio(audio_sender_config_,
+                                base::Bind(&ExpectAudioSuccess));
+  cast_sender_->InitializeVideo(video_sender_config_,
+                                base::Bind(&ExpectVideoSuccess),
+                                CreateDefaultVideoEncodeAcceleratorCallback(),
+                                CreateDefaultVideoEncodeMemoryCallback());
+
+  receiver_to_sender_->Initialize(CreateSimplePipe(p),
+                                  transport_sender_.PacketReceiverForTesting(),
+                                  task_runner_, &testing_clock_);
+  sender_to_receiver_->Initialize(
+      CreateSimplePipe(p), transport_receiver_->PacketReceiverForTesting(),
+      task_runner_, &testing_clock_);
+
+  task_runner_->RunTasks();
+}
+
 enum CacheResult { FOUND_TRUE, FOUND_FALSE, NOT_FOUND };
 
 template <class T>
diff --git a/media/cast/test/end2end_unittest.cc b/media/cast/test/end2end_unittest.cc
index 2dd2f93..7145ba3 100644
--- a/media/cast/test/end2end_unittest.cc
+++ b/media/cast/test/end2end_unittest.cc
@@ -94,12 +94,6 @@
   return compressed;
 }
 
-void UpdateCastTransportStatus(CastTransportStatus status) {
-  bool result = (status == TRANSPORT_AUDIO_INITIALIZED ||
-                 status == TRANSPORT_VIDEO_INITIALIZED);
-  EXPECT_TRUE(result);
-}
-
 void ExpectSuccessOperationalStatus(OperationalStatus status) {
   EXPECT_EQ(STATUS_INITIALIZED, status);
 }
@@ -213,6 +207,11 @@
 
   int64_t GetBytesSent() final { return bytes_sent_; }
 
+  void StartReceiving(
+      const PacketReceiverCallbackWithStatus& packet_receiver) final {}
+
+  void StopReceiving() final {}
+
   void SetSendPackets(bool send_packets) { send_packets_ = send_packets; }
 
   void DropAllPacketsBelongingToOddFrames() {
@@ -397,6 +396,11 @@
 // The actual test class, generate synthetic data for both audio and video and
 // send those through the sender and receiver and analyzes the result.
 class End2EndTest : public ::testing::Test {
+ public:
+  void ReceivePacket(scoped_ptr<media::cast::Packet> packet) {
+    cast_receiver_->ReceivePacket(std::move(packet));
+  };
+
  protected:
   End2EndTest()
       : start_time_(),
@@ -417,8 +421,8 @@
             task_runner_receiver_,
             task_runner_receiver_,
             task_runner_receiver_)),
-        receiver_to_sender_(cast_environment_receiver_),
-        sender_to_receiver_(cast_environment_sender_),
+        receiver_to_sender_(new LoopBackTransport(cast_environment_receiver_)),
+        sender_to_receiver_(new LoopBackTransport(cast_environment_sender_)),
         test_receiver_audio_callback_(new TestReceiverAudioCallback()),
         test_receiver_video_callback_(new TestReceiverVideoCallback()) {
     testing_clock_.Advance(
@@ -549,68 +553,7 @@
     }
   }
 
-  void ReceivePacket(scoped_ptr<Packet> packet) {
-    cast_receiver_->ReceivePacket(std::move(packet));
-  }
-
-  void Create() {
-    net::IPEndPoint dummy_endpoint;
-    transport_sender_.reset(new CastTransportSenderImpl(
-        nullptr, testing_clock_sender_, dummy_endpoint, dummy_endpoint,
-        make_scoped_ptr(new base::DictionaryValue),
-        base::Bind(&UpdateCastTransportStatus),
-        base::Bind(&LogEventDispatcher::DispatchBatchOfEvents,
-                   base::Unretained(cast_environment_sender_->logger())),
-        base::TimeDelta::FromMilliseconds(1), task_runner_sender_,
-        PacketReceiverCallback(), &sender_to_receiver_));
-
-    transport_receiver_.reset(new CastTransportSenderImpl(
-        nullptr, testing_clock_sender_, dummy_endpoint, dummy_endpoint,
-        make_scoped_ptr(new base::DictionaryValue),
-        base::Bind(&UpdateCastTransportStatus),
-        base::Bind(&LogEventDispatcher::DispatchBatchOfEvents,
-                   base::Unretained(cast_environment_receiver_->logger())),
-        base::TimeDelta::FromMilliseconds(1), task_runner_sender_,
-        base::Bind(&End2EndTest::ReceivePacket, base::Unretained(this)),
-        &receiver_to_sender_));
-
-    cast_receiver_ = CastReceiver::Create(cast_environment_receiver_,
-                                          audio_receiver_config_,
-                                          video_receiver_config_,
-                                          transport_receiver_.get());
-
-    cast_sender_ =
-        CastSender::Create(cast_environment_sender_, transport_sender_.get());
-
-    // Initializing audio and video senders.
-    cast_sender_->InitializeAudio(
-        audio_sender_config_,
-        base::Bind(&ExpectSuccessOperationalStatus));
-    cast_sender_->InitializeVideo(
-        video_sender_config_,
-        base::Bind(&ExpectSuccessOperationalStatus),
-        CreateDefaultVideoEncodeAcceleratorCallback(),
-        CreateDefaultVideoEncodeMemoryCallback());
-    task_runner_->RunTasks();
-
-    receiver_to_sender_.SetPacketReceiver(
-        transport_sender_->PacketReceiverForTesting(),
-        task_runner_,
-        &testing_clock_);
-    sender_to_receiver_.SetPacketReceiver(
-        transport_receiver_->PacketReceiverForTesting(),
-        task_runner_,
-        &testing_clock_);
-
-    audio_frame_input_ = cast_sender_->audio_frame_input();
-    video_frame_input_ = cast_sender_->video_frame_input();
-
-    audio_bus_factory_.reset(
-        new TestAudioBusFactory(audio_sender_config_.channels,
-                                audio_sender_config_.frequency,
-                                kSoundFrequency,
-                                kSoundVolume));
-  }
+  void Create();
 
   ~End2EndTest() override {
     cast_environment_sender_->logger()->Unsubscribe(&event_subscriber_sender_);
@@ -916,8 +859,9 @@
   scoped_refptr<CastEnvironment> cast_environment_sender_;
   scoped_refptr<CastEnvironment> cast_environment_receiver_;
 
-  LoopBackTransport receiver_to_sender_;
-  LoopBackTransport sender_to_receiver_;
+  LoopBackTransport* receiver_to_sender_;  // Owned by CastTransportSender.
+  LoopBackTransport* sender_to_receiver_;  // Owned by CastTransportSender.
+
   scoped_ptr<CastTransportSenderImpl> transport_sender_;
   scoped_ptr<CastTransportSenderImpl> transport_receiver_;
 
@@ -940,6 +884,83 @@
   base::MessageLoop message_loop_;
 };
 
+namespace {
+
+class TransportClient : public CastTransportSender::Client {
+ public:
+  TransportClient(LogEventDispatcher* log_event_dispatcher,
+                  End2EndTest* e2e_test)
+      : log_event_dispatcher_(log_event_dispatcher), e2e_test_(e2e_test) {}
+
+  void OnStatusChanged(media::cast::CastTransportStatus status) final {
+    bool result = (status == TRANSPORT_AUDIO_INITIALIZED ||
+                   status == TRANSPORT_VIDEO_INITIALIZED);
+    EXPECT_TRUE(result);
+  };
+  void OnLoggingEventsReceived(
+      scoped_ptr<std::vector<FrameEvent>> frame_events,
+      scoped_ptr<std::vector<PacketEvent>> packet_events) final {
+    log_event_dispatcher_->DispatchBatchOfEvents(std::move(frame_events),
+                                                 std::move(packet_events));
+  };
+  void ProcessRtpPacket(scoped_ptr<Packet> packet) final {
+    if (e2e_test_)
+      e2e_test_->ReceivePacket(std::move(packet));
+  };
+
+ private:
+  LogEventDispatcher* const log_event_dispatcher_;  // Not owned by this class.
+  End2EndTest* const e2e_test_;                     // Not owned by this class.
+
+  DISALLOW_COPY_AND_ASSIGN(TransportClient);
+};
+
+}  // namespace
+
+void End2EndTest::Create() {
+  transport_sender_.reset(new CastTransportSenderImpl(
+      testing_clock_sender_, base::TimeDelta::FromMilliseconds(1),
+      make_scoped_ptr(
+          new TransportClient(cast_environment_sender_->logger(), nullptr)),
+      make_scoped_ptr(sender_to_receiver_), task_runner_sender_));
+
+  transport_receiver_.reset(new CastTransportSenderImpl(
+      testing_clock_sender_, base::TimeDelta::FromMilliseconds(1),
+      make_scoped_ptr(
+          new TransportClient(cast_environment_receiver_->logger(), this)),
+      make_scoped_ptr(receiver_to_sender_), task_runner_sender_));
+
+  cast_receiver_ =
+      CastReceiver::Create(cast_environment_receiver_, audio_receiver_config_,
+                           video_receiver_config_, transport_receiver_.get());
+
+  cast_sender_ =
+      CastSender::Create(cast_environment_sender_, transport_sender_.get());
+
+  // Initializing audio and video senders.
+  cast_sender_->InitializeAudio(audio_sender_config_,
+                                base::Bind(&ExpectSuccessOperationalStatus));
+  cast_sender_->InitializeVideo(video_sender_config_,
+                                base::Bind(&ExpectSuccessOperationalStatus),
+                                CreateDefaultVideoEncodeAcceleratorCallback(),
+                                CreateDefaultVideoEncodeMemoryCallback());
+  task_runner_->RunTasks();
+
+  receiver_to_sender_->SetPacketReceiver(
+      transport_sender_->PacketReceiverForTesting(), task_runner_,
+      &testing_clock_);
+  sender_to_receiver_->SetPacketReceiver(
+      transport_receiver_->PacketReceiverForTesting(), task_runner_,
+      &testing_clock_);
+
+  audio_frame_input_ = cast_sender_->audio_frame_input();
+  video_frame_input_ = cast_sender_->video_frame_input();
+
+  audio_bus_factory_.reset(new TestAudioBusFactory(
+      audio_sender_config_.channels, audio_sender_config_.frequency,
+      kSoundFrequency, kSoundVolume));
+}
+
 TEST_F(End2EndTest, LoopWithLosslessEncoding) {
   Configure(CODEC_VIDEO_FAKE, CODEC_AUDIO_PCM16);
   Create();
@@ -980,7 +1001,7 @@
   int frame_number = 0;
   int audio_diff = kFrameTimerMs;
 
-  sender_to_receiver_.SetSendPackets(false);
+  sender_to_receiver_->SetSendPackets(false);
 
   const int test_delay_ms = 100;
 
@@ -1015,7 +1036,7 @@
   }
 
   RunTasks(test_delay_ms);
-  sender_to_receiver_.SetSendPackets(true);
+  sender_to_receiver_->SetSendPackets(true);
 
   int num_audio_frames_requested = 0;
   for (int j = 0; j < 10; ++j) {
@@ -1142,8 +1163,8 @@
 
 TEST_F(End2EndTest, EvilNetwork) {
   Configure(CODEC_VIDEO_FAKE, CODEC_AUDIO_PCM16);
-  receiver_to_sender_.SetPacketPipe(test::EvilNetwork());
-  sender_to_receiver_.SetPacketPipe(test::EvilNetwork());
+  receiver_to_sender_->SetPacketPipe(test::EvilNetwork());
+  sender_to_receiver_->SetPacketPipe(test::EvilNetwork());
   Create();
   StartBasicPlayer();
 
@@ -1164,8 +1185,8 @@
 // at a much higher frame rate.
 TEST_F(End2EndTest, ShoveHighFrameRateDownYerThroat) {
   Configure(CODEC_VIDEO_FAKE, CODEC_AUDIO_PCM16);
-  receiver_to_sender_.SetPacketPipe(test::EvilNetwork());
-  sender_to_receiver_.SetPacketPipe(test::EvilNetwork());
+  receiver_to_sender_->SetPacketPipe(test::EvilNetwork());
+  sender_to_receiver_->SetPacketPipe(test::EvilNetwork());
   Create();
   StartBasicPlayer();
 
@@ -1185,7 +1206,7 @@
 
 TEST_F(End2EndTest, OldPacketNetwork) {
   Configure(CODEC_VIDEO_FAKE, CODEC_AUDIO_PCM16);
-  sender_to_receiver_.SetPacketPipe(test::NewRandomDrop(0.01));
+  sender_to_receiver_->SetPacketPipe(test::NewRandomDrop(0.01));
   scoped_ptr<test::PacketPipe> echo_chamber(
       test::NewDuplicateAndDelay(1, 10 * kFrameTimerMs));
   echo_chamber->AppendToPipe(
@@ -1197,7 +1218,7 @@
   echo_chamber->AppendToPipe(
       test::NewDuplicateAndDelay(1, 160 * kFrameTimerMs));
 
-  receiver_to_sender_.SetPacketPipe(std::move(echo_chamber));
+  receiver_to_sender_->SetPacketPipe(std::move(echo_chamber));
   Create();
   StartBasicPlayer();
 
diff --git a/media/cast/test/fake_media_source.h b/media/cast/test/fake_media_source.h
index a400cb3..7c4d456 100644
--- a/media/cast/test/fake_media_source.h
+++ b/media/cast/test/fake_media_source.h
@@ -38,6 +38,7 @@
 class AudioTimestampHelper;
 class FFmpegGlue;
 class InMemoryUrlProtocol;
+class VideoFrame;
 
 namespace cast {
 
diff --git a/media/cast/test/loopback_transport.h b/media/cast/test/loopback_transport.h
index e61ae4d7..7f32c6f 100644
--- a/media/cast/test/loopback_transport.h
+++ b/media/cast/test/loopback_transport.h
@@ -36,6 +36,11 @@
 
   int64_t GetBytesSent() final;
 
+  void StartReceiving(
+      const PacketReceiverCallbackWithStatus& packet_receiver) final {}
+
+  void StopReceiving() final {}
+
   // Initiailize this loopback transport.
   // Establish a flow of packets from |pipe| to |packet_receiver|.
   //
diff --git a/media/cast/test/receiver.cc b/media/cast/test/receiver.cc
index 67d8462..c9e52da 100644
--- a/media/cast/test/receiver.cc
+++ b/media/cast/test/receiver.cc
@@ -44,7 +44,6 @@
 #include "media/cast/test/utility/in_process_receiver.h"
 #include "media/cast/test/utility/input_builder.h"
 #include "media/cast/test/utility/standalone_cast_environment.h"
-#include "net/base/net_util.h"
 
 #if defined(USE_X11)
 #include "media/cast/test/linux_output_window.h"
diff --git a/media/cast/test/sender.cc b/media/cast/test/sender.cc
index 206bfb5f..fa508dc 100644
--- a/media/cast/test/sender.cc
+++ b/media/cast/test/sender.cc
@@ -160,6 +160,31 @@
   VLOG(0) << "Audio stats: " << json;
 }
 
+class TransportClient : public media::cast::CastTransportSender::Client {
+ public:
+  explicit TransportClient(
+      media::cast::LogEventDispatcher* log_event_dispatcher)
+      : log_event_dispatcher_(log_event_dispatcher) {}
+
+  void OnStatusChanged(media::cast::CastTransportStatus status) final {
+    VLOG(1) << "Transport status: " << status;
+  };
+  void OnLoggingEventsReceived(
+      scoped_ptr<std::vector<media::cast::FrameEvent>> frame_events,
+      scoped_ptr<std::vector<media::cast::PacketEvent>> packet_events) final {
+    DCHECK(log_event_dispatcher_);
+    log_event_dispatcher_->DispatchBatchOfEvents(std::move(frame_events),
+                                                 std::move(packet_events));
+  };
+  void ProcessRtpPacket(scoped_ptr<media::cast::Packet> packet) final {}
+
+ private:
+  media::cast::LogEventDispatcher* const
+      log_event_dispatcher_;  // Not owned by this class.
+
+  DISALLOW_COPY_AND_ASSIGN(TransportClient);
+};
+
 }  // namespace
 
 int main(int argc, char** argv) {
@@ -235,14 +260,12 @@
   // CastTransportSender initialization.
   scoped_ptr<media::cast::CastTransportSender> transport_sender =
       media::cast::CastTransportSender::Create(
-          nullptr,  // net log.
-          cast_environment->Clock(), net::IPEndPoint(), remote_endpoint,
-          make_scoped_ptr(new base::DictionaryValue),  // options
-          base::Bind(&UpdateCastTransportStatus),
-          base::Bind(&media::cast::LogEventDispatcher::DispatchBatchOfEvents,
-                     base::Unretained(cast_environment->logger())),
-          base::TimeDelta::FromSeconds(1),
-          media::cast::PacketReceiverCallback(), io_message_loop.task_runner());
+          cast_environment->Clock(), base::TimeDelta::FromSeconds(1),
+          make_scoped_ptr(new TransportClient(cast_environment->logger())),
+          make_scoped_ptr(new media::cast::UdpTransport(
+              nullptr, io_message_loop.task_runner(), net::IPEndPoint(),
+              remote_endpoint, base::Bind(&UpdateCastTransportStatus))),
+          io_message_loop.task_runner());
 
   // Set up event subscribers.
   scoped_ptr<media::cast::EncodingEventSubscriber> video_event_subscriber;
diff --git a/media/cast/test/simulator.cc b/media/cast/test/simulator.cc
index a2aa6e4..78c1ccf 100644
--- a/media/cast/test/simulator.cc
+++ b/media/cast/test/simulator.cc
@@ -114,10 +114,6 @@
   return as_int;
 }
 
-void UpdateCastTransportStatus(CastTransportStatus status) {
-  LOG(INFO) << "Cast transport status: " << status;
-}
-
 void LogAudioOperationalStatus(OperationalStatus status) {
   LOG(INFO) << "Audio status: " << status;
 }
@@ -126,6 +122,44 @@
   LOG(INFO) << "Video status: " << status;
 }
 
+struct PacketProxy {
+  PacketProxy() : receiver(NULL) {}
+  void ReceivePacket(scoped_ptr<Packet> packet) {
+    if (receiver)
+      receiver->ReceivePacket(std::move(packet));
+  }
+  CastReceiver* receiver;
+};
+
+class TransportClient : public CastTransportSender::Client {
+ public:
+  TransportClient(LogEventDispatcher* log_event_dispatcher,
+                  PacketProxy* packet_proxy)
+      : log_event_dispatcher_(log_event_dispatcher),
+        packet_proxy_(packet_proxy) {}
+
+  void OnStatusChanged(CastTransportStatus status) final {
+    LOG(INFO) << "Cast transport status: " << status;
+  };
+  void OnLoggingEventsReceived(
+      scoped_ptr<std::vector<FrameEvent>> frame_events,
+      scoped_ptr<std::vector<PacketEvent>> packet_events) final {
+    DCHECK(log_event_dispatcher_);
+    log_event_dispatcher_->DispatchBatchOfEvents(std::move(frame_events),
+                                                 std::move(packet_events));
+  };
+  void ProcessRtpPacket(scoped_ptr<Packet> packet) final {
+    if (packet_proxy_)
+      packet_proxy_->ReceivePacket(std::move(packet));
+  };
+
+ private:
+  LogEventDispatcher* const log_event_dispatcher_;  // Not owned by this class.
+  PacketProxy* const packet_proxy_;                 // Not owned by this class.
+
+  DISALLOW_COPY_AND_ASSIGN(TransportClient);
+};
+
 // Maintains a queue of encoded video frames.
 // This works by tracking FRAME_CAPTURE_END and FRAME_ENCODED events.
 // If a video frame is detected to be encoded it transfers a frame
@@ -345,33 +379,19 @@
   video_receiver_config.rtp_max_delay_ms =
       video_sender_config.max_playout_delay.InMilliseconds();
 
-  // Loopback transport.
-  LoopBackTransport receiver_to_sender(receiver_env);
-  LoopBackTransport sender_to_receiver(sender_env);
-
-  struct PacketProxy {
-    PacketProxy() : receiver(NULL) {}
-    void ReceivePacket(scoped_ptr<Packet> packet) {
-      if (receiver)
-        receiver->ReceivePacket(std::move(packet));
-    }
-    CastReceiver* receiver;
-  };
+  // Loopback transport. Owned by CastTransportSender.
+  LoopBackTransport* receiver_to_sender = new LoopBackTransport(receiver_env);
+  LoopBackTransport* sender_to_receiver = new LoopBackTransport(sender_env);
 
   PacketProxy packet_proxy;
 
   // Cast receiver.
   scoped_ptr<CastTransportSender> transport_receiver(
       new CastTransportSenderImpl(
-          nullptr, &testing_clock, net::IPEndPoint(), net::IPEndPoint(),
-          make_scoped_ptr(new base::DictionaryValue),
-          base::Bind(&UpdateCastTransportStatus),
-          base::Bind(&LogEventDispatcher::DispatchBatchOfEvents,
-                     base::Unretained(receiver_env->logger())),
-          base::TimeDelta::FromSeconds(1), task_runner,
-          base::Bind(&PacketProxy::ReceivePacket,
-                     base::Unretained(&packet_proxy)),
-          &receiver_to_sender));
+          &testing_clock, base::TimeDelta::FromSeconds(1),
+          make_scoped_ptr(
+              new TransportClient(receiver_env->logger(), &packet_proxy)),
+          make_scoped_ptr(receiver_to_sender), task_runner));
   scoped_ptr<CastReceiver> cast_receiver(
       CastReceiver::Create(receiver_env,
                            audio_receiver_config,
@@ -382,13 +402,9 @@
 
   // Cast sender and transport sender.
   scoped_ptr<CastTransportSender> transport_sender(new CastTransportSenderImpl(
-      nullptr, &testing_clock, net::IPEndPoint(), net::IPEndPoint(),
-      make_scoped_ptr(new base::DictionaryValue),
-      base::Bind(&UpdateCastTransportStatus),
-      base::Bind(&LogEventDispatcher::DispatchBatchOfEvents,
-                 base::Unretained(sender_env->logger())),
-      base::TimeDelta::FromSeconds(1), task_runner, PacketReceiverCallback(),
-      &sender_to_receiver));
+      &testing_clock, base::TimeDelta::FromSeconds(1),
+      make_scoped_ptr(new TransportClient(sender_env->logger(), nullptr)),
+      make_scoped_ptr(sender_to_receiver), task_runner));
   scoped_ptr<CastSender> cast_sender(
       CastSender::Create(sender_env, transport_sender.get()));
 
@@ -406,20 +422,19 @@
     ipp.reset(new test::InterruptedPoissonProcess(
         average_rates,
         ipp_model.coef_burstiness(), ipp_model.coef_variance(), 0));
-    receiver_to_sender.Initialize(ipp->NewBuffer(128 * 1024),
-                                  transport_sender->PacketReceiverForTesting(),
-                                  task_runner, &testing_clock);
-    sender_to_receiver.Initialize(
+    receiver_to_sender->Initialize(ipp->NewBuffer(128 * 1024),
+                                   transport_sender->PacketReceiverForTesting(),
+                                   task_runner, &testing_clock);
+    sender_to_receiver->Initialize(
         ipp->NewBuffer(128 * 1024),
         transport_receiver->PacketReceiverForTesting(), task_runner,
         &testing_clock);
   } else {
     LOG(INFO) << "No network simulation.";
-    receiver_to_sender.Initialize(
-        scoped_ptr<test::PacketPipe>(),
-        transport_sender->PacketReceiverForTesting(),
-        task_runner, &testing_clock);
-    sender_to_receiver.Initialize(
+    receiver_to_sender->Initialize(scoped_ptr<test::PacketPipe>(),
+                                   transport_sender->PacketReceiverForTesting(),
+                                   task_runner, &testing_clock);
+    sender_to_receiver->Initialize(
         scoped_ptr<test::PacketPipe>(),
         transport_receiver->PacketReceiverForTesting(), task_runner,
         &testing_clock);
diff --git a/media/cast/test/utility/in_process_receiver.cc b/media/cast/test/utility/in_process_receiver.cc
index 1e97c9ab..b4da3a8 100644
--- a/media/cast/test/utility/in_process_receiver.cc
+++ b/media/cast/test/utility/in_process_receiver.cc
@@ -23,6 +23,19 @@
 namespace media {
 namespace cast {
 
+void InProcessReceiver::TransportClient::OnStatusChanged(
+    CastTransportStatus status) {
+  LOG_IF(ERROR, status == media::cast::TRANSPORT_SOCKET_ERROR)
+      << "Transport socket error occurred.  InProcessReceiver is likely "
+         "dead.";
+  VLOG(1) << "CastTransportStatus is now " << status;
+}
+
+void InProcessReceiver::TransportClient::ProcessRtpPacket(
+    scoped_ptr<Packet> packet) {
+  in_process_receiver_->ReceivePacket(std::move(packet));
+}
+
 InProcessReceiver::InProcessReceiver(
     const scoped_refptr<CastEnvironment>& cast_environment,
     const net::IPEndPoint& local_end_point,
@@ -63,8 +76,8 @@
 
 void InProcessReceiver::StopOnMainThread(base::WaitableEvent* event) {
   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
-  cast_receiver_.reset(NULL);
-  transport_.reset(NULL);
+  cast_receiver_.reset(nullptr);
+  transport_.reset(nullptr);
   weak_factory_.InvalidateWeakPtrs();
   event->Signal();
 }
@@ -81,17 +94,13 @@
   DCHECK(!transport_ && !cast_receiver_);
 
   transport_ = CastTransportSender::Create(
-      NULL,
-      cast_environment_->Clock(),
-      local_end_point_,
-      remote_end_point_,
-      scoped_ptr<base::DictionaryValue>(new base::DictionaryValue),
-      base::Bind(&InProcessReceiver::UpdateCastTransportStatus,
-                 base::Unretained(this)),
-      BulkRawEventsCallback(),
-      base::TimeDelta(),
-      base::Bind(&InProcessReceiver::ReceivePacket,
-                 base::Unretained(this)),
+      cast_environment_->Clock(), base::TimeDelta(),
+      make_scoped_ptr(new InProcessReceiver::TransportClient(this)),
+      make_scoped_ptr(new UdpTransport(
+          nullptr, cast_environment_->GetTaskRunner(CastEnvironment::MAIN),
+          local_end_point_, remote_end_point_,
+          base::Bind(&InProcessReceiver::UpdateCastTransportStatus,
+                     base::Unretained(this)))),
       cast_environment_->GetTaskRunner(CastEnvironment::MAIN));
 
   cast_receiver_ = CastReceiver::Create(
diff --git a/media/cast/test/utility/in_process_receiver.h b/media/cast/test/utility/in_process_receiver.h
index cd957d4..8248ceb 100644
--- a/media/cast/test/utility/in_process_receiver.h
+++ b/media/cast/test/utility/in_process_receiver.h
@@ -33,6 +33,7 @@
 class CastEnvironment;
 class CastReceiver;
 class UdpTransport;
+class InProcessReceiver;
 
 // Common base functionality for an in-process Cast receiver.  This is meant to
 // be subclassed with the OnAudioFrame() and OnVideoFrame() methods implemented,
@@ -40,6 +41,23 @@
 // rather than on the boilerplate "glue" code.
 class InProcessReceiver {
  public:
+  class TransportClient : public CastTransportSender::Client {
+   public:
+    explicit TransportClient(InProcessReceiver* in_process_receiver)
+        : in_process_receiver_(in_process_receiver) {}
+
+    void OnStatusChanged(CastTransportStatus status) final;
+    void OnLoggingEventsReceived(
+        scoped_ptr<std::vector<FrameEvent>> frame_events,
+        scoped_ptr<std::vector<PacketEvent>> packet_events) final {}
+    void ProcessRtpPacket(scoped_ptr<Packet> packet) final;
+
+   private:
+    InProcessReceiver* in_process_receiver_;
+
+    DISALLOW_COPY_AND_ASSIGN(TransportClient);
+  };
+
   // Construct a receiver with the given configuration.  |remote_end_point| can
   // be left empty, if the transport should automatically mate with the first
   // remote sender it encounters.
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc
index 1afbc6d..e931c3fd 100644
--- a/media/filters/chunk_demuxer.cc
+++ b/media/filters/chunk_demuxer.cc
@@ -160,11 +160,12 @@
   return stream_->GetBufferedSize();
 }
 
-void ChunkDemuxerStream::OnNewMediaSegment(DecodeTimestamp start_timestamp) {
-  DVLOG(2) << "ChunkDemuxerStream::OnNewMediaSegment("
+void ChunkDemuxerStream::OnStartOfCodedFrameGroup(
+    DecodeTimestamp start_timestamp) {
+  DVLOG(2) << "ChunkDemuxerStream::OnStartOfCodedFrameGroup("
            << start_timestamp.InSecondsF() << ")";
   base::AutoLock auto_lock(lock_);
-  stream_->OnNewMediaSegment(start_timestamp);
+  stream_->OnStartOfCodedFrameGroup(start_timestamp);
 }
 
 bool ChunkDemuxerStream::UpdateAudioConfig(
diff --git a/media/filters/chunk_demuxer.h b/media/filters/chunk_demuxer.h
index 6954793..2425412 100644
--- a/media/filters/chunk_demuxer.h
+++ b/media/filters/chunk_demuxer.h
@@ -80,8 +80,8 @@
   size_t GetBufferedSize() const;
 
   // Signal to the stream that buffers handed in through subsequent calls to
-  // Append() belong to a media segment that starts at |start_timestamp|.
-  void OnNewMediaSegment(DecodeTimestamp start_timestamp);
+  // Append() belong to a coded frame group that starts at |start_timestamp|.
+  void OnStartOfCodedFrameGroup(DecodeTimestamp start_timestamp);
 
   // Called when midstream config updates occur.
   // Returns true if the new config is accepted.
diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc
index 8549f61e..c095f5a 100644
--- a/media/filters/chunk_demuxer_unittest.cc
+++ b/media/filters/chunk_demuxer_unittest.cc
@@ -685,7 +685,8 @@
     AppendMuxedCluster(msi);
   }
 
-  void AppendMuxedCluster(const std::vector<MuxedStreamInfo> msi) {
+  scoped_ptr<Cluster> GenerateMuxedCluster(
+      const std::vector<MuxedStreamInfo> msi) {
     std::priority_queue<BlockInfo> block_queue;
     for (size_t i = 0; i < msi.size(); ++i) {
       std::vector<BlockInfo> track_blocks;
@@ -701,8 +702,11 @@
             msi[i].last_blocks_estimated_duration));
       }
     }
+    return GenerateCluster(block_queue, false);
+  }
 
-    AppendCluster(kSourceId, GenerateCluster(block_queue, false));
+  void AppendMuxedCluster(const std::vector<MuxedStreamInfo> msi) {
+    AppendCluster(kSourceId, GenerateMuxedCluster(msi));
   }
 
   void AppendData(const std::string& source_id,
@@ -902,7 +906,7 @@
   // The resulting video stream returns data from each file for the following
   // time ranges.
   // bear-320x240.webm : [0-501)       [801-2736)
-  // bear-640x360.webm :       [527-793)
+  // bear-640x360.webm :       [527-760)
   //
   // bear-320x240.webm AudioDecoderConfig returns 3863 for its extra_data size.
   // bear-640x360.webm AudioDecoderConfig returns 3935 for its extra_data size.
@@ -3201,7 +3205,7 @@
   // Read until the next config change.
   ReadUntilNotOkOrEndOfStream(DemuxerStream::VIDEO, &status, &last_timestamp);
   ASSERT_EQ(status, DemuxerStream::kConfigChanged);
-  EXPECT_EQ(last_timestamp.InMilliseconds(), 793);
+  EXPECT_EQ(last_timestamp.InMilliseconds(), 760);
 
   // Get the new config and verify that it matches the first one.
   ASSERT_TRUE(video_config_1.Matches(video->video_decoder_config()));
@@ -4401,4 +4405,212 @@
   AppendCluster(GenerateEmptyCluster(0));
 }
 
+TEST_F(ChunkDemuxerTest, RelaxedKeyframe_FirstSegmentMissingKeyframe) {
+  // Append V:[n n n][n n K]
+  // Expect V:           [K]
+  ASSERT_TRUE(InitDemuxer(HAS_VIDEO));
+  DemuxerStream* video_stream = demuxer_->GetStream(DemuxerStream::VIDEO);
+
+  EXPECT_MEDIA_LOG(WebMSimpleBlockDurationEstimated(10)).Times(2);
+  AppendSingleStreamCluster(kSourceId, kVideoTrackNum, "0 10 20");
+  AppendSingleStreamCluster(kSourceId, kVideoTrackNum, "30 40 50K");
+  CheckExpectedRanges("{ [50,60) }");
+  CheckExpectedBuffers(video_stream, "50K");
+}
+
+TEST_F(ChunkDemuxerTest, RelaxedKeyframe_SecondSegmentMissingKeyframe) {
+  // Append V:[K n n][n n n]
+  // Expect V:[K n n][n n n]
+  ASSERT_TRUE(InitDemuxer(HAS_VIDEO));
+  DemuxerStream* video_stream = demuxer_->GetStream(DemuxerStream::VIDEO);
+
+  EXPECT_MEDIA_LOG(WebMSimpleBlockDurationEstimated(10)).Times(2);
+  AppendSingleStreamCluster(kSourceId, kVideoTrackNum, "0K 10 20");
+  AppendSingleStreamCluster(kSourceId, kVideoTrackNum, "30 40 50");
+  CheckExpectedRanges("{ [0,60) }");
+  CheckExpectedBuffers(video_stream, "0K 10 20 30 40 50");
+}
+
+TEST_F(ChunkDemuxerTest, RelaxedKeyframe_RemoveInterruptsCodedFrameGroup_1) {
+  // Append V:[K n n]
+  // Remove    *****
+  // Append V:       [n n n][n K n]
+  // Expect:                  [K n]
+  ASSERT_TRUE(InitDemuxer(HAS_VIDEO));
+  DemuxerStream* video_stream = demuxer_->GetStream(DemuxerStream::VIDEO);
+
+  EXPECT_MEDIA_LOG(WebMSimpleBlockDurationEstimated(10)).Times(3);
+  AppendSingleStreamCluster(kSourceId, kVideoTrackNum, "0K 10 20");
+  demuxer_->Remove(kSourceId, base::TimeDelta(),
+                   base::TimeDelta::FromMilliseconds(30));
+  AppendSingleStreamCluster(kSourceId, kVideoTrackNum, "30 40 50");
+  AppendSingleStreamCluster(kSourceId, kVideoTrackNum, "60 70K 80");
+  CheckExpectedRanges("{ [70,90) }");
+  CheckExpectedBuffers(video_stream, "70K 80");
+}
+
+TEST_F(ChunkDemuxerTest, RelaxedKeyframe_RemoveInterruptsCodedFrameGroup_2) {
+  // Append V:[K n n][n n n][n K n]
+  // Remove    *
+  // Expect:                  [K n]
+  ASSERT_TRUE(InitDemuxer(HAS_VIDEO));
+  DemuxerStream* video_stream = demuxer_->GetStream(DemuxerStream::VIDEO);
+
+  EXPECT_MEDIA_LOG(WebMSimpleBlockDurationEstimated(10)).Times(3);
+  AppendSingleStreamCluster(kSourceId, kVideoTrackNum, "0K 10 20");
+  AppendSingleStreamCluster(kSourceId, kVideoTrackNum, "30 40 50");
+  AppendSingleStreamCluster(kSourceId, kVideoTrackNum, "60 70K 80");
+  demuxer_->Remove(kSourceId, base::TimeDelta(),
+                   base::TimeDelta::FromMilliseconds(10));
+  CheckExpectedRanges("{ [70,90) }");
+  CheckExpectedBuffers(video_stream, "70K 80");
+}
+
+TEST_F(ChunkDemuxerTest, RelaxedKeyframe_RemoveInterruptsCodedFrameGroup_3) {
+  // Append V:[K n n][n n n][n K n]
+  // Remove               *
+  // Expect:  [K n n..n n]    [K n]
+  ASSERT_TRUE(InitDemuxer(HAS_VIDEO));
+  DemuxerStream* video_stream = demuxer_->GetStream(DemuxerStream::VIDEO);
+
+  EXPECT_MEDIA_LOG(WebMSimpleBlockDurationEstimated(10)).Times(3);
+  AppendSingleStreamCluster(kSourceId, kVideoTrackNum, "0K 10 20");
+  AppendSingleStreamCluster(kSourceId, kVideoTrackNum, "30 40 50");
+  AppendSingleStreamCluster(kSourceId, kVideoTrackNum, "60 70K 80");
+  demuxer_->Remove(kSourceId, base::TimeDelta::FromMilliseconds(50),
+                   base::TimeDelta::FromMilliseconds(60));
+  CheckExpectedRanges("{ [0,50) [70,90) }");
+  CheckExpectedBuffers(video_stream, "0K 10 20 30 40");
+  Seek(base::TimeDelta::FromMilliseconds(70));
+  CheckExpectedBuffers(video_stream, "70K 80");
+}
+
+TEST_F(ChunkDemuxerTest,
+       RelaxedKeyframe_RemoveInterruptsMuxedCodedFrameGroup_1) {
+  // Append muxed:
+  //        A:[K K K]
+  //        V:[K n n]
+  // Remove    *****
+  // Append muxed:
+  //        A:       [K K K][K K K]
+  //        V:       [n n n][n K n]
+  // Expect:
+  //        A:       [K K K][K K K]
+  //        V                 [K n]
+  ASSERT_TRUE(InitDemuxer(HAS_AUDIO | HAS_VIDEO));
+  DemuxerStream* audio_stream = demuxer_->GetStream(DemuxerStream::AUDIO);
+  DemuxerStream* video_stream = demuxer_->GetStream(DemuxerStream::VIDEO);
+
+  AppendMuxedCluster(MuxedStreamInfo(kAudioTrackNum, "0K 10K 20D10K"),
+                     MuxedStreamInfo(kVideoTrackNum, "0K 10 20", 10));
+  demuxer_->Remove(kSourceId, base::TimeDelta(),
+                   base::TimeDelta::FromMilliseconds(30));
+  AppendMuxedCluster(MuxedStreamInfo(kAudioTrackNum, "30K 40K 50D10K"),
+                     MuxedStreamInfo(kVideoTrackNum, "30 40 50", 10));
+  AppendMuxedCluster(MuxedStreamInfo(kAudioTrackNum, "60K 70K 80D10K"),
+                     MuxedStreamInfo(kVideoTrackNum, "60 70K 80", 10));
+  CheckExpectedRanges(DemuxerStream::AUDIO, "{ [30,90) }");
+  CheckExpectedRanges(DemuxerStream::VIDEO, "{ [70,90) }");
+  CheckExpectedRanges("{ [70,90) }");
+  CheckExpectedBuffers(audio_stream, "30K 40K 50K 60K 70K 80K");
+  CheckExpectedBuffers(video_stream, "70K 80");
+}
+
+TEST_F(ChunkDemuxerTest,
+       RelaxedKeyframe_RemoveInterruptsMuxedCodedFrameGroup_2) {
+  // Append muxed:
+  //        A:[K K K]
+  //        V:(Nothing, simulating jagged cluster start or a long previous
+  //          video frame)
+  // Remove    *****
+  // Append muxed:
+  //        A:       [K K K][K K K]
+  //        V:       [n n n][n K n]
+  // Expect:
+  //        A:       [K K K][K K K]
+  //        V [................K n] (As would occur if there really were a
+  //        jagged cluster start and not badly muxed clusters as used to
+  //        simulate a jagged start in this test.)
+  ASSERT_TRUE(InitDemuxer(HAS_AUDIO | HAS_VIDEO));
+  DemuxerStream* audio_stream = demuxer_->GetStream(DemuxerStream::AUDIO);
+  DemuxerStream* video_stream = demuxer_->GetStream(DemuxerStream::VIDEO);
+
+  EXPECT_MEDIA_LOG(SegmentMissingFrames("video"));
+  AppendMuxedCluster(MuxedStreamInfo(kAudioTrackNum, "0K 10K 20D10K"),
+                     MuxedStreamInfo(kVideoTrackNum, ""));
+  demuxer_->Remove(kSourceId, base::TimeDelta(),
+                   base::TimeDelta::FromMilliseconds(30));
+  AppendMuxedCluster(MuxedStreamInfo(kAudioTrackNum, "30K 40K 50D10K"),
+                     MuxedStreamInfo(kVideoTrackNum, "30 40 50", 10));
+  AppendMuxedCluster(MuxedStreamInfo(kAudioTrackNum, "60K 70K 80D10K"),
+                     MuxedStreamInfo(kVideoTrackNum, "60 70K 80", 10));
+  CheckExpectedRanges(DemuxerStream::AUDIO, "{ [30,90) }");
+  CheckExpectedRanges(DemuxerStream::VIDEO, "{ [0,90) }");
+  CheckExpectedRanges("{ [30,90) }");
+  CheckExpectedBuffers(audio_stream, "30K 40K 50K 60K 70K 80K");
+  CheckExpectedBuffers(video_stream, "70K 80");
+}
+
+TEST_F(ChunkDemuxerTest,
+       RelaxedKeyframe_RemoveInterruptsMuxedCodedFrameGroup_3) {
+  // Append muxed:
+  //        A:[K K K
+  //        V:(Nothing yet. This is a jagged start, not simulated.)
+  // Remove    *****
+  // Append muxed:
+  //        A:       K K K K K K]
+  //        V:       n n n n K n]
+  // Expect:
+  //        A:      [K K K K K K]
+  //        V [..............K n]
+  ASSERT_TRUE(InitDemuxer(HAS_AUDIO | HAS_VIDEO));
+  DemuxerStream* audio_stream = demuxer_->GetStream(DemuxerStream::AUDIO);
+  DemuxerStream* video_stream = demuxer_->GetStream(DemuxerStream::VIDEO);
+
+  std::vector<MuxedStreamInfo> msi(2);
+  msi[0] =
+      MuxedStreamInfo(kAudioTrackNum, "0K 10K 20K 30K 40K 50K 60K 70K 80D10K");
+  msi[1] = MuxedStreamInfo(kVideoTrackNum, "31 41 51 61 71K 81", 10);
+  scoped_ptr<Cluster> cluster = GenerateMuxedCluster(msi);
+
+  // Append the first part of the cluster, up to the beginning of the first
+  // video simpleblock. The result should be just 4 audio blocks and no video
+  // blocks are appended. Since the stream parser does not yet have a duration
+  // for the 4th audio block in this partial cluster append, it is not yet
+  // emitted from the parser, and only the first 3 audio blocks are expected to
+  // be buffered by and available from the demuxer.
+  ASSERT_EQ(kVideoTrackNum, 1);
+  int video_start = 0;
+  bool found = false;
+  while (video_start < cluster->size() - 10) {
+    if (cluster->data()[video_start] == 0xA3 &&
+        cluster->data()[video_start + 9] == 0x81) {
+      found = true;
+      break;
+    }
+    video_start++;
+  }
+
+  ASSERT_TRUE(found);
+  ASSERT_GT(video_start, 0);
+  ASSERT_LT(video_start, cluster->size() - 3);
+
+  AppendData(kSourceId, cluster->data(), video_start);
+  CheckExpectedRanges(DemuxerStream::AUDIO, "{ [0,30) }");
+  CheckExpectedRanges(DemuxerStream::VIDEO, "{ }");
+
+  demuxer_->Remove(kSourceId, base::TimeDelta(),
+                   base::TimeDelta::FromMilliseconds(30));
+
+  // Append the remainder of the cluster
+  AppendData(kSourceId, cluster->data() + video_start,
+             cluster->size() - video_start);
+
+  CheckExpectedRanges(DemuxerStream::AUDIO, "{ [30,90) }");
+  CheckExpectedRanges(DemuxerStream::VIDEO, "{ [0,91) }");
+  CheckExpectedRanges("{ [30,90) }");
+  CheckExpectedBuffers(audio_stream, "30K 40K 50K 60K 70K 80K");
+  CheckExpectedBuffers(video_stream, "71K 81");
+}
+
 }  // namespace media
diff --git a/media/filters/decoder_selector.cc b/media/filters/decoder_selector.cc
index c3341e7..732dd53 100644
--- a/media/filters/decoder_selector.cc
+++ b/media/filters/decoder_selector.cc
@@ -16,7 +16,6 @@
 #include "media/base/cdm_context.h"
 #include "media/base/demuxer_stream.h"
 #include "media/base/media_log.h"
-#include "media/base/pipeline.h"
 #include "media/base/video_decoder.h"
 #include "media/filters/decoder_stream_traits.h"
 #include "media/filters/decrypting_demuxer_stream.h"
diff --git a/media/filters/decrypting_audio_decoder.cc b/media/filters/decrypting_audio_decoder.cc
index 3f8e7553..b8876dd 100644
--- a/media/filters/decrypting_audio_decoder.cc
+++ b/media/filters/decrypting_audio_decoder.cc
@@ -20,7 +20,6 @@
 #include "media/base/cdm_context.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/media_log.h"
-#include "media/base/pipeline.h"
 #include "media/base/timestamp_constants.h"
 
 namespace media {
diff --git a/media/filters/decrypting_demuxer_stream.cc b/media/filters/decrypting_demuxer_stream.cc
index 15d7cbc..637de2a 100644
--- a/media/filters/decrypting_demuxer_stream.cc
+++ b/media/filters/decrypting_demuxer_stream.cc
@@ -12,7 +12,6 @@
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/media_log.h"
-#include "media/base/pipeline.h"
 
 namespace media {
 
@@ -163,8 +162,6 @@
     decryptor_->CancelDecrypt(GetDecryptorStreamType());
     decryptor_ = NULL;
   }
-  if (!set_cdm_ready_cb_.is_null())
-    base::ResetAndReturn(&set_cdm_ready_cb_).Run(CdmReadyCB());
   if (!init_cb_.is_null())
     base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT);
   if (!read_cb_.is_null())
diff --git a/media/filters/decrypting_demuxer_stream.h b/media/filters/decrypting_demuxer_stream.h
index 1ac8d4c3..9dfcb327 100644
--- a/media/filters/decrypting_demuxer_stream.h
+++ b/media/filters/decrypting_demuxer_stream.h
@@ -117,9 +117,6 @@
   AudioDecoderConfig audio_config_;
   VideoDecoderConfig video_config_;
 
-  // Callback to request/cancel CDM ready notification.
-  SetCdmReadyCB set_cdm_ready_cb_;
-
   Decryptor* decryptor_;
 
   // The buffer returned by the demuxer that needs to be decrypted.
diff --git a/media/filters/decrypting_video_decoder.cc b/media/filters/decrypting_video_decoder.cc
index aee0a2b..a639130 100644
--- a/media/filters/decrypting_video_decoder.cc
+++ b/media/filters/decrypting_video_decoder.cc
@@ -14,7 +14,6 @@
 #include "media/base/cdm_context.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/media_log.h"
-#include "media/base/pipeline.h"
 #include "media/base/video_frame.h"
 
 namespace media {
diff --git a/media/filters/ffmpeg_demuxer.h b/media/filters/ffmpeg_demuxer.h
index 5308980e0..9bad5ff 100644
--- a/media/filters/ffmpeg_demuxer.h
+++ b/media/filters/ffmpeg_demuxer.h
@@ -38,7 +38,7 @@
 #include "media/base/decoder_buffer.h"
 #include "media/base/decoder_buffer_queue.h"
 #include "media/base/demuxer.h"
-#include "media/base/pipeline.h"
+#include "media/base/pipeline_status.h"
 #include "media/base/text_track_config.h"
 #include "media/base/video_decoder_config.h"
 #include "media/ffmpeg/ffmpeg_deleters.h"
diff --git a/media/filters/ffmpeg_demuxer_unittest.cc b/media/filters/ffmpeg_demuxer_unittest.cc
index e22e454..a0611e9 100644
--- a/media/filters/ffmpeg_demuxer_unittest.cc
+++ b/media/filters/ffmpeg_demuxer_unittest.cc
@@ -98,21 +98,34 @@
 
   MOCK_METHOD1(CheckPoint, void(int v));
 
-  void InitializeDemuxerWithTimelineOffset(bool enable_text,
-                                           base::Time timeline_offset) {
-    EXPECT_CALL(host_, SetDuration(_));
+  void InitializeDemuxerInternal(bool enable_text,
+                                 media::PipelineStatus expected_pipeline_status,
+                                 base::Time timeline_offset) {
+    if (expected_pipeline_status == PIPELINE_OK)
+      EXPECT_CALL(host_, SetDuration(_));
     WaitableMessageLoopEvent event;
     demuxer_->Initialize(&host_, event.GetPipelineStatusCB(), enable_text);
     demuxer_->timeline_offset_ = timeline_offset;
-    event.RunAndWaitForStatus(PIPELINE_OK);
-  }
-
-  void InitializeDemuxerText(bool enable_text) {
-    InitializeDemuxerWithTimelineOffset(enable_text, base::Time());
+    event.RunAndWaitForStatus(expected_pipeline_status);
   }
 
   void InitializeDemuxer() {
-    InitializeDemuxerText(false);
+    InitializeDemuxerInternal(/*enable_text=*/false, PIPELINE_OK, base::Time());
+  }
+
+  void InitializeDemuxerWithText() {
+    InitializeDemuxerInternal(/*enable_text=*/true, PIPELINE_OK, base::Time());
+  }
+
+  void InitializeDemuxerWithTimelineOffset(base::Time timeline_offset) {
+    InitializeDemuxerInternal(/*enable_text=*/false, PIPELINE_OK,
+                              timeline_offset);
+  }
+
+  void InitializeDemuxerAndExpectPipelineStatus(
+      media::PipelineStatus expected_pipeline_status) {
+    InitializeDemuxerInternal(/*enable_text=*/false, expected_pipeline_status,
+                              base::Time());
   }
 
   MOCK_METHOD2(OnReadDoneCalled, void(int, int64_t));
@@ -357,7 +370,7 @@
   DemuxerStream* text_stream = NULL;
   EXPECT_CALL(host_, AddTextStream(_, _))
       .WillOnce(SaveArg<0>(&text_stream));
-  InitializeDemuxerText(true);
+  InitializeDemuxerWithText();
   ASSERT_TRUE(text_stream);
   EXPECT_EQ(DemuxerStream::TEXT, text_stream->type());
 
@@ -430,7 +443,7 @@
   DemuxerStream* text_stream = NULL;
   EXPECT_CALL(host_, AddTextStream(_, _))
       .WillOnce(SaveArg<0>(&text_stream));
-  InitializeDemuxerText(true);
+  InitializeDemuxerWithText();
   ASSERT_TRUE(text_stream);
   EXPECT_EQ(DemuxerStream::TEXT, text_stream->type());
 
@@ -453,7 +466,7 @@
   // Test the start time is the first timestamp of the video and audio stream.
   CreateDemuxer("nonzero-start-time.webm");
   InitializeDemuxerWithTimelineOffset(
-      false, base::Time::FromJsTime(kTimelineOffsetMs));
+      base::Time::FromJsTime(kTimelineOffsetMs));
 
   // Attempt a read from the video stream and run the message loop until done.
   DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
@@ -689,7 +702,7 @@
   DemuxerStream* text_stream = NULL;
   EXPECT_CALL(host_, AddTextStream(_, _))
       .WillOnce(SaveArg<0>(&text_stream));
-  InitializeDemuxerText(true);
+  InitializeDemuxerWithText();
   ASSERT_TRUE(text_stream);
   EXPECT_EQ(DemuxerStream::TEXT, text_stream->type());
 
@@ -787,7 +800,7 @@
   DemuxerStream* text_stream = NULL;
   EXPECT_CALL(host_, AddTextStream(_, _))
       .WillOnce(SaveArg<0>(&text_stream));
-  InitializeDemuxerText(true);
+  InitializeDemuxerWithText();
   ASSERT_TRUE(text_stream);
   EXPECT_EQ(DemuxerStream::TEXT, text_stream->type());
 
@@ -1115,11 +1128,9 @@
   EXPECT_EQ(gfx::Size(639, 360), video_config.natural_size());
 }
 
-#endif
-
-#if BUILDFLAG(ENABLE_HEVC_DEMUXING)
 TEST_F(FFmpegDemuxerTest, HEVC_in_MP4_container) {
   CreateDemuxer("bear-hevc-frag.mp4");
+#if BUILDFLAG(ENABLE_HEVC_DEMUXING)
   InitializeDemuxer();
 
   DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
@@ -1130,12 +1141,14 @@
 
   video->Read(NewReadCB(FROM_HERE, 1042, 200200, false));
   message_loop_.Run();
-}
+#else
+  InitializeDemuxerAndExpectPipelineStatus(DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
 #endif
+}
 
-#if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
 TEST_F(FFmpegDemuxerTest, Read_AC3_Audio) {
   CreateDemuxer("bear-ac3-only-frag.mp4");
+#if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
   InitializeDemuxer();
 
   // Attempt a read from the audio stream and run the message loop until done.
@@ -1147,10 +1160,14 @@
 
   audio->Read(NewReadCB(FROM_HERE, 836, 34830, true));
   message_loop_.Run();
+#else
+  InitializeDemuxerAndExpectPipelineStatus(DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
+#endif
 }
 
 TEST_F(FFmpegDemuxerTest, Read_EAC3_Audio) {
   CreateDemuxer("bear-eac3-only-frag.mp4");
+#if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
   InitializeDemuxer();
 
   // Attempt a read from the audio stream and run the message loop until done.
@@ -1162,7 +1179,11 @@
 
   audio->Read(NewReadCB(FROM_HERE, 872, 34830, true));
   message_loop_.Run();
+#else
+  InitializeDemuxerAndExpectPipelineStatus(DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
+#endif
 }
-#endif  // ENABLE_AC3_EAC3_AUDIO_DEMUXING
+
+#endif  // defined(USE_PROPRIETARY_CODECS)
 
 }  // namespace media
diff --git a/media/filters/ffmpeg_video_decoder.cc b/media/filters/ffmpeg_video_decoder.cc
index aeade11..5438126 100644
--- a/media/filters/ffmpeg_video_decoder.cc
+++ b/media/filters/ffmpeg_video_decoder.cc
@@ -20,7 +20,6 @@
 #include "media/base/decoder_buffer.h"
 #include "media/base/limits.h"
 #include "media/base/media_switches.h"
-#include "media/base/pipeline.h"
 #include "media/base/timestamp_constants.h"
 #include "media/base/video_frame.h"
 #include "media/base/video_util.h"
diff --git a/media/filters/frame_processor.cc b/media/filters/frame_processor.cc
index 6f7706df..2850315 100644
--- a/media/filters/frame_processor.cc
+++ b/media/filters/frame_processor.cc
@@ -197,7 +197,6 @@
     const StreamParser::TextBufferQueueMap& text_map,
     base::TimeDelta append_window_start,
     base::TimeDelta append_window_end,
-    bool* new_media_segment,
     base::TimeDelta* timestamp_offset) {
   StreamParser::BufferQueue frames;
   if (!MergeBufferQueues(audio_buffers, video_buffers, text_map, &frames)) {
@@ -217,7 +216,7 @@
   for (StreamParser::BufferQueue::const_iterator frames_itr = frames.begin();
        frames_itr != frames.end(); ++frames_itr) {
     if (!ProcessFrame(*frames_itr, append_window_start, append_window_end,
-                      timestamp_offset, new_media_segment)) {
+                      timestamp_offset)) {
       FlushProcessedFrames();
       return false;
     }
@@ -291,10 +290,16 @@
     itr->second->Reset();
   }
 
-  if (sequence_mode_) {
-    DCHECK(kNoTimestamp() != group_end_timestamp_);
-    group_start_timestamp_ = group_end_timestamp_;
+  // Maintain current |in_coded_frame_group_| state for Reset() during
+  // sequence mode. Reset it here only if in segments mode.
+  if (!sequence_mode_) {
+    in_coded_frame_group_ = false;
+    return;
   }
+
+  // Sequence mode
+  DCHECK(kNoTimestamp() != group_end_timestamp_);
+  group_start_timestamp_ = group_end_timestamp_;
 }
 
 void FrameProcessor::OnPossibleAudioConfigUpdate(
@@ -320,14 +325,14 @@
   return itr->second;
 }
 
-void FrameProcessor::NotifyNewMediaSegmentStarting(
-    DecodeTimestamp segment_timestamp) {
-  DVLOG(2) << __FUNCTION__ << "(" << segment_timestamp.InSecondsF() << ")";
+void FrameProcessor::NotifyStartOfCodedFrameGroup(
+    DecodeTimestamp start_timestamp) {
+  DVLOG(2) << __FUNCTION__ << "(" << start_timestamp.InSecondsF() << ")";
 
   for (TrackBufferMap::iterator itr = track_buffers_.begin();
        itr != track_buffers_.end();
        ++itr) {
-    itr->second->stream()->OnNewMediaSegment(segment_timestamp);
+    itr->second->stream()->OnStartOfCodedFrameGroup(start_timestamp);
   }
 }
 
@@ -448,8 +453,7 @@
     const scoped_refptr<StreamParserBuffer>& frame,
     base::TimeDelta append_window_start,
     base::TimeDelta append_window_end,
-    base::TimeDelta* timestamp_offset,
-    bool* new_media_segment) {
+    base::TimeDelta* timestamp_offset) {
   // Implements the loop within step 1 of the coded frame processing algorithm
   // for a single input frame per April 1, 2014 MSE spec editor's draft:
   // https://dvcs.w3.org/hg/html-media/raw-file/d471a4412040/media-source/
@@ -587,12 +591,14 @@
     //    If last decode timestamp for track buffer is set and the difference
     //    between decode timestamp and last decode timestamp is greater than 2
     //    times last frame duration:
-    DecodeTimestamp last_decode_timestamp =
+    DecodeTimestamp track_last_decode_timestamp =
         track_buffer->last_decode_timestamp();
-    if (last_decode_timestamp != kNoDecodeTimestamp()) {
-      base::TimeDelta dts_delta = decode_timestamp - last_decode_timestamp;
-      if (dts_delta < base::TimeDelta() ||
-          dts_delta > 2 * track_buffer->last_frame_duration()) {
+    if (track_last_decode_timestamp != kNoDecodeTimestamp()) {
+      base::TimeDelta track_dts_delta =
+          decode_timestamp - track_last_decode_timestamp;
+      if (track_dts_delta < base::TimeDelta() ||
+          track_dts_delta > 2 * track_buffer->last_frame_duration()) {
+        DCHECK(in_coded_frame_group_);
         // 7.1. If mode equals "segments": Set group end timestamp to
         //      presentation timestamp.
         //      If mode equals "sequence": Set group start timestamp equal to
@@ -601,8 +607,8 @@
           group_end_timestamp_ = presentation_timestamp;
           // This triggers a discontinuity so we need to treat the next frames
           // appended within the append window as if they were the beginning of
-          // a new segment.
-          *new_media_segment = true;
+          // a new coded frame group.
+          in_coded_frame_group_ = false;
         } else {
           DVLOG(3) << __FUNCTION__ << " : Sequence mode discontinuity, GETS: "
                    << group_end_timestamp_.InSecondsF();
@@ -692,19 +698,19 @@
     }
 
     // We now have a processed buffer to append to the track buffer's stream.
-    // If it is the first in a new media segment or following a discontinuity,
-    // notify all the track buffers' streams that a new segment is beginning.
-    if (*new_media_segment) {
-      // First, complete the append to track buffer streams of previous media
-      // segment's frames, if any.
+    // If it is the first in a new coded frame group (such as following a
+    // discontinuity), notify all the track buffers' streams that a coded frame
+    // group is starting.
+    if (!in_coded_frame_group_) {
+      // First, complete the append to track buffer streams of the previous
+      // coded frame group's frames, if any.
       if (!FlushProcessedFrames())
         return false;
 
-      *new_media_segment = false;
-
       // TODO(acolwell/wolenetz): This should be changed to a presentation
       // timestamp. See http://crbug.com/402502
-      NotifyNewMediaSegmentStarting(decode_timestamp);
+      NotifyStartOfCodedFrameGroup(decode_timestamp);
+      in_coded_frame_group_ = true;
     }
 
     DVLOG(3) << __FUNCTION__ << ": Sending processed frame to stream, "
@@ -713,9 +719,7 @@
 
     // Steps 13-18: Note, we optimize by appending groups of contiguous
     // processed frames for each track buffer at end of ProcessFrames() or prior
-    // to NotifyNewMediaSegmentStarting().
-    // TODO(wolenetz): Refactor SourceBufferStream to conform to spec GC timing.
-    // See http://crbug.com/371197.
+    // to NotifyStartOfCodedFrameGroup().
     track_buffer->EnqueueProcessedFrame(frame);
 
     // 19. Set last decode timestamp for track buffer to decode timestamp.
diff --git a/media/filters/frame_processor.h b/media/filters/frame_processor.h
index 68148f4f..0a1ecc6 100644
--- a/media/filters/frame_processor.h
+++ b/media/filters/frame_processor.h
@@ -49,9 +49,6 @@
   // |append_window_start| and |append_window_end| correspond to the MSE spec's
   // similarly named source buffer attributes that are used in coded frame
   // processing.
-  // |*new_media_segment| tracks whether the next buffers processed within the
-  // append window represent the start of a new media segment. This method may
-  // both use and update this flag.
   // Uses |*timestamp_offset| according to the coded frame processing algorithm,
   // including updating it as required in 'sequence' mode frame processing.
   bool ProcessFrames(const StreamParser::BufferQueue& audio_buffers,
@@ -59,7 +56,6 @@
                      const StreamParser::TextBufferQueueMap& text_map,
                      base::TimeDelta append_window_start,
                      base::TimeDelta append_window_end,
-                     bool* new_media_segment,
                      base::TimeDelta* timestamp_offset);
 
   // Signals the frame processor to update its group start timestamp to be
@@ -93,15 +89,17 @@
   void OnPossibleAudioConfigUpdate(const AudioDecoderConfig& config);
 
  private:
+  friend class FrameProcessorTest;
+
   typedef std::map<StreamParser::TrackId, MseTrackBuffer*> TrackBufferMap;
 
   // If |track_buffers_| contains |id|, returns a pointer to the associated
   // MseTrackBuffer. Otherwise, returns NULL.
   MseTrackBuffer* FindTrack(StreamParser::TrackId id);
 
-  // Signals all track buffers' streams that a new media segment is starting
-  // with decode timestamp |segment_timestamp|.
-  void NotifyNewMediaSegmentStarting(DecodeTimestamp segment_timestamp);
+  // Signals all track buffers' streams that a coded frame group is starting
+  // with decode timestamp |start_timestamp|.
+  void NotifyStartOfCodedFrameGroup(DecodeTimestamp start_timestamp);
 
   // Helper that signals each track buffer to append any processed, but not yet
   // appended, frames to its stream. Returns true on success, or false if one or
@@ -134,8 +132,7 @@
   bool ProcessFrame(const scoped_refptr<StreamParserBuffer>& frame,
                     base::TimeDelta append_window_start,
                     base::TimeDelta append_window_end,
-                    base::TimeDelta* timestamp_offset,
-                    bool* new_media_segment);
+                    base::TimeDelta* timestamp_offset);
 
   // TrackId-indexed map of each track's stream.
   TrackBufferMap track_buffers_;
@@ -155,6 +152,12 @@
   // set to false ("segments").
   bool sequence_mode_ = false;
 
+  // Flag to track whether or not the next processed frame is a continuation of
+  // a coded frame group. This flag resets to false upon detection of
+  // discontinuity, and becomes true once a processed coded frame for the
+  // current coded frame group is sent to its track buffer.
+  bool in_coded_frame_group_ = false;
+
   // Tracks the MSE coded frame processing variable of same name.
   // Initially kNoTimestamp(), meaning "unset".
   base::TimeDelta group_start_timestamp_;
diff --git a/media/filters/frame_processor_unittest.cc b/media/filters/frame_processor_unittest.cc
index b7fc48d..289ca8e8 100644
--- a/media/filters/frame_processor_unittest.cc
+++ b/media/filters/frame_processor_unittest.cc
@@ -67,7 +67,6 @@
                 base::Unretained(&callbacks_)),
             new MediaLog())),
         append_window_end_(kInfiniteDuration()),
-        new_media_segment_(false),
         audio_id_(FrameProcessor::kAudioTrackId),
         video_id_(FrameProcessor::kVideoTrackId),
         frame_duration_(base::TimeDelta::FromMilliseconds(10)) {}
@@ -157,9 +156,8 @@
     ASSERT_TRUE(frame_processor_->ProcessFrames(
         StringToBufferQueue(audio_timestamps, audio_id_, DemuxerStream::AUDIO),
         StringToBufferQueue(video_timestamps, video_id_, DemuxerStream::VIDEO),
-        empty_text_buffers_,
-        append_window_start_, append_window_end_,
-        &new_media_segment_, &timestamp_offset_));
+        empty_text_buffers_, append_window_start_, append_window_end_,
+        &timestamp_offset_));
   }
 
   void CheckExpectedRangesByTimestamp(ChunkDemuxerStream* stream,
@@ -246,13 +244,19 @@
     CheckReadStalls(stream);
   }
 
+  // TODO(wolenetz): Refactor to instead verify the expected signalling or lack
+  // thereof of new coded frame group by the FrameProcessor. See
+  // https://crbug.com/580613.
+  bool in_coded_frame_group() {
+    return frame_processor_->in_coded_frame_group_;
+  }
+
   base::MessageLoop message_loop_;
   StrictMock<FrameProcessorTestCallbackHelper> callbacks_;
 
   scoped_ptr<FrameProcessor> frame_processor_;
   base::TimeDelta append_window_start_;
   base::TimeDelta append_window_end_;
-  bool new_media_segment_;
   base::TimeDelta timestamp_offset_;
   scoped_ptr<ChunkDemuxerStream> audio_;
   scoped_ptr<ChunkDemuxerStream> video_;
@@ -316,15 +320,13 @@
 
 TEST_F(FrameProcessorTest, WrongTypeInAppendedBuffer) {
   AddTestTracks(HAS_AUDIO);
-  new_media_segment_ = true;
+  EXPECT_FALSE(in_coded_frame_group());
 
   ASSERT_FALSE(frame_processor_->ProcessFrames(
-      StringToBufferQueue("0K", audio_id_, DemuxerStream::VIDEO),
-      empty_queue_,
-      empty_text_buffers_,
-      append_window_start_, append_window_end_,
-      &new_media_segment_, &timestamp_offset_));
-  EXPECT_TRUE(new_media_segment_);
+      StringToBufferQueue("0K", audio_id_, DemuxerStream::VIDEO), empty_queue_,
+      empty_text_buffers_, append_window_start_, append_window_end_,
+      &timestamp_offset_));
+  EXPECT_FALSE(in_coded_frame_group());
   EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
   CheckExpectedRangesByTimestamp(audio_.get(), "{ }");
   CheckReadStalls(audio_.get());
@@ -332,15 +334,12 @@
 
 TEST_F(FrameProcessorTest, NonMonotonicallyIncreasingTimestampInOneCall) {
   AddTestTracks(HAS_AUDIO);
-  new_media_segment_ = true;
 
   ASSERT_FALSE(frame_processor_->ProcessFrames(
       StringToBufferQueue("10K 0K", audio_id_, DemuxerStream::AUDIO),
-      empty_queue_,
-      empty_text_buffers_,
-      append_window_start_, append_window_end_,
-      &new_media_segment_, &timestamp_offset_));
-  EXPECT_TRUE(new_media_segment_);
+      empty_queue_, empty_text_buffers_, append_window_start_,
+      append_window_end_, &timestamp_offset_));
+  EXPECT_FALSE(in_coded_frame_group());
   EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
   CheckExpectedRangesByTimestamp(audio_.get(), "{ }");
   CheckReadStalls(audio_.get());
@@ -350,13 +349,12 @@
   // Tests A: P(A) -> (a)
   InSequence s;
   AddTestTracks(HAS_AUDIO);
-  new_media_segment_ = true;
   if (GetParam())
     frame_processor_->SetSequenceMode(true);
 
   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_));
   ProcessFrames("0K", "");
-  EXPECT_FALSE(new_media_segment_);
+  EXPECT_TRUE(in_coded_frame_group());
   EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
   CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,10) }");
   CheckReadsThenReadStalls(audio_.get(), "0");
@@ -366,13 +364,12 @@
   // Tests V: P(V) -> (v)
   InSequence s;
   AddTestTracks(HAS_VIDEO);
-  new_media_segment_ = true;
   if (GetParam())
     frame_processor_->SetSequenceMode(true);
 
   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_));
   ProcessFrames("", "0K");
-  EXPECT_FALSE(new_media_segment_);
+  EXPECT_TRUE(in_coded_frame_group());
   EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
   CheckExpectedRangesByTimestamp(video_.get(), "{ [0,10) }");
   CheckReadsThenReadStalls(video_.get(), "0");
@@ -382,13 +379,12 @@
   // Tests A: P(A0, A10) -> (a0, a10)
   InSequence s;
   AddTestTracks(HAS_AUDIO);
-  new_media_segment_ = true;
   if (GetParam())
     frame_processor_->SetSequenceMode(true);
 
   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_ * 2));
   ProcessFrames("0K 10K", "");
-  EXPECT_FALSE(new_media_segment_);
+  EXPECT_TRUE(in_coded_frame_group());
   EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
   CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
   CheckReadsThenReadStalls(audio_.get(), "0 10");
@@ -398,7 +394,6 @@
   // Tests A: STSO(50)+P(A0) -> TSO==50,(a0@50)
   InSequence s;
   AddTestTracks(HAS_AUDIO);
-  new_media_segment_ = true;
   if (GetParam())
     frame_processor_->SetSequenceMode(true);
 
@@ -406,7 +401,7 @@
   SetTimestampOffset(fifty_ms);
   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_ + fifty_ms));
   ProcessFrames("0K", "");
-  EXPECT_FALSE(new_media_segment_);
+  EXPECT_TRUE(in_coded_frame_group());
   EXPECT_EQ(fifty_ms, timestamp_offset_);
   CheckExpectedRangesByTimestamp(audio_.get(), "{ [50,60) }");
 
@@ -421,7 +416,6 @@
   //   if segments mode: TSO==50,(a20@70)
   InSequence s;
   AddTestTracks(HAS_AUDIO);
-  new_media_segment_ = true;
   bool using_sequence_mode = GetParam();
   if (using_sequence_mode)
     frame_processor_->SetSequenceMode(true);
@@ -439,7 +433,7 @@
   }
 
   ProcessFrames("20K", "");
-  EXPECT_FALSE(new_media_segment_);
+  EXPECT_TRUE(in_coded_frame_group());
 
   // We do not stall on reading without seeking to 50ms / 70ms due to
   // SourceBufferStream::kSeekToStartFudgeRoom().
@@ -458,19 +452,18 @@
   // Tests A: P(A0,A10)+P(A20,A30) -> (a0,a10,a20,a30)
   InSequence s;
   AddTestTracks(HAS_AUDIO);
-  new_media_segment_ = true;
   if (GetParam())
     frame_processor_->SetSequenceMode(true);
 
   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_ * 2));
   ProcessFrames("0K 10K", "");
-  EXPECT_FALSE(new_media_segment_);
+  EXPECT_TRUE(in_coded_frame_group());
   EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
   CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
 
   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_ * 4));
   ProcessFrames("20K 30K", "");
-  EXPECT_FALSE(new_media_segment_);
+  EXPECT_TRUE(in_coded_frame_group());
   EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
   CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,40) }");
 
@@ -484,7 +477,6 @@
   //   if segments mode: TSO==0,(a0,a10,a20,a30)
   InSequence s;
   AddTestTracks(HAS_AUDIO);
-  new_media_segment_ = true;
   bool using_sequence_mode = GetParam();
   if (using_sequence_mode) {
     frame_processor_->SetSequenceMode(true);
@@ -494,7 +486,7 @@
   }
 
   ProcessFrames("20K 30K", "");
-  EXPECT_FALSE(new_media_segment_);
+  EXPECT_TRUE(in_coded_frame_group());
 
   if (using_sequence_mode) {
     CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
@@ -507,7 +499,7 @@
   }
 
   ProcessFrames("0K 10K", "");
-  EXPECT_FALSE(new_media_segment_);
+  EXPECT_TRUE(in_coded_frame_group());
 
   if (using_sequence_mode) {
     CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,40) }");
@@ -531,20 +523,19 @@
   //   (a0,a10,a20,a30,a40);(v0,v10,v20,v30)
   InSequence s;
   AddTestTracks(HAS_AUDIO | HAS_VIDEO);
-  new_media_segment_ = true;
   if (GetParam())
     frame_processor_->SetSequenceMode(true);
 
   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_ * 3));
   ProcessFrames("0K 10K", "0K 10 20");
-  EXPECT_FALSE(new_media_segment_);
+  EXPECT_TRUE(in_coded_frame_group());
   EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
   CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
   CheckExpectedRangesByTimestamp(video_.get(), "{ [0,30) }");
 
   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_ * 5));
   ProcessFrames("20K 30K 40K", "30");
-  EXPECT_FALSE(new_media_segment_);
+  EXPECT_TRUE(in_coded_frame_group());
   EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
   CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,50) }");
   CheckExpectedRangesByTimestamp(video_.get(), "{ [0,40) }");
@@ -561,7 +552,6 @@
   // MergeBufferQueues() behavior.
   InSequence s;
   AddTestTracks(HAS_AUDIO | HAS_VIDEO);
-  new_media_segment_ = true;
   bool using_sequence_mode = GetParam();
   if (using_sequence_mode) {
     frame_processor_->SetSequenceMode(true);
@@ -571,7 +561,7 @@
   }
 
   ProcessFrames("0K 10K 30K 40K 50K", "0K 10 40 50K");
-  EXPECT_FALSE(new_media_segment_);
+  EXPECT_TRUE(in_coded_frame_group());
 
   if (using_sequence_mode) {
     EXPECT_EQ(frame_duration_, timestamp_offset_);
@@ -596,14 +586,13 @@
        AppendWindowFilterOfNegativeBufferTimestampsWithPrerollDiscard) {
   InSequence s;
   AddTestTracks(HAS_AUDIO);
-  new_media_segment_ = true;
   if (GetParam())
     frame_processor_->SetSequenceMode(true);
 
   SetTimestampOffset(frame_duration_ * -2);
   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_));
   ProcessFrames("0K 10K 20K", "");
-  EXPECT_FALSE(new_media_segment_);
+  EXPECT_TRUE(in_coded_frame_group());
   EXPECT_EQ(frame_duration_ * -2, timestamp_offset_);
   CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,10) }");
   CheckReadsThenReadStalls(audio_.get(), "0:10P 0:20");
@@ -612,7 +601,6 @@
 TEST_P(FrameProcessorTest, AppendWindowFilterWithInexactPreroll) {
   InSequence s;
   AddTestTracks(HAS_AUDIO);
-  new_media_segment_ = true;
   if (GetParam())
     frame_processor_->SetSequenceMode(true);
   SetTimestampOffset(-frame_duration_);
@@ -625,7 +613,6 @@
 TEST_P(FrameProcessorTest, AppendWindowFilterWithInexactPreroll_2) {
   InSequence s;
   AddTestTracks(HAS_AUDIO);
-  new_media_segment_ = true;
   if (GetParam())
     frame_processor_->SetSequenceMode(true);
   SetTimestampOffset(-frame_duration_);
@@ -638,7 +625,6 @@
 TEST_P(FrameProcessorTest, AllowNegativeFramePTSAndDTSBeforeOffsetAdjustment) {
   InSequence s;
   AddTestTracks(HAS_AUDIO);
-  new_media_segment_ = true;
   bool using_sequence_mode = GetParam();
   if (using_sequence_mode) {
     frame_processor_->SetSequenceMode(true);
@@ -666,7 +652,6 @@
   // trimmed frame.
   InSequence s;
   AddTestTracks(HAS_AUDIO);
-  new_media_segment_ = true;
   if (GetParam())
     frame_processor_->SetSequenceMode(true);
   EXPECT_CALL(callbacks_,
@@ -686,7 +671,6 @@
   // frame that originally had DTS > PTS.
   InSequence s;
   AddTestTracks(HAS_AUDIO);
-  new_media_segment_ = true;
   bool using_sequence_mode = GetParam();
   if (using_sequence_mode) {
     frame_processor_->SetSequenceMode(true);
@@ -725,7 +709,6 @@
   // discontinuity.
   InSequence s;
   AddTestTracks(HAS_AUDIO | HAS_VIDEO);
-  new_media_segment_ = true;
   frame_processor_->SetSequenceMode(GetParam());
   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_));
   ProcessFrames("", "0K");
@@ -735,7 +718,7 @@
   ProcessFrames("", "10");
 
   EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
-  EXPECT_FALSE(new_media_segment_);
+  EXPECT_TRUE(in_coded_frame_group());
   CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,5) }");
   CheckExpectedRangesByTimestamp(video_.get(), "{ [0,20) }");
   CheckReadsThenReadStalls(audio_.get(), "0:-5");
@@ -745,7 +728,6 @@
 TEST_F(FrameProcessorTest, AudioOnly_SequenceModeContinuityAcrossReset) {
   InSequence s;
   AddTestTracks(HAS_AUDIO);
-  new_media_segment_ = true;
   frame_processor_->SetSequenceMode(true);
   EXPECT_CALL(callbacks_, PossibleDurationIncrease(frame_duration_));
   ProcessFrames("0K", "");
@@ -754,7 +736,7 @@
   ProcessFrames("100K", "");
 
   EXPECT_EQ(frame_duration_ * -9, timestamp_offset_);
-  EXPECT_FALSE(new_media_segment_);
+  EXPECT_TRUE(in_coded_frame_group());
   CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,20) }");
   CheckReadsThenReadStalls(audio_.get(), "0 10:100");
 }
diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc
index 55e8f21..6801aaf 100644
--- a/media/filters/gpu_video_decoder.cc
+++ b/media/filters/gpu_video_decoder.cc
@@ -21,7 +21,7 @@
 #include "media/base/cdm_context.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/media_switches.h"
-#include "media/base/pipeline.h"
+#include "media/base/pipeline_status.h"
 #include "media/base/surface_manager.h"
 #include "media/base/video_decoder_config.h"
 #include "media/renderers/gpu_video_accelerator_factories.h"
diff --git a/media/filters/media_source_state.cc b/media/filters/media_source_state.cc
index 9ca39aa6..ede9605 100644
--- a/media/filters/media_source_state.cc
+++ b/media/filters/media_source_state.cc
@@ -90,7 +90,6 @@
     const scoped_refptr<MediaLog>& media_log)
     : create_demuxer_stream_cb_(create_demuxer_stream_cb),
       timestamp_offset_during_append_(NULL),
-      new_media_segment_(false),
       parsing_media_segment_(false),
       media_segment_contained_audio_frame_(false),
       media_segment_contained_video_frame_(false),
@@ -647,7 +646,6 @@
 void MediaSourceState::OnNewMediaSegment() {
   DVLOG(2) << "OnNewMediaSegment()";
   parsing_media_segment_ = true;
-  new_media_segment_ = true;
   media_segment_contained_audio_frame_ = false;
   media_segment_contained_video_frame_ = false;
 }
@@ -655,7 +653,6 @@
 void MediaSourceState::OnEndOfMediaSegment() {
   DVLOG(2) << "OnEndOfMediaSegment()";
   parsing_media_segment_ = false;
-  new_media_segment_ = false;
 
   const bool missing_audio = audio_ && !media_segment_contained_audio_frame_;
   const bool missing_video = video_ && !media_segment_contained_video_frame_;
@@ -702,10 +699,10 @@
     }
   }
 
-  if (!frame_processor_->ProcessFrames(
-          audio_buffers, video_buffers, text_map,
-          append_window_start_during_append_, append_window_end_during_append_,
-          &new_media_segment_, timestamp_offset_during_append_)) {
+  if (!frame_processor_->ProcessFrames(audio_buffers, video_buffers, text_map,
+                                       append_window_start_during_append_,
+                                       append_window_end_during_append_,
+                                       timestamp_offset_during_append_)) {
     return false;
   }
 
diff --git a/media/filters/media_source_state.h b/media/filters/media_source_state.h
index 8d41b1e..1a8e42a 100644
--- a/media/filters/media_source_state.h
+++ b/media/filters/media_source_state.h
@@ -171,16 +171,6 @@
   TimeDelta append_window_start_during_append_;
   TimeDelta append_window_end_during_append_;
 
-  // Set to true if the next buffers appended within the append window
-  // represent the start of a new media segment. This flag being set
-  // triggers a call to |new_segment_cb_| when the new buffers are
-  // appended. The flag is set on actual media segment boundaries and
-  // when the "append window" filtering causes discontinuities in the
-  // appended data.
-  // TODO(wolenetz/acolwell): Investigate if we need this, or if coded frame
-  // processing's discontinuity logic is enough. See http://crbug.com/351489.
-  bool new_media_segment_;
-
   // Keeps track of whether a media segment is being parsed.
   bool parsing_media_segment_;
 
diff --git a/media/filters/source_buffer_range.cc b/media/filters/source_buffer_range.cc
index 6e664f97..ba6b66c 100644
--- a/media/filters/source_buffer_range.cc
+++ b/media/filters/source_buffer_range.cc
@@ -22,34 +22,38 @@
   return buffer->GetDecodeTimestamp() < decode_timestamp;
 }
 
-bool SourceBufferRange::AllowSameTimestamp(
-    bool prev_is_keyframe, bool current_is_keyframe) {
-  return prev_is_keyframe || !current_is_keyframe;
+bool SourceBufferRange::IsUncommonSameTimestampSequence(
+    bool prev_is_keyframe,
+    bool current_is_keyframe) {
+  return current_is_keyframe && !prev_is_keyframe;
 }
 
 SourceBufferRange::SourceBufferRange(
-    GapPolicy gap_policy, const BufferQueue& new_buffers,
-    DecodeTimestamp media_segment_start_time,
+    GapPolicy gap_policy,
+    const BufferQueue& new_buffers,
+    DecodeTimestamp range_start_time,
     const InterbufferDistanceCB& interbuffer_distance_cb)
     : gap_policy_(gap_policy),
       keyframe_map_index_base_(0),
       next_buffer_index_(-1),
-      media_segment_start_time_(media_segment_start_time),
+      range_start_time_(range_start_time),
       interbuffer_distance_cb_(interbuffer_distance_cb),
       size_in_bytes_(0) {
   CHECK(!new_buffers.empty());
   DCHECK(new_buffers.front()->is_key_frame());
   DCHECK(!interbuffer_distance_cb.is_null());
-  AppendBuffersToEnd(new_buffers);
+  AppendBuffersToEnd(new_buffers, range_start_time_);
 }
 
 SourceBufferRange::~SourceBufferRange() {}
 
-void SourceBufferRange::AppendBuffersToEnd(const BufferQueue& new_buffers) {
-  DCHECK(buffers_.empty() || CanAppendBuffersToEnd(new_buffers));
-  DCHECK(media_segment_start_time_ == kNoDecodeTimestamp() ||
-         media_segment_start_time_ <=
-             new_buffers.front()->GetDecodeTimestamp());
+void SourceBufferRange::AppendBuffersToEnd(
+    const BufferQueue& new_buffers,
+    DecodeTimestamp new_buffers_group_start_timestamp) {
+  CHECK(buffers_.empty() ||
+        CanAppendBuffersToEnd(new_buffers, new_buffers_group_start_timestamp));
+  DCHECK(range_start_time_ == kNoDecodeTimestamp() ||
+         range_start_time_ <= new_buffers.front()->GetDecodeTimestamp());
 
   AdjustEstimatedDurationForNewAppend(new_buffers);
 
@@ -154,10 +158,9 @@
   DecodeTimestamp new_range_start_timestamp = kNoDecodeTimestamp();
   if (GetStartTimestamp() < buffers_.front()->GetDecodeTimestamp() &&
       timestamp < removed_buffers.front()->GetDecodeTimestamp()) {
-    // The split is in the gap between |media_segment_start_time_| and
-    // the first buffer of the new range so we should set the start
-    // time of the new range to |timestamp| so we preserve part of the
-    // gap in the new range.
+    // The split is in the gap between |range_start_time_| and the first buffer
+    // of the new range so we should set the start time of the new range to
+    // |timestamp| so we preserve part of the gap in the new range.
     new_range_start_timestamp = timestamp;
   }
 
@@ -174,8 +177,14 @@
   // this range and |split_range| accordingly.
   if (next_buffer_index_ >= static_cast<int>(buffers_.size())) {
     split_range->next_buffer_index_ = next_buffer_index_ - keyframe_index;
-    CHECK_GE(split_range->next_buffer_index_, 0)
-        << split_range->next_buffer_index_;
+
+    int split_range_next_buffer_index = split_range->next_buffer_index_;
+    CHECK_GE(split_range_next_buffer_index, 0);
+    // Note that a SourceBufferRange's |next_buffer_index_| can be the index
+    // of a buffer one beyond what is currently in |buffers_|.
+    CHECK_LE(split_range_next_buffer_index,
+             static_cast<int>(split_range->buffers_.size()));
+
     ResetNextBufferPosition();
   }
 
@@ -271,10 +280,9 @@
                                     << buffers_deleted;
   }
 
-  // Invalidate media segment start time if we've deleted the first buffer of
-  // the range.
+  // Invalidate range start time if we've deleted the first buffer of the range.
   if (buffers_deleted > 0)
-    media_segment_start_time_ = kNoDecodeTimestamp();
+    range_start_time_ = kNoDecodeTimestamp();
 
   return total_bytes_deleted;
 }
@@ -483,25 +491,31 @@
   if (transfer_current_position && range.next_buffer_index_ >= 0)
     next_buffer_index_ = range.next_buffer_index_ + buffers_.size();
 
-  AppendBuffersToEnd(range.buffers_);
+  AppendBuffersToEnd(range.buffers_, kNoDecodeTimestamp());
 }
 
 bool SourceBufferRange::CanAppendRangeToEnd(
     const SourceBufferRange& range) const {
-  return CanAppendBuffersToEnd(range.buffers_);
+  return CanAppendBuffersToEnd(range.buffers_, kNoDecodeTimestamp());
 }
 
 bool SourceBufferRange::CanAppendBuffersToEnd(
-    const BufferQueue& buffers) const {
+    const BufferQueue& buffers,
+    DecodeTimestamp new_buffers_group_start_timestamp) const {
   DCHECK(!buffers_.empty());
-  return IsNextInSequence(buffers.front()->GetDecodeTimestamp(),
-                          buffers.front()->is_key_frame());
+  if (new_buffers_group_start_timestamp == kNoDecodeTimestamp()) {
+    return IsNextInSequence(buffers.front()->GetDecodeTimestamp());
+  }
+  DCHECK(new_buffers_group_start_timestamp >= GetEndTimestamp());
+  DCHECK(buffers.front()->GetDecodeTimestamp() >=
+         new_buffers_group_start_timestamp);
+  return IsNextInSequence(new_buffers_group_start_timestamp);
 }
 
 bool SourceBufferRange::BelongsToRange(DecodeTimestamp timestamp) const {
   DCHECK(!buffers_.empty());
 
-  return (IsNextInSequence(timestamp, false) ||
+  return (IsNextInSequence(timestamp) ||
           (GetStartTimestamp() <= timestamp && timestamp <= GetEndTimestamp()));
 }
 
@@ -525,7 +539,7 @@
 
 DecodeTimestamp SourceBufferRange::GetStartTimestamp() const {
   DCHECK(!buffers_.empty());
-  DecodeTimestamp start_timestamp = media_segment_start_time_;
+  DecodeTimestamp start_timestamp = range_start_time_;
   if (start_timestamp == kNoDecodeTimestamp())
     start_timestamp = buffers_.front()->GetDecodeTimestamp();
   return start_timestamp;
@@ -555,11 +569,10 @@
   if (itr == keyframe_map_.end())
     return kNoDecodeTimestamp();
 
-  // If the timestamp is inside the gap between the start of the media
-  // segment and the first buffer, then just pretend there is a
-  // keyframe at the specified timestamp.
-  if (itr == keyframe_map_.begin() &&
-      timestamp > media_segment_start_time_ &&
+  // If the timestamp is inside the gap between the start of the coded frame
+  // group and the first buffer, then just pretend there is a keyframe at the
+  // specified timestamp.
+  if (itr == keyframe_map_.begin() && timestamp > range_start_time_ &&
       timestamp < itr->first) {
     return timestamp;
   }
@@ -577,17 +590,11 @@
   return GetFirstKeyframeAtOrBefore(timestamp)->first;
 }
 
-bool SourceBufferRange::IsNextInSequence(
-    DecodeTimestamp timestamp, bool is_key_frame) const {
+bool SourceBufferRange::IsNextInSequence(DecodeTimestamp timestamp) const {
   DecodeTimestamp end = buffers_.back()->GetDecodeTimestamp();
-  if (end < timestamp &&
-      (gap_policy_ == ALLOW_GAPS ||
-       timestamp <= end + GetFudgeRoom())) {
-    return true;
-  }
-
-  return timestamp == end && AllowSameTimestamp(
-      buffers_.back()->is_key_frame(), is_key_frame);
+  return (end == timestamp ||
+          (end < timestamp &&
+           (gap_policy_ == ALLOW_GAPS || timestamp <= end + GetFudgeRoom())));
 }
 
 base::TimeDelta SourceBufferRange::GetFudgeRoom() const {
diff --git a/media/filters/source_buffer_range.h b/media/filters/source_buffer_range.h
index f387ad83..7e35dbd 100644
--- a/media/filters/source_buffer_range.h
+++ b/media/filters/source_buffer_range.h
@@ -37,40 +37,59 @@
     ALLOW_GAPS
   };
 
-  // Buffers with the same timestamp are only allowed under certain conditions.
-  // More precisely, it is allowed in all situations except when the previous
-  // frame is not a key frame and the current is a key frame.
-  // Examples of situations where DTS of two consecutive frames can be equal:
+  // Sequential buffers with the same decode timestamp make sense under certain
+  // conditions, typically when the first buffer is a keyframe. Due to some
+  // atypical media append behaviors where a new keyframe might have the same
+  // timestamp as a previous non-keyframe, the playback of the sequence might
+  // involve some throwaway decode work. This method supports detecting this
+  // situation so that callers can log warnings (it returns true in this case
+  // only).
+  // For all other cases, including more typical same-DTS sequences, this method
+  // returns false. Examples of typical situations where DTS of two consecutive
+  // frames can be equal:
   // - Video: VP8 Alt-Ref frames.
   // - Video: IPBPBP...: DTS for I frame and for P frame can be equal.
   // - Text track cues that start at same time.
   // Returns true if |prev_is_keyframe| and |current_is_keyframe| indicate a
-  // same timestamp situation that is allowed. False is returned otherwise.
-  static bool AllowSameTimestamp(bool prev_is_keyframe,
-                                 bool current_is_keyframe);
+  // same timestamp situation that is atypical. False is returned otherwise.
+  static bool IsUncommonSameTimestampSequence(bool prev_is_keyframe,
+                                              bool current_is_keyframe);
 
   // Creates a source buffer range with |new_buffers|. |new_buffers| cannot be
   // empty and the front of |new_buffers| must be a keyframe.
-  // |media_segment_start_time| refers to the starting timestamp for the media
-  // segment to which these buffers belong.
+  // |range_start_time| refers to the starting timestamp for the coded frame
+  // group to which these buffers belong.
   SourceBufferRange(GapPolicy gap_policy,
                     const BufferQueue& new_buffers,
-                    DecodeTimestamp media_segment_start_time,
+                    DecodeTimestamp range_start_time,
                     const InterbufferDistanceCB& interbuffer_distance_cb);
 
   ~SourceBufferRange();
 
   // Appends |buffers| to the end of the range and updates |keyframe_map_| as
-  // it encounters new keyframes. Assumes |buffers| belongs at the end of the
-  // range.
-  void AppendBuffersToEnd(const BufferQueue& buffers);
-  bool CanAppendBuffersToEnd(const BufferQueue& buffers) const;
+  // it encounters new keyframes.
+  // If |new_buffers_group_start_timestamp| is kNoDecodeTimestamp(), then the
+  // first buffer in |buffers| must come directly after the last buffer in this
+  // range (within the fudge room).
+  // If |new_buffers_group_start_timestamp| is set otherwise, then that time
+  // must come directly after the last buffer in this range (within the fudge
+  // room). The latter scenario is required when a muxed coded frame group has
+  // such a large jagged start across tracks that its first buffer is not within
+  // the fudge room, yet its group start was.
+  void AppendBuffersToEnd(const BufferQueue& buffers,
+                          DecodeTimestamp new_buffers_group_start_timestamp);
+  bool CanAppendBuffersToEnd(
+      const BufferQueue& buffers,
+      DecodeTimestamp new_buffers_group_start_timestamp) const;
 
   // Appends the buffers from |range| into this range.
   // The first buffer in |range| must come directly after the last buffer
   // in this range.
   // If |transfer_current_position| is true, |range|'s |next_buffer_index_|
   // is transfered to this SourceBufferRange.
+  // Note: Use these only to merge existing ranges. |range|'s first buffer
+  // timestamp must be adjacent to this range. No group start timestamp
+  // adjacency is involved in these methods.
   void AppendRangeToEnd(const SourceBufferRange& range,
                         bool transfer_current_position);
   bool CanAppendRangeToEnd(const SourceBufferRange& range) const;
@@ -94,7 +113,8 @@
   // and creates and returns a new SourceBufferRange with the buffers from that
   // keyframe onward. The buffers in the new SourceBufferRange are moved out of
   // this range. If there is no keyframe at or after |timestamp|, SplitRange()
-  // returns null and this range is unmodified.
+  // returns null and this range is unmodified. This range can become empty if
+  // |timestamp| <= the DTS of the first buffer in this range.
   SourceBufferRange* SplitRange(DecodeTimestamp timestamp);
 
   // Deletes the buffers from this range starting at |timestamp|, exclusive if
@@ -203,7 +223,7 @@
 
   // Returns true if |timestamp| is the timestamp of the next buffer in
   // sequence after |buffers_.back()|, false otherwise.
-  bool IsNextInSequence(DecodeTimestamp timestamp, bool is_key_frame) const;
+  bool IsNextInSequence(DecodeTimestamp timestamp) const;
 
   // Adds all buffers which overlap [start, end) to the end of |buffers|.  If
   // no buffers exist in the range returns false, true otherwise.
@@ -279,15 +299,17 @@
   // GetNextBuffer(), set to -1 before Seek().
   int next_buffer_index_;
 
-  // If the first buffer in this range is the beginning of a media segment,
-  // |media_segment_start_time_| is the time when the media segment begins.
-  // |media_segment_start_time_| may be <= the timestamp of the first buffer in
-  // |buffers_|. |media_segment_start_time_| is kNoTimestamp() if this range
-  // does not start at the beginning of a media segment, which can only happen
-  // garbage collection or after an end overlap that results in a split range
-  // (we don't have a way of knowing the media segment timestamp for the new
-  // range).
-  DecodeTimestamp media_segment_start_time_;
+  // If the first buffer in this range is the beginning of a coded frame group,
+  // |range_start_time_| is the time when the coded frame group begins. This is
+  // especially important in muxed media where the first coded frames for each
+  // track do not necessarily begin at the same time.
+  // |range_start_time_| may be <= the timestamp of the first buffer in
+  // |buffers_|. |range_start_time_| is kNoDecodeTimestamp() if this range does
+  // not start at the beginning of a coded frame group, which can happen by
+  // range removal or split when we don't have a way of knowing, across
+  // potentially multiple muxed streams, the coded frame group start timestamp
+  // for the new range.
+  DecodeTimestamp range_start_time_;
 
   // Called to get the largest interbuffer distance seen so far in the stream.
   InterbufferDistanceCB interbuffer_distance_cb_;
diff --git a/media/filters/source_buffer_stream.cc b/media/filters/source_buffer_stream.cc
index d2b4fae6..e03a8c3 100644
--- a/media/filters/source_buffer_stream.cc
+++ b/media/filters/source_buffer_stream.cc
@@ -37,6 +37,15 @@
 // Limit the number of MEDIA_LOG() logs for MSE GC algorithm warnings.
 const int kMaxGarbageCollectAlgorithmWarningLogs = 20;
 
+// Limit the number of MEDIA_LOG() logs for same DTS for non-keyframe followed
+// by keyframe. Prior to relaxing the "media segments must begin with a
+// keyframe" requirement, we issued decode error for this situation. That was
+// likely too strict, and now that the keyframe requirement is relaxed, we have
+// no knowledge of media segment boundaries here. Now, we log but don't trigger
+// decode error, since we allow these sequences which may cause extra decoder
+// work or other side-effects.
+const int kMaxStrangeSameTimestampsLogs = 20;
+
 // Helper method that returns true if |ranges| is sorted in increasing order,
 // false otherwise.
 bool IsRangeListSorted(const std::list<media::SourceBufferRange*>& ranges) {
@@ -137,7 +146,7 @@
                                        bool splice_frames_enabled)
     : media_log_(media_log),
       seek_buffer_timestamp_(kNoTimestamp()),
-      media_segment_start_time_(kNoDecodeTimestamp()),
+      coded_frame_group_start_time_(kNoDecodeTimestamp()),
       range_for_next_append_(ranges_.end()),
       last_output_buffer_timestamp_(kNoDecodeTimestamp()),
       max_interbuffer_distance_(kNoTimestamp()),
@@ -152,7 +161,7 @@
                                        bool splice_frames_enabled)
     : media_log_(media_log),
       seek_buffer_timestamp_(kNoTimestamp()),
-      media_segment_start_time_(kNoDecodeTimestamp()),
+      coded_frame_group_start_time_(kNoDecodeTimestamp()),
       range_for_next_append_(ranges_.end()),
       last_output_buffer_timestamp_(kNoDecodeTimestamp()),
       max_interbuffer_distance_(kNoTimestamp()),
@@ -168,7 +177,7 @@
     : media_log_(media_log),
       text_track_config_(text_config),
       seek_buffer_timestamp_(kNoTimestamp()),
-      media_segment_start_time_(kNoDecodeTimestamp()),
+      coded_frame_group_start_time_(kNoDecodeTimestamp()),
       range_for_next_append_(ranges_.end()),
       last_output_buffer_timestamp_(kNoDecodeTimestamp()),
       max_interbuffer_distance_(kNoTimestamp()),
@@ -182,26 +191,29 @@
   }
 }
 
-void SourceBufferStream::OnNewMediaSegment(
-    DecodeTimestamp media_segment_start_time) {
-  DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName()
-           << " (" << media_segment_start_time.InSecondsF() << ")";
+void SourceBufferStream::OnStartOfCodedFrameGroup(
+    DecodeTimestamp coded_frame_group_start_time) {
+  DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName() << " ("
+           << coded_frame_group_start_time.InSecondsF() << ")";
   DCHECK(!end_of_stream_);
-  media_segment_start_time_ = media_segment_start_time;
-  new_media_segment_ = true;
+  coded_frame_group_start_time_ = coded_frame_group_start_time;
+  new_coded_frame_group_ = true;
 
   RangeList::iterator last_range = range_for_next_append_;
-  range_for_next_append_ = FindExistingRangeFor(media_segment_start_time);
+  range_for_next_append_ = FindExistingRangeFor(coded_frame_group_start_time);
 
-  // Only reset |last_appended_buffer_timestamp_| if this new media segment is
-  // not adjacent to the previous media segment appended to the stream.
+  // Only reset |last_appended_buffer_timestamp_| if this new coded frame group
+  // is not adjacent to the previous coded frame group appended to the stream.
   if (range_for_next_append_ == ranges_.end() ||
       !AreAdjacentInSequence(last_appended_buffer_timestamp_,
-                             media_segment_start_time)) {
+                             coded_frame_group_start_time)) {
     last_appended_buffer_timestamp_ = kNoDecodeTimestamp();
     last_appended_buffer_duration_ = kNoTimestamp();
     last_appended_buffer_is_keyframe_ = false;
-    DVLOG(3) << __FUNCTION__ << " next appended buffers will be in a new range";
+    DVLOG(3) << __FUNCTION__ << " next appended buffers will "
+             << (range_for_next_append_ == ranges_.end()
+                     ? "be in a new range"
+                     : "overlap an existing range");
   } else if (last_range != ranges_.end()) {
     DCHECK(last_range == range_for_next_append_);
     DVLOG(3) << __FUNCTION__ << " next appended buffers will continue range "
@@ -215,41 +227,29 @@
                "buffers to append", buffers.size());
 
   DCHECK(!buffers.empty());
-  DCHECK(media_segment_start_time_ != kNoDecodeTimestamp());
-  DCHECK(media_segment_start_time_ <= buffers.front()->GetDecodeTimestamp());
+  DCHECK(coded_frame_group_start_time_ != kNoDecodeTimestamp());
+  DCHECK(coded_frame_group_start_time_ <=
+         buffers.front()->GetDecodeTimestamp());
   DCHECK(!end_of_stream_);
 
   DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName()
            << ": buffers " << BufferQueueToLogString(buffers);
 
-  // New media segments must begin with a keyframe.
-  // TODO(wolenetz): Relax this requirement. See http://crbug.com/229412.
-  if (new_media_segment_ && !buffers.front()->is_key_frame()) {
-    MEDIA_LOG(ERROR, media_log_) << "Media segment did not begin with key "
-                                    "frame. Support for such segments will be "
-                                    "available in a future version. Please see "
-                                    "https://crbug.com/229412.";
+  // New coded frame groups emitted by the coded frame processor must begin with
+  // a keyframe. TODO(wolenetz): Change this to [DCHECK + MEDIA_LOG(ERROR...) +
+  // return false] once the CHECK has baked in a stable release. See
+  // https://crbug.com/580621.
+  CHECK(!new_coded_frame_group_ || buffers.front()->is_key_frame());
+
+  // Buffers within a coded frame group should be monotonically increasing.
+  if (!IsMonotonicallyIncreasing(buffers)) {
     return false;
   }
 
-  // Buffers within a media segment should be monotonically increasing.
-  if (!IsMonotonicallyIncreasing(buffers))
-    return false;
-
-  if (media_segment_start_time_ < DecodeTimestamp() ||
+  if (coded_frame_group_start_time_ < DecodeTimestamp() ||
       buffers.front()->GetDecodeTimestamp() < DecodeTimestamp()) {
     MEDIA_LOG(ERROR, media_log_)
-        << "Cannot append a media segment with negative timestamps.";
-    return false;
-  }
-
-  if (!IsNextTimestampValid(buffers.front()->GetDecodeTimestamp(),
-                            buffers.front()->is_key_frame())) {
-    const DecodeTimestamp& dts = buffers.front()->GetDecodeTimestamp();
-    MEDIA_LOG(ERROR, media_log_)
-        << "Invalid same timestamp construct detected at"
-        << " time " << dts.InSecondsF();
-
+        << "Cannot append a coded frame group with negative timestamps.";
     return false;
   }
 
@@ -265,21 +265,40 @@
   // If there's a range for |buffers|, insert |buffers| accordingly. Otherwise,
   // create a new range with |buffers|.
   if (range_for_next_append_ != ranges_.end()) {
-    (*range_for_next_append_)->AppendBuffersToEnd(buffers);
+    if (new_coded_frame_group_ && (!splice_frames_enabled_ ||
+                                   buffers.front()->splice_buffers().empty())) {
+      // If the first append to this stream in a new coded frame group continues
+      // a previous range, use the new group's start time instead of the first
+      // new buffer's timestamp as the proof of adjacency to the existing range.
+      // A large gap (larger than our normal buffer adjacency test) can occur in
+      // a muxed set of streams (which share a common coded frame group start
+      // time) with a significantly jagged start across the streams.
+      // Don't do this logic if there was a splice frame generated for the first
+      // new buffer, since splices are guaranteed to be in the same range and
+      // adjacent, and since the splice frame's timestamp can be less than
+      // |coded_frame_group_start_time_| due to the splicing.
+      (*range_for_next_append_)
+          ->AppendBuffersToEnd(buffers, coded_frame_group_start_time_);
+    } else {
+      // Otherwise, use the first new buffer's timestamp as the proof of
+      // adjacency.
+      (*range_for_next_append_)
+          ->AppendBuffersToEnd(buffers, kNoDecodeTimestamp());
+    }
+
     last_appended_buffer_timestamp_ = buffers.back()->GetDecodeTimestamp();
     last_appended_buffer_duration_ = buffers.back()->duration();
     last_appended_buffer_is_keyframe_ = buffers.back()->is_key_frame();
   } else {
     DecodeTimestamp new_range_start_time = std::min(
-        media_segment_start_time_, buffers.front()->GetDecodeTimestamp());
+        coded_frame_group_start_time_, buffers.front()->GetDecodeTimestamp());
     const BufferQueue* buffers_for_new_range = &buffers;
     BufferQueue trimmed_buffers;
 
-    // If the new range is not being created because of a new media
-    // segment, then we must make sure that we start with a key frame.
-    // This can happen if the GOP in the previous append gets destroyed
-    // by a Remove() call.
-    if (!new_media_segment_) {
+    // If the new range is not being created because of a new coded frame group,
+    // then we must make sure that we start with a key frame.  This can happen
+    // if the GOP in the previous append gets destroyed by a Remove() call.
+    if (!new_coded_frame_group_) {
       BufferQueue::const_iterator itr = buffers.begin();
 
       // Scan past all the non-key-frames.
@@ -294,7 +313,7 @@
         last_appended_buffer_duration_ = buffers.back()->duration();
         last_appended_buffer_is_keyframe_ = buffers.back()->is_key_frame();
         DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName()
-                 << ": new buffers in the middle of media segment depend on"
+                 << ": new buffers in the middle of coded frame group depend on"
                     "keyframe that has been removed, and contain no keyframes."
                     "Skipping further processing.";
         DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName()
@@ -324,7 +343,7 @@
         buffers_for_new_range->back()->is_key_frame();
   }
 
-  new_media_segment_ = false;
+  new_coded_frame_group_ = false;
 
   MergeWithAdjacentRangeIfNecessary(range_for_next_append_);
 
@@ -413,6 +432,28 @@
   }
 }
 
+DecodeTimestamp SourceBufferStream::PotentialNextAppendTimestamp() const {
+  // The next potential append will either be just at or after
+  // |last_appended_buffer_timestamp_| (if known), or if unknown and we are
+  // still at the beginning of a new coded frame group, then will be into the
+  // range (if any) to which |coded_frame_group_start_time_| belongs.
+  if (last_appended_buffer_timestamp_ != kNoDecodeTimestamp()) {
+    // TODO(wolenetz): Determine if this +1us is still necessary. See
+    // https://crbug.com/589295.
+    return last_appended_buffer_timestamp_ +
+           base::TimeDelta::FromInternalValue(1);
+  }
+
+  if (new_coded_frame_group_)
+    return coded_frame_group_start_time_;
+
+  // If we still don't know a potential next append timestamp, then we have
+  // removed the ranged to which it previously belonged and have not completed a
+  // subsequent append or received a subsequent OnStartOfCodedFrameGroup()
+  // signal.
+  return kNoDecodeTimestamp();
+}
+
 void SourceBufferStream::RemoveInternal(DecodeTimestamp start,
                                         DecodeTimestamp end,
                                         bool exclude_start,
@@ -440,6 +481,19 @@
     SourceBufferRange* new_range = range->SplitRange(end);
     if (new_range) {
       itr = ranges_.insert(++itr, new_range);
+
+      // Update |range_for_next_append_| if it was previously |range| and should
+      // be |new_range| now.
+      if (range_for_next_append_ != ranges_.end() &&
+          *range_for_next_append_ == range) {
+        DecodeTimestamp potential_next_append_timestamp =
+            PotentialNextAppendTimestamp();
+        if (potential_next_append_timestamp != kNoDecodeTimestamp() &&
+            new_range->BelongsToRange(potential_next_append_timestamp)) {
+          range_for_next_append_ = itr;
+        }
+      }
+
       --itr;
 
       // Update the selected range if the next buffer position was transferred
@@ -476,11 +530,9 @@
     // operation makes it impossible for the next append to be added
     // to the current range.
     if (range_for_next_append_ != ranges_.end() &&
-        *range_for_next_append_ == range &&
-        last_appended_buffer_timestamp_ != kNoDecodeTimestamp()) {
+        *range_for_next_append_ == range) {
       DecodeTimestamp potential_next_append_timestamp =
-          last_appended_buffer_timestamp_ +
-          base::TimeDelta::FromInternalValue(1);
+          PotentialNextAppendTimestamp();
 
       if (!range->BelongsToRange(potential_next_append_timestamp)) {
         DVLOG(1) << "Resetting range_for_next_append_ since the next append"
@@ -522,8 +574,7 @@
           beginning_of_buffered < kSeekToStartFudgeRoom());
 }
 
-bool SourceBufferStream::IsMonotonicallyIncreasing(
-    const BufferQueue& buffers) const {
+bool SourceBufferStream::IsMonotonicallyIncreasing(const BufferQueue& buffers) {
   DCHECK(!buffers.empty());
   DecodeTimestamp prev_timestamp = last_appended_buffer_timestamp_;
   bool prev_is_keyframe = last_appended_buffer_is_keyframe_;
@@ -546,12 +597,13 @@
       }
 
       if (current_timestamp == prev_timestamp &&
-          !SourceBufferRange::AllowSameTimestamp(prev_is_keyframe,
-                                                 current_is_keyframe)) {
-        MEDIA_LOG(ERROR, media_log_) << "Unexpected combination of buffers with"
-                                     << " the same timestamp detected at "
-                                     << current_timestamp.InSecondsF();
-        return false;
+          SourceBufferRange::IsUncommonSameTimestampSequence(
+              prev_is_keyframe, current_is_keyframe)) {
+        LIMITED_MEDIA_LOG(DEBUG, media_log_, num_strange_same_timestamps_logs_,
+                          kMaxStrangeSameTimestampsLogs)
+            << "Detected an append sequence with keyframe following a "
+               "non-keyframe, both with the same decode timestamp of "
+            << current_timestamp.InSecondsF();
       }
     }
 
@@ -561,15 +613,6 @@
   return true;
 }
 
-bool SourceBufferStream::IsNextTimestampValid(
-    DecodeTimestamp next_timestamp, bool next_is_keyframe) const {
-  return (last_appended_buffer_timestamp_ != next_timestamp) ||
-      new_media_segment_ ||
-      SourceBufferRange::AllowSameTimestamp(last_appended_buffer_is_keyframe_,
-                                            next_is_keyframe);
-}
-
-
 bool SourceBufferStream::OnlySelectedRangeIsSeeked() const {
   for (RangeList::const_iterator itr = ranges_.begin();
        itr != ranges_.end(); ++itr) {
@@ -938,9 +981,7 @@
     GenerateSpliceFrame(new_buffers);
 
   DecodeTimestamp prev_timestamp = last_appended_buffer_timestamp_;
-  bool prev_is_keyframe = last_appended_buffer_is_keyframe_;
   DecodeTimestamp next_timestamp = new_buffers.front()->GetDecodeTimestamp();
-  bool next_is_keyframe = new_buffers.front()->is_key_frame();
 
   if (prev_timestamp != kNoDecodeTimestamp() &&
       prev_timestamp != next_timestamp) {
@@ -949,22 +990,25 @@
     RemoveInternal(prev_timestamp, next_timestamp, true, deleted_buffers);
   }
 
-  // Make the delete range exclusive if we are dealing with an allowed same
-  // timestamp situation. This prevents the first buffer in the current append
-  // from deleting the last buffer in the previous append if both buffers
-  // have the same timestamp.
-  //
-  // The delete range should never be exclusive if a splice frame was generated
-  // because we don't generate splice frames for same timestamp situations.
+  // Always make the start of the delete range exclusive for same timestamp
+  // across the last buffer in the previous append and the first buffer in the
+  // current append. Never be exclusive if a splice frame was generated because
+  // we don't generate splice frames for same timestamp situations.
   DCHECK(new_buffers.front()->splice_timestamp() !=
          new_buffers.front()->timestamp());
-  const bool exclude_start =
-      new_buffers.front()->splice_buffers().empty() &&
-      prev_timestamp == next_timestamp &&
-      SourceBufferRange::AllowSameTimestamp(prev_is_keyframe, next_is_keyframe);
+  const bool exclude_start = new_buffers.front()->splice_buffers().empty() &&
+                             prev_timestamp == next_timestamp;
 
   // Delete the buffers that |new_buffers| overlaps.
   DecodeTimestamp start = new_buffers.front()->GetDecodeTimestamp();
+  if (new_coded_frame_group_) {
+    // Extend the deletion range earlier to the coded frame group start time if
+    // this is the first append in a new coded frame group. Note that |start|
+    // could already be less than |coded_frame_group_start_time_| if a splice
+    // was generated.
+    DCHECK(coded_frame_group_start_time_ != kNoDecodeTimestamp());
+    start = std::min(coded_frame_group_start_time_, start);
+  }
   DecodeTimestamp end = new_buffers.back()->GetDecodeTimestamp();
   base::TimeDelta duration = new_buffers.back()->duration();
 
diff --git a/media/filters/source_buffer_stream.h b/media/filters/source_buffer_stream.h
index 8921595..91613fd6 100644
--- a/media/filters/source_buffer_stream.h
+++ b/media/filters/source_buffer_stream.h
@@ -68,11 +68,11 @@
 
   ~SourceBufferStream();
 
-  // Signals that the next buffers appended are part of a new media segment
-  // starting at |media_segment_start_time|.
+  // Signals that the next buffers appended are part of a new coded frame group
+  // starting at |coded_frame_group_start_time|.
   // TODO(acolwell/wolenetz): This should be changed to a presentation
   // timestamp. See http://crbug.com/402502
-  void OnNewMediaSegment(DecodeTimestamp media_segment_start_time);
+  void OnStartOfCodedFrameGroup(DecodeTimestamp coded_frame_group_start_time);
 
   // Add the |buffers| to the SourceBufferStream. Buffers within the queue are
   // expected to be in order, but multiple calls to Append() may add buffers out
@@ -211,7 +211,7 @@
   // if in between seeking (i.e. |selected_range_| is null).
   DecodeTimestamp GetNextBufferTimestamp();
 
-  // Finds the range that should contain a media segment that begins with
+  // Finds the range that should contain a coded frame group that begins with
   // |start_timestamp| and returns the iterator pointing to it. Returns
   // |ranges_.end()| if there's no such existing range.
   RangeList::iterator FindExistingRangeFor(DecodeTimestamp start_timestamp);
@@ -241,13 +241,8 @@
   bool ShouldSeekToStartOfBuffered(base::TimeDelta seek_timestamp) const;
 
   // Returns true if the timestamps of |buffers| are monotonically increasing
-  // since the previous append to the media segment, false otherwise.
-  bool IsMonotonicallyIncreasing(const BufferQueue& buffers) const;
-
-  // Returns true if |next_timestamp| and |next_is_keyframe| are valid for
-  // the first buffer after the previous append.
-  bool IsNextTimestampValid(DecodeTimestamp next_timestamp,
-                            bool next_is_keyframe) const;
+  // since the previous append to the coded frame group, false otherwise.
+  bool IsMonotonicallyIncreasing(const BufferQueue& buffers);
 
   // Returns true if |selected_range_| is the only range in |ranges_| that
   // HasNextBufferPosition().
@@ -300,6 +295,15 @@
   // was removed or to |ranges_.end()| if the last range was removed.
   void DeleteAndRemoveRange(RangeList::iterator* itr);
 
+  // Helper function used when updating |range_for_next_append_|.
+  // Returns a guess of what the next append timestamp will be based on
+  // |last_appended_buffer_timestamp_|, |new_coded_frame_group_| and
+  // |coded_frame_group_start_time_|. Returns kNoDecodeTimestamp() if unable to
+  // guess, which can occur prior to first OnStartOfCodedFrameGroup(), or
+  // when the most recent GOP appended to since the last
+  // OnStartOfCodedFrameGroup() is removed.
+  DecodeTimestamp PotentialNextAppendTimestamp() const;
+
   // Helper function used by Remove() and PrepareRangesForNextAppend() to
   // remove buffers and ranges between |start| and |end|.
   // |exclude_start| - If set to true, buffers with timestamps that
@@ -397,17 +401,19 @@
   // emitted buffer emptied |track_buffer_|.
   bool just_exhausted_track_buffer_ = false;
 
-  // The start time of the current media segment being appended.
-  DecodeTimestamp media_segment_start_time_;
+  // The start time of the current coded frame group being appended.
+  DecodeTimestamp coded_frame_group_start_time_;
 
-  // Points to the range containing the current media segment being appended.
+  // Points to the range containing the current coded frame group being
+  // appended.
   RangeList::iterator range_for_next_append_;
 
-  // True when the next call to Append() begins a new media segment.
-  bool new_media_segment_ = false;
+  // True when the next call to Append() begins a new coded frame group.
+  // TODO(wolenetz): Simplify by passing this flag into Append().
+  bool new_coded_frame_group_ = false;
 
-  // The timestamp of the last buffer appended to the media segment, set to
-  // kNoDecodeTimestamp() if the beginning of the segment.
+  // The timestamp of the last buffer appended to the coded frame group, set to
+  // kNoDecodeTimestamp() if the beginning of the group.
   DecodeTimestamp last_appended_buffer_timestamp_ = kNoDecodeTimestamp();
   base::TimeDelta last_appended_buffer_duration_ = kNoTimestamp();
   bool last_appended_buffer_is_keyframe_ = false;
@@ -449,6 +455,7 @@
   int num_splice_generation_success_logs_ = 0;
   int num_track_buffer_gap_warning_logs_ = 0;
   int num_garbage_collect_algorithm_logs_ = 0;
+  int num_strange_same_timestamps_logs_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(SourceBufferStream);
 };
diff --git a/media/filters/source_buffer_stream_unittest.cc b/media/filters/source_buffer_stream_unittest.cc
index cb8d2174..53e8066 100644
--- a/media/filters/source_buffer_stream_unittest.cc
+++ b/media/filters/source_buffer_stream_unittest.cc
@@ -41,17 +41,11 @@
 static const int kDataSize = 1;
 
 // Matchers for verifying common media log entry strings.
-MATCHER(ContainsMissingKeyframeLog, "") {
-  return CONTAINS_STRING(arg,
-                         "Media segment did not begin with key frame. Support "
-                         "for such segments will be available in a future "
-                         "version. Please see https://crbug.com/229412.");
-}
-
 MATCHER(ContainsSameTimestampAt30MillisecondsLog, "") {
   return CONTAINS_STRING(arg,
-                         "Unexpected combination of buffers with the same "
-                         "timestamp detected at 0.03");
+                         "Detected an append sequence with keyframe following "
+                         "a non-keyframe, both with the same decode timestamp "
+                         "of 0.03");
 }
 
 MATCHER_P(ContainsTrackBufferExhaustionSkipLog, skip_milliseconds, "") {
@@ -115,27 +109,28 @@
     SetStreamInfo(500, 500);
   }
 
-  void NewSegmentAppend(int starting_position, int number_of_buffers) {
+  void NewCodedFrameGroupAppend(int starting_position, int number_of_buffers) {
     AppendBuffers(starting_position, number_of_buffers, true,
                   base::TimeDelta(), true, &kDataA, kDataSize);
   }
 
-  void NewSegmentAppend(int starting_position,
-                        int number_of_buffers,
-                        const uint8_t* data) {
+  void NewCodedFrameGroupAppend(int starting_position,
+                                int number_of_buffers,
+                                const uint8_t* data) {
     AppendBuffers(starting_position, number_of_buffers, true,
                   base::TimeDelta(), true, data, kDataSize);
   }
 
-  void NewSegmentAppend_OffsetFirstBuffer(
-      int starting_position, int number_of_buffers,
+  void NewCodedFrameGroupAppend_OffsetFirstBuffer(
+      int starting_position,
+      int number_of_buffers,
       base::TimeDelta first_buffer_offset) {
     AppendBuffers(starting_position, number_of_buffers, true,
                   first_buffer_offset, true, &kDataA, kDataSize);
   }
 
-  void NewSegmentAppend_ExpectFailure(
-      int starting_position, int number_of_buffers) {
+  void NewCodedFrameGroupAppend_ExpectFailure(int starting_position,
+                                              int number_of_buffers) {
     AppendBuffers(starting_position, number_of_buffers, true,
                   base::TimeDelta(), false, &kDataA, kDataSize);
   }
@@ -152,12 +147,12 @@
                   base::TimeDelta(), true, data, kDataSize);
   }
 
-  void NewSegmentAppend(const std::string& buffers_to_append) {
+  void NewCodedFrameGroupAppend(const std::string& buffers_to_append) {
     AppendBuffers(buffers_to_append, true, kNoTimestamp(), false, true);
   }
 
-  void NewSegmentAppend(base::TimeDelta start_timestamp,
-                        const std::string& buffers_to_append) {
+  void NewCodedFrameGroupAppend(base::TimeDelta start_timestamp,
+                                const std::string& buffers_to_append) {
     AppendBuffers(buffers_to_append, true, start_timestamp, false, true);
   }
 
@@ -165,7 +160,7 @@
     AppendBuffers(buffers_to_append, false, kNoTimestamp(), false, true);
   }
 
-  void NewSegmentAppendOneByOne(const std::string& buffers_to_append) {
+  void NewCodedFrameGroupAppendOneByOne(const std::string& buffers_to_append) {
     AppendBuffers(buffers_to_append, true, kNoTimestamp(), true, true);
   }
 
@@ -173,7 +168,8 @@
     AppendBuffers(buffers_to_append, false, kNoTimestamp(), true, true);
   }
 
-  void NewSegmentAppend_ExpectFailure(const std::string& buffers_to_append) {
+  void NewCodedFrameGroupAppend_ExpectFailure(
+      const std::string& buffers_to_append) {
     AppendBuffers(buffers_to_append, true, kNoTimestamp(), false, false);
   }
 
@@ -206,6 +202,11 @@
     stream_->Remove(start, end, duration);
   }
 
+  void SignalStartOfCodedFrameGroup(base::TimeDelta start_timestamp) {
+    stream_->OnStartOfCodedFrameGroup(
+        DecodeTimestamp::FromPresentationTime(start_timestamp));
+  }
+
   int GetRemovalRangeInMs(int start, int end, int bytes_to_free,
                           int* removal_end) {
     DecodeTimestamp removal_end_timestamp =
@@ -439,13 +440,13 @@
 
   void AppendBuffers(int starting_position,
                      int number_of_buffers,
-                     bool begin_media_segment,
+                     bool begin_coded_frame_group,
                      base::TimeDelta first_buffer_offset,
                      bool expect_success,
                      const uint8_t* data,
                      int size) {
-    if (begin_media_segment)
-      stream_->OnNewMediaSegment(DecodeTimestamp::FromPresentationTime(
+    if (begin_coded_frame_group)
+      stream_->OnStartOfCodedFrameGroup(DecodeTimestamp::FromPresentationTime(
           starting_position * frame_duration_));
 
     int keyframe_interval = frames_per_second_ / keyframes_per_second_;
@@ -687,20 +688,20 @@
   }
 
   void AppendBuffers(const std::string& buffers_to_append,
-                     bool start_new_segment,
-                     base::TimeDelta segment_start_timestamp,
+                     bool start_new_coded_frame_group,
+                     base::TimeDelta coded_frame_group_start_timestamp,
                      bool one_by_one,
                      bool expect_success) {
     BufferQueue buffers = StringToBufferQueue(buffers_to_append);
 
-    if (start_new_segment) {
-      base::TimeDelta start_timestamp = segment_start_timestamp;
+    if (start_new_coded_frame_group) {
+      base::TimeDelta start_timestamp = coded_frame_group_start_timestamp;
       if (start_timestamp == kNoTimestamp())
         start_timestamp = buffers[0]->timestamp();
 
       ASSERT_TRUE(start_timestamp <= buffers[0]->timestamp());
 
-      stream_->OnNewMediaSegment(
+      stream_->OnStartOfCodedFrameGroup(
           DecodeTimestamp::FromPresentationTime(start_timestamp));
     }
 
@@ -725,7 +726,7 @@
 
 TEST_F(SourceBufferStreamTest, Append_SingleRange) {
   // Append 15 buffers at positions 0 through 14.
-  NewSegmentAppend(0, 15);
+  NewCodedFrameGroupAppend(0, 15);
 
   // Check expected range.
   CheckExpectedRanges("{ [0,14) }");
@@ -736,7 +737,7 @@
 
 TEST_F(SourceBufferStreamTest, Append_SingleRange_OneBufferAtATime) {
   // Append 15 buffers starting at position 0, one buffer at a time.
-  NewSegmentAppend(0, 1);
+  NewCodedFrameGroupAppend(0, 1);
   for (int i = 1; i < 15; i++)
     AppendBuffers(i, 1);
 
@@ -749,10 +750,10 @@
 
 TEST_F(SourceBufferStreamTest, Append_DisjointRanges) {
   // Append 5 buffers at positions 0 through 4.
-  NewSegmentAppend(0, 5);
+  NewCodedFrameGroupAppend(0, 5);
 
   // Append 10 buffers at positions 15 through 24.
-  NewSegmentAppend(15, 10);
+  NewCodedFrameGroupAppend(15, 10);
 
   // Check expected ranges.
   CheckExpectedRanges("{ [0,4) [15,24) }");
@@ -765,13 +766,13 @@
 
 TEST_F(SourceBufferStreamTest, Append_AdjacentRanges) {
   // Append 10 buffers at positions 0 through 9.
-  NewSegmentAppend(0, 10);
+  NewCodedFrameGroupAppend(0, 10);
 
   // Append 11 buffers at positions 15 through 25.
-  NewSegmentAppend(15, 11);
+  NewCodedFrameGroupAppend(15, 11);
 
   // Append 5 buffers at positions 10 through 14 to bridge the gap.
-  NewSegmentAppend(10, 5);
+  NewCodedFrameGroupAppend(10, 5);
 
   // Check expected range.
   CheckExpectedRanges("{ [0,25) }");
@@ -780,52 +781,12 @@
   CheckExpectedBuffers(0, 25);
 }
 
-TEST_F(SourceBufferStreamTest, Append_DoesNotBeginWithKeyframe) {
-  EXPECT_MEDIA_LOG(ContainsMissingKeyframeLog()).Times(2);
-
-  // Append fails because the range doesn't begin with a keyframe.
-  NewSegmentAppend_ExpectFailure(3, 2);
-
-  // Append 10 buffers at positions 5 through 14.
-  NewSegmentAppend(5, 10);
-
-  // Check expected range.
-  CheckExpectedRanges("{ [5,14) }");
-  // Check buffers in range.
-  Seek(5);
-  CheckExpectedBuffers(5, 14);
-
-  // Append fails because the range doesn't begin with a keyframe.
-  NewSegmentAppend_ExpectFailure(17, 3);
-
-  CheckExpectedRanges("{ [5,14) }");
-  Seek(5);
-  CheckExpectedBuffers(5, 14);
-}
-
-TEST_F(SourceBufferStreamTest, Append_DoesNotBeginWithKeyframe_Adjacent) {
-  EXPECT_MEDIA_LOG(ContainsMissingKeyframeLog());
-
-  // Append 8 buffers at positions 0 through 7.
-  NewSegmentAppend(0, 8);
-
-  // Now start a new media segment at position 8. Append should fail because
-  // the media segment does not begin with a keyframe.
-  NewSegmentAppend_ExpectFailure(8, 2);
-
-  // Check expected range.
-  CheckExpectedRanges("{ [0,7) }");
-  // Check buffers in range.
-  Seek(0);
-  CheckExpectedBuffers(0, 7);
-}
-
 TEST_F(SourceBufferStreamTest, Complete_Overlap) {
   // Append 5 buffers at positions 5 through 9.
-  NewSegmentAppend(5, 5);
+  NewCodedFrameGroupAppend(5, 5);
 
   // Append 15 buffers at positions 0 through 14.
-  NewSegmentAppend(0, 15);
+  NewCodedFrameGroupAppend(0, 15);
 
   // Check expected range.
   CheckExpectedRanges("{ [0,14) }");
@@ -835,18 +796,19 @@
 }
 
 TEST_F(SourceBufferStreamTest,
-       Complete_Overlap_AfterSegmentTimestampAndBeforeFirstBufferTimestamp) {
-  // Append a segment with a start timestamp of 0, but the first
+       Complete_Overlap_AfterGroupTimestampAndBeforeFirstBufferTimestamp) {
+  // Append a coded frame group with a start timestamp of 0, but the first
   // buffer starts at 30ms. This can happen in muxed content where the
   // audio starts before the first frame.
-  NewSegmentAppend(base::TimeDelta::FromMilliseconds(0), "30K 60K 90K 120K");
+  NewCodedFrameGroupAppend(base::TimeDelta::FromMilliseconds(0),
+                           "30K 60K 90K 120K");
 
   CheckExpectedRangesByTimestamp("{ [0,150) }");
 
-  // Completely overlap the old buffers, with a segment that starts
-  // after the old segment start timestamp, but before the timestamp
-  // of the first buffer in the segment.
-  NewSegmentAppend("20K 50K 80K 110D10K");
+  // Completely overlap the old buffers, with a coded frame group that starts
+  // after the old coded frame group start timestamp, but before the timestamp
+  // of the first buffer in the coded frame group.
+  NewCodedFrameGroupAppend("20K 50K 80K 110D10K");
 
   // Verify that the buffered ranges are updated properly and we don't crash.
   CheckExpectedRangesByTimestamp("{ [20,150) }");
@@ -861,10 +823,10 @@
   SetStreamInfo(30, 30);
 
   // Append 6 buffers at positions 6 through 11.
-  NewSegmentAppend(6, 6);
+  NewCodedFrameGroupAppend(6, 6);
 
   // Append 8 buffers at positions 5 through 12.
-  NewSegmentAppend(5, 8);
+  NewCodedFrameGroupAppend(5, 8);
 
   // Check expected range.
   CheckExpectedRanges("{ [5,12) }");
@@ -875,10 +837,10 @@
 
 TEST_F(SourceBufferStreamTest, Start_Overlap) {
   // Append 10 buffers at positions 5 through 14.
-  NewSegmentAppend(5, 5);
+  NewCodedFrameGroupAppend(5, 5);
 
   // Append 6 buffers at positions 10 through 15.
-  NewSegmentAppend(10, 6);
+  NewCodedFrameGroupAppend(10, 6);
 
   // Check expected range.
   CheckExpectedRanges("{ [5,15) }");
@@ -889,10 +851,10 @@
 
 TEST_F(SourceBufferStreamTest, End_Overlap) {
   // Append 10 buffers at positions 10 through 19.
-  NewSegmentAppend(10, 10);
+  NewCodedFrameGroupAppend(10, 10);
 
   // Append 10 buffers at positions 5 through 14.
-  NewSegmentAppend(5, 10);
+  NewCodedFrameGroupAppend(5, 10);
 
   // Check expected range.
   CheckExpectedRanges("{ [5,19) }");
@@ -903,10 +865,10 @@
 
 TEST_F(SourceBufferStreamTest, End_Overlap_Several) {
   // Append 10 buffers at positions 10 through 19.
-  NewSegmentAppend(10, 10);
+  NewCodedFrameGroupAppend(10, 10);
 
   // Append 8 buffers at positions 5 through 12.
-  NewSegmentAppend(5, 8);
+  NewCodedFrameGroupAppend(5, 8);
 
   // Check expected ranges: stream should not have kept buffers 13 and 14
   // because the keyframe on which they depended was overwritten.
@@ -931,10 +893,10 @@
   // Seek to start of stream.
   SeekToTimestampMs(0);
 
-  NewSegmentAppend("0K 30 60 90 120K 150");
+  NewCodedFrameGroupAppend("0K 30 60 90 120K 150");
   CheckExpectedRangesByTimestamp("{ [0,180) }");
 
-  NewSegmentAppend("0D30K");
+  NewCodedFrameGroupAppend("0D30K");
   CheckExpectedRangesByTimestamp("{ [0,30) [120,180) }");
 
   CheckExpectedBuffers("0K");
@@ -943,19 +905,19 @@
 
 TEST_F(SourceBufferStreamTest, Complete_Overlap_Several) {
   // Append 2 buffers at positions 5 through 6.
-  NewSegmentAppend(5, 2);
+  NewCodedFrameGroupAppend(5, 2);
 
   // Append 2 buffers at positions 10 through 11.
-  NewSegmentAppend(10, 2);
+  NewCodedFrameGroupAppend(10, 2);
 
   // Append 2 buffers at positions 15 through 16.
-  NewSegmentAppend(15, 2);
+  NewCodedFrameGroupAppend(15, 2);
 
   // Check expected ranges.
   CheckExpectedRanges("{ [5,6) [10,11) [15,16) }");
 
   // Append buffers at positions 0 through 19.
-  NewSegmentAppend(0, 20);
+  NewCodedFrameGroupAppend(0, 20);
 
   // Check expected range.
   CheckExpectedRanges("{ [0,19) }");
@@ -966,19 +928,19 @@
 
 TEST_F(SourceBufferStreamTest, Complete_Overlap_Several_Then_Merge) {
   // Append 2 buffers at positions 5 through 6.
-  NewSegmentAppend(5, 2);
+  NewCodedFrameGroupAppend(5, 2);
 
   // Append 2 buffers at positions 10 through 11.
-  NewSegmentAppend(10, 2);
+  NewCodedFrameGroupAppend(10, 2);
 
   // Append 2 buffers at positions 15 through 16.
-  NewSegmentAppend(15, 2);
+  NewCodedFrameGroupAppend(15, 2);
 
   // Append 2 buffers at positions 20 through 21.
-  NewSegmentAppend(20, 2);
+  NewCodedFrameGroupAppend(20, 2);
 
   // Append buffers at positions 0 through 19.
-  NewSegmentAppend(0, 20);
+  NewCodedFrameGroupAppend(0, 20);
 
   // Check expected ranges.
   CheckExpectedRanges("{ [0,21) }");
@@ -989,13 +951,13 @@
 
 TEST_F(SourceBufferStreamTest, Complete_Overlap_Selected) {
   // Append 10 buffers at positions 5 through 14.
-  NewSegmentAppend(5, 10, &kDataA);
+  NewCodedFrameGroupAppend(5, 10, &kDataA);
 
   // Seek to buffer at position 5.
   Seek(5);
 
   // Replace old data with new data.
-  NewSegmentAppend(5, 10, &kDataB);
+  NewCodedFrameGroupAppend(5, 10, &kDataB);
 
   // Check ranges are correct.
   CheckExpectedRanges("{ [5,14) }");
@@ -1010,14 +972,14 @@
 // the keyframe of the new data, after which it will return the new data.
 TEST_F(SourceBufferStreamTest, Complete_Overlap_Selected_TrackBuffer) {
   // Append 10 buffers at positions 5 through 14.
-  NewSegmentAppend(5, 10, &kDataA);
+  NewCodedFrameGroupAppend(5, 10, &kDataA);
 
   // Seek to buffer at position 5 and get next buffer.
   Seek(5);
   CheckExpectedBuffers(5, 5, &kDataA);
 
   // Do a complete overlap by appending 20 buffers at positions 0 through 19.
-  NewSegmentAppend(0, 20, &kDataB);
+  NewCodedFrameGroupAppend(0, 20, &kDataB);
 
   // Check range is correct.
   CheckExpectedRanges("{ [0,19) }");
@@ -1039,14 +1001,14 @@
 
 TEST_F(SourceBufferStreamTest, Complete_Overlap_Selected_EdgeCase) {
   // Append 10 buffers at positions 5 through 14.
-  NewSegmentAppend(5, 10, &kDataA);
+  NewCodedFrameGroupAppend(5, 10, &kDataA);
 
   // Seek to buffer at position 5 and get next buffer.
   Seek(5);
   CheckExpectedBuffers(5, 5, &kDataA);
 
   // Replace existing data with new data.
-  NewSegmentAppend(5, 10, &kDataB);
+  NewCodedFrameGroupAppend(5, 10, &kDataB);
 
   // Check ranges are correct.
   CheckExpectedRanges("{ [5,14) }");
@@ -1071,23 +1033,23 @@
   static const uint8_t kDataD = 0x77;
 
   // Append 5 buffers at positions 5 through 9.
-  NewSegmentAppend(5, 5, &kDataA);
+  NewCodedFrameGroupAppend(5, 5, &kDataA);
 
   // Seek to buffer at position 5 and get next buffer.
   Seek(5);
   CheckExpectedBuffers(5, 5, &kDataA);
 
   // Replace existing data with new data.
-  NewSegmentAppend(5, 5, &kDataB);
+  NewCodedFrameGroupAppend(5, 5, &kDataB);
 
   // Then replace it again with different data.
-  NewSegmentAppend(5, 5, &kDataC);
+  NewCodedFrameGroupAppend(5, 5, &kDataC);
 
   // Now append 5 new buffers at positions 10 through 14.
-  NewSegmentAppend(10, 5, &kDataC);
+  NewCodedFrameGroupAppend(10, 5, &kDataC);
 
   // Now replace all the data entirely.
-  NewSegmentAppend(5, 10, &kDataD);
+  NewCodedFrameGroupAppend(5, 10, &kDataD);
 
   // Expect buffers 6 through 9 to be DataA, and the remaining
   // buffers to be kDataD.
@@ -1104,11 +1066,11 @@
 
 TEST_F(SourceBufferStreamTest, Start_Overlap_Selected) {
   // Append 10 buffers at positions 0 through 9.
-  NewSegmentAppend(0, 10, &kDataA);
+  NewCodedFrameGroupAppend(0, 10, &kDataA);
 
   // Seek to position 5, then add buffers to overlap data at that position.
   Seek(5);
-  NewSegmentAppend(5, 10, &kDataB);
+  NewCodedFrameGroupAppend(5, 10, &kDataB);
 
   // Check expected range.
   CheckExpectedRanges("{ [0,14) }");
@@ -1124,14 +1086,14 @@
 
 TEST_F(SourceBufferStreamTest, Start_Overlap_Selected_TrackBuffer) {
   // Append 15 buffers at positions 0 through 14.
-  NewSegmentAppend(0, 15, &kDataA);
+  NewCodedFrameGroupAppend(0, 15, &kDataA);
 
   // Seek to 10 and get buffer.
   Seek(10);
   CheckExpectedBuffers(10, 10, &kDataA);
 
   // Now append 10 buffers of new data at positions 10 through 19.
-  NewSegmentAppend(10, 10, &kDataB);
+  NewCodedFrameGroupAppend(10, 10, &kDataB);
 
   // Check expected range.
   CheckExpectedRanges("{ [0,19) }");
@@ -1156,13 +1118,13 @@
 
 TEST_F(SourceBufferStreamTest, Start_Overlap_Selected_EdgeCase) {
   // Append 10 buffers at positions 5 through 14.
-  NewSegmentAppend(5, 10, &kDataA);
+  NewCodedFrameGroupAppend(5, 10, &kDataA);
 
   Seek(10);
   CheckExpectedBuffers(10, 10, &kDataA);
 
   // Now replace the last 5 buffers with new data.
-  NewSegmentAppend(10, 5, &kDataB);
+  NewCodedFrameGroupAppend(10, 5, &kDataB);
 
   // The next 4 buffers should be the origial data, held in the track buffer.
   CheckExpectedBuffers(11, 14, &kDataA);
@@ -1172,7 +1134,7 @@
   CheckNoNextBuffer();
 
   // Now append data at 15 through 19 and check to make sure it's correct.
-  NewSegmentAppend(15, 5, &kDataB);
+  NewCodedFrameGroupAppend(15, 5, &kDataB);
   CheckExpectedBuffers(15, 19, &kDataB);
 
   // Seek to beginning of buffered range and check buffers.
@@ -1193,13 +1155,13 @@
 // after:  B b b b b*B*b b b b A a a a a
 TEST_F(SourceBufferStreamTest, End_Overlap_Selected) {
   // Append 10 buffers at positions 5 through 14.
-  NewSegmentAppend(5, 10, &kDataA);
+  NewCodedFrameGroupAppend(5, 10, &kDataA);
 
   // Seek to position 5.
   Seek(5);
 
   // Now append 10 buffers at positions 0 through 9.
-  NewSegmentAppend(0, 10, &kDataB);
+  NewCodedFrameGroupAppend(0, 10, &kDataB);
 
   // Check expected range.
   CheckExpectedRanges("{ [0,14) }");
@@ -1223,14 +1185,14 @@
 // after: |B b b b b B b b b b A a a*a*a|
 TEST_F(SourceBufferStreamTest, End_Overlap_Selected_AfterEndOfNew_1) {
   // Append 10 buffers at positions 5 through 14.
-  NewSegmentAppend(5, 10, &kDataA);
+  NewCodedFrameGroupAppend(5, 10, &kDataA);
 
   // Seek to position 10, then move to position 13.
   Seek(10);
   CheckExpectedBuffers(10, 12, &kDataA);
 
   // Now append 10 buffers at positions 0 through 9.
-  NewSegmentAppend(0, 10, &kDataB);
+  NewCodedFrameGroupAppend(0, 10, &kDataB);
 
   // Check expected range.
   CheckExpectedRanges("{ [0,14) }");
@@ -1255,14 +1217,14 @@
 // after: |B b b b b B b b|   |A a a*a*a|
 TEST_F(SourceBufferStreamTest, End_Overlap_Selected_AfterEndOfNew_2) {
   // Append 10 buffers at positions 5 through 14.
-  NewSegmentAppend(5, 10, &kDataA);
+  NewCodedFrameGroupAppend(5, 10, &kDataA);
 
   // Seek to position 10, then move to position 13.
   Seek(10);
   CheckExpectedBuffers(10, 12, &kDataA);
 
   // Now append 8 buffers at positions 0 through 7.
-  NewSegmentAppend(0, 8, &kDataB);
+  NewCodedFrameGroupAppend(0, 8, &kDataB);
 
   // Check expected ranges.
   CheckExpectedRanges("{ [0,7) [10,14) }");
@@ -1291,14 +1253,14 @@
 // track:                 |a a|
 TEST_F(SourceBufferStreamTest, End_Overlap_Selected_AfterEndOfNew_3) {
   // Append 10 buffers at positions 5 through 14.
-  NewSegmentAppend(5, 10, &kDataA);
+  NewCodedFrameGroupAppend(5, 10, &kDataA);
 
   // Seek to position 5, then move to position 8.
   Seek(5);
   CheckExpectedBuffers(5, 7, &kDataA);
 
   // Now append 8 buffers at positions 0 through 7.
-  NewSegmentAppend(0, 8, &kDataB);
+  NewCodedFrameGroupAppend(0, 8, &kDataB);
 
   // Check expected ranges.
   CheckExpectedRanges("{ [0,7) [10,14) }");
@@ -1326,14 +1288,14 @@
 // track:                 |a a|
 TEST_F(SourceBufferStreamTest, End_Overlap_Selected_OverlappedByNew_1) {
   // Append 10 buffers at positions 5 through 14.
-  NewSegmentAppend(5, 10, &kDataA);
+  NewCodedFrameGroupAppend(5, 10, &kDataA);
 
   // Seek to position 5, then move to position 8.
   Seek(5);
   CheckExpectedBuffers(5, 7, &kDataA);
 
   // Now append 10 buffers at positions 0 through 9.
-  NewSegmentAppend(0, 10, &kDataB);
+  NewCodedFrameGroupAppend(0, 10, &kDataB);
 
   // Check expected range.
   CheckExpectedRanges("{ [0,14) }");
@@ -1361,14 +1323,14 @@
 // track:             |a a a a|
 TEST_F(SourceBufferStreamTest, End_Overlap_Selected_OverlappedByNew_2) {
   // Append 10 buffers at positions 5 through 14.
-  NewSegmentAppend(5, 10, &kDataA);
+  NewCodedFrameGroupAppend(5, 10, &kDataA);
 
   // Seek to position 5, then move to position 6.
   Seek(5);
   CheckExpectedBuffers(5, 5, &kDataA);
 
   // Now append 7 buffers at positions 0 through 6.
-  NewSegmentAppend(0, 7, &kDataB);
+  NewCodedFrameGroupAppend(0, 7, &kDataB);
 
   // Check expected ranges.
   CheckExpectedRanges("{ [0,6) [10,14) }");
@@ -1399,14 +1361,14 @@
 // track:             |a a a a|
 TEST_F(SourceBufferStreamTest, End_Overlap_Selected_OverlappedByNew_3) {
   // Append 15 buffers at positions 5 through 19.
-  NewSegmentAppend(5, 15, &kDataA);
+  NewCodedFrameGroupAppend(5, 15, &kDataA);
 
   // Seek to position 5, then move to position 6.
   Seek(5);
   CheckExpectedBuffers(5, 5, &kDataA);
 
   // Now append 13 buffers at positions 0 through 12.
-  NewSegmentAppend(0, 13, &kDataB);
+  NewCodedFrameGroupAppend(0, 13, &kDataB);
 
   // Check expected ranges.
   CheckExpectedRanges("{ [0,12) [15,19) }");
@@ -1435,14 +1397,14 @@
 // track:             |a a a a|
 TEST_F(SourceBufferStreamTest, End_Overlap_Selected_NoKeyframeAfterNew) {
   // Append 5 buffers at positions 5 through 9.
-  NewSegmentAppend(5, 5, &kDataA);
+  NewCodedFrameGroupAppend(5, 5, &kDataA);
 
   // Seek to position 5, then move to position 6.
   Seek(5);
   CheckExpectedBuffers(5, 5, &kDataA);
 
   // Now append 6 buffers at positions 0 through 5.
-  NewSegmentAppend(0, 6, &kDataB);
+  NewCodedFrameGroupAppend(0, 6, &kDataB);
 
   // Check expected range.
   CheckExpectedRanges("{ [0,5) }");
@@ -1474,19 +1436,19 @@
   EXPECT_MEDIA_LOG(ContainsTrackBufferExhaustionSkipLog(133));
 
   // Append 7 buffers at positions 10 through 16.
-  NewSegmentAppend(10, 7, &kDataA);
+  NewCodedFrameGroupAppend(10, 7, &kDataA);
 
   // Seek to position 15, then move to position 16.
   Seek(15);
   CheckExpectedBuffers(15, 15, &kDataA);
 
   // Now append 11 buffers at positions 5 through 15.
-  NewSegmentAppend(5, 11, &kDataB);
+  NewCodedFrameGroupAppend(5, 11, &kDataB);
   CheckExpectedRanges("{ [5,15) }");
 
   // Now do another end-overlap to split the range into two parts, where the
   // 2nd range should have the next buffer position.
-  NewSegmentAppend(0, 6, &kDataA);
+  NewCodedFrameGroupAppend(0, 6, &kDataA);
   CheckExpectedRanges("{ [0,5) [10,15) }");
 
   // Check for data in the track buffer.
@@ -1497,7 +1459,7 @@
 
   // Add data to the 2nd range, should not be able to fulfill the next read
   // until we've added a keyframe.
-  NewSegmentAppend(15, 1, &kDataB);
+  NewCodedFrameGroupAppend(15, 1, &kDataB);
   CheckNoNextBuffer();
   for (int i = 16; i <= 19; i++) {
     AppendBuffers(i, 1, &kDataB);
@@ -1520,10 +1482,10 @@
 // track:             |a a a a|
 TEST_F(SourceBufferStreamTest, End_Overlap_Selected_NoKeyframeAfterNew3) {
   // Append 5 buffers at positions 5 through 9.
-  NewSegmentAppend(5, 5, &kDataA);
+  NewCodedFrameGroupAppend(5, 5, &kDataA);
 
   // Append 5 buffers at positions 15 through 19.
-  NewSegmentAppend(15, 5, &kDataA);
+  NewCodedFrameGroupAppend(15, 5, &kDataA);
 
   // Check expected range.
   CheckExpectedRanges("{ [5,9) [15,19) }");
@@ -1533,7 +1495,7 @@
   CheckExpectedBuffers(5, 5, &kDataA);
 
   // Now append 6 buffers at positions 0 through 5.
-  NewSegmentAppend(0, 6, &kDataB);
+  NewCodedFrameGroupAppend(0, 6, &kDataB);
 
   // Check expected range.
   CheckExpectedRanges("{ [0,5) [15,19) }");
@@ -1566,13 +1528,13 @@
 // after:  A a a a a*B*b b b b A a a a a
 TEST_F(SourceBufferStreamTest, Middle_Overlap_Selected_1) {
   // Append 15 buffers at positions 0 through 14.
-  NewSegmentAppend(0, 15, &kDataA);
+  NewCodedFrameGroupAppend(0, 15, &kDataA);
 
   // Seek to position 5.
   Seek(5);
 
   // Now append 5 buffers at positions 5 through 9.
-  NewSegmentAppend(5, 5, &kDataB);
+  NewCodedFrameGroupAppend(5, 5, &kDataB);
 
   // Check expected range.
   CheckExpectedRanges("{ [0,14) }");
@@ -1596,14 +1558,14 @@
 // after:  A a a a a B b b b b A*a*a a a
 TEST_F(SourceBufferStreamTest, Middle_Overlap_Selected_2) {
   // Append 15 buffers at positions 0 through 14.
-  NewSegmentAppend(0, 15, &kDataA);
+  NewCodedFrameGroupAppend(0, 15, &kDataA);
 
   // Seek to 10 then move to position 11.
   Seek(10);
   CheckExpectedBuffers(10, 10, &kDataA);
 
   // Now append 5 buffers at positions 5 through 9.
-  NewSegmentAppend(5, 5, &kDataB);
+  NewCodedFrameGroupAppend(5, 5, &kDataB);
 
   // Check expected range.
   CheckExpectedRanges("{ [0,14) }");
@@ -1625,14 +1587,14 @@
 // after:  A a*a*a a B b b|   |A a a a a
 TEST_F(SourceBufferStreamTest, Middle_Overlap_Selected_3) {
   // Append 15 buffers at positions 0 through 14.
-  NewSegmentAppend(0, 15, &kDataA);
+  NewCodedFrameGroupAppend(0, 15, &kDataA);
 
   // Seek to beginning then move to position 2.
   Seek(0);
   CheckExpectedBuffers(0, 1, &kDataA);
 
   // Now append 3 buffers at positions 5 through 7.
-  NewSegmentAppend(5, 3, &kDataB);
+  NewCodedFrameGroupAppend(5, 3, &kDataB);
 
   // Check expected range.
   CheckExpectedRanges("{ [0,7) [10,14) }");
@@ -1654,14 +1616,14 @@
 // track:                 |a a|
 TEST_F(SourceBufferStreamTest, Middle_Overlap_Selected_4) {
   // Append 15 buffers at positions 0 through 14.
-  NewSegmentAppend(0, 15, &kDataA);
+  NewCodedFrameGroupAppend(0, 15, &kDataA);
 
   // Seek to 5 then move to position 8.
   Seek(5);
   CheckExpectedBuffers(5, 7, &kDataA);
 
   // Now append 3 buffers at positions 5 through 7.
-  NewSegmentAppend(5, 3, &kDataB);
+  NewCodedFrameGroupAppend(5, 3, &kDataB);
 
   // Check expected range.
   CheckExpectedRanges("{ [0,7) [10,14) }");
@@ -1681,14 +1643,14 @@
 
 TEST_F(SourceBufferStreamTest, Overlap_OneByOne) {
   // Append 5 buffers starting at 10ms, 30ms apart.
-  NewSegmentAppendOneByOne("10K 40 70 100 130");
+  NewCodedFrameGroupAppendOneByOne("10K 40 70 100 130");
 
   // The range ends at 160, accounting for the last buffer's duration.
   CheckExpectedRangesByTimestamp("{ [10,160) }");
 
   // Overlap with 10 buffers starting at the beginning, appended one at a
   // time.
-  NewSegmentAppend(0, 1, &kDataB);
+  NewCodedFrameGroupAppend(0, 1, &kDataB);
   for (int i = 1; i < 10; i++)
     AppendBuffers(i, 1, &kDataB);
 
@@ -1699,14 +1661,14 @@
 }
 
 TEST_F(SourceBufferStreamTest, Overlap_OneByOne_DeleteGroup) {
-  NewSegmentAppendOneByOne("10K 40 70 100 130K");
+  NewCodedFrameGroupAppendOneByOne("10K 40 70 100 130K");
   CheckExpectedRangesByTimestamp("{ [10,160) }");
 
   // Seek to 130ms.
   SeekToTimestampMs(130);
 
-  // Overlap with a new segment from 0 to 130ms.
-  NewSegmentAppendOneByOne("0K 120D10");
+  // Overlap with a new coded frame group from 0 to 130ms.
+  NewCodedFrameGroupAppendOneByOne("0K 120D10");
 
   // Next buffer should still be 130ms.
   CheckExpectedBuffers("130K");
@@ -1716,15 +1678,16 @@
   CheckExpectedBuffers("0K 120 130K");
 }
 
-TEST_F(SourceBufferStreamTest, Overlap_OneByOne_BetweenMediaSegments) {
+TEST_F(SourceBufferStreamTest, Overlap_OneByOne_BetweenCodedFrameGroups) {
   // Append 5 buffers starting at 110ms, 30ms apart.
-  NewSegmentAppendOneByOne("110K 140 170 200 230");
+  NewCodedFrameGroupAppendOneByOne("110K 140 170 200 230");
   CheckExpectedRangesByTimestamp("{ [110,260) }");
 
-  // Now append 2 media segments from 0ms to 210ms, 30ms apart. Note that the
-  // old keyframe 110ms falls in between these two segments.
-  NewSegmentAppendOneByOne("0K 30 60 90");
-  NewSegmentAppendOneByOne("120K 150 180 210");
+  // Now append 2 coded frame groups from 0ms to 210ms, 30ms apart. Note that
+  // the
+  // old keyframe 110ms falls in between these two groups.
+  NewCodedFrameGroupAppendOneByOne("0K 30 60 90");
+  NewCodedFrameGroupAppendOneByOne("120K 150 180 210");
   CheckExpectedRangesByTimestamp("{ [0,240) }");
 
   // Check the final buffers is correct; the keyframe at 110ms should be
@@ -1739,15 +1702,15 @@
 TEST_F(SourceBufferStreamTest, Overlap_OneByOne_TrackBuffer) {
   EXPECT_MEDIA_LOG(ContainsTrackBufferExhaustionSkipLog(50));
 
-  NewSegmentAppendOneByOne("10K 40 70 100K 125 130D30K");
+  NewCodedFrameGroupAppendOneByOne("10K 40 70 100K 125 130D30K");
   CheckExpectedRangesByTimestamp("{ [10,160) }");
 
   // Seek to 70ms.
   SeekToTimestampMs(70);
   CheckExpectedBuffers("10K 40");
 
-  // Overlap with a new segment from 0 to 130ms.
-  NewSegmentAppendOneByOne("0K 30 60 90 120D10K");
+  // Overlap with a new coded frame group from 0 to 130ms.
+  NewCodedFrameGroupAppendOneByOne("0K 30 60 90 120D10K");
   CheckExpectedRangesByTimestamp("{ [0,160) }");
 
   // Should return frame 70ms from the track buffer, then switch
@@ -1771,20 +1734,21 @@
 TEST_F(SourceBufferStreamTest, Overlap_OneByOne_TrackBuffer2) {
   EXPECT_MEDIA_LOG(ContainsTrackBufferExhaustionSkipLog(40));
 
-  NewSegmentAppendOneByOne("10K 40 70 100K 125 130D30K");
+  NewCodedFrameGroupAppendOneByOne("10K 40 70 100K 125 130D30K");
   CheckExpectedRangesByTimestamp("{ [10,160) }");
 
   // Seek to 70ms.
   SeekToTimestampMs(70);
   CheckExpectedBuffers("10K 40");
 
-  // Overlap with a new segment from 0 to 120ms; 70ms and 100ms go in track
+  // Overlap with a new coded frame group from 0 to 120ms; 70ms and 100ms go in
+  // track
   // buffer.
-  NewSegmentAppendOneByOne("0K 30 60 90 120D10K");
+  NewCodedFrameGroupAppendOneByOne("0K 30 60 90 120D10K");
   CheckExpectedRangesByTimestamp("{ [0,160) }");
 
   // Now overlap the keyframe at 120ms.
-  NewSegmentAppendOneByOne("110K 130");
+  NewCodedFrameGroupAppendOneByOne("110K 130");
 
   // Should return frame 70ms from the track buffer. Then it should
   // return the keyframe after the track buffer, which is at 110ms.
@@ -1803,19 +1767,20 @@
 TEST_F(SourceBufferStreamTest, Overlap_OneByOne_TrackBuffer3) {
   EXPECT_MEDIA_LOG(ContainsTrackBufferExhaustionSkipLog(80));
 
-  NewSegmentAppendOneByOne("10K 40 70 100K 125 130D30K");
+  NewCodedFrameGroupAppendOneByOne("10K 40 70 100K 125 130D30K");
   CheckExpectedRangesByTimestamp("{ [10,160) }");
 
   // Seek to 70ms.
   SeekToTimestampMs(70);
   CheckExpectedBuffers("10K 40");
 
-  // Overlap with a new segment from 0 to 120ms; 70ms goes in track buffer.
-  NewSegmentAppendOneByOne("0K 30 60 90 120D10K");
+  // Overlap with a new coded frame group from 0 to 120ms; 70ms goes in track
+  // buffer.
+  NewCodedFrameGroupAppendOneByOne("0K 30 60 90 120D10K");
   CheckExpectedRangesByTimestamp("{ [0,160) }");
 
   // Now overlap the keyframe at 120ms and 130ms.
-  NewSegmentAppendOneByOne("50K 80 110 140");
+  NewCodedFrameGroupAppendOneByOne("50K 80 110 140");
   CheckExpectedRangesByTimestamp("{ [0,170) }");
 
   // Should have all the buffers from the track buffer, then stall.
@@ -1838,20 +1803,21 @@
 // after: 0K   30   60   *80K*  110   140
 // track:               70
 TEST_F(SourceBufferStreamTest, Overlap_OneByOne_TrackBuffer4) {
-  NewSegmentAppendOneByOne("10K 40 70 100K 125 130D30K");
+  NewCodedFrameGroupAppendOneByOne("10K 40 70 100K 125 130D30K");
   CheckExpectedRangesByTimestamp("{ [10,160) }");
 
   // Seek to 70ms.
   SeekToTimestampMs(70);
   CheckExpectedBuffers("10K 40");
 
-  // Overlap with a new segment from 0 to 120ms; 70ms and 100ms go in track
+  // Overlap with a new coded frame group from 0 to 120ms; 70ms and 100ms go in
+  // track
   // buffer.
-  NewSegmentAppendOneByOne("0K 30 60 90 120D10K");
+  NewCodedFrameGroupAppendOneByOne("0K 30 60 90 120D10K");
   CheckExpectedRangesByTimestamp("{ [0,160) }");
 
   // Now append a keyframe at 80ms.
-  NewSegmentAppendOneByOne("80K 110 140");
+  NewCodedFrameGroupAppendOneByOne("80K 110 140");
 
   CheckExpectedBuffers("70 80K 110 140");
   CheckNoNextBuffer();
@@ -1868,20 +1834,20 @@
 // after: 0K   30   60   *80K*  110   140
 // track:               70
 TEST_F(SourceBufferStreamTest, Overlap_OneByOne_TrackBuffer5) {
-  NewSegmentAppendOneByOne("10K 40 70 100K");
+  NewCodedFrameGroupAppendOneByOne("10K 40 70 100K");
   CheckExpectedRangesByTimestamp("{ [10,130) }");
 
   // Seek to 70ms.
   SeekToTimestampMs(70);
   CheckExpectedBuffers("10K 40");
 
-  // Overlap with a new segment from 0 to 120ms; 70ms goes in track
+  // Overlap with a new coded frame group from 0 to 120ms; 70ms goes in track
   // buffer.
-  NewSegmentAppendOneByOne("0K 30 60 90 120");
+  NewCodedFrameGroupAppendOneByOne("0K 30 60 90 120");
   CheckExpectedRangesByTimestamp("{ [0,150) }");
 
   // Now append a keyframe at 80ms.
-  NewSegmentAppendOneByOne("80K 110 140");
+  NewCodedFrameGroupAppendOneByOne("80K 110 140");
 
   CheckExpectedBuffers("70 80K 110 140");
   CheckNoNextBuffer();
@@ -1900,23 +1866,23 @@
 TEST_F(SourceBufferStreamTest, Overlap_OneByOne_TrackBuffer6) {
   EXPECT_MEDIA_LOG(ContainsTrackBufferExhaustionSkipLog(50));
 
-  NewSegmentAppendOneByOne("10K 40 70 100K 125 130D30K");
-  NewSegmentAppendOneByOne("200K 230");
+  NewCodedFrameGroupAppendOneByOne("10K 40 70 100K 125 130D30K");
+  NewCodedFrameGroupAppendOneByOne("200K 230");
   CheckExpectedRangesByTimestamp("{ [10,160) [200,260) }");
 
   // Seek to 70ms.
   SeekToTimestampMs(70);
   CheckExpectedBuffers("10K 40");
 
-  // Overlap with a new segment from 0 to 120ms.
-  NewSegmentAppendOneByOne("0K 30 60 90 120D10K");
+  // Overlap with a new coded frame group from 0 to 120ms.
+  NewCodedFrameGroupAppendOneByOne("0K 30 60 90 120D10K");
   CheckExpectedRangesByTimestamp("{ [0,160) [200,260) }");
 
   // Verify that 70 gets read out of the track buffer.
   CheckExpectedBuffers("70");
 
   // Append more data to the unselected range.
-  NewSegmentAppendOneByOne("260K 290");
+  NewCodedFrameGroupAppendOneByOne("260K 290");
   CheckExpectedRangesByTimestamp("{ [0,160) [200,320) }");
 
   CheckExpectedBuffers("120K 130K");
@@ -1930,7 +1896,7 @@
 
 TEST_F(SourceBufferStreamTest, Seek_Keyframe) {
   // Append 6 buffers at positions 0 through 5.
-  NewSegmentAppend(0, 6);
+  NewCodedFrameGroupAppend(0, 6);
 
   // Seek to beginning.
   Seek(0);
@@ -1939,7 +1905,7 @@
 
 TEST_F(SourceBufferStreamTest, Seek_NonKeyframe) {
   // Append 15 buffers at positions 0 through 14.
-  NewSegmentAppend(0, 15);
+  NewCodedFrameGroupAppend(0, 15);
 
   // Seek to buffer at position 13.
   Seek(13);
@@ -1962,7 +1928,7 @@
   CheckNoNextBuffer();
 
   // Append 2 buffers at positions 0.
-  NewSegmentAppend(0, 2);
+  NewCodedFrameGroupAppend(0, 2);
   Seek(0);
   CheckExpectedBuffers(0, 1);
 
@@ -1973,7 +1939,7 @@
 
 TEST_F(SourceBufferStreamTest, Seek_InBetweenTimestamps) {
   // Append 10 buffers at positions 0 through 9.
-  NewSegmentAppend(0, 10);
+  NewCodedFrameGroupAppend(0, 10);
 
   base::TimeDelta bump = frame_duration() / 4;
   CHECK(bump > base::TimeDelta());
@@ -1993,14 +1959,14 @@
 // response to the Seek().
 TEST_F(SourceBufferStreamTest, Seek_After_TrackBuffer_Filled) {
   // Append 10 buffers at positions 5 through 14.
-  NewSegmentAppend(5, 10, &kDataA);
+  NewCodedFrameGroupAppend(5, 10, &kDataA);
 
   // Seek to buffer at position 5 and get next buffer.
   Seek(5);
   CheckExpectedBuffers(5, 5, &kDataA);
 
   // Do a complete overlap by appending 20 buffers at positions 0 through 19.
-  NewSegmentAppend(0, 20, &kDataB);
+  NewCodedFrameGroupAppend(0, 20, &kDataB);
 
   // Check range is correct.
   CheckExpectedRanges("{ [0,19) }");
@@ -2013,14 +1979,14 @@
   CheckExpectedRanges("{ [0,19) }");
 }
 
-TEST_F(SourceBufferStreamTest, Seek_StartOfSegment) {
+TEST_F(SourceBufferStreamTest, Seek_StartOfGroup) {
   base::TimeDelta bump = frame_duration() / 4;
   CHECK(bump > base::TimeDelta());
 
-  // Append 5 buffers at position (5 + |bump|) through 9, where the media
-  // segment begins at position 5.
+  // Append 5 buffers at position (5 + |bump|) through 9, where the coded frame
+  // group begins at position 5.
   Seek(5);
-  NewSegmentAppend_OffsetFirstBuffer(5, 5, bump);
+  NewCodedFrameGroupAppend_OffsetFirstBuffer(5, 5, bump);
   scoped_refptr<StreamParserBuffer> buffer;
 
   // GetNextBuffer() should return the next buffer at position (5 + |bump|).
@@ -2034,9 +2000,9 @@
   // Seek to position 15.
   Seek(15);
 
-  // Append 5 buffers at positions (15 + |bump|) through 19, where the media
-  // segment begins at 15.
-  NewSegmentAppend_OffsetFirstBuffer(15, 5, bump);
+  // Append 5 buffers at positions (15 + |bump|) through 19, where the coded
+  // frame group begins at 15.
+  NewCodedFrameGroupAppend_OffsetFirstBuffer(15, 5, bump);
 
   // GetNextBuffer() should return the next buffer at position (15 + |bump|).
   EXPECT_EQ(stream_->GetNextBuffer(&buffer), SourceBufferStream::kSuccess);
@@ -2047,9 +2013,9 @@
   CheckExpectedBuffers(16, 19);
 }
 
-TEST_F(SourceBufferStreamTest, Seek_BeforeStartOfSegment) {
+TEST_F(SourceBufferStreamTest, Seek_BeforeStartOfGroup) {
   // Append 10 buffers at positions 5 through 14.
-  NewSegmentAppend(5, 10);
+  NewCodedFrameGroupAppend(5, 10);
 
   // Seek to a time before the first buffer in the range.
   Seek(0);
@@ -2060,18 +2026,18 @@
 
 TEST_F(SourceBufferStreamTest, OldSeekPoint_CompleteOverlap) {
   // Append 5 buffers at positions 0 through 4.
-  NewSegmentAppend(0, 4);
+  NewCodedFrameGroupAppend(0, 4);
 
   // Append 5 buffers at positions 10 through 14, and seek to the beginning of
   // this range.
-  NewSegmentAppend(10, 5);
+  NewCodedFrameGroupAppend(10, 5);
   Seek(10);
 
   // Now seek to the beginning of the first range.
   Seek(0);
 
   // Completely overlap the old seek point.
-  NewSegmentAppend(5, 15);
+  NewCodedFrameGroupAppend(5, 15);
 
   // The GetNextBuffer() call should respect the 2nd seek point.
   CheckExpectedBuffers(0, 0);
@@ -2079,18 +2045,18 @@
 
 TEST_F(SourceBufferStreamTest, OldSeekPoint_CompleteOverlap_Pending) {
   // Append 2 buffers at positions 0 through 1.
-  NewSegmentAppend(0, 2);
+  NewCodedFrameGroupAppend(0, 2);
 
   // Append 5 buffers at positions 15 through 19 and seek to beginning of the
   // range.
-  NewSegmentAppend(15, 5);
+  NewCodedFrameGroupAppend(15, 5);
   Seek(15);
 
   // Now seek position 5.
   Seek(5);
 
   // Completely overlap the old seek point.
-  NewSegmentAppend(10, 15);
+  NewCodedFrameGroupAppend(10, 15);
 
   // The seek at position 5 should still be pending.
   CheckNoNextBuffer();
@@ -2098,17 +2064,17 @@
 
 TEST_F(SourceBufferStreamTest, OldSeekPoint_MiddleOverlap) {
   // Append 2 buffers at positions 0 through 1.
-  NewSegmentAppend(0, 2);
+  NewCodedFrameGroupAppend(0, 2);
 
   // Append 15 buffers at positions 5 through 19 and seek to position 15.
-  NewSegmentAppend(5, 15);
+  NewCodedFrameGroupAppend(5, 15);
   Seek(15);
 
   // Now seek to the beginning of the stream.
   Seek(0);
 
   // Overlap the middle of the range such that there are now three ranges.
-  NewSegmentAppend(10, 3);
+  NewCodedFrameGroupAppend(10, 3);
   CheckExpectedRanges("{ [0,1) [5,12) [15,19) }");
 
   // The GetNextBuffer() call should respect the 2nd seek point.
@@ -2117,17 +2083,17 @@
 
 TEST_F(SourceBufferStreamTest, OldSeekPoint_MiddleOverlap_Pending) {
   // Append 2 buffers at positions 0 through 1.
-  NewSegmentAppend(0, 2);
+  NewCodedFrameGroupAppend(0, 2);
 
   // Append 15 buffers at positions 10 through 24 and seek to position 20.
-  NewSegmentAppend(10, 15);
+  NewCodedFrameGroupAppend(10, 15);
   Seek(20);
 
   // Now seek to position 5.
   Seek(5);
 
   // Overlap the middle of the range such that it is now split into two ranges.
-  NewSegmentAppend(15, 3);
+  NewCodedFrameGroupAppend(15, 3);
   CheckExpectedRanges("{ [0,1) [10,17) [20,24) }");
 
   // The seek at position 5 should still be pending.
@@ -2136,17 +2102,17 @@
 
 TEST_F(SourceBufferStreamTest, OldSeekPoint_StartOverlap) {
   // Append 2 buffers at positions 0 through 1.
-  NewSegmentAppend(0, 2);
+  NewCodedFrameGroupAppend(0, 2);
 
   // Append 15 buffers at positions 5 through 19 and seek to position 15.
-  NewSegmentAppend(5, 15);
+  NewCodedFrameGroupAppend(5, 15);
   Seek(15);
 
   // Now seek to the beginning of the stream.
   Seek(0);
 
   // Start overlap the old seek point.
-  NewSegmentAppend(10, 10);
+  NewCodedFrameGroupAppend(10, 10);
 
   // The GetNextBuffer() call should respect the 2nd seek point.
   CheckExpectedBuffers(0, 0);
@@ -2154,17 +2120,17 @@
 
 TEST_F(SourceBufferStreamTest, OldSeekPoint_StartOverlap_Pending) {
   // Append 2 buffers at positions 0 through 1.
-  NewSegmentAppend(0, 2);
+  NewCodedFrameGroupAppend(0, 2);
 
   // Append 15 buffers at positions 10 through 24 and seek to position 20.
-  NewSegmentAppend(10, 15);
+  NewCodedFrameGroupAppend(10, 15);
   Seek(20);
 
   // Now seek to position 5.
   Seek(5);
 
   // Start overlap the old seek point.
-  NewSegmentAppend(15, 10);
+  NewCodedFrameGroupAppend(15, 10);
 
   // The seek at time 0 should still be pending.
   CheckNoNextBuffer();
@@ -2172,17 +2138,17 @@
 
 TEST_F(SourceBufferStreamTest, OldSeekPoint_EndOverlap) {
   // Append 5 buffers at positions 0 through 4.
-  NewSegmentAppend(0, 4);
+  NewCodedFrameGroupAppend(0, 4);
 
   // Append 15 buffers at positions 10 through 24 and seek to start of range.
-  NewSegmentAppend(10, 15);
+  NewCodedFrameGroupAppend(10, 15);
   Seek(10);
 
   // Now seek to the beginning of the stream.
   Seek(0);
 
   // End overlap the old seek point.
-  NewSegmentAppend(5, 10);
+  NewCodedFrameGroupAppend(5, 10);
 
   // The GetNextBuffer() call should respect the 2nd seek point.
   CheckExpectedBuffers(0, 0);
@@ -2190,17 +2156,17 @@
 
 TEST_F(SourceBufferStreamTest, OldSeekPoint_EndOverlap_Pending) {
   // Append 2 buffers at positions 0 through 1.
-  NewSegmentAppend(0, 2);
+  NewCodedFrameGroupAppend(0, 2);
 
   // Append 15 buffers at positions 15 through 29 and seek to start of range.
-  NewSegmentAppend(15, 15);
+  NewCodedFrameGroupAppend(15, 15);
   Seek(15);
 
   // Now seek to position 5
   Seek(5);
 
   // End overlap the old seek point.
-  NewSegmentAppend(10, 10);
+  NewCodedFrameGroupAppend(10, 10);
 
   // The seek at time 0 should still be pending.
   CheckNoNextBuffer();
@@ -2208,13 +2174,13 @@
 
 TEST_F(SourceBufferStreamTest, GetNextBuffer_AfterMerges) {
   // Append 5 buffers at positions 10 through 14.
-  NewSegmentAppend(10, 5);
+  NewCodedFrameGroupAppend(10, 5);
 
   // Seek to buffer at position 12.
   Seek(12);
 
   // Append 5 buffers at positions 5 through 9.
-  NewSegmentAppend(5, 5);
+  NewCodedFrameGroupAppend(5, 5);
 
   // Make sure ranges are merged.
   CheckExpectedRanges("{ [5,14) }");
@@ -2223,7 +2189,7 @@
   CheckExpectedBuffers(10, 10);
 
   // Append 5 buffers at positions 15 through 19.
-  NewSegmentAppend(15, 5);
+  NewCodedFrameGroupAppend(15, 5);
   CheckExpectedRanges("{ [5,19) }");
 
   // Make sure the remaining next buffers are correct.
@@ -2232,7 +2198,7 @@
 
 TEST_F(SourceBufferStreamTest, GetNextBuffer_ExhaustThenAppend) {
   // Append 4 buffers at positions 0 through 3.
-  NewSegmentAppend(0, 4);
+  NewCodedFrameGroupAppend(0, 4);
 
   // Seek to buffer at position 0 and get all buffers.
   Seek(0);
@@ -2250,7 +2216,7 @@
 // buffer is not buffered.
 TEST_F(SourceBufferStreamTest, GetNextBuffer_ExhaustThenStartOverlap) {
   // Append 10 buffers at positions 0 through 9 and exhaust the buffers.
-  NewSegmentAppend(0, 10, &kDataA);
+  NewCodedFrameGroupAppend(0, 10, &kDataA);
   Seek(0);
   CheckExpectedBuffers(0, 9, &kDataA);
 
@@ -2260,7 +2226,7 @@
   // Append 6 buffers at positons 5 through 10. This is to test that doing a
   // start-overlap successfully fulfills the read at position 10, even though
   // position 10 was unbuffered.
-  NewSegmentAppend(5, 6, &kDataB);
+  NewCodedFrameGroupAppend(5, 6, &kDataB);
   CheckExpectedBuffers(10, 10, &kDataB);
 
   // Then add 5 buffers from positions 11 though 15.
@@ -2271,7 +2237,7 @@
   CheckExpectedBuffers(11, 14, &kDataB);
 
   // Replace the next buffer at position 15 with another start overlap.
-  NewSegmentAppend(15, 2, &kDataA);
+  NewCodedFrameGroupAppend(15, 2, &kDataA);
   CheckExpectedBuffers(15, 16, &kDataA);
 }
 
@@ -2280,18 +2246,18 @@
 // GetNextBuffer() skips to second GOP in the newly appended data instead
 // of returning two buffers with the same timestamp.
 TEST_F(SourceBufferStreamTest, GetNextBuffer_ExhaustThenStartOverlap2) {
-  NewSegmentAppend("0K 30 60 90 120");
+  NewCodedFrameGroupAppend("0K 30 60 90 120");
 
   Seek(0);
   CheckExpectedBuffers("0K 30 60 90 120");
   CheckNoNextBuffer();
 
   // Append a keyframe with the same timestamp as the last buffer output.
-  NewSegmentAppend("120D30K");
+  NewCodedFrameGroupAppend("120D30K");
   CheckNoNextBuffer();
 
-  // Append the rest of the segment and make sure that buffers are returned
-  // from the first GOP after 120.
+  // Append the rest of the coded frame group and make sure that buffers are
+  // returned from the first GOP after 120.
   AppendBuffers("150 180 210K 240");
   CheckExpectedBuffers("210K 240");
 
@@ -2305,7 +2271,7 @@
 // whose next buffer is not buffered.
 TEST_F(SourceBufferStreamTest, GetNextBuffer_ExhaustThenCompleteOverlap) {
   // Append 5 buffers at positions 10 through 14 and exhaust the buffers.
-  NewSegmentAppend(10, 5, &kDataA);
+  NewCodedFrameGroupAppend(10, 5, &kDataA);
   Seek(10);
   CheckExpectedBuffers(10, 14, &kDataA);
 
@@ -2314,7 +2280,7 @@
 
   // Do a complete overlap and test that this successfully fulfills the read
   // at position 15.
-  NewSegmentAppend(5, 11, &kDataB);
+  NewCodedFrameGroupAppend(5, 11, &kDataB);
   CheckExpectedBuffers(15, 15, &kDataB);
 
   // Then add 5 buffers from positions 16 though 20.
@@ -2325,7 +2291,7 @@
   CheckExpectedBuffers(16, 19, &kDataB);
 
   // Do a complete overlap and replace the buffer at position 20.
-  NewSegmentAppend(0, 21, &kDataA);
+  NewCodedFrameGroupAppend(0, 21, &kDataA);
   CheckExpectedBuffers(20, 20, &kDataA);
 }
 
@@ -2333,7 +2299,7 @@
 // buffer, then an end-overlap causes the end of the range to be deleted.
 TEST_F(SourceBufferStreamTest, GetNextBuffer_ExhaustThenEndOverlap) {
   // Append 5 buffers at positions 10 through 14 and exhaust the buffers.
-  NewSegmentAppend(10, 5, &kDataA);
+  NewCodedFrameGroupAppend(10, 5, &kDataA);
   Seek(10);
   CheckExpectedBuffers(10, 14, &kDataA);
   CheckExpectedRanges("{ [10,14) }");
@@ -2342,7 +2308,7 @@
   CheckNoNextBuffer();
 
   // Do an end overlap that causes the latter half of the range to be deleted.
-  NewSegmentAppend(5, 6, &kDataB);
+  NewCodedFrameGroupAppend(5, 6, &kDataB);
   CheckNoNextBuffer();
   CheckExpectedRanges("{ [5,10) }");
 
@@ -2365,14 +2331,14 @@
 // "next buffer" position.
 TEST_F(SourceBufferStreamTest, GetNextBuffer_Overlap_Selected_Complete) {
   // Append 5 buffers at positions 5 through 9.
-  NewSegmentAppend(5, 5, &kDataA);
+  NewCodedFrameGroupAppend(5, 5, &kDataA);
 
   // Seek to buffer at position 5 and get next buffer.
   Seek(5);
   CheckExpectedBuffers(5, 5, &kDataA);
 
   // Replace existing data with new data.
-  NewSegmentAppend(5, 5, &kDataB);
+  NewCodedFrameGroupAppend(5, 5, &kDataB);
 
   // Expect old data up until next keyframe in new data.
   CheckExpectedBuffers(6, 9, &kDataA);
@@ -2388,7 +2354,7 @@
 
 TEST_F(SourceBufferStreamTest, PresentationTimestampIndependence) {
   // Append 20 buffers at position 0.
-  NewSegmentAppend(0, 20);
+  NewCodedFrameGroupAppend(0, 20);
   Seek(0);
 
   int last_keyframe_idx = -1;
@@ -2424,7 +2390,7 @@
   SetMemoryLimit(20);
 
   // Append 20 buffers at positions 0 through 19.
-  NewSegmentAppend(0, 1, &kDataA);
+  NewCodedFrameGroupAppend(0, 1, &kDataA);
   for (int i = 1; i < 20; i++)
     AppendBuffers(i, 1, &kDataA);
 
@@ -2456,8 +2422,8 @@
   // Set memory limit to 15 buffers.
   SetMemoryLimit(15);
 
-  NewSegmentAppend("0K 10 20 30 40 50K 60 70 80 90");
-  NewSegmentAppend("1000K 1010 1020 1030 1040");
+  NewCodedFrameGroupAppend("0K 10 20 30 40 50K 60 70 80 90");
+  NewCodedFrameGroupAppend("1000K 1010 1020 1030 1040");
 
   // GC should be a no-op, since we are just under memory limit.
   EXPECT_TRUE(stream_->GarbageCollectIfNeeded(DecodeTimestamp(), 0));
@@ -2482,7 +2448,7 @@
   SetMemoryLimit(20);
 
   // Append 20 buffers at positions 0 through 19.
-  NewSegmentAppend(0, 20, &kDataA);
+  NewCodedFrameGroupAppend(0, 20, &kDataA);
 
   // Seek to position 10.
   Seek(10);
@@ -2505,11 +2471,11 @@
   SetMemoryLimit(5);
 
   // Append 5 buffers at positions 15 through 19.
-  NewSegmentAppend(15, 5, &kDataA);
+  NewCodedFrameGroupAppend(15, 5, &kDataA);
   EXPECT_TRUE(GarbageCollectWithPlaybackAtBuffer(0, 0));
 
   // Append 5 buffers at positions 0 through 4.
-  NewSegmentAppend(0, 5, &kDataA);
+  NewCodedFrameGroupAppend(0, 5, &kDataA);
   CheckExpectedRanges("{ [0,4) [15,19) }");
 
   // Seek to position 0.
@@ -2528,11 +2494,11 @@
   Seek(15);
 
   // Append 40 buffers at positions 0 through 39.
-  NewSegmentAppend(0, 40, &kDataA);
+  NewCodedFrameGroupAppend(0, 40, &kDataA);
   // GC will try to keep data between current playback position and last append
   // position. This will ensure that the last append position is 19 and will
   // allow GC algorithm to collect data outside of the range [15,19)
-  NewSegmentAppend(15, 5, &kDataA);
+  NewCodedFrameGroupAppend(15, 5, &kDataA);
   CheckExpectedRanges("{ [0,39) }");
 
   // Should leave the GOP containing the current playback position 15 and the
@@ -2545,16 +2511,16 @@
 
 TEST_F(SourceBufferStreamTest, GarbageCollection_DeleteSeveralRanges) {
   // Append 5 buffers at positions 0 through 4.
-  NewSegmentAppend(0, 5);
+  NewCodedFrameGroupAppend(0, 5);
 
   // Append 5 buffers at positions 10 through 14.
-  NewSegmentAppend(10, 5);
+  NewCodedFrameGroupAppend(10, 5);
 
   // Append 5 buffers at positions 20 through 24.
-  NewSegmentAppend(20, 5);
+  NewCodedFrameGroupAppend(20, 5);
 
   // Append 5 buffers at positions 40 through 44.
-  NewSegmentAppend(40, 5);
+  NewCodedFrameGroupAppend(40, 5);
 
   CheckExpectedRanges("{ [0,4) [10,14) [20,24) [40,44) }");
 
@@ -2566,7 +2532,7 @@
   SetMemoryLimit(1);
 
   // Append 5 buffers at positions 30 through 34.
-  NewSegmentAppend(30, 5);
+  NewCodedFrameGroupAppend(30, 5);
 
   // We will have more than 1 buffer left, GC will fail
   EXPECT_FALSE(GarbageCollectWithPlaybackAtBuffer(20, 0));
@@ -2585,13 +2551,13 @@
 
   // Make sure appending before and after the ranges didn't somehow break.
   SetMemoryLimit(100);
-  NewSegmentAppend(0, 10);
+  NewCodedFrameGroupAppend(0, 10);
   EXPECT_TRUE(GarbageCollectWithPlaybackAtBuffer(20, 0));
   CheckExpectedRanges("{ [0,9) [20,24) [30,44) }");
   Seek(0);
   CheckExpectedBuffers(0, 9);
 
-  NewSegmentAppend(90, 10);
+  NewCodedFrameGroupAppend(90, 10);
   EXPECT_TRUE(GarbageCollectWithPlaybackAtBuffer(0, 0));
   CheckExpectedRanges("{ [0,9) [20,24) [30,44) [90,99) }");
   Seek(30);
@@ -2607,10 +2573,10 @@
   SetMemoryLimit(10);
 
   // Append 1 GOP starting at 310ms, 30ms apart.
-  NewSegmentAppend("310K 340 370");
+  NewCodedFrameGroupAppend("310K 340 370");
 
   // Append 2 GOPs starting at 490ms, 30ms apart.
-  NewSegmentAppend("490K 520 550 580K 610 640");
+  NewCodedFrameGroupAppend("490K 520 550 580K 610 640");
 
   EXPECT_TRUE(GarbageCollectWithPlaybackAtBuffer(0, 0));
 
@@ -2621,7 +2587,7 @@
 
   // Append 2 GOPs before the existing ranges.
   // So the ranges before GC are "{ [100,280) [310,400) [490,670) }".
-  NewSegmentAppend("100K 130 160 190K 220 250K");
+  NewCodedFrameGroupAppend("100K 130 160 190K 220 250K");
 
   EXPECT_TRUE(stream_->GarbageCollectIfNeeded(
       DecodeTimestamp::FromMilliseconds(580), 0));
@@ -2635,14 +2601,14 @@
   SetMemoryLimit(10);
 
   // Append 3 GOPs starting at 400ms, 30ms apart.
-  NewSegmentAppend("400K 430 460 490K 520 550 580K 610 640");
+  NewCodedFrameGroupAppend("400K 430 460 490K 520 550 580K 610 640");
 
   // Seek to the GOP at 580ms.
   SeekToTimestampMs(580);
 
   // Append 2 GOPs starting at 220ms, and they will be merged with the existing
   // range.  So the range before GC is "{ [220,670) }".
-  NewSegmentAppend("220K 250 280 310K 340 370");
+  NewCodedFrameGroupAppend("220K 250 280 310K 340 370");
 
   EXPECT_TRUE(stream_->GarbageCollectIfNeeded(
       DecodeTimestamp::FromMilliseconds(580), 0));
@@ -2656,7 +2622,7 @@
   SetMemoryLimit(20);
 
   // Append 25 buffers at positions 0 through 24.
-  NewSegmentAppend(0, 25, &kDataA);
+  NewCodedFrameGroupAppend(0, 25, &kDataA);
 
   // If playback is still in the first GOP (starting at 0), GC should fail.
   EXPECT_FALSE(GarbageCollectWithPlaybackAtBuffer(2, 0));
@@ -2673,10 +2639,10 @@
 
 TEST_F(SourceBufferStreamTest, GarbageCollection_PendingSeek) {
   // Append 10 buffers at positions 0 through 9.
-  NewSegmentAppend(0, 10, &kDataA);
+  NewCodedFrameGroupAppend(0, 10, &kDataA);
 
   // Append 5 buffers at positions 25 through 29.
-  NewSegmentAppend(25, 5, &kDataA);
+  NewCodedFrameGroupAppend(25, 5, &kDataA);
 
   // Seek to position 15.
   Seek(15);
@@ -2700,7 +2666,7 @@
 
   // Append data to fulfill seek.
   EXPECT_TRUE(GarbageCollectWithPlaybackAtBuffer(30, 5));
-  NewSegmentAppend(15, 5, &kDataA);
+  NewCodedFrameGroupAppend(15, 5, &kDataA);
 
   // Check to make sure all is well.
   CheckExpectedRanges("{ [15,19) [30,34) }");
@@ -2714,7 +2680,7 @@
   SetMemoryLimit(15);
 
   // Append 10 buffers at positions 0 through 9.
-  NewSegmentAppend(0, 10, &kDataA);
+  NewCodedFrameGroupAppend(0, 10, &kDataA);
 
   // Advance next buffer position to 10.
   Seek(0);
@@ -2723,7 +2689,7 @@
   CheckNoNextBuffer();
 
   // Append 20 buffers at positions 15 through 34.
-  NewSegmentAppend(15, 20, &kDataA);
+  NewCodedFrameGroupAppend(15, 20, &kDataA);
   CheckExpectedRanges("{ [0,9) [15,34) }");
 
   // GC should save the keyframe before the next buffer position and the data
@@ -2735,7 +2701,7 @@
 
   // Now fulfill the seek at position 10. This will make GC delete the data
   // before position 10 to keep it within cap.
-  NewSegmentAppend(10, 5, &kDataA);
+  NewCodedFrameGroupAppend(10, 5, &kDataA);
   EXPECT_TRUE(GarbageCollectWithPlaybackAtBuffer(10, 0));
   CheckExpectedRanges("{ [10,24) }");
   CheckExpectedBuffers(10, 24, &kDataA);
@@ -2751,7 +2717,7 @@
   Seek(15);
 
   // Append 18 buffers at positions 0 through 17.
-  NewSegmentAppend(0, 18, &kDataA);
+  NewCodedFrameGroupAppend(0, 18, &kDataA);
 
   EXPECT_TRUE(GarbageCollectWithPlaybackAtBuffer(15, 0));
 
@@ -2762,7 +2728,7 @@
   CheckExpectedBuffers(15, 15, &kDataA);
 
   // Completely overlap the existing buffers.
-  NewSegmentAppend(0, 20, &kDataB);
+  NewCodedFrameGroupAppend(0, 20, &kDataB);
 
   // Final GOP [15,19) contains 5 buffers, which is more than memory limit of
   // 3 buffers set at the beginning of the test, so GC will fail.
@@ -2793,7 +2759,7 @@
   // Set memory limit to 30 buffers = 1 second of data.
   SetMemoryLimit(30);
   // And append 300 buffers = 10 seconds of data.
-  NewSegmentAppend(0, 300, &kDataA);
+  NewCodedFrameGroupAppend(0, 300, &kDataA);
   CheckExpectedRanges("{ [0,299) }");
 
   // Playback position at 0, all data must be preserved.
@@ -2851,7 +2817,7 @@
   // Set memory limit to 3 and make sure the 4-byte GOP is not garbage
   // collected.
   SetMemoryLimit(3);
-  NewSegmentAppend("0K 30 60 90");
+  NewCodedFrameGroupAppend("0K 30 60 90");
   EXPECT_FALSE(GarbageCollectWithPlaybackAtBuffer(0, 0));
   CheckExpectedRangesByTimestamp("{ [0,120) }");
 
@@ -2862,7 +2828,7 @@
   CheckExpectedRangesByTimestamp("{ [0,150) }");
 
   // Append a 2nd range after this without triggering GC.
-  NewSegmentAppend("200K 230 260 290K 320 350");
+  NewCodedFrameGroupAppend("200K 230 260 290K 320 350");
   CheckExpectedRangesByTimestamp("{ [0,150) [200,380) }");
 
   // Seek to 290ms.
@@ -2871,7 +2837,7 @@
   // Now append a GOP in a separate range after the selected range and trigger
   // GC. Because it is after 290ms, this tests that the GOP is saved when
   // deleting from the back.
-  NewSegmentAppend("500K 530 560 590");
+  NewCodedFrameGroupAppend("500K 530 560 590");
   EXPECT_FALSE(stream_->GarbageCollectIfNeeded(
       DecodeTimestamp::FromMilliseconds(290), 0));
 
@@ -2889,13 +2855,13 @@
 // non-selected range.
 TEST_F(SourceBufferStreamTest, GarbageCollection_SaveAppendGOP_Middle) {
   // Append 3 GOPs starting at 0ms, 30ms apart.
-  NewSegmentAppend("0K 30 60 90K 120 150 180K 210 240");
+  NewCodedFrameGroupAppend("0K 30 60 90K 120 150 180K 210 240");
   CheckExpectedRangesByTimestamp("{ [0,270) }");
 
   // Now set the memory limit to 1 and overlap the middle of the range with a
   // new GOP.
   SetMemoryLimit(1);
-  NewSegmentAppend("80K 110 140");
+  NewCodedFrameGroupAppend("80K 110 140");
 
   // This whole GOP should be saved after GC, which will fail due to GOP being
   // larger than 1 buffer
@@ -2909,7 +2875,7 @@
   CheckExpectedRangesByTimestamp("{ [80,200) }");
 
   // Append a 2nd range after this range, without triggering GC.
-  NewSegmentAppend("400K 430 460 490K 520 550 580K 610 640");
+  NewCodedFrameGroupAppend("400K 430 460 490K 520 550 580K 610 640");
   CheckExpectedRangesByTimestamp("{ [80,200) [400,670) }");
 
   // Seek to 80ms to make the first range the selected range.
@@ -2918,7 +2884,7 @@
   // Now append a GOP in the middle of the second range and trigger GC. Because
   // it is after the selected range, this tests that the GOP is saved when
   // deleting from the back.
-  NewSegmentAppend("500K 530 560 590");
+  NewCodedFrameGroupAppend("500K 530 560 590");
   EXPECT_FALSE(stream_->GarbageCollectIfNeeded(
       DecodeTimestamp::FromMilliseconds(80), 0));
 
@@ -2936,7 +2902,7 @@
 // adjacent to the last GOP appended.
 TEST_F(SourceBufferStreamTest, GarbageCollection_SaveAppendGOP_Selected1) {
   // Append 3 GOPs at 0ms, 90ms, and 180ms.
-  NewSegmentAppend("0K 30 60 90K 120 150 180K 210 240");
+  NewCodedFrameGroupAppend("0K 30 60 90K 120 150 180K 210 240");
   CheckExpectedRangesByTimestamp("{ [0,270) }");
 
   // Seek to the GOP at 90ms.
@@ -2944,7 +2910,7 @@
 
   // Set the memory limit to 1, then overlap the GOP at 0.
   SetMemoryLimit(1);
-  NewSegmentAppend("0K 30 60");
+  NewCodedFrameGroupAppend("0K 30 60");
 
   // GC should save the GOP at 0ms and 90ms, and will fail since GOP larger
   // than 1 buffer
@@ -2959,7 +2925,7 @@
 
   // Now seek back to 90ms and append a GOP at 180ms.
   SeekToTimestampMs(90);
-  NewSegmentAppend("180K 210 240");
+  NewCodedFrameGroupAppend("180K 210 240");
 
   // Should save the GOP at 90ms and the GOP at 180ms.
   EXPECT_FALSE(stream_->GarbageCollectIfNeeded(
@@ -2974,7 +2940,7 @@
 // GOP containing the next buffer, but not directly adjacent to this GOP.
 TEST_F(SourceBufferStreamTest, GarbageCollection_SaveAppendGOP_Selected2) {
   // Append 4 GOPs starting at positions 0ms, 90ms, 180ms, 270ms.
-  NewSegmentAppend("0K 30 60 90K 120 150 180K 210 240 270K 300 330");
+  NewCodedFrameGroupAppend("0K 30 60 90K 120 150 180K 210 240 270K 300 330");
   CheckExpectedRangesByTimestamp("{ [0,360) }");
 
   // Seek to the last GOP at 270ms.
@@ -2982,7 +2948,7 @@
 
   // Set the memory limit to 1, then overlap the GOP at 90ms.
   SetMemoryLimit(1);
-  NewSegmentAppend("90K 120 150");
+  NewCodedFrameGroupAppend("90K 120 150");
 
   // GC will save data in the range where the most recent append has happened
   // [0; 180) and the range where the next read position is [270;360)
@@ -2991,12 +2957,12 @@
   CheckExpectedRangesByTimestamp("{ [0,180) [270,360) }");
 
   // Add 3 GOPs to the end of the selected range at 360ms, 450ms, and 540ms.
-  NewSegmentAppend("360K 390 420 450K 480 510 540K 570 600");
+  NewCodedFrameGroupAppend("360K 390 420 450K 480 510 540K 570 600");
   CheckExpectedRangesByTimestamp("{ [0,180) [270,630) }");
 
   // Overlap the GOP at 450ms and garbage collect to test deleting from the
   // back.
-  NewSegmentAppend("450K 480 510");
+  NewCodedFrameGroupAppend("450K 480 510");
   EXPECT_FALSE(stream_->GarbageCollectIfNeeded(
       DecodeTimestamp::FromMilliseconds(270), 0));
 
@@ -3011,13 +2977,13 @@
   SeekToTimestampMs(0);
 
   // Append 3 GOPs starting at 0ms, 90ms, 180ms.
-  NewSegmentAppend("0K 30 60 90K 120 150 180K 210 240");
+  NewCodedFrameGroupAppend("0K 30 60 90K 120 150 180K 210 240");
   CheckExpectedRangesByTimestamp("{ [0,270) }");
 
   // Set the memory limit to 1 then begin appending the start of a GOP starting
   // at 0ms.
   SetMemoryLimit(1);
-  NewSegmentAppend("0K 30");
+  NewCodedFrameGroupAppend("0K 30");
 
   // GC should save the newly appended GOP, which is also the next GOP that
   // will be returned from the seek request.
@@ -3047,7 +3013,7 @@
   SetMemoryLimit(10);
 
   // Append 5 buffers at positions 10 through 14 and exhaust the buffers.
-  NewSegmentAppend(10, 5, &kDataA);
+  NewCodedFrameGroupAppend(10, 5, &kDataA);
   Seek(10);
   CheckExpectedBuffers(10, 14, &kDataA);
   CheckExpectedRanges("{ [10,14) }");
@@ -3056,12 +3022,12 @@
   CheckNoNextBuffer();
 
   // Do an end overlap that causes the latter half of the range to be deleted.
-  NewSegmentAppend(5, 6, &kDataA);
+  NewCodedFrameGroupAppend(5, 6, &kDataA);
   CheckNoNextBuffer();
   CheckExpectedRanges("{ [5,10) }");
 
   // Append buffers from position 20 to 29. This should trigger GC.
-  NewSegmentAppend(20, 10, &kDataA);
+  NewCodedFrameGroupAppend(20, 10, &kDataA);
 
   // GC should keep the keyframe before the seek position 15, and the next 9
   // buffers closest to the seek position.
@@ -3069,7 +3035,7 @@
   CheckExpectedRanges("{ [10,10) [20,28) }");
 
   // Fulfill the seek by appending one buffer at 15.
-  NewSegmentAppend(15, 1, &kDataA);
+  NewCodedFrameGroupAppend(15, 1, &kDataA);
   CheckExpectedBuffers(15, 15, &kDataA);
   CheckExpectedRanges("{ [15,15) [20,28) }");
 }
@@ -3084,7 +3050,7 @@
 
   int buffers_appended = 0;
 
-  NewSegmentAppend(0, kBuffersToKeep);
+  NewCodedFrameGroupAppend(0, kBuffersToKeep);
   buffers_appended += kBuffersToKeep;
 
   const int kBuffersToAppend = 1000;
@@ -3100,7 +3066,7 @@
   SetMemoryLimit(10);
 
   // Append 12 buffers. The duration of the last buffer is 30
-  NewSegmentAppend("0K 30 60 90 120K 150 180 210K 240 270 300K 330D30");
+  NewCodedFrameGroupAppend("0K 30 60 90 120K 150 180 210K 240 270 300K 330D30");
   CheckExpectedRangesByTimestamp("{ [0,360) }");
 
   // Do a garbage collection with the media time higher than the timestamp of
@@ -3121,7 +3087,7 @@
   SetMemoryLimit(10);
 
   // Append 12 buffers.
-  NewSegmentAppend("0K 30 60 90 120K 150 180 210K 240 270 300K 330");
+  NewCodedFrameGroupAppend("0K 30 60 90 120K 150 180 210K 240 270 300K 330");
   CheckExpectedRangesByTimestamp("{ [0,360) }");
 
   // Seek in order to set the stream read position to 330 an ensure that the
@@ -3145,13 +3111,13 @@
 
 TEST_F(SourceBufferStreamTest, GetRemovalRange_BytesToFree) {
   // Append 2 GOPs starting at 300ms, 30ms apart.
-  NewSegmentAppend("300K 330 360 390K 420 450");
+  NewCodedFrameGroupAppend("300K 330 360 390K 420 450");
 
   // Append 2 GOPs starting at 600ms, 30ms apart.
-  NewSegmentAppend("600K 630 660 690K 720 750");
+  NewCodedFrameGroupAppend("600K 630 660 690K 720 750");
 
   // Append 2 GOPs starting at 900ms, 30ms apart.
-  NewSegmentAppend("900K 930 960 990K 1020 1050");
+  NewCodedFrameGroupAppend("900K 930 960 990K 1020 1050");
 
   CheckExpectedRangesByTimestamp("{ [300,480) [600,780) [900,1080) }");
 
@@ -3207,13 +3173,13 @@
 
 TEST_F(SourceBufferStreamTest, GetRemovalRange_Range) {
   // Append 2 GOPs starting at 300ms, 30ms apart.
-  NewSegmentAppend("300K 330 360 390K 420 450");
+  NewCodedFrameGroupAppend("300K 330 360 390K 420 450");
 
   // Append 2 GOPs starting at 600ms, 30ms apart.
-  NewSegmentAppend("600K 630 660 690K 720 750");
+  NewCodedFrameGroupAppend("600K 630 660 690K 720 750");
 
   // Append 2 GOPs starting at 900ms, 30ms apart.
-  NewSegmentAppend("900K 930 960 990K 1020 1050");
+  NewCodedFrameGroupAppend("900K 930 960 990K 1020 1050");
 
   CheckExpectedRangesByTimestamp("{ [300,480) [600,780) [900,1080) }");
 
@@ -3279,7 +3245,7 @@
   CheckVideoConfig(video_config_);
 
   // Append 5 buffers at positions 0 through 4
-  NewSegmentAppend(0, 5, &kDataA);
+  NewCodedFrameGroupAppend(0, 5, &kDataA);
 
   CheckVideoConfig(video_config_);
 
@@ -3291,7 +3257,7 @@
   CheckVideoConfig(video_config_);
 
   // Append 5 buffers at positions 5 through 9.
-  NewSegmentAppend(5, 5, &kDataB);
+  NewCodedFrameGroupAppend(5, 5, &kDataB);
 
   // Consume the buffers associated with the initial config.
   scoped_refptr<StreamParserBuffer> buffer;
@@ -3319,9 +3285,9 @@
   VideoDecoderConfig new_config = TestVideoConfig::Large();
 
   Seek(0);
-  NewSegmentAppend(0, 5, &kDataA);
+  NewCodedFrameGroupAppend(0, 5, &kDataA);
   stream_->UpdateVideoConfig(new_config);
-  NewSegmentAppend(5, 5, &kDataB);
+  NewCodedFrameGroupAppend(5, 5, &kDataB);
 
   // Seek to the start of the buffers with the new config and make sure a
   // config change is signalled.
@@ -3353,13 +3319,13 @@
 
 TEST_F(SourceBufferStreamTest, SetExplicitDuration) {
   // Append 2 buffers at positions 5 through 6.
-  NewSegmentAppend(5, 2);
+  NewCodedFrameGroupAppend(5, 2);
 
   // Append 2 buffers at positions 10 through 11.
-  NewSegmentAppend(10, 2);
+  NewCodedFrameGroupAppend(10, 2);
 
   // Append 2 buffers at positions 15 through 16.
-  NewSegmentAppend(15, 2);
+  NewCodedFrameGroupAppend(15, 2);
 
   // Check expected ranges.
   CheckExpectedRanges("{ [5,6) [10,11) [15,16) }");
@@ -3371,16 +3337,16 @@
   CheckExpectedRanges("{ [5,6) }");
 
   // Adding data past the previous duration should still work.
-  NewSegmentAppend(0, 20);
+  NewCodedFrameGroupAppend(0, 20);
   CheckExpectedRanges("{ [0,19) }");
 }
 
 TEST_F(SourceBufferStreamTest, SetExplicitDuration_EdgeCase) {
   // Append 10 buffers at positions 10 through 19.
-  NewSegmentAppend(10, 10);
+  NewCodedFrameGroupAppend(10, 10);
 
   // Append 5 buffers at positions 25 through 29.
-  NewSegmentAppend(25, 5);
+  NewCodedFrameGroupAppend(25, 5);
 
   // Check expected ranges.
   CheckExpectedRanges("{ [10,19) [25,29) }");
@@ -3394,13 +3360,13 @@
 
 TEST_F(SourceBufferStreamTest, SetExplicitDuration_DeletePartialRange) {
   // Append 5 buffers at positions 0 through 4.
-  NewSegmentAppend(0, 5);
+  NewCodedFrameGroupAppend(0, 5);
 
   // Append 10 buffers at positions 10 through 19.
-  NewSegmentAppend(10, 10);
+  NewCodedFrameGroupAppend(10, 10);
 
   // Append 5 buffers at positions 25 through 29.
-  NewSegmentAppend(25, 5);
+  NewCodedFrameGroupAppend(25, 5);
 
   // Check expected ranges.
   CheckExpectedRanges("{ [0,4) [10,19) [25,29) }");
@@ -3414,13 +3380,13 @@
 
 TEST_F(SourceBufferStreamTest, SetExplicitDuration_DeleteSelectedRange) {
   // Append 2 buffers at positions 5 through 6.
-  NewSegmentAppend(5, 2);
+  NewCodedFrameGroupAppend(5, 2);
 
   // Append 2 buffers at positions 10 through 11.
-  NewSegmentAppend(10, 2);
+  NewCodedFrameGroupAppend(10, 2);
 
   // Append 2 buffers at positions 15 through 16.
-  NewSegmentAppend(15, 2);
+  NewCodedFrameGroupAppend(15, 2);
 
   // Check expected ranges.
   CheckExpectedRanges("{ [5,6) [10,11) [15,16) }");
@@ -3440,17 +3406,17 @@
   // point, then the seek point is reset and the SourceBufferStream waits
   // for a new seek request. Therefore even if the data is re-appended, it
   // should not fulfill the old seek.)
-  NewSegmentAppend(0, 15);
+  NewCodedFrameGroupAppend(0, 15);
   CheckNoNextBuffer();
   CheckExpectedRanges("{ [0,14) }");
 }
 
 TEST_F(SourceBufferStreamTest, SetExplicitDuration_DeletePartialSelectedRange) {
   // Append 5 buffers at positions 0 through 4.
-  NewSegmentAppend(0, 5);
+  NewCodedFrameGroupAppend(0, 5);
 
   // Append 20 buffers at positions 10 through 29.
-  NewSegmentAppend(10, 20);
+  NewCodedFrameGroupAppend(10, 20);
 
   // Check expected ranges.
   CheckExpectedRanges("{ [0,4) [10,29) }");
@@ -3483,7 +3449,7 @@
   // Seek to start of stream.
   SeekToTimestampMs(0);
 
-  NewSegmentAppend("0K 30 60 90");
+  NewCodedFrameGroupAppend("0K 30 60 90");
 
   // Read out the first few buffers.
   CheckExpectedBuffers("0K 30");
@@ -3495,23 +3461,22 @@
   CheckNoNextBuffer();
 
   // We should be able to append new buffers at this point.
-  NewSegmentAppend("120K 150");
+  NewCodedFrameGroupAppend("120K 150");
 
   CheckExpectedRangesByTimestamp("{ [0,60) [120,180) }");
 }
 
 TEST_F(SourceBufferStreamTest,
-       SetExplicitDuration_AfterSegmentTimestampAndBeforeFirstBufferTimestamp) {
+       SetExplicitDuration_AfterGroupTimestampAndBeforeFirstBufferTimestamp) {
+  NewCodedFrameGroupAppend("0K 30K 60K");
 
-  NewSegmentAppend("0K 30K 60K");
-
-  // Append a segment with a start timestamp of 200, but the first
+  // Append a coded frame group with a start timestamp of 200, but the first
   // buffer starts at 230ms. This can happen in muxed content where the
   // audio starts before the first frame.
-  NewSegmentAppend(base::TimeDelta::FromMilliseconds(200),
-                   "230K 260K 290K 320K");
+  NewCodedFrameGroupAppend(base::TimeDelta::FromMilliseconds(200),
+                           "230K 260K 290K 320K");
 
-  NewSegmentAppend("400K 430K 460K");
+  NewCodedFrameGroupAppend("400K 430K 460K");
 
   CheckExpectedRangesByTimestamp("{ [0,90) [200,350) [400,490) }");
 
@@ -3523,7 +3488,7 @@
 
 TEST_F(SourceBufferStreamTest, SetExplicitDuration_MarkEOS) {
   // Append 1 buffer at positions 0 through 8.
-  NewSegmentAppend(0, 9);
+  NewCodedFrameGroupAppend(0, 9);
 
   // Check expected ranges.
   CheckExpectedRanges("{ [0,8) }");
@@ -3548,7 +3513,7 @@
 
 TEST_F(SourceBufferStreamTest, SetExplicitDuration_MarkEOS_IsSeekPending) {
   // Append 1 buffer at positions 0 through 8.
-  NewSegmentAppend(0, 9);
+  NewCodedFrameGroupAppend(0, 9);
 
   // Check expected ranges.
   CheckExpectedRanges("{ [0,8) }");
@@ -3577,7 +3542,7 @@
   // Seek to start of stream.
   SeekToTimestampMs(0);
 
-  NewSegmentAppend("0K 30 60 90 120K 150");
+  NewCodedFrameGroupAppend("0K 30 60 90 120K 150");
   CheckExpectedRangesByTimestamp("{ [0,180) }");
 
   // Read all the buffered data.
@@ -3586,11 +3551,11 @@
 
   // Append data over the current GOP so that a keyframe is needed before
   // playback can continue from the current position.
-  NewSegmentAppend("120K 150");
+  NewCodedFrameGroupAppend("120K 150");
   CheckExpectedRangesByTimestamp("{ [0,180) }");
 
   // Append buffers that cause the range to get split.
-  NewSegmentAppend("0K 30");
+  NewCodedFrameGroupAppend("0K 30");
   CheckExpectedRangesByTimestamp("{ [0,60) [120,180) }");
 
   // Append buffers that cause the ranges to get merged.
@@ -3602,7 +3567,7 @@
   CheckNoNextBuffer();
 
   // Add more data to the end and verify that this new data is read correctly.
-  NewSegmentAppend("180K 210");
+  NewCodedFrameGroupAppend("180K 210");
   CheckExpectedRangesByTimestamp("{ [0,240) }");
   CheckExpectedBuffers("180K 210");
 }
@@ -3611,7 +3576,7 @@
 // append are handled correctly.
 TEST_F(SourceBufferStreamTest, SameTimestamp_Video_SingleAppend) {
   Seek(0);
-  NewSegmentAppend("0K 30 30 60 90 120K 150");
+  NewCodedFrameGroupAppend("0K 30 30 60 90 120K 150");
   CheckExpectedBuffers("0K 30 30 60 90 120K 150");
 }
 
@@ -3619,62 +3584,64 @@
 // in different appends.
 TEST_F(SourceBufferStreamTest, SameTimestamp_Video_TwoAppends) {
   Seek(0);
-  NewSegmentAppend("0K 30");
+  NewCodedFrameGroupAppend("0K 30");
   AppendBuffers("30 60 90 120K 150");
   CheckExpectedBuffers("0K 30 30 60 90 120K 150");
 }
 
 // Verify that a non-keyframe followed by a keyframe with the same timestamp
-// is not allowed.
-TEST_F(SourceBufferStreamTest, SameTimestamp_Video_Invalid_1) {
+// is allowed, but also results in a MediaLog.
+TEST_F(SourceBufferStreamTest, SameTimestamp_Video_SingleAppend_Warning) {
   EXPECT_MEDIA_LOG(ContainsSameTimestampAt30MillisecondsLog());
 
   Seek(0);
-  NewSegmentAppend("0K 30");
-  AppendBuffers_ExpectFailure("30K 60");
+  NewCodedFrameGroupAppend("0K 30 30K 60");
+  CheckExpectedBuffers("0K 30 30K 60");
 }
 
-TEST_F(SourceBufferStreamTest, SameTimestamp_Video_Invalid_2) {
+TEST_F(SourceBufferStreamTest, SameTimestamp_Video_TwoAppends_Warning) {
   EXPECT_MEDIA_LOG(ContainsSameTimestampAt30MillisecondsLog());
 
   Seek(0);
-  NewSegmentAppend_ExpectFailure("0K 30 30K 60");
+  NewCodedFrameGroupAppend("0K 30");
+  AppendBuffers("30K 60");
+  CheckExpectedBuffers("0K 30 30K 60");
 }
 
 // Verify that a keyframe followed by a non-keyframe with the same timestamp
 // is allowed.
 TEST_F(SourceBufferStreamTest, SameTimestamp_VideoKeyFrame_TwoAppends) {
   Seek(0);
-  NewSegmentAppend("0K 30K");
+  NewCodedFrameGroupAppend("0K 30K");
   AppendBuffers("30 60");
   CheckExpectedBuffers("0K 30K 30 60");
 }
 
 TEST_F(SourceBufferStreamTest, SameTimestamp_VideoKeyFrame_SingleAppend) {
   Seek(0);
-  NewSegmentAppend("0K 30K 30 60");
+  NewCodedFrameGroupAppend("0K 30K 30 60");
   CheckExpectedBuffers("0K 30K 30 60");
 }
 
 TEST_F(SourceBufferStreamTest, SameTimestamp_Video_Overlap_1) {
   Seek(0);
-  NewSegmentAppend("0K 30 60 60 90 120K 150");
+  NewCodedFrameGroupAppend("0K 30 60 60 90 120K 150");
 
-  NewSegmentAppend("60K 91 121K 151");
+  NewCodedFrameGroupAppend("60K 91 121K 151");
   CheckExpectedBuffers("0K 30 60K 91 121K 151");
 }
 
 TEST_F(SourceBufferStreamTest, SameTimestamp_Video_Overlap_2) {
   Seek(0);
-  NewSegmentAppend("0K 30 60 60 90 120K 150");
-  NewSegmentAppend("0K 30 61");
+  NewCodedFrameGroupAppend("0K 30 60 60 90 120K 150");
+  NewCodedFrameGroupAppend("0K 30 61");
   CheckExpectedBuffers("0K 30 61 120K 150");
 }
 
 TEST_F(SourceBufferStreamTest, SameTimestamp_Video_Overlap_3) {
   Seek(0);
-  NewSegmentAppend("0K 20 40 60 80 100K 101 102 103K");
-  NewSegmentAppend("0K 20 40 60 80 90");
+  NewCodedFrameGroupAppend("0K 20 40 60 80 100K 101 102 103K");
+  NewCodedFrameGroupAppend("0K 20 40 60 80 90");
   CheckExpectedBuffers("0K 20 40 60 80 90 100K 101 102 103K");
   AppendBuffers("90 110K 150");
   Seek(0);
@@ -3689,18 +3656,22 @@
                             44100, EmptyExtraData(), false);
   stream_.reset(new SourceBufferStream(config, media_log_, true));
   Seek(0);
-  NewSegmentAppend("0K 0K 30K 30 60 60");
+  NewCodedFrameGroupAppend("0K 0K 30K 30 60 60");
   CheckExpectedBuffers("0K 0K 30K 30 60 60");
 }
 
-TEST_F(SourceBufferStreamTest, SameTimestamp_Audio_Invalid_1) {
+TEST_F(SourceBufferStreamTest, SameTimestamp_Audio_SingleAppend_Warning) {
   EXPECT_MEDIA_LOG(ContainsSameTimestampAt30MillisecondsLog());
 
   AudioDecoderConfig config(kCodecMP3, kSampleFormatF32, CHANNEL_LAYOUT_STEREO,
                             44100, EmptyExtraData(), false);
   stream_.reset(new SourceBufferStream(config, media_log_, true));
   Seek(0);
-  NewSegmentAppend_ExpectFailure("0K 30 30K 60");
+
+  // Note, in reality, a non-keyframe audio frame is rare or perhaps not
+  // possible.
+  NewCodedFrameGroupAppend("0K 30 30K 60");
+  CheckExpectedBuffers("0K 30 30K 60");
 }
 
 // If seeking past any existing range and the seek is pending
@@ -3708,7 +3679,7 @@
 // the stream position can be considered as the end of stream.
 TEST_F(SourceBufferStreamTest, EndSelected_During_PendingSeek) {
   // Append 15 buffers at positions 0 through 14.
-  NewSegmentAppend(0, 15);
+  NewCodedFrameGroupAppend(0, 15);
 
   Seek(20);
   EXPECT_TRUE(stream_->IsSeekPending());
@@ -3722,8 +3693,8 @@
   // Append:
   // - 10 buffers at positions 0 through 9.
   // - 10 buffers at positions 30 through 39
-  NewSegmentAppend(0, 10);
-  NewSegmentAppend(30, 10);
+  NewCodedFrameGroupAppend(0, 10);
+  NewCodedFrameGroupAppend(30, 10);
 
   Seek(20);
   EXPECT_TRUE(stream_->IsSeekPending());
@@ -3735,7 +3706,7 @@
 // Removing exact start & end of a range.
 TEST_F(SourceBufferStreamTest, Remove_WholeRange1) {
   Seek(0);
-  NewSegmentAppend("10K 40 70K 100 130K");
+  NewCodedFrameGroupAppend("10K 40 70K 100 130K");
   CheckExpectedRangesByTimestamp("{ [10,160) }");
   RemoveInMs(10, 160, 160);
   CheckExpectedRangesByTimestamp("{ }");
@@ -3744,7 +3715,7 @@
 // Removal range starts before range and ends exactly at end.
 TEST_F(SourceBufferStreamTest, Remove_WholeRange2) {
   Seek(0);
-  NewSegmentAppend("10K 40 70K 100 130K");
+  NewCodedFrameGroupAppend("10K 40 70K 100 130K");
   CheckExpectedRangesByTimestamp("{ [10,160) }");
   RemoveInMs(0, 160, 160);
   CheckExpectedRangesByTimestamp("{ }");
@@ -3754,7 +3725,7 @@
 // range end.
 TEST_F(SourceBufferStreamTest, Remove_WholeRange3) {
   Seek(0);
-  NewSegmentAppend("10K 40 70K 100 130K");
+  NewCodedFrameGroupAppend("10K 40 70K 100 130K");
   CheckExpectedRangesByTimestamp("{ [10,160) }");
   RemoveInMs(10, 200, 200);
   CheckExpectedRangesByTimestamp("{ }");
@@ -3763,7 +3734,7 @@
 // Removal range starts before range start and ends after the range end.
 TEST_F(SourceBufferStreamTest, Remove_WholeRange4) {
   Seek(0);
-  NewSegmentAppend("10K 40 70K 100 130K");
+  NewCodedFrameGroupAppend("10K 40 70K 100 130K");
   CheckExpectedRangesByTimestamp("{ [10,160) }");
   RemoveInMs(0, 200, 200);
   CheckExpectedRangesByTimestamp("{ }");
@@ -3772,9 +3743,9 @@
 // Removes multiple ranges.
 TEST_F(SourceBufferStreamTest, Remove_WholeRange5) {
   Seek(0);
-  NewSegmentAppend("10K 40 70K 100 130K");
-  NewSegmentAppend("1000K 1030 1060K 1090 1120K");
-  NewSegmentAppend("2000K 2030 2060K 2090 2120K");
+  NewCodedFrameGroupAppend("10K 40 70K 100 130K");
+  NewCodedFrameGroupAppend("1000K 1030 1060K 1090 1120K");
+  NewCodedFrameGroupAppend("2000K 2030 2060K 2090 2120K");
   CheckExpectedRangesByTimestamp("{ [10,160) [1000,1150) [2000,2150) }");
   RemoveInMs(10, 3000, 3000);
   CheckExpectedRangesByTimestamp("{ }");
@@ -3783,9 +3754,9 @@
 // Verifies a [0-infinity) range removes everything.
 TEST_F(SourceBufferStreamTest, Remove_ZeroToInfinity) {
   Seek(0);
-  NewSegmentAppend("10K 40 70K 100 130K");
-  NewSegmentAppend("1000K 1030 1060K 1090 1120K");
-  NewSegmentAppend("2000K 2030 2060K 2090 2120K");
+  NewCodedFrameGroupAppend("10K 40 70K 100 130K");
+  NewCodedFrameGroupAppend("1000K 1030 1060K 1090 1120K");
+  NewCodedFrameGroupAppend("2000K 2030 2060K 2090 2120K");
   CheckExpectedRangesByTimestamp("{ [10,160) [1000,1150) [2000,2150) }");
   Remove(base::TimeDelta(), kInfiniteDuration(), kInfiniteDuration());
   CheckExpectedRangesByTimestamp("{ }");
@@ -3795,8 +3766,8 @@
 // middle of the range. This test verifies that full GOPs are removed.
 TEST_F(SourceBufferStreamTest, Remove_Partial1) {
   Seek(0);
-  NewSegmentAppend("10K 40 70K 100 130K");
-  NewSegmentAppend("1000K 1030 1060K 1090 1120K");
+  NewCodedFrameGroupAppend("10K 40 70K 100 130K");
+  NewCodedFrameGroupAppend("1000K 1030 1060K 1090 1120K");
   CheckExpectedRangesByTimestamp("{ [10,160) [1000,1150) }");
   RemoveInMs(0, 80, 2200);
   CheckExpectedRangesByTimestamp("{ [130,160) [1000,1150) }");
@@ -3806,8 +3777,8 @@
 // end of the range.
 TEST_F(SourceBufferStreamTest, Remove_Partial2) {
   Seek(0);
-  NewSegmentAppend("10K 40 70K 100 130K");
-  NewSegmentAppend("1000K 1030 1060K 1090 1120K");
+  NewCodedFrameGroupAppend("10K 40 70K 100 130K");
+  NewCodedFrameGroupAppend("1000K 1030 1060K 1090 1120K");
   CheckExpectedRangesByTimestamp("{ [10,160) [1000,1150) }");
   RemoveInMs(40, 160, 2200);
   CheckExpectedRangesByTimestamp("{ [10,40) [1000,1150) }");
@@ -3816,8 +3787,8 @@
 // Removal range starts and ends within a range.
 TEST_F(SourceBufferStreamTest, Remove_Partial3) {
   Seek(0);
-  NewSegmentAppend("10K 40 70K 100 130K");
-  NewSegmentAppend("1000K 1030 1060K 1090 1120K");
+  NewCodedFrameGroupAppend("10K 40 70K 100 130K");
+  NewCodedFrameGroupAppend("1000K 1030 1060K 1090 1120K");
   CheckExpectedRangesByTimestamp("{ [10,160) [1000,1150) }");
   RemoveInMs(40, 120, 2200);
   CheckExpectedRangesByTimestamp("{ [10,40) [130,160) [1000,1150) }");
@@ -3827,9 +3798,9 @@
 // middle of another range.
 TEST_F(SourceBufferStreamTest, Remove_Partial4) {
   Seek(0);
-  NewSegmentAppend("10K 40 70K 100 130K");
-  NewSegmentAppend("1000K 1030 1060K 1090 1120K");
-  NewSegmentAppend("2000K 2030 2060K 2090 2120K");
+  NewCodedFrameGroupAppend("10K 40 70K 100 130K");
+  NewCodedFrameGroupAppend("1000K 1030 1060K 1090 1120K");
+  NewCodedFrameGroupAppend("2000K 2030 2060K 2090 2120K");
   CheckExpectedRangesByTimestamp("{ [10,160) [1000,1150) [2000,2150) }");
   RemoveInMs(40, 2030, 2200);
   CheckExpectedRangesByTimestamp("{ [10,40) [2060,2150) }");
@@ -3839,7 +3810,7 @@
 // are appended over the removal range.
 TEST_F(SourceBufferStreamTest, Remove_CurrentPosition) {
   Seek(0);
-  NewSegmentAppend("0K 30 60 90K 120 150 180K 210 240 270K 300 330");
+  NewCodedFrameGroupAppend("0K 30 60 90K 120 150 180K 210 240 270K 300 330");
   CheckExpectedRangesByTimestamp("{ [0,360) }");
   CheckExpectedBuffers("0K 30 60 90K 120");
 
@@ -3851,7 +3822,7 @@
   CheckNoNextBuffer();
 
   // Append some buffers to fill the gap that was created.
-  NewSegmentAppend("120K 150 180 210K 240");
+  NewCodedFrameGroupAppend("120K 150 180 210K 240");
   CheckExpectedRangesByTimestamp("{ [0,360) }");
 
   // Verify that buffers resume at the next keyframe after the
@@ -3863,7 +3834,7 @@
 // are removed.
 TEST_F(SourceBufferStreamTest, Remove_BeforeCurrentPosition) {
   Seek(0);
-  NewSegmentAppend("0K 30 60 90K 120 150 180K 210 240 270K 300 330");
+  NewCodedFrameGroupAppend("0K 30 60 90K 120 150 180K 210 240 270K 300 330");
   CheckExpectedRangesByTimestamp("{ [0,360) }");
   CheckExpectedBuffers("0K 30 60 90K 120");
 
@@ -3874,14 +3845,14 @@
   CheckExpectedBuffers("150 180K 210 240 270K 300 330");
 }
 
-// Test removing the entire range for the current media segment
+// Test removing the entire range for the current coded frame group
 // being appended.
-TEST_F(SourceBufferStreamTest, Remove_MidSegment) {
+TEST_F(SourceBufferStreamTest, Remove_MidGroup) {
   Seek(0);
-  NewSegmentAppend("0K 30 60 90 120K 150 180 210");
+  NewCodedFrameGroupAppend("0K 30 60 90 120K 150 180 210");
   CheckExpectedRangesByTimestamp("{ [0,240) }");
 
-  NewSegmentAppend("0K 30");
+  NewCodedFrameGroupAppend("0K 30");
 
   CheckExpectedBuffers("0K");
 
@@ -3907,7 +3878,6 @@
   // Verify that new GOP replaces the existing range.
   CheckExpectedRangesByTimestamp("{ [150,210) }");
 
-
   SeekToTimestampMs(150);
   CheckExpectedBuffers("150K 180");
   CheckNoNextBuffer();
@@ -3917,7 +3887,7 @@
 // the entire range the GOP belongs to.
 TEST_F(SourceBufferStreamTest, Remove_GOPBeingAppended) {
   Seek(0);
-  NewSegmentAppend("0K 30 60 90 120K 150 180");
+  NewCodedFrameGroupAppend("0K 30 60 90 120K 150 180");
   CheckExpectedRangesByTimestamp("{ [0,210) }");
 
   // Remove the current GOP being appended.
@@ -3941,7 +3911,7 @@
 
 TEST_F(SourceBufferStreamTest, Remove_WholeGOPBeingAppended) {
   SeekToTimestampMs(1000);
-  NewSegmentAppend("1000K 1030 1060 1090");
+  NewCodedFrameGroupAppend("1000K 1030 1060 1090");
   CheckExpectedRangesByTimestamp("{ [1000,1120) }");
 
   // Remove the keyframe of the current GOP being appended.
@@ -3970,11 +3940,11 @@
        Remove_PreviousAppendDestroyedAndOverwriteExistingRange) {
   SeekToTimestampMs(90);
 
-  NewSegmentAppend("90K 120 150");
+  NewCodedFrameGroupAppend("90K 120 150");
   CheckExpectedRangesByTimestamp("{ [90,180) }");
 
-  // Append a segment before the previously appended data.
-  NewSegmentAppend("0K 30 60");
+  // Append a coded frame group before the previously appended data.
+  NewCodedFrameGroupAppend("0K 30 60");
 
   // Verify that the ranges get merged.
   CheckExpectedRangesByTimestamp("{ [0,180) }");
@@ -3983,19 +3953,19 @@
   RemoveInMs(0, 90, 360);
   CheckExpectedRangesByTimestamp("{ [90,180) }");
 
-  // Append a new segment that follows the removed segment and
+  // Append a new coded frame group that follows the removed group and
   // starts at the beginning of the range left over from the
   // remove.
-  NewSegmentAppend("90K 121 151");
+  NewCodedFrameGroupAppend("90K 121 151");
   CheckExpectedBuffers("90K 121 151");
 }
 
-TEST_F(SourceBufferStreamTest, Remove_GapAtBeginningOfMediaSegment) {
+TEST_F(SourceBufferStreamTest, Remove_GapAtBeginningOfGroup) {
   Seek(0);
 
-  // Append a media segment that has a gap at the beginning of it.
-  NewSegmentAppend(base::TimeDelta::FromMilliseconds(0),
-                   "30K 60 90 120K 150");
+  // Append a coded frame group that has a gap at the beginning of it.
+  NewCodedFrameGroupAppend(base::TimeDelta::FromMilliseconds(0),
+                           "30K 60 90 120K 150");
   CheckExpectedRangesByTimestamp("{ [0,180) }");
 
   // Remove the gap that doesn't contain any buffers.
@@ -4022,7 +3992,7 @@
 
 TEST_F(SourceBufferStreamTest, Text_Append_SingleRange) {
   SetTextStream();
-  NewSegmentAppend("0K 500K 1000K");
+  NewCodedFrameGroupAppend("0K 500K 1000K");
   CheckExpectedRangesByTimestamp("{ [0,1500) }");
 
   Seek(0);
@@ -4031,9 +4001,9 @@
 
 TEST_F(SourceBufferStreamTest, Text_Append_DisjointAfter) {
   SetTextStream();
-  NewSegmentAppend("0K 500K 1000K");
+  NewCodedFrameGroupAppend("0K 500K 1000K");
   CheckExpectedRangesByTimestamp("{ [0,1500) }");
-  NewSegmentAppend("3000K 3500K 4000K");
+  NewCodedFrameGroupAppend("3000K 3500K 4000K");
   CheckExpectedRangesByTimestamp("{ [0,4500) }");
 
   Seek(0);
@@ -4042,9 +4012,9 @@
 
 TEST_F(SourceBufferStreamTest, Text_Append_DisjointBefore) {
   SetTextStream();
-  NewSegmentAppend("3000K 3500K 4000K");
+  NewCodedFrameGroupAppend("3000K 3500K 4000K");
   CheckExpectedRangesByTimestamp("{ [3000,4500) }");
-  NewSegmentAppend("0K 500K 1000K");
+  NewCodedFrameGroupAppend("0K 500K 1000K");
   CheckExpectedRangesByTimestamp("{ [0,4500) }");
 
   Seek(0);
@@ -4053,10 +4023,11 @@
 
 TEST_F(SourceBufferStreamTest, Text_CompleteOverlap) {
   SetTextStream();
-  NewSegmentAppend("3000K 3500K 4000K");
+  NewCodedFrameGroupAppend("3000K 3500K 4000K");
   CheckExpectedRangesByTimestamp("{ [3000,4500) }");
-  NewSegmentAppend("0K 501K 1001K 1501K 2001K 2501K "
-                   "3001K 3501K 4001K 4501K 5001K");
+  NewCodedFrameGroupAppend(
+      "0K 501K 1001K 1501K 2001K 2501K "
+      "3001K 3501K 4001K 4501K 5001K");
   CheckExpectedRangesByTimestamp("{ [0,5501) }");
 
   Seek(0);
@@ -4066,9 +4037,9 @@
 
 TEST_F(SourceBufferStreamTest, Text_OverlapAfter) {
   SetTextStream();
-  NewSegmentAppend("0K 500K 1000K 1500K 2000K");
+  NewCodedFrameGroupAppend("0K 500K 1000K 1500K 2000K");
   CheckExpectedRangesByTimestamp("{ [0,2500) }");
-  NewSegmentAppend("1499K 2001K 2501K 3001K");
+  NewCodedFrameGroupAppend("1499K 2001K 2501K 3001K");
   CheckExpectedRangesByTimestamp("{ [0,3501) }");
 
   Seek(0);
@@ -4077,9 +4048,9 @@
 
 TEST_F(SourceBufferStreamTest, Text_OverlapBefore) {
   SetTextStream();
-  NewSegmentAppend("1500K 2000K 2500K 3000K 3500K");
+  NewCodedFrameGroupAppend("1500K 2000K 2500K 3000K 3500K");
   CheckExpectedRangesByTimestamp("{ [1500,4000) }");
-  NewSegmentAppend("0K 501K 1001K 1501K 2001K");
+  NewCodedFrameGroupAppend("0K 501K 1001K 1501K 2001K");
   CheckExpectedRangesByTimestamp("{ [0,4000) }");
 
   Seek(0);
@@ -4088,14 +4059,14 @@
 
 TEST_F(SourceBufferStreamTest, SpliceFrame_Basic) {
   Seek(0);
-  NewSegmentAppend("0K S(3K 6 9D3 10D5) 15 20 S(25K 30D5 35D5) 40");
+  NewCodedFrameGroupAppend("0K S(3K 6 9D3 10D5) 15 20 S(25K 30D5 35D5) 40");
   CheckExpectedBuffers("0K 3K 6 9 C 10 15 20 25K 30 C 35 40");
   CheckNoNextBuffer();
 }
 
 TEST_F(SourceBufferStreamTest, SpliceFrame_SeekClearsSplice) {
   Seek(0);
-  NewSegmentAppend("0K S(3K 6 9D3 10D5) 15K 20");
+  NewCodedFrameGroupAppend("0K S(3K 6 9D3 10D5) 15K 20");
   CheckExpectedBuffers("0K 3K 6");
 
   SeekToTimestampMs(15);
@@ -4105,11 +4076,11 @@
 
 TEST_F(SourceBufferStreamTest, SpliceFrame_SeekClearsSpliceFromTrackBuffer) {
   Seek(0);
-  NewSegmentAppend("0K 2K S(3K 6 9D3 10D5) 15K 20");
+  NewCodedFrameGroupAppend("0K 2K S(3K 6 9D3 10D5) 15K 20");
   CheckExpectedBuffers("0K 2K");
 
-  // Overlap the existing segment.
-  NewSegmentAppend("5K 15K 20");
+  // Overlap the existing coded frame group.
+  NewCodedFrameGroupAppend("5K 15K 20");
   CheckExpectedBuffers("3K 6");
 
   SeekToTimestampMs(15);
@@ -4127,7 +4098,7 @@
 
   Seek(0);
   CheckVideoConfig(video_config_);
-  NewSegmentAppend("0K S(3K 6C 9D3 10D5) 15");
+  NewCodedFrameGroupAppend("0K S(3K 6C 9D3 10D5) 15");
 
   CheckExpectedBuffers("0K 3K C");
   CheckVideoConfig(new_config);
@@ -4140,11 +4111,11 @@
 
 TEST_F(SourceBufferStreamTest, SpliceFrame_BasicFromTrackBuffer) {
   Seek(0);
-  NewSegmentAppend("0K 5K S(8K 9D1 10D10) 20");
+  NewCodedFrameGroupAppend("0K 5K S(8K 9D1 10D10) 20");
   CheckExpectedBuffers("0K 5K");
 
-  // Overlap the existing segment.
-  NewSegmentAppend("5K 20");
+  // Overlap the existing coded frame group.
+  NewCodedFrameGroupAppend("5K 20");
   CheckExpectedBuffers("8K 9 C 10 20");
   CheckNoNextBuffer();
 }
@@ -4160,11 +4131,11 @@
 
   Seek(0);
   CheckVideoConfig(video_config_);
-  NewSegmentAppend("0K 5K S(7K 8C 9D1 10D10) 20");
+  NewCodedFrameGroupAppend("0K 5K S(7K 8C 9D1 10D10) 20");
   CheckExpectedBuffers("0K 5K");
 
-  // Overlap the existing segment.
-  NewSegmentAppend("5K 20");
+  // Overlap the existing coded frame group.
+  NewCodedFrameGroupAppend("5K 20");
   CheckExpectedBuffers("7K C");
   CheckVideoConfig(new_config);
   CheckExpectedBuffers("8 9 C");
@@ -4179,8 +4150,8 @@
 
   SetAudioStream();
   Seek(0);
-  NewSegmentAppend("0K 2K 4K 6K 8K 10K 12K");
-  NewSegmentAppend("11K 13K 15K 17K");
+  NewCodedFrameGroupAppend("0K 2K 4K 6K 8K 10K 12K");
+  NewCodedFrameGroupAppend("11K 13K 15K 17K");
   CheckExpectedBuffers("0K 2K 4K 6K 8K 10K 12K C 11K 13K 15K 17K");
   CheckNoNextBuffer();
 }
@@ -4192,8 +4163,8 @@
 
   SetAudioStream();
   Seek(0);
-  NewSegmentAppend("0K 2K 4K 6K 8K 10K 12K");
-  NewSegmentAppend("10K 14K");
+  NewCodedFrameGroupAppend("0K 2K 4K 6K 8K 10K 12K");
+  NewCodedFrameGroupAppend("10K 14K");
   CheckExpectedBuffers("0K 2K 4K 6K 8K 10K 14K");
   CheckNoNextBuffer();
 }
@@ -4208,8 +4179,8 @@
 
   SetAudioStream();
   Seek(0);
-  NewSegmentAppend("0K 2K 4K 6K 8K 10K 12K");
-  NewSegmentAppend("11K 13K 15K 17K");
+  NewCodedFrameGroupAppend("0K 2K 4K 6K 8K 10K 12K");
+  NewCodedFrameGroupAppend("11K 13K 15K 17K");
 
   // Verify the splice was created.
   CheckExpectedBuffers("0K 2K 4K 6K 8K 10K 12K C 11K 13K 15K 17K");
@@ -4217,7 +4188,7 @@
   Seek(0);
 
   // Create a splice before the first splice which would include it.
-  NewSegmentAppend("9D2K");
+  NewCodedFrameGroupAppend("9D2K");
 
   // A splice on top of a splice should result in a discard of the original
   // splice and no new splice frame being generated.
@@ -4230,22 +4201,22 @@
 TEST_F(SourceBufferStreamTest, Audio_SpliceFrame_NoSplice) {
   SetAudioStream();
   Seek(0);
-  NewSegmentAppend("0K 2K 4K 6K 8K 10K");
-  NewSegmentAppend("12K 14K 16K 18K");
+  NewCodedFrameGroupAppend("0K 2K 4K 6K 8K 10K");
+  NewCodedFrameGroupAppend("12K 14K 16K 18K");
   CheckExpectedBuffers("0K 2K 4K 6K 8K 10K 12K 14K 16K 18K");
   CheckNoNextBuffer();
 }
 
-TEST_F(SourceBufferStreamTest, Audio_SpliceFrame_CorrectMediaSegmentStartTime) {
+TEST_F(SourceBufferStreamTest, Audio_SpliceFrame_CorrectGroupStartTime) {
   EXPECT_MEDIA_LOG(ContainsGeneratedSpliceLog(5000, 1000));
 
   SetAudioStream();
   Seek(0);
-  NewSegmentAppend("0K 2K 4K");
+  NewCodedFrameGroupAppend("0K 2K 4K");
   CheckExpectedRangesByTimestamp("{ [0,6) }");
-  NewSegmentAppend("6K 8K 10K");
+  NewCodedFrameGroupAppend("6K 8K 10K");
   CheckExpectedRangesByTimestamp("{ [0,12) }");
-  NewSegmentAppend("1K 4D2K");
+  NewCodedFrameGroupAppend("1K 4D2K");
   CheckExpectedRangesByTimestamp("{ [0,12) }");
   CheckExpectedBuffers("0K 2K 4K C 1K 4K 6K 8K 10K");
   CheckNoNextBuffer();
@@ -4263,9 +4234,9 @@
 
   Seek(0);
   CheckAudioConfig(audio_config_);
-  NewSegmentAppend("0K 2K 4K 6K");
+  NewCodedFrameGroupAppend("0K 2K 4K 6K");
   stream_->UpdateAudioConfig(new_config);
-  NewSegmentAppend("5K 8K 12K");
+  NewCodedFrameGroupAppend("5K 8K 12K");
   CheckExpectedBuffers("0K 2K 4K 6K C 5K 8K 12K");
   CheckAudioConfig(new_config);
   CheckNoNextBuffer();
@@ -4284,9 +4255,9 @@
   // 2ms this results in an overlap of 1ms between the ranges.  A splice frame
   // should not be generated since it requires at least 2 frames, or 2ms in this
   // case, of data to crossfade.
-  NewSegmentAppend("0D2K");
+  NewCodedFrameGroupAppend("0D2K");
   CheckExpectedRangesByTimestamp("{ [0,2) }");
-  NewSegmentAppend("1D2K");
+  NewCodedFrameGroupAppend("1D2K");
   CheckExpectedRangesByTimestamp("{ [0,3) }");
   CheckExpectedBuffers("0K 1K");
   CheckNoNextBuffer();
@@ -4307,19 +4278,19 @@
   Seek(0);
 
   // Append four buffers with a 0.5ms duration each.
-  NewSegmentAppend(0, 4);
+  NewCodedFrameGroupAppend(0, 4);
   CheckExpectedRangesByTimestamp("{ [0,2) }");
 
   // Overlap the range [0, 2) with [1.25, 2); this results in an overlap of
   // 0.75ms between the ranges.
-  NewSegmentAppend_OffsetFirstBuffer(2, 2,
-                                     base::TimeDelta::FromMillisecondsD(0.25));
+  NewCodedFrameGroupAppend_OffsetFirstBuffer(
+      2, 2, base::TimeDelta::FromMillisecondsD(0.25));
   CheckExpectedRangesByTimestamp("{ [0,2) }");
 
   // A splice frame should not be generated (indicated by the lack of a config
   // change in the expected buffer string) since it requires at least 1ms of
   // data to crossfade.
-  CheckExpectedBuffers("0K 0K 1K 1K 1K");
+  CheckExpectedBuffers("0K 0K 1K 1K");
   CheckNoNextBuffer();
 }
 
@@ -4328,22 +4299,22 @@
 
   SetAudioStream();
   Seek(0);
-  NewSegmentAppend("0K 2K 4K 6K 8K 10K 12K");
-  NewSegmentAppend("11P 13K 15K 17K");
+  NewCodedFrameGroupAppend("0K 2K 4K 6K 8K 10K 12K");
+  NewCodedFrameGroupAppend("11P 13K 15K 17K");
   CheckExpectedBuffers("0K 2K 4K 6K 8K 10K 12K C 11P 13K 15K 17K");
   CheckNoNextBuffer();
 }
 
 TEST_F(SourceBufferStreamTest, Audio_PrerollFrame) {
   Seek(0);
-  NewSegmentAppend("0K 3P 6K");
+  NewCodedFrameGroupAppend("0K 3P 6K");
   CheckExpectedBuffers("0K 3P 6K");
   CheckNoNextBuffer();
 }
 
 TEST_F(SourceBufferStreamTest, BFrames) {
   Seek(0);
-  NewSegmentAppend("0K 120|30 30|60 60|90 90|120");
+  NewCodedFrameGroupAppend("0K 120|30 30|60 60|90 90|120");
   CheckExpectedRangesByTimestamp("{ [0,150) }");
 
   CheckExpectedBuffers("0K 120|30 30|60 60|90 90|120");
@@ -4351,11 +4322,12 @@
 }
 
 TEST_F(SourceBufferStreamTest, RemoveShouldAlwaysExcludeEnd) {
-  NewSegmentAppend("10D2K 12D2 14D2");
+  NewCodedFrameGroupAppend("10D2K 12D2 14D2");
   CheckExpectedRangesByTimestamp("{ [10,16) }");
 
-  // Start new segment, appending KF to abut the start of previous segment.
-  NewSegmentAppend("0D10K");
+  // Start new coded frame group, appending KF to abut the start of previous
+  // group.
+  NewCodedFrameGroupAppend("0D10K");
   Seek(0);
   CheckExpectedRangesByTimestamp("{ [0,16) }");
   CheckExpectedBuffers("0K 10K 12 14");
@@ -4377,7 +4349,7 @@
 
 TEST_F(SourceBufferStreamTest, RefinedDurationEstimates_BackOverlap) {
   // Append a few buffers, the last one having estimated duration.
-  NewSegmentAppend("0K 5 10 20D10E");
+  NewCodedFrameGroupAppend("0K 5 10 20D10E");
   CheckExpectedRangesByTimestamp("{ [0,30) }");
   Seek(0);
   CheckExpectedBuffers("0K 5 10 20D10E");
@@ -4403,7 +4375,7 @@
 
 TEST_F(SourceBufferStreamTest, RefinedDurationEstimates_FrontOverlap) {
   // Append a few buffers.
-  NewSegmentAppend("10K 15 20D5");
+  NewCodedFrameGroupAppend("10K 15 20D5");
   CheckExpectedRangesByTimestamp("{ [10,25) }");
   SeekToTimestampMs(10);
   CheckExpectedBuffers("10K 15 20");
@@ -4412,7 +4384,7 @@
   // Append new buffers, where the last has estimated duration that overlaps the
   // *front* of the existing range. The overlap should trigger refinement of the
   // estimated duration from 7ms to 5ms.
-  NewSegmentAppend("0K 5D7E");
+  NewCodedFrameGroupAppend("0K 5D7E");
   CheckExpectedRangesByTimestamp("{ [0,25) }");
   Seek(0);
   CheckExpectedBuffers("0K 5D5E 10K 15 20");
@@ -4428,7 +4400,7 @@
 }
 
 TEST_F(SourceBufferStreamTest, SeekToStartSatisfiedUpToThreshold) {
-  NewSegmentAppend("999K 1010 1020D10");
+  NewCodedFrameGroupAppend("999K 1010 1020D10");
   CheckExpectedRangesByTimestamp("{ [999,1030) }");
 
   SeekToTimestampMs(0);
@@ -4437,7 +4409,7 @@
 }
 
 TEST_F(SourceBufferStreamTest, SeekToStartUnsatisfiedBeyondThreshold) {
-  NewSegmentAppend("1000K 1010 1020D10");
+  NewCodedFrameGroupAppend("1000K 1010 1020D10");
   CheckExpectedRangesByTimestamp("{ [1000,1030) }");
 
   SeekToTimestampMs(0);
@@ -4447,7 +4419,7 @@
 TEST_F(SourceBufferStreamTest,
        ReSeekToStartSatisfiedUpToThreshold_SameTimestamps) {
   // Append a few buffers.
-  NewSegmentAppend("999K 1010 1020D10");
+  NewCodedFrameGroupAppend("999K 1010 1020D10");
   CheckExpectedRangesByTimestamp("{ [999,1030) }");
 
   // Don't read any buffers between Seek and Remove.
@@ -4457,7 +4429,7 @@
   CheckNoNextBuffer();
 
   // Append buffers at the original timestamps and verify no stall.
-  NewSegmentAppend("999K 1010 1020D10");
+  NewCodedFrameGroupAppend("999K 1010 1020D10");
   CheckExpectedRangesByTimestamp("{ [999,1030) }");
   CheckExpectedBuffers("999K 1010 1020D10");
   CheckNoNextBuffer();
@@ -4466,7 +4438,7 @@
 TEST_F(SourceBufferStreamTest,
        ReSeekToStartSatisfiedUpToThreshold_EarlierTimestamps) {
   // Append a few buffers.
-  NewSegmentAppend("999K 1010 1020D10");
+  NewCodedFrameGroupAppend("999K 1010 1020D10");
   CheckExpectedRangesByTimestamp("{ [999,1030) }");
 
   // Don't read any buffers between Seek and Remove.
@@ -4477,7 +4449,7 @@
 
   // Append buffers before the original timestamps and verify no stall (the
   // re-seek to time 0 should still be satisfied with the new buffers).
-  NewSegmentAppend("500K 510 520D10");
+  NewCodedFrameGroupAppend("500K 510 520D10");
   CheckExpectedRangesByTimestamp("{ [500,530) }");
   CheckExpectedBuffers("500K 510 520D10");
   CheckNoNextBuffer();
@@ -4486,7 +4458,7 @@
 TEST_F(SourceBufferStreamTest,
        ReSeekToStartSatisfiedUpToThreshold_LaterTimestamps) {
   // Append a few buffers.
-  NewSegmentAppend("500K 510 520D10");
+  NewCodedFrameGroupAppend("500K 510 520D10");
   CheckExpectedRangesByTimestamp("{ [500,530) }");
 
   // Don't read any buffers between Seek and Remove.
@@ -4498,7 +4470,7 @@
   // Append buffers beginning after original timestamps, but still below the
   // start threshold, and verify no stall (the re-seek to time 0 should still be
   // satisfied with the new buffers).
-  NewSegmentAppend("999K 1010 1020D10");
+  NewCodedFrameGroupAppend("999K 1010 1020D10");
   CheckExpectedRangesByTimestamp("{ [999,1030) }");
   CheckExpectedBuffers("999K 1010 1020D10");
   CheckNoNextBuffer();
@@ -4506,7 +4478,7 @@
 
 TEST_F(SourceBufferStreamTest, ReSeekBeyondStartThreshold_SameTimestamps) {
   // Append a few buffers.
-  NewSegmentAppend("1000K 1010 1020D10");
+  NewCodedFrameGroupAppend("1000K 1010 1020D10");
   CheckExpectedRangesByTimestamp("{ [1000,1030) }");
 
   // Don't read any buffers between Seek and Remove.
@@ -4516,7 +4488,7 @@
   CheckNoNextBuffer();
 
   // Append buffers at the original timestamps and verify no stall.
-  NewSegmentAppend("1000K 1010 1020D10");
+  NewCodedFrameGroupAppend("1000K 1010 1020D10");
   CheckExpectedRangesByTimestamp("{ [1000,1030) }");
   CheckExpectedBuffers("1000K 1010 1020D10");
   CheckNoNextBuffer();
@@ -4524,7 +4496,7 @@
 
 TEST_F(SourceBufferStreamTest, ReSeekBeyondThreshold_EarlierTimestamps) {
   // Append a few buffers.
-  NewSegmentAppend("2000K 2010 2020D10");
+  NewCodedFrameGroupAppend("2000K 2010 2020D10");
   CheckExpectedRangesByTimestamp("{ [2000,2030) }");
 
   // Don't read any buffers between Seek and Remove.
@@ -4536,7 +4508,7 @@
   // Append buffers before the original timestamps and verify no stall (the
   // re-seek to time 2 seconds should still be satisfied with the new buffers
   // and should emit preroll from last keyframe).
-  NewSegmentAppend("1080K 1090 2000D10");
+  NewCodedFrameGroupAppend("1080K 1090 2000D10");
   CheckExpectedRangesByTimestamp("{ [1080,2010) }");
   CheckExpectedBuffers("1080K 1090 2000D10");
   CheckNoNextBuffer();
@@ -4545,9 +4517,9 @@
 TEST_F(SourceBufferStreamTest, ConfigChange_ReSeek) {
   // Append a few buffers, with a config change in the middle.
   VideoDecoderConfig new_config = TestVideoConfig::Large();
-  NewSegmentAppend("2000K 2010 2020D10");
+  NewCodedFrameGroupAppend("2000K 2010 2020D10");
   stream_->UpdateVideoConfig(new_config);
-  NewSegmentAppend("2030K 2040 2050D10");
+  NewCodedFrameGroupAppend("2030K 2040 2050D10");
   CheckExpectedRangesByTimestamp("{ [2000,2060) }");
 
   // Read the config change, but don't read any non-config-change buffer between
@@ -4566,7 +4538,7 @@
 
   // Append buffers at the original timestamps and verify no stall or redundant
   // signalling of config change.
-  NewSegmentAppend("2030K 2040 2050D10");
+  NewCodedFrameGroupAppend("2030K 2040 2050D10");
   CheckVideoConfig(new_config);
   CheckExpectedRangesByTimestamp("{ [2000,2060) }");
   CheckExpectedBuffers("2030K 2040 2050D10");
@@ -4589,7 +4561,7 @@
 }
 
 TEST_F(SourceBufferStreamTest, TrackBuffer_ExhaustionWithSkipForward) {
-  NewSegmentAppend("0K 10 20 30 40");
+  NewCodedFrameGroupAppend("0K 10 20 30 40");
 
   // Read the first 4 buffers, so next buffer is at time 40.
   Seek(0);
@@ -4599,7 +4571,7 @@
   // Overlap-append, populating track buffer with timestamp 40 from original
   // append. Confirm there could be a large jump in time until the next key
   // frame after exhausting the track buffer.
-  NewSegmentAppend(
+  NewCodedFrameGroupAppend(
       "31K 41 51 61 71 81 91 101 111 121 "
       "131K 141");
   CheckExpectedRangesByTimestamp("{ [0,151) }");
@@ -4615,7 +4587,7 @@
 
 TEST_F(SourceBufferStreamTest,
        TrackBuffer_ExhaustionAndImmediateNewTrackBuffer) {
-  NewSegmentAppend("0K 10 20 30 40");
+  NewCodedFrameGroupAppend("0K 10 20 30 40");
 
   // Read the first 4 buffers, so next buffer is at time 40.
   Seek(0);
@@ -4623,7 +4595,7 @@
   CheckExpectedBuffers("0K 10 20 30");
 
   // Overlap-append
-  NewSegmentAppend(
+  NewCodedFrameGroupAppend(
       "31K 41 51 61 71 81 91 101 111 121 "
       "131K 141");
   CheckExpectedRangesByTimestamp("{ [0,151) }");
@@ -4635,7 +4607,8 @@
   // append. (See TrackBuffer_ExhaustionWithSkipForward for that verification.)
   // Do another overlap-append to immediately create another track buffer and
   // verify both track buffer exhaustions skip forward and emit log warnings.
-  NewSegmentAppend("22K 32 42 52 62 72 82 92 102 112 122K 132 142 152K 162");
+  NewCodedFrameGroupAppend(
+      "22K 32 42 52 62 72 82 92 102 112 122K 132 142 152K 162");
   CheckExpectedRangesByTimestamp("{ [0,172) }");
 
   InSequence s;
@@ -4646,6 +4619,150 @@
   CheckNoNextBuffer();
 }
 
+TEST_F(
+    SourceBufferStreamTest,
+    AdjacentCodedFrameGroupContinuation_NoGapCreatedByTinyGapInGroupContinuation) {
+  NewCodedFrameGroupAppend("0K 10 20K 30 40K 50D10");
+  CheckExpectedRangesByTimestamp("{ [0,60) }");
+
+  // Continue appending to the previously started coded frame group, albeit with
+  // a tiny (1ms) gap. This gap should *NOT* produce a buffered range gap.
+  AppendBuffers("61K 71D10");
+  CheckExpectedRangesByTimestamp("{ [0,81) }");
+}
+
+TEST_F(SourceBufferStreamTest,
+       AdjacentCodedFrameGroupContinuation_NoGapCreatedPrefixRemoved) {
+  NewCodedFrameGroupAppend("0K 10 20K 30 40K 50D10");
+  CheckExpectedRangesByTimestamp("{ [0,60) }");
+
+  RemoveInMs(0, 35, 60);
+  CheckExpectedRangesByTimestamp("{ [40,60) }");
+
+  // Continue appending to the previously started coded frame group, albeit with
+  // a tiny (1ms) gap. This gap should *NOT* produce a buffered range gap.
+  AppendBuffers("61K 71D10");
+  CheckExpectedRangesByTimestamp("{ [40,81) }");
+}
+
+TEST_F(SourceBufferStreamTest,
+       AdjacentNewCodedFrameGroupContinuation_NoGapCreatedPrefixRemoved) {
+  NewCodedFrameGroupAppend("0K 10 20K 30 40K 50D10");
+  CheckExpectedRangesByTimestamp("{ [0,60) }");
+
+  RemoveInMs(0, 35, 60);
+  CheckExpectedRangesByTimestamp("{ [40,60) }");
+
+  // Continue appending, with a new coded frame group, albeit with
+  // a tiny (1ms) gap. This gap should *NOT* produce a buffered range gap.
+  // This test demonstrates the "pre-relaxation" behavior, where a new "media
+  // segment" (now a new "coded frame group") was signaled at every media
+  // segment boundary.
+  NewCodedFrameGroupAppend("61K 71D10");
+  CheckExpectedRangesByTimestamp("{ [40,81) }");
+}
+
+TEST_F(SourceBufferStreamTest,
+       StartCodedFrameGroup_RemoveThenAppendMoreMuchLater) {
+  NewCodedFrameGroupAppend("1000K 1010 1020 1030K 1040 1050 1060K 1070 1080");
+  NewCodedFrameGroupAppend("0K 10 20");
+  CheckExpectedRangesByTimestamp("{ [0,30) [1000,1090) }");
+
+  SignalStartOfCodedFrameGroup(base::TimeDelta::FromMilliseconds(1070));
+  CheckExpectedRangesByTimestamp("{ [0,30) [1000,1090) }");
+
+  RemoveInMs(1030, 1050, 1090);
+  CheckExpectedRangesByTimestamp("{ [0,30) [1000,1030) [1060,1090) }");
+
+  // We've signalled that we're about to do some appends to a coded frame group
+  // which starts at time 1070ms. Note that the first frame, if any ever,
+  // appended to this SourceBufferStream for that coded frame group must have a
+  // decode timestamp >= 1070ms (it can be significantly in the future).
+  // Regardless, that appended frame must be buffered into the same existing
+  // range as current [1060,1090), since the new coded frame group's start of
+  // 1070ms is within that range.
+  AppendBuffers("2000K 2010");
+  CheckExpectedRangesByTimestamp("{ [0,30) [1000,1030) [1060,2020) }");
+  SeekToTimestampMs(1060);
+  CheckExpectedBuffers("1060K 2000K 2010");
+  CheckNoNextBuffer();
+}
+
+TEST_F(SourceBufferStreamTest,
+       StartCodedFrameGroup_InExisting_AppendMuchLater) {
+  NewCodedFrameGroupAppend("0K 10 20 30K 40 50");
+  SignalStartOfCodedFrameGroup(base::TimeDelta::FromMilliseconds(45));
+  CheckExpectedRangesByTimestamp("{ [0,60) }");
+
+  AppendBuffers("2000K 2010");
+  CheckExpectedRangesByTimestamp("{ [0,2020) }");
+  Seek(0);
+  CheckExpectedBuffers("0K 10 20 30K 40 2000K 2010");
+  CheckNoNextBuffer();
+}
+
+TEST_F(SourceBufferStreamTest,
+       StartCodedFrameGroup_InExisting_RemoveGOP_ThenAppend_1) {
+  NewCodedFrameGroupAppend("0K 10 20 30K 40 50");
+  SignalStartOfCodedFrameGroup(base::TimeDelta::FromMilliseconds(30));
+  RemoveInMs(30, 60, 60);
+  CheckExpectedRangesByTimestamp("{ [0,30) }");
+
+  AppendBuffers("2000K 2010");
+  CheckExpectedRangesByTimestamp("{ [0,2020) }");
+  Seek(0);
+  CheckExpectedBuffers("0K 10 20 2000K 2010");
+  CheckNoNextBuffer();
+}
+
+TEST_F(SourceBufferStreamTest,
+       StartCodedFrameGroup_InExisting_RemoveGOP_ThenAppend_2) {
+  NewCodedFrameGroupAppend("0K 10 20 30K 40 50");
+  SignalStartOfCodedFrameGroup(base::TimeDelta::FromMilliseconds(45));
+  RemoveInMs(30, 60, 60);
+  CheckExpectedRangesByTimestamp("{ [0,30) }");
+
+  AppendBuffers("2000K 2010");
+  CheckExpectedRangesByTimestamp("{ [0,30) [45,2020) }");
+  Seek(0);
+  CheckExpectedBuffers("0K 10 20");
+  CheckNoNextBuffer();
+  SeekToTimestampMs(45);
+  CheckExpectedBuffers("2000K 2010");
+  CheckNoNextBuffer();
+  SeekToTimestampMs(1000);
+  CheckExpectedBuffers("2000K 2010");
+  CheckNoNextBuffer();
+}
+
+TEST_F(SourceBufferStreamTest,
+       StartCodedFrameGroup_InExisting_RemoveMostRecentAppend_ThenAppend_1) {
+  NewCodedFrameGroupAppend("0K 10 20 30K 40 50");
+  SignalStartOfCodedFrameGroup(base::TimeDelta::FromMilliseconds(45));
+  RemoveInMs(50, 60, 60);
+  CheckExpectedRangesByTimestamp("{ [0,50) }");
+
+  AppendBuffers("2000K 2010");
+  CheckExpectedRangesByTimestamp("{ [0,2020) }");
+  Seek(0);
+  CheckExpectedBuffers("0K 10 20 30K 40 2000K 2010");
+  CheckNoNextBuffer();
+}
+
+TEST_F(SourceBufferStreamTest,
+       StartCodedFrameGroup_InExisting_RemoveMostRecentAppend_ThenAppend_2) {
+  NewCodedFrameGroupAppend("0K 10 20 30K 40 50");
+  SignalStartOfCodedFrameGroup(base::TimeDelta::FromMilliseconds(50));
+  RemoveInMs(50, 60, 60);
+  CheckExpectedRangesByTimestamp("{ [0,50) }");
+
+  AppendBuffers("2000K 2010");
+  CheckExpectedRangesByTimestamp("{ [0,2020) }");
+  Seek(0);
+  CheckExpectedBuffers("0K 10 20 30K 40 2000K 2010");
+  CheckNoNextBuffer();
+}
+
 // TODO(vrk): Add unit tests where keyframes are unaligned between streams.
 // (crbug.com/133557)
 
diff --git a/media/formats/mp2t/mp2t_stream_parser.cc b/media/formats/mp2t/mp2t_stream_parser.cc
index 3bc8d25..12c8a82d 100644
--- a/media/formats/mp2t/mp2t_stream_parser.cc
+++ b/media/formats/mp2t/mp2t_stream_parser.cc
@@ -180,6 +180,7 @@
   DCHECK(!config_cb.is_null());
   DCHECK(!new_buffers_cb.is_null());
   DCHECK(!encrypted_media_init_data_cb.is_null());
+  DCHECK(!new_segment_cb.is_null());
   DCHECK(!end_of_segment_cb.is_null());
 
   init_cb_ = init_cb;
diff --git a/media/formats/mp4/mp4_stream_parser.cc b/media/formats/mp4/mp4_stream_parser.cc
index 2c8d6d7..7becdf9 100644
--- a/media/formats/mp4/mp4_stream_parser.cc
+++ b/media/formats/mp4/mp4_stream_parser.cc
@@ -62,6 +62,7 @@
   DCHECK(!config_cb.is_null());
   DCHECK(!new_buffers_cb.is_null());
   DCHECK(!encrypted_media_init_data_cb.is_null());
+  DCHECK(!new_segment_cb.is_null());
   DCHECK(!end_of_segment_cb.is_null());
 
   ChangeState(kParsingBoxes);
@@ -443,7 +444,7 @@
 
   if (!runs_->IsRunValid()) {
     // Flush any buffers we've gotten in this chunk so that buffers don't
-    // cross NewSegment() calls
+    // cross |new_segment_cb_| calls
     *err = !SendAndFlushSamples(audio_buffers, video_buffers);
     if (*err)
       return false;
diff --git a/media/formats/mp4/mp4_stream_parser_unittest.cc b/media/formats/mp4/mp4_stream_parser_unittest.cc
index dd9305b..bd1ae91 100644
--- a/media/formats/mp4/mp4_stream_parser_unittest.cc
+++ b/media/formats/mp4/mp4_stream_parser_unittest.cc
@@ -46,6 +46,10 @@
   return CONTAINS_STRING(arg, "Aux Info is not available.");
 }
 
+MATCHER_P(ErrorLog, error_string, "") {
+  return CONTAINS_STRING(arg, error_string);
+}
+
 class MP4StreamParserTest : public testing::Test {
  public:
   MP4StreamParserTest()
@@ -300,14 +304,19 @@
   ParseMP4File("bear-1280x720-av_with-aud-nalus_frag.mp4", 512);
 }
 
-#if BUILDFLAG(ENABLE_HEVC_DEMUXING)
 TEST_F(MP4StreamParserTest, HEVC_in_MP4_container) {
+#if BUILDFLAG(ENABLE_HEVC_DEMUXING)
+  bool expect_success = true;
+  EXPECT_MEDIA_LOG(VideoCodecLog("hevc"));
+#else
+  bool expect_success = false;
+  EXPECT_MEDIA_LOG(ErrorLog("Parse unsupported video format hev1"));
+#endif
   InitializeParserAndExpectLiveness(DemuxerStream::LIVENESS_RECORDED);
   scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile("bear-hevc-frag.mp4");
-  EXPECT_MEDIA_LOG(VideoCodecLog("hevc"));
-  EXPECT_TRUE(AppendDataInPieces(buffer->data(), buffer->data_size(), 512));
+  EXPECT_EQ(expect_success,
+            AppendDataInPieces(buffer->data(), buffer->data_size(), 512));
 }
-#endif
 
 TEST_F(MP4StreamParserTest, CENC) {
   // Encrypted test mp4 files have non-zero duration and are treated as
@@ -342,27 +351,43 @@
   EXPECT_EQ(gfx::Size(639, 360), video_decoder_config_.natural_size());
 }
 
-#if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
 TEST_F(MP4StreamParserTest, DemuxingAC3) {
   std::set<int> audio_object_types;
   audio_object_types.insert(kAC3);
   parser_.reset(new MP4StreamParser(audio_object_types, false));
+
+#if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
+  bool expect_success = true;
+#else
+  bool expect_success = false;
+  EXPECT_MEDIA_LOG(ErrorLog("Unsupported audio format 0x61632d33 in stsd box"));
+#endif
+
   InitializeParserAndExpectLiveness(DemuxerStream::LIVENESS_RECORDED);
   scoped_refptr<DecoderBuffer> buffer =
       ReadTestDataFile("bear-ac3-only-frag.mp4");
-  EXPECT_TRUE(AppendDataInPieces(buffer->data(), buffer->data_size(), 512));
+  EXPECT_EQ(expect_success,
+            AppendDataInPieces(buffer->data(), buffer->data_size(), 512));
 }
 
 TEST_F(MP4StreamParserTest, DemuxingEAC3) {
   std::set<int> audio_object_types;
   audio_object_types.insert(kEAC3);
   parser_.reset(new MP4StreamParser(audio_object_types, false));
+
+#if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
+  bool expect_success = true;
+#else
+  bool expect_success = false;
+  EXPECT_MEDIA_LOG(ErrorLog("Unsupported audio format 0x65632d33 in stsd box"));
+#endif
+
   InitializeParserAndExpectLiveness(DemuxerStream::LIVENESS_RECORDED);
   scoped_refptr<DecoderBuffer> buffer =
       ReadTestDataFile("bear-eac3-only-frag.mp4");
-  EXPECT_TRUE(AppendDataInPieces(buffer->data(), buffer->data_size(), 512));
+  EXPECT_EQ(expect_success,
+            AppendDataInPieces(buffer->data(), buffer->data_size(), 512));
 }
-#endif
 
 }  // namespace mp4
 }  // namespace media
diff --git a/media/formats/webm/webm_stream_parser.h b/media/formats/webm/webm_stream_parser.h
index 128a5ab..6de1deda 100644
--- a/media/formats/webm/webm_stream_parser.h
+++ b/media/formats/webm/webm_stream_parser.h
@@ -65,7 +65,7 @@
   // Returning > 0 indicates success & the number of bytes parsed.
   int ParseCluster(const uint8_t* data, int size);
 
-  // Fire needkey event through the |encrypted_media_init_data_cb_|.
+  // Fire the encrypted event through the |encrypted_media_init_data_cb_|.
   void OnEncryptedMediaInitData(const std::string& key_id);
 
   State state_;
diff --git a/media/media.gyp b/media/media.gyp
index ef51a58c..5104c172 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -251,6 +251,8 @@
         'base/audio_hash.h',
         'base/audio_pull_fifo.cc',
         'base/audio_pull_fifo.h',
+        'base/audio_push_fifo.cc',
+        'base/audio_push_fifo.h',
         'base/audio_renderer.cc',
         'base/audio_renderer.h',
         'base/audio_renderer_mixer.cc',
@@ -367,8 +369,9 @@
         'base/null_video_sink.cc',
         'base/null_video_sink.h',
         'base/output_device.h',
-        'base/pipeline.cc',
         'base/pipeline.h',
+        'base/pipeline_impl.cc',
+        'base/pipeline_impl.h',
         'base/pipeline_status.h',
         'base/player_tracker.cc',
         'base/player_tracker.h',
@@ -511,6 +514,8 @@
         'capture/video/win/video_capture_device_mf_win.h',
         'capture/video/win/video_capture_device_win.cc',
         'capture/video/win/video_capture_device_win.h',
+        'capture/device_monitor_mac.h',
+        'capture/device_monitor_mac.mm',
         'cdm/aes_decryptor.cc',
         'cdm/aes_decryptor.h',
         'cdm/cdm_adapter.cc',
@@ -1239,6 +1244,7 @@
         'base/audio_hardware_config_unittest.cc',
         'base/audio_hash_unittest.cc',
         'base/audio_pull_fifo_unittest.cc',
+        'base/audio_push_fifo_unittest.cc',
         'base/audio_renderer_mixer_input_unittest.cc',
         'base/audio_renderer_mixer_unittest.cc',
         'base/audio_shifter_unittest.cc',
@@ -1265,7 +1271,7 @@
         'base/moving_average_unittest.cc',
         'base/multi_channel_resampler_unittest.cc',
         'base/null_video_sink_unittest.cc',
-        'base/pipeline_unittest.cc',
+        'base/pipeline_impl_unittest.cc',
         'base/ranges_unittest.cc',
         'base/run_all_unittests.cc',
         'base/seekable_buffer_unittest.cc',
diff --git a/media/mojo/services/mojo_media_application.cc b/media/mojo/services/mojo_media_application.cc
index e343efdb..d954bdd 100644
--- a/media/mojo/services/mojo_media_application.cc
+++ b/media/mojo/services/mojo_media_application.cc
@@ -27,7 +27,8 @@
 
 void MojoMediaApplication::Initialize(mojo::Shell* shell,
                                       const std::string& /* url */,
-                                      uint32_t /* id */) {
+                                      uint32_t /* id */,
+                                      uint32_t user_id) {
   shell_ = shell;
   mojo_media_client_->Initialize();
 }
diff --git a/media/mojo/services/mojo_media_application.h b/media/mojo/services/mojo_media_application.h
index 6cf98c9..ece3264 100644
--- a/media/mojo/services/mojo_media_application.h
+++ b/media/mojo/services/mojo_media_application.h
@@ -28,7 +28,8 @@
   // mojo::ShellClient implementation.
   void Initialize(mojo::Shell* shell,
                   const std::string& url,
-                  uint32_t id) final;
+                  uint32_t id,
+                  uint32_t user_id) final;
   bool AcceptConnection(mojo::Connection* connection) final;
 
   // mojo::InterfaceFactory<interfaces::ServiceFactory> implementation.
diff --git a/media/mojo/services/mojo_renderer_service.cc b/media/mojo/services/mojo_renderer_service.cc
index 2e25e05..680e7b9 100644
--- a/media/mojo/services/mojo_renderer_service.cc
+++ b/media/mojo/services/mojo_renderer_service.cc
@@ -21,8 +21,8 @@
     mojo::InterfaceRequest<interfaces::Renderer> request)
     : binding_(this, std::move(request)),
       cdm_context_provider_(cdm_context_provider),
-      renderer_(std::move(renderer)),
       state_(STATE_UNINITIALIZED),
+      renderer_(std::move(renderer)),
       last_media_time_usec_(0),
       weak_factory_(this) {
   DVLOG(1) << __FUNCTION__;
diff --git a/media/mojo/services/mojo_renderer_service.h b/media/mojo/services/mojo_renderer_service.h
index 7c43d3f..146290a 100644
--- a/media/mojo/services/mojo_renderer_service.h
+++ b/media/mojo/services/mojo_renderer_service.h
@@ -94,14 +94,15 @@
   mojo::StrongBinding<interfaces::Renderer> binding_;
 
   base::WeakPtr<CdmContextProvider> cdm_context_provider_;
-  scoped_ptr<media::Renderer> renderer_;
 
   State state_;
 
-  // Note: stream_provider_ must be destructed after renderer_ to avoid access
-  // violation.
+  // Note: |stream_provider_| must be destructed after |renderer_| to avoid
+  // access violation.
   scoped_ptr<DemuxerStreamProviderShim> stream_provider_;
 
+  scoped_ptr<media::Renderer> renderer_;
+
   base::RepeatingTimer time_update_timer_;
   uint64_t last_media_time_usec_;
 
diff --git a/media/renderers/video_renderer_impl.cc b/media/renderers/video_renderer_impl.cc
index 9b56a26..ab7d0795 100644
--- a/media/renderers/video_renderer_impl.cc
+++ b/media/renderers/video_renderer_impl.cc
@@ -19,7 +19,7 @@
 #include "media/base/limits.h"
 #include "media/base/media_log.h"
 #include "media/base/media_switches.h"
-#include "media/base/pipeline.h"
+#include "media/base/pipeline_status.h"
 #include "media/base/video_frame.h"
 #include "media/renderers/gpu_video_accelerator_factories.h"
 #include "media/video/gpu_memory_buffer_video_frame_pool.h"
diff --git a/media/test/data/eme_player_js/player_utils.js b/media/test/data/eme_player_js/player_utils.js
index 85a3c96..d1a1161 100644
--- a/media/test/data/eme_player_js/player_utils.js
+++ b/media/test/data/eme_player_js/player_utils.js
@@ -16,10 +16,6 @@
   // event listeners to be named onEventName.
   var eventListenerMap = {
     'encrypted': 'onEncrypted',
-    'webkitneedkey': 'onWebkitNeedKey',
-    'webkitkeymessage': 'onWebkitKeyMessage',
-    'webkitkeyadded': 'onWebkitKeyAdded',
-    'webkitkeyerror': 'onWebkitKeyError'
   };
   for (eventName in eventListenerMap) {
     var eventListenerFunction = player[eventListenerMap[eventName]];
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc
index 77fe5ec..87ee95b9 100644
--- a/media/test/pipeline_integration_test.cc
+++ b/media/test/pipeline_integration_test.cc
@@ -105,16 +105,12 @@
 #endif  // defined(USE_PROPRIETARY_CODECS)
 
 // Key used to encrypt test files.
-const uint8_t kSecretKey[] = {
-  0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
-  0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c
-};
+const uint8_t kSecretKey[] = {0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
+                              0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c};
 
 // The key ID for all encrypted files.
-const uint8_t kKeyId[] = {
-  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
-  0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35
-};
+const uint8_t kKeyId[] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+                          0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35};
 
 const size_t kAppendWholeFile = std::numeric_limits<size_t>::max();
 
@@ -287,7 +283,7 @@
 
 enum PromiseResult { RESOLVED, REJECTED };
 
-// Provides |kSecretKey| in response to needkey.
+// Provides |kSecretKey| in response to the encrypted event.
 class KeyProvidingApp : public FakeEncryptedMedia::AppBase {
  public:
   KeyProvidingApp() {}
@@ -299,9 +295,7 @@
     current_session_id_ = session_id;
   }
 
-  void OnResolve(PromiseResult expected) {
-    EXPECT_EQ(expected, RESOLVED);
-  }
+  void OnResolve(PromiseResult expected) { EXPECT_EQ(expected, RESOLVED); }
 
   void OnReject(PromiseResult expected,
                 media::MediaKeys::Exception exception_code,
@@ -312,10 +306,10 @@
 
   scoped_ptr<SimpleCdmPromise> CreatePromise(PromiseResult expected) {
     scoped_ptr<media::SimpleCdmPromise> promise(new media::CdmCallbackPromise<>(
-        base::Bind(
-            &KeyProvidingApp::OnResolve, base::Unretained(this), expected),
-        base::Bind(
-            &KeyProvidingApp::OnReject, base::Unretained(this), expected)));
+        base::Bind(&KeyProvidingApp::OnResolve, base::Unretained(this),
+                   expected),
+        base::Bind(&KeyProvidingApp::OnReject, base::Unretained(this),
+                   expected)));
     return promise;
   }
 
@@ -324,10 +318,9 @@
     scoped_ptr<media::NewSessionCdmPromise> promise(
         new media::CdmCallbackPromise<std::string>(
             base::Bind(&KeyProvidingApp::OnResolveWithSession,
-                       base::Unretained(this),
-                       expected),
-            base::Bind(
-                &KeyProvidingApp::OnReject, base::Unretained(this), expected)));
+                       base::Unretained(this), expected),
+            base::Bind(&KeyProvidingApp::OnReject, base::Unretained(this),
+                       expected)));
     return promise;
   }
 
@@ -450,7 +443,7 @@
   uint32_t num_distinct_need_key_calls_;
 };
 
-// Ignores needkey and does not perform a license request
+// Ignores the encrypted event and does not perform a license request.
 class NoResponseApp : public FakeEncryptedMedia::AppBase {
  public:
   void OnSessionMessage(const std::string& session_id,
@@ -520,9 +513,9 @@
             size_t seek_append_size) {
     chunk_demuxer_->StartWaitingForSeek(seek_time);
 
-    chunk_demuxer_->ResetParserState(
-        kSourceId,
-        base::TimeDelta(), kInfiniteDuration(), &last_timestamp_offset_);
+    chunk_demuxer_->ResetParserState(kSourceId, base::TimeDelta(),
+                                     kInfiniteDuration(),
+                                     &last_timestamp_offset_);
 
     DCHECK_LT(new_position, file_data_->data_size());
     current_position_ = new_position;
@@ -551,9 +544,8 @@
                     const uint8_t* pData,
                     int size) {
     CHECK(!chunk_demuxer_->IsParsingMediaSegment(kSourceId));
-    chunk_demuxer_->AppendData(kSourceId, pData, size,
-                               base::TimeDelta(), kInfiniteDuration(),
-                               &timestamp_offset,
+    chunk_demuxer_->AppendData(kSourceId, pData, size, base::TimeDelta(),
+                               kInfiniteDuration(), &timestamp_offset,
                                base::Bind(&MockMediaSource::InitSegmentReceived,
                                           base::Unretained(this)));
     last_timestamp_offset_ = timestamp_offset;
@@ -565,12 +557,8 @@
                               const uint8_t* pData,
                               int size) {
     CHECK(!chunk_demuxer_->IsParsingMediaSegment(kSourceId));
-    chunk_demuxer_->AppendData(kSourceId,
-                               pData,
-                               size,
-                               append_window_start,
-                               append_window_end,
-                               &timestamp_offset,
+    chunk_demuxer_->AppendData(kSourceId, pData, size, append_window_start,
+                               append_window_end, &timestamp_offset,
                                base::Bind(&MockMediaSource::InitSegmentReceived,
                                           base::Unretained(this)));
     last_timestamp_offset_ = timestamp_offset;
@@ -589,16 +577,14 @@
     chunk_demuxer_->Remove(kSourceId, start, end);
   }
 
-  void EndOfStream() {
-    chunk_demuxer_->MarkEndOfStream(PIPELINE_OK);
-  }
+  void EndOfStream() { chunk_demuxer_->MarkEndOfStream(PIPELINE_OK); }
 
   void Shutdown() {
     if (!chunk_demuxer_)
       return;
-    chunk_demuxer_->ResetParserState(
-        kSourceId,
-        base::TimeDelta(), kInfiniteDuration(), &last_timestamp_offset_);
+    chunk_demuxer_->ResetParserState(kSourceId, base::TimeDelta(),
+                                     kInfiniteDuration(),
+                                     &last_timestamp_offset_);
     chunk_demuxer_->Shutdown();
     chunk_demuxer_ = NULL;
   }
@@ -622,17 +608,16 @@
 
       CHECK_NE(codecs_param_start, std::string::npos);
 
-      codecs_param_start += 8; // Skip over the codecs=".
+      codecs_param_start += 8;  // Skip over the codecs=".
 
       size_t codecs_param_end = mimetype_.find("\"", codecs_param_start);
 
       CHECK_NE(codecs_param_end, std::string::npos);
 
-      std::string codecs_param =
-          mimetype_.substr(codecs_param_start,
-                           codecs_param_end - codecs_param_start);
-      codecs = base::SplitString(
-          codecs_param, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+      std::string codecs_param = mimetype_.substr(
+          codecs_param_start, codecs_param_end - codecs_param_start);
+      codecs = base::SplitString(codecs_param, ",", base::KEEP_WHITESPACE,
+                                 base::SPLIT_WANT_NONEMPTY);
     }
 
     CHECK_EQ(chunk_demuxer_->AddId(kSourceId, type, codecs), ChunkDemuxer::kOk);
@@ -739,9 +724,8 @@
     StartPipelineWithMediaSource(source);
   }
 
-  void StartPipelineWithEncryptedMedia(
-      MockMediaSource* source,
-      FakeEncryptedMedia* encrypted_media) {
+  void StartPipelineWithEncryptedMedia(MockMediaSource* source,
+                                       FakeEncryptedMedia* encrypted_media) {
     EXPECT_CALL(*source, InitSegmentReceived()).Times(AtLeast(1));
     EXPECT_CALL(*this, OnMetadata(_))
         .Times(AtMost(1))
@@ -1007,8 +991,7 @@
 
   ASSERT_TRUE(WaitUntilOnEnded());
 
-  EXPECT_EQ(kLiveTimelineOffset(),
-            demuxer_->GetTimelineOffset());
+  EXPECT_EQ(kLiveTimelineOffset(), demuxer_->GetTimelineOffset());
   source.Shutdown();
   Stop();
 }
@@ -1294,11 +1277,9 @@
       source.last_timestamp_offset() - adts_preroll_duration;
 
   scoped_refptr<DecoderBuffer> second_file = ReadTestDataFile("sfx.adts");
-  source.AppendAtTimeWithWindow(append_time,
-                                append_time + adts_preroll_duration,
-                                kInfiniteDuration(),
-                                second_file->data(),
-                                second_file->data_size());
+  source.AppendAtTimeWithWindow(
+      append_time, append_time + adts_preroll_duration, kInfiniteDuration(),
+      second_file->data(), second_file->data_size());
   source.EndOfStream();
 
   EXPECT_EQ(592, source.last_timestamp_offset().InMilliseconds());
@@ -1428,10 +1409,8 @@
       source.last_timestamp_offset() - mp3_preroll_duration;
 
   scoped_refptr<DecoderBuffer> second_file = ReadTestDataFile("sfx.mp3");
-  source.AppendAtTimeWithWindow(append_time,
-                                append_time + mp3_preroll_duration,
-                                kInfiniteDuration(),
-                                second_file->data(),
+  source.AppendAtTimeWithWindow(append_time, append_time + mp3_preroll_duration,
+                                kInfiniteDuration(), second_file->data(),
                                 second_file->data_size());
   source.EndOfStream();
 
@@ -1878,17 +1857,15 @@
 // Verify audio decoder & renderer can handle aborted demuxer reads.
 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_AudioOnly) {
   ASSERT_TRUE(TestSeekDuringRead("bear-320x240-audio-only.webm", kAudioOnlyWebM,
-                                 16384,
-                                 base::TimeDelta::FromMilliseconds(464),
-                                 base::TimeDelta::FromMilliseconds(617),
-                                 0x10CA, 19730));
+                                 16384, base::TimeDelta::FromMilliseconds(464),
+                                 base::TimeDelta::FromMilliseconds(617), 0x10CA,
+                                 19730));
 }
 
 // Verify video decoder & renderer can handle aborted demuxer reads.
 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_VideoOnly) {
   ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", kVideoOnlyWebM,
-                                 32768,
-                                 base::TimeDelta::FromMilliseconds(167),
+                                 32768, base::TimeDelta::FromMilliseconds(167),
                                  base::TimeDelta::FromMilliseconds(1668),
                                  0x1C896, 65536));
 }
@@ -1983,26 +1960,24 @@
   ASSERT_EQ(PIPELINE_OK, Start("sfx-opus-441.webm"));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_EQ(48000,
-            demuxer_->GetStream(DemuxerStream::AUDIO)
-                ->audio_decoder_config()
-                .samples_per_second());
+  EXPECT_EQ(48000, demuxer_->GetStream(DemuxerStream::AUDIO)
+                       ->audio_decoder_config()
+                       .samples_per_second());
 }
 
 // Same as above but using MediaSource.
 TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_Opus441kHz) {
-  MockMediaSource source(
-      "sfx-opus-441.webm", kOpusAudioOnlyWebM, kAppendWholeFile);
+  MockMediaSource source("sfx-opus-441.webm", kOpusAudioOnlyWebM,
+                         kAppendWholeFile);
   StartPipelineWithMediaSource(&source);
   source.EndOfStream();
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
   source.Shutdown();
   Stop();
-  EXPECT_EQ(48000,
-            demuxer_->GetStream(DemuxerStream::AUDIO)
-                ->audio_decoder_config()
-                .samples_per_second());
+  EXPECT_EQ(48000, demuxer_->GetStream(DemuxerStream::AUDIO)
+                       ->audio_decoder_config()
+                       .samples_per_second());
 }
 
 // Ensures audio-only playback with missing or negative timestamps works.  Tests
diff --git a/media/test/pipeline_integration_test_base.cc b/media/test/pipeline_integration_test_base.cc
index a2e4254..11da971 100644
--- a/media/test/pipeline_integration_test_base.cc
+++ b/media/test/pipeline_integration_test_base.cc
@@ -41,7 +41,7 @@
 PipelineIntegrationTestBase::PipelineIntegrationTestBase()
     : hashing_enabled_(false),
       clockless_playback_(false),
-      pipeline_(new Pipeline(message_loop_.task_runner(), new MediaLog())),
+      pipeline_(new PipelineImpl(message_loop_.task_runner(), new MediaLog())),
       ended_(false),
       pipeline_status_(PIPELINE_OK),
       last_video_frame_format_(PIXEL_FORMAT_UNKNOWN),
@@ -63,8 +63,7 @@
   pipeline_status_ = status;
 }
 
-void PipelineIntegrationTestBase::OnStatusCallback(
-    PipelineStatus status) {
+void PipelineIntegrationTestBase::OnStatusCallback(PipelineStatus status) {
   pipeline_status_ = status;
   message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
 }
@@ -224,8 +223,7 @@
   message_loop_.PostDelayedTask(
       FROM_HERE,
       base::Bind(&PipelineIntegrationTestBase::QuitAfterCurrentTimeTask,
-                 base::Unretained(this),
-                 wait_time),
+                 base::Unretained(this), wait_time),
       base::TimeDelta::FromMilliseconds(10));
   message_loop_.Run();
   return (pipeline_status_ == PIPELINE_OK);
@@ -285,16 +283,12 @@
       new FFmpegAudioDecoder(message_loop_.task_runner(), new MediaLog()));
 #endif
 
-  audio_decoders.push_back(
-      new OpusAudioDecoder(message_loop_.task_runner()));
+  audio_decoders.push_back(new OpusAudioDecoder(message_loop_.task_runner()));
 
   // Don't allow the audio renderer to resample buffers if hashing is enabled.
   if (!hashing_enabled_) {
     AudioParameters out_params(AudioParameters::AUDIO_PCM_LOW_LATENCY,
-                               CHANNEL_LAYOUT_STEREO,
-                               44100,
-                               16,
-                               512);
+                               CHANNEL_LAYOUT_STEREO, 44100, 16, 512);
     hardware_config_.UpdateOutputConfig(out_params);
   }
 
diff --git a/media/test/pipeline_integration_test_base.h b/media/test/pipeline_integration_test_base.h
index 4f4bd2f..d920fb9 100644
--- a/media/test/pipeline_integration_test_base.h
+++ b/media/test/pipeline_integration_test_base.h
@@ -15,7 +15,8 @@
 #include "media/base/demuxer.h"
 #include "media/base/media_keys.h"
 #include "media/base/null_video_sink.h"
-#include "media/base/pipeline.h"
+#include "media/base/pipeline_impl.h"
+#include "media/base/pipeline_status.h"
 #include "media/base/text_track.h"
 #include "media/base/text_track_config.h"
 #include "media/base/video_frame.h"
@@ -75,7 +76,7 @@
   // benchmarking purposes (e.g., underflow is disabled to ensure consistent
   // hashes).  May be combined using the bitwise or operator (and as such must
   // have values that are powers of two).
-  enum TestTypeFlags { kHashed = 1, kClockless = 2};
+  enum TestTypeFlags { kHashed = 1, kClockless = 2 };
   PipelineStatus Start(const std::string& filename, uint8_t test_type);
 
   void Play();
@@ -108,7 +109,7 @@
   bool clockless_playback_;
   scoped_ptr<Demuxer> demuxer_;
   scoped_ptr<DataSource> data_source_;
-  scoped_ptr<Pipeline> pipeline_;
+  scoped_ptr<PipelineImpl> pipeline_;
   scoped_refptr<NullAudioSink> audio_sink_;
   scoped_refptr<ClocklessAudioSink> clockless_audio_sink_;
   scoped_ptr<NullVideoSink> video_sink_;
diff --git a/media/video/gpu_memory_buffer_video_frame_pool.cc b/media/video/gpu_memory_buffer_video_frame_pool.cc
index e7ffd99..6663a94 100644
--- a/media/video/gpu_memory_buffer_video_frame_pool.cc
+++ b/media/video/gpu_memory_buffer_video_frame_pool.cc
@@ -199,7 +199,7 @@
   switch (format) {
     case PIXEL_FORMAT_I420:
       DCHECK_LE(plane, 2u);
-      return GL_RED_EXT;
+      return GL_R8_EXT;
     case PIXEL_FORMAT_NV12:
       DCHECK_LE(plane, 1u);
       return GL_RGB_YCBCR_420V_CHROMIUM;
diff --git a/mojo/converters/input_events/input_events_type_converters.cc b/mojo/converters/input_events/input_events_type_converters.cc
index 8d6e7250..840c3e2 100644
--- a/mojo/converters/input_events/input_events_type_converters.cc
+++ b/mojo/converters/input_events/input_events_type_converters.cc
@@ -145,15 +145,18 @@
   switch (type) {
     case ui::ET_MOUSE_PRESSED:
     case ui::ET_TOUCH_PRESSED:
+    case ui::ET_POINTER_DOWN:
       return mus::mojom::EventType::POINTER_DOWN;
 
     case ui::ET_MOUSE_DRAGGED:
     case ui::ET_MOUSE_MOVED:
     case ui::ET_MOUSE_ENTERED:
     case ui::ET_TOUCH_MOVED:
+    case ui::ET_POINTER_MOVED:
       return mus::mojom::EventType::POINTER_MOVE;
 
     case ui::ET_MOUSE_EXITED:
+    case ui::ET_POINTER_EXITED:
       return mus::mojom::EventType::MOUSE_EXIT;
 
     case ui::ET_MOUSEWHEEL:
@@ -161,9 +164,11 @@
 
     case ui::ET_MOUSE_RELEASED:
     case ui::ET_TOUCH_RELEASED:
+    case ui::ET_POINTER_UP:
       return mus::mojom::EventType::POINTER_UP;
 
     case ui::ET_TOUCH_CANCELLED:
+    case ui::ET_POINTER_CANCELLED:
       return mus::mojom::EventType::POINTER_CANCEL;
 
     case ui::ET_KEY_PRESSED:
@@ -190,7 +195,40 @@
   event->flags = input.flags();
   event->time_stamp = input.time_stamp().ToInternalValue();
 
-  if (input.IsMouseEvent()) {
+  if (input.IsPointerEvent()) {
+    const ui::PointerEvent* pointer_event =
+        static_cast<const ui::PointerEvent*>(&input);
+    const ui::PointerDetails& pointer_details =
+        pointer_event->pointer_details();
+
+    mus::mojom::PointerDataPtr pointer_data(mus::mojom::PointerData::New());
+    pointer_data->pointer_id = pointer_event->pointer_id();
+
+    switch (pointer_details.pointer_type) {
+      case ui::EventPointerType::POINTER_TYPE_MOUSE:
+        pointer_data->kind = mus::mojom::PointerKind::MOUSE;
+        break;
+      case ui::EventPointerType::POINTER_TYPE_TOUCH:
+        pointer_data->kind = mus::mojom::PointerKind::TOUCH;
+        break;
+      default:
+        NOTIMPLEMENTED();
+    }
+
+    mus::mojom::LocationDataPtr location_data(mus::mojom::LocationData::New());
+    SetPointerDataLocationFromEvent(*pointer_event, location_data.get());
+    pointer_data->location = std::move(location_data);
+
+    mus::mojom::BrushDataPtr brush_data(mus::mojom::BrushData::New());
+    brush_data->width = pointer_details.radius_x;
+    brush_data->height = pointer_details.radius_y;
+    brush_data->pressure = pointer_details.force;
+    brush_data->tilt_x = pointer_details.tilt_x;
+    brush_data->tilt_y = pointer_details.tilt_y;
+    pointer_data->brush_data = std::move(brush_data);
+    event->pointer_data = std::move(pointer_data);
+
+  } else if (input.IsMouseEvent()) {
     const ui::LocatedEvent* located_event =
         static_cast<const ui::LocatedEvent*>(&input);
     mus::mojom::PointerDataPtr pointer_data(mus::mojom::PointerData::New());
diff --git a/mojo/edk/js/BUILD.gn b/mojo/edk/js/BUILD.gn
index 5c28a24..005416d 100644
--- a/mojo/edk/js/BUILD.gn
+++ b/mojo/edk/js/BUILD.gn
@@ -42,7 +42,7 @@
   ]
 
   deps = [
-    "//mojo/public/cpp/environment",
+    "//mojo/message_pump",
     "//mojo/public/cpp/system",
   ]
 }
diff --git a/mojo/edk/js/drain_data.cc b/mojo/edk/js/drain_data.cc
index bc5d2230..3b0a195 100644
--- a/mojo/edk/js/drain_data.cc
+++ b/mojo/edk/js/drain_data.cc
@@ -7,12 +7,12 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include "base/bind.h"
 #include "gin/array_buffer.h"
 #include "gin/converter.h"
 #include "gin/dictionary.h"
 #include "gin/per_context_data.h"
 #include "gin/per_isolate_data.h"
-#include "mojo/public/cpp/environment/environment.h"
 #include "mojo/public/cpp/system/core.h"
 
 namespace mojo {
@@ -20,10 +20,7 @@
 namespace js {
 
 DrainData::DrainData(v8::Isolate* isolate, mojo::Handle handle)
-    : isolate_(isolate),
-      handle_(DataPipeConsumerHandle(handle.value())),
-      wait_id_(0) {
-
+    : isolate_(isolate), handle_(DataPipeConsumerHandle(handle.value())) {
   v8::Handle<v8::Context> context(isolate_->GetCurrentContext());
   runner_ = gin::PerContextData::From(context)->runner()->GetWeakPtr();
 
@@ -39,22 +36,16 @@
 }
 
 DrainData::~DrainData() {
-  if (wait_id_)
-    Environment::GetDefaultAsyncWaiter()->CancelWait(wait_id_);
   resolver_.Reset();
 }
 
 void DrainData::WaitForData() {
-  wait_id_ = Environment::GetDefaultAsyncWaiter()->AsyncWait(
-      handle_.get().value(),
-      MOJO_HANDLE_SIGNAL_READABLE,
-      MOJO_DEADLINE_INDEFINITE,
-      &DrainData::WaitCompleted,
-      this);
+  handle_watcher_.Start(
+      handle_.get(), MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE,
+      base::Bind(&DrainData::DataReady, base::Unretained(this)));
 }
 
 void DrainData::DataReady(MojoResult result) {
-  wait_id_ = 0;
   if (result != MOJO_RESULT_OK) {
     DeliverData(result);
     return;
diff --git a/mojo/edk/js/drain_data.h b/mojo/edk/js/drain_data.h
index 9fcdba2..13af286 100644
--- a/mojo/edk/js/drain_data.h
+++ b/mojo/edk/js/drain_data.h
@@ -7,7 +7,7 @@
 
 #include "base/memory/scoped_vector.h"
 #include "gin/runner.h"
-#include "mojo/public/c/environment/async_waiter.h"
+#include "mojo/message_pump/handle_watcher.h"
 #include "mojo/public/cpp/system/core.h"
 #include "v8/include/v8.h"
 
@@ -34,11 +34,8 @@
  private:
   ~DrainData();
 
-  // Registers an "async waiter" that calls DataReady() via WaitCompleted().
+  // Waits for data to be available. DataReady() will be notified.
   void WaitForData();
-  static void WaitCompleted(void* self, MojoResult result) {
-    static_cast<DrainData*>(self)->DataReady(result);
-  }
 
   // Use ReadData() to read whatever is availble now on handle_ and save
   // it in data_buffers_.
@@ -53,7 +50,7 @@
 
   v8::Isolate* isolate_;
   ScopedDataPipeConsumerHandle handle_;
-  MojoAsyncWaitID wait_id_;
+  common::HandleWatcher handle_watcher_;
   base::WeakPtr<gin::Runner> runner_;
   v8::UniquePersistent<v8::Promise::Resolver> resolver_;
   ScopedVector<DataBuffer> data_buffers_;
diff --git a/mojo/edk/js/test/run_js_tests.cc b/mojo/edk/js/test/run_js_tests.cc
index eb41b89..d0e8edc 100644
--- a/mojo/edk/js/test/run_js_tests.cc
+++ b/mojo/edk/js/test/run_js_tests.cc
@@ -11,7 +11,6 @@
 #include "gin/test/gtest.h"
 #include "mojo/edk/js/core.h"
 #include "mojo/edk/js/support.h"
-#include "mojo/public/cpp/environment/environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace mojo {
diff --git a/mojo/edk/js/waiting_callback.cc b/mojo/edk/js/waiting_callback.cc
index a28791c..af34d87e 100644
--- a/mojo/edk/js/waiting_callback.cc
+++ b/mojo/edk/js/waiting_callback.cc
@@ -7,7 +7,6 @@
 #include "base/bind.h"
 #include "base/message_loop/message_loop.h"
 #include "gin/per_context_data.h"
-#include "mojo/public/cpp/environment/environment.h"
 
 namespace mojo {
 namespace edk {
@@ -32,29 +31,27 @@
     MojoHandleSignals signals) {
   gin::Handle<WaitingCallback> waiting_callback = gin::CreateHandle(
       isolate, new WaitingCallback(isolate, callback, handle_wrapper));
-  waiting_callback->wait_id_ = Environment::GetDefaultAsyncWaiter()->AsyncWait(
-      handle_wrapper->get().value(),
-      signals,
-      MOJO_DEADLINE_INDEFINITE,
-      &WaitingCallback::CallOnHandleReady,
-      waiting_callback.get());
+
+  waiting_callback->handle_watcher_.Start(
+      handle_wrapper->get(), signals, MOJO_DEADLINE_INDEFINITE,
+      base::Bind(&WaitingCallback::OnHandleReady,
+                 base::Unretained(waiting_callback.get())));
   return waiting_callback;
 }
 
 void WaitingCallback::Cancel() {
-  if (!wait_id_)
+  if (!handle_watcher_.is_watching())
     return;
 
-  handle_wrapper_->RemoveCloseObserver(this);
-  handle_wrapper_ = NULL;
-  Environment::GetDefaultAsyncWaiter()->CancelWait(wait_id_);
-  wait_id_ = 0;
+  RemoveHandleCloseObserver();
+  handle_watcher_.Stop();
 }
 
 WaitingCallback::WaitingCallback(v8::Isolate* isolate,
                                  v8::Handle<v8::Function> callback,
                                  gin::Handle<HandleWrapper> handle_wrapper)
-    : wait_id_(0), handle_wrapper_(handle_wrapper.get()), weak_factory_(this) {
+    : handle_wrapper_(handle_wrapper.get()),
+      weak_factory_(this) {
   handle_wrapper_->AddCloseObserver(this);
   v8::Handle<v8::Context> context = isolate->GetCurrentContext();
   runner_ = gin::PerContextData::From(context)->runner()->GetWeakPtr();
@@ -67,25 +64,18 @@
   Cancel();
 }
 
-// static
-void WaitingCallback::CallOnHandleReady(void* closure, MojoResult result) {
-  static_cast<WaitingCallback*>(closure)->OnHandleReady(result);
-}
-
-void WaitingCallback::ClearWaitId() {
-  wait_id_ = 0;
+void WaitingCallback::RemoveHandleCloseObserver() {
   handle_wrapper_->RemoveCloseObserver(this);
   handle_wrapper_ = nullptr;
 }
 
 void WaitingCallback::OnHandleReady(MojoResult result) {
-  ClearWaitId();
+  RemoveHandleCloseObserver();
   CallCallback(result);
 }
 
 void WaitingCallback::CallCallback(MojoResult result) {
-  // ClearWaitId must already have been called.
-  DCHECK(!wait_id_);
+  DCHECK(!handle_watcher_.is_watching());
   DCHECK(!handle_wrapper_);
 
   if (!runner_)
@@ -107,11 +97,11 @@
 }
 
 void WaitingCallback::OnWillCloseHandle() {
-  Environment::GetDefaultAsyncWaiter()->CancelWait(wait_id_);
+  handle_watcher_.Stop();
 
   // This may be called from GC, so we can't execute Javascript now, call
-  // ClearWaitId explicitly, and CallCallback asynchronously.
-  ClearWaitId();
+  // RemoveHandleCloseObserver explicitly, and CallCallback asynchronously.
+  RemoveHandleCloseObserver();
   base::MessageLoop::current()->PostTask(
       FROM_HERE,
       base::Bind(&WaitingCallback::CallCallback, weak_factory_.GetWeakPtr(),
diff --git a/mojo/edk/js/waiting_callback.h b/mojo/edk/js/waiting_callback.h
index b11fcc39..f2554bc2 100644
--- a/mojo/edk/js/waiting_callback.h
+++ b/mojo/edk/js/waiting_callback.h
@@ -12,7 +12,7 @@
 #include "gin/wrappable.h"
 #include "mojo/edk/js/handle.h"
 #include "mojo/edk/js/handle_close_observer.h"
-#include "mojo/public/c/environment/async_waiter.h"
+#include "mojo/message_pump/handle_watcher.h"
 #include "mojo/public/cpp/system/core.h"
 
 namespace mojo {
@@ -42,21 +42,19 @@
                   gin::Handle<HandleWrapper> handle_wrapper);
   ~WaitingCallback() override;
 
-  // Callback from MojoAsyncWaiter. |closure| is the WaitingCallback.
-  static void CallOnHandleReady(void* closure, MojoResult result);
-
-  // Invoked from CallOnHandleReady() (CallOnHandleReady() must be static).
+  // Callback from common::HandleWatcher.
   void OnHandleReady(MojoResult result);
 
   // Invoked by the HandleWrapper if the handle is closed while this wait is
   // still in progress.
   void OnWillCloseHandle() override;
 
-  void ClearWaitId();
+  void RemoveHandleCloseObserver();
   void CallCallback(MojoResult result);
 
   base::WeakPtr<gin::Runner> runner_;
-  MojoAsyncWaitID wait_id_;
+
+  common::HandleWatcher handle_watcher_;
 
   HandleWrapper* handle_wrapper_;
   base::WeakPtrFactory<WaitingCallback> weak_factory_;
diff --git a/mojo/edk/system/ports/message_queue.h b/mojo/edk/system/ports/message_queue.h
index f1e37fb6..d90ac1a 100644
--- a/mojo/edk/system/ports/message_queue.h
+++ b/mojo/edk/system/ports/message_queue.h
@@ -9,6 +9,7 @@
 
 #include <deque>
 #include <functional>
+#include <limits>
 #include <vector>
 
 #include "base/macros.h"
@@ -19,7 +20,7 @@
 namespace ports {
 
 const uint64_t kInitialSequenceNum = 1;
-const uint64_t kInvalidSequenceNum = 0xFFFFFFFF;
+const uint64_t kInvalidSequenceNum = std::numeric_limits<uint64_t>::max();
 
 // An incoming message queue for a port. MessageQueue keeps track of the highest
 // known sequence number and can indicate whether the next sequential message is
diff --git a/mojo/gles2/command_buffer_client_impl.cc b/mojo/gles2/command_buffer_client_impl.cc
index 4813c42..fecd6aa21 100644
--- a/mojo/gles2/command_buffer_client_impl.cc
+++ b/mojo/gles2/command_buffer_client_impl.cc
@@ -68,7 +68,6 @@
 CommandBufferClientImpl::CommandBufferClientImpl(
     CommandBufferDelegate* delegate,
     const std::vector<int32_t>& attribs,
-    const MojoAsyncWaiter* async_waiter,
     mojo::ScopedMessagePipeHandle command_buffer_handle)
     : delegate_(delegate),
       attribs_(attribs),
@@ -79,11 +78,9 @@
       next_transfer_buffer_id_(0),
       next_image_id_(0),
       next_fence_sync_release_(1),
-      flushed_fence_sync_release_(0),
-      async_waiter_(async_waiter) {
+      flushed_fence_sync_release_(0) {
   command_buffer_.Bind(mojo::InterfacePtrInfo<mus::mojom::CommandBuffer>(
-                           std::move(command_buffer_handle), 0u),
-                       async_waiter);
+      std::move(command_buffer_handle), 0u));
   command_buffer_.set_connection_error_handler(
       [this]() { Destroyed(gpu::error::kUnknown, gpu::error::kLostContext); });
 }
@@ -104,7 +101,7 @@
   shared_state()->Initialize();
 
   mus::mojom::CommandBufferClientPtr client_ptr;
-  client_binding_.Bind(GetProxy(&client_ptr), async_waiter_);
+  client_binding_.Bind(GetProxy(&client_ptr));
 
   mus::mojom::CommandBufferInitializeResultPtr initialize_result;
   command_buffer_->Initialize(
diff --git a/mojo/gles2/command_buffer_client_impl.h b/mojo/gles2/command_buffer_client_impl.h
index 473c228..995ff1c 100644
--- a/mojo/gles2/command_buffer_client_impl.h
+++ b/mojo/gles2/command_buffer_client_impl.h
@@ -41,7 +41,6 @@
   explicit CommandBufferClientImpl(
       CommandBufferDelegate* delegate,
       const std::vector<int32_t>& attribs,
-      const MojoAsyncWaiter* async_waiter,
       mojo::ScopedMessagePipeHandle command_buffer_handle);
   ~CommandBufferClientImpl() override;
 
@@ -115,8 +114,6 @@
 
   uint64_t next_fence_sync_release_;
   uint64_t flushed_fence_sync_release_;
-
-  const MojoAsyncWaiter* async_waiter_;
 };
 
 }  // gles2
diff --git a/mojo/gles2/gles2_context.cc b/mojo/gles2/gles2_context.cc
index c9c5a81..90ba14e 100644
--- a/mojo/gles2/gles2_context.cc
+++ b/mojo/gles2/gles2_context.cc
@@ -25,14 +25,10 @@
 }
 
 GLES2Context::GLES2Context(const std::vector<int32_t>& attribs,
-                           const MojoAsyncWaiter* async_waiter,
                            mojo::ScopedMessagePipeHandle command_buffer_handle,
                            MojoGLES2ContextLost lost_callback,
                            void* closure)
-    : command_buffer_(this,
-                      attribs,
-                      async_waiter,
-                      std::move(command_buffer_handle)),
+    : command_buffer_(this, attribs, std::move(command_buffer_handle)),
       lost_callback_(lost_callback),
       closure_(closure) {}
 
diff --git a/mojo/gles2/gles2_context.h b/mojo/gles2/gles2_context.h
index ecb7af52..684b485 100644
--- a/mojo/gles2/gles2_context.h
+++ b/mojo/gles2/gles2_context.h
@@ -31,7 +31,6 @@
                      public MojoGLES2ContextPrivate {
  public:
   explicit GLES2Context(const std::vector<int32_t>& attribs,
-                        const MojoAsyncWaiter* async_waiter,
                         mojo::ScopedMessagePipeHandle command_buffer_handle,
                         MojoGLES2ContextLost lost_callback,
                         void* closure);
diff --git a/mojo/gles2/gles2_impl.cc b/mojo/gles2/gles2_impl.cc
index bb117f5..c1875f41 100644
--- a/mojo/gles2/gles2_impl.cc
+++ b/mojo/gles2/gles2_impl.cc
@@ -31,8 +31,7 @@
 MojoGLES2Context MojoGLES2CreateContext(MojoHandle handle,
                                         const int32_t* attrib_list,
                                         MojoGLES2ContextLost lost_callback,
-                                        void* closure,
-                                        const MojoAsyncWaiter* async_waiter) {
+                                        void* closure) {
   mojo::MessagePipeHandle mph(handle);
   mojo::ScopedMessagePipeHandle scoped_handle(mph);
   std::vector<int32_t> attribs;
@@ -44,7 +43,7 @@
   }
   attribs.push_back(kNone);
   scoped_ptr<GLES2Context> client(new GLES2Context(
-      attribs, async_waiter, std::move(scoped_handle), lost_callback, closure));
+      attribs, std::move(scoped_handle), lost_callback, closure));
   if (!client->Initialize())
     client.reset();
   return client.release();
diff --git a/mojo/gpu/mojo_gles2_impl_autogen.cc b/mojo/gpu/mojo_gles2_impl_autogen.cc
index 453f9e2..09a0d382 100644
--- a/mojo/gpu/mojo_gles2_impl_autogen.cc
+++ b/mojo/gpu/mojo_gles2_impl_autogen.cc
@@ -1921,5 +1921,13 @@
   MojoGLES2MakeCurrent(context_);
   return glGetFragDataIndexEXT(program, name);
 }
+void MojoGLES2Impl::UniformMatrix4fvStreamTextureMatrixCHROMIUM(
+    GLint location,
+    GLboolean transpose,
+    const GLfloat* default_value) {
+  MojoGLES2MakeCurrent(context_);
+  glUniformMatrix4fvStreamTextureMatrixCHROMIUM(location, transpose,
+                                                default_value);
+}
 
 }  // namespace mojo
diff --git a/mojo/gpu/mojo_gles2_impl_autogen.h b/mojo/gpu/mojo_gles2_impl_autogen.h
index e3de37b..503e392 100644
--- a/mojo/gpu/mojo_gles2_impl_autogen.h
+++ b/mojo/gpu/mojo_gles2_impl_autogen.h
@@ -888,6 +888,10 @@
                                GLuint colorNumber,
                                const char* name) override;
   GLint GetFragDataIndexEXT(GLuint program, const char* name) override;
+  void UniformMatrix4fvStreamTextureMatrixCHROMIUM(
+      GLint location,
+      GLboolean transpose,
+      const GLfloat* default_value) override;
 
  private:
   MojoGLES2Context context_;
diff --git a/mojo/message_pump/handle_watcher.h b/mojo/message_pump/handle_watcher.h
index d855e45..18211ca 100644
--- a/mojo/message_pump/handle_watcher.h
+++ b/mojo/message_pump/handle_watcher.h
@@ -45,6 +45,8 @@
   // Stops listening. Does nothing if not in the process of listening.
   void Stop();
 
+  bool is_watching() const { return !!state_; }
+
  private:
   class StateBase;
   class SameThreadWatchingState;
diff --git a/mojo/mojo_base.gyp b/mojo/mojo_base.gyp
index 8f54076..71b77da 100644
--- a/mojo/mojo_base.gyp
+++ b/mojo/mojo_base.gyp
@@ -36,31 +36,6 @@
       'type': 'none',
     },
     {
-      # GN version: //mojo/message_pump
-      'target_name': 'mojo_message_pump_lib',
-      'type': '<(component)',
-      'defines': [
-        'MOJO_MESSAGE_PUMP_IMPLEMENTATION',
-      ],
-      'dependencies': [
-        '../base/base.gyp:base',
-        '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
-        '<(mojo_system_for_component)',
-      ],
-      'export_dependent_settings': [
-        '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
-      ],
-      'sources': [
-        'message_pump/handle_watcher.cc',
-        'message_pump/handle_watcher.h',
-        'message_pump/message_pump_mojo.cc',
-        'message_pump/message_pump_mojo.h',
-        'message_pump/message_pump_mojo_handler.h',
-        'message_pump/time_helper.cc',
-        'message_pump/time_helper.h',
-      ],
-    },
-    {
       # GN version: //mojo/common
       'target_name': 'mojo_common_lib',
       'type': '<(component)',
@@ -135,8 +110,8 @@
         'mojo_edk.gyp:mojo_common_test_support',
         'mojo_edk.gyp:mojo_run_all_unittests',
         'mojo_environment_chromium',
-        'mojo_message_pump_lib',
         'mojo_public.gyp:mojo_cpp_bindings',
+        'mojo_public.gyp:mojo_message_pump_lib',
         'mojo_public.gyp:mojo_public_test_utils',
         'mojo_url_type_converters',
       ],
@@ -182,7 +157,7 @@
       'dependencies': [
         '../base/base.gyp:base',
         '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
-        'mojo_message_pump_lib',
+        'mojo_public.gyp:mojo_message_pump_lib',
         '<(mojo_system_for_component)',
       ],
       'sources': [
@@ -224,6 +199,7 @@
         'shell/public/cpp/application_runner.h',
         'shell/public/cpp/connect.h',
         'shell/public/cpp/connection.h',
+        'shell/public/cpp/connector.h',
         'shell/public/cpp/initialize_base_and_icu.cc',
         'shell/public/cpp/initialize_base_and_icu.h',
         'shell/public/cpp/interface_binder.h',
@@ -233,6 +209,8 @@
         'shell/public/cpp/lib/application_runner.cc',
         'shell/public/cpp/lib/connection_impl.cc',
         'shell/public/cpp/lib/connection_impl.h',
+        'shell/public/cpp/lib/connector_impl.cc',
+        'shell/public/cpp/lib/connector_impl.h',
         'shell/public/cpp/lib/interface_factory_binder.h',
         'shell/public/cpp/lib/interface_registry.cc',
         'shell/public/cpp/lib/shell_client.cc',
@@ -244,7 +222,7 @@
       'dependencies': [
         '../base/base.gyp:base_i18n',
         'mojo_application_bindings',
-        'mojo_message_pump_lib',
+        'mojo_public.gyp:mojo_message_pump_lib',
         'mojo_services.gyp:network_type_converters',
       ],
     },
diff --git a/mojo/mojo_edk.gyp b/mojo/mojo_edk.gyp
index 989e503..144d8c0c 100644
--- a/mojo/mojo_edk.gyp
+++ b/mojo/mojo_edk.gyp
@@ -150,6 +150,7 @@
         '../base/base.gyp:base',
         '../gin/gin.gyp:gin',
         '../v8/tools/gyp/v8.gyp:v8',
+        'mojo_public.gyp:mojo_message_pump_lib',
       ],
       'export_dependent_settings': [
         '../base/base.gyp:base',
diff --git a/mojo/mojo_edk_tests.gyp b/mojo/mojo_edk_tests.gyp
index e55389c..03e60d3 100644
--- a/mojo/mojo_edk_tests.gyp
+++ b/mojo/mojo_edk_tests.gyp
@@ -48,9 +48,9 @@
       'dependencies': [
         '../testing/gtest.gyp:gtest',
         'mojo_base.gyp:mojo_environment_chromium',
-        'mojo_base.gyp:mojo_message_pump_lib',
         'mojo_edk.gyp:mojo_run_all_unittests',
         'mojo_public.gyp:mojo_cpp_bindings',
+        'mojo_public.gyp:mojo_message_pump_lib',
         'mojo_public.gyp:mojo_public_bindings_test_utils',
         'mojo_public.gyp:mojo_public_test_associated_interfaces',
         'mojo_public.gyp:mojo_public_test_interfaces',
diff --git a/mojo/mojo_platform_handle.gyp b/mojo/mojo_platform_handle.gyp
index 247c699..46ce6c7 100644
--- a/mojo/mojo_platform_handle.gyp
+++ b/mojo/mojo_platform_handle.gyp
@@ -13,7 +13,7 @@
     {
       # GN version: //mojo/platform_handle:platform_handle/platform_handle_impl
       'target_name': 'platform_handle',
-      'type': 'static_library',
+      'type': '<(component)',
       'include_dirs': [
         '../..',
       ],
diff --git a/mojo/mojo_public.gyp b/mojo/mojo_public.gyp
index d833edd1..3017df8 100644
--- a/mojo/mojo_public.gyp
+++ b/mojo/mojo_public.gyp
@@ -188,6 +188,31 @@
       ],
     },
     {
+      # GN version: //mojo/message_pump
+      'target_name': 'mojo_message_pump_lib',
+      'type': '<(component)',
+      'defines': [
+        'MOJO_MESSAGE_PUMP_IMPLEMENTATION',
+      ],
+      'dependencies': [
+        '../base/base.gyp:base',
+        '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+        '<(mojo_system_for_component)',
+      ],
+      'export_dependent_settings': [
+        '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+      ],
+      'sources': [
+        'message_pump/handle_watcher.cc',
+        'message_pump/handle_watcher.h',
+        'message_pump/message_pump_mojo.cc',
+        'message_pump/message_pump_mojo.h',
+        'message_pump/message_pump_mojo_handler.h',
+        'message_pump/time_helper.cc',
+        'message_pump/time_helper.h',
+      ],
+    },
+    {
       # GN version: //mojo/public/js
       'target_name': 'mojo_js_bindings',
       'type': 'static_library',
diff --git a/mojo/public/c/gles2/gles2.h b/mojo/public/c/gles2/gles2.h
index 247084d..6c0b44e 100644
--- a/mojo/public/c/gles2/gles2.h
+++ b/mojo/public/c/gles2/gles2.h
@@ -10,7 +10,6 @@
 #include <GLES2/gl2.h>
 #include <stdint.h>
 
-#include "mojo/public/c/environment/async_waiter.h"
 #include "mojo/public/c/gles2/gles2_export.h"
 #include "mojo/public/c/gles2/gles2_types.h"
 #include "mojo/public/c/system/types.h"
@@ -20,11 +19,10 @@
 #endif
 
 MOJO_GLES2_EXPORT MojoGLES2Context
-    MojoGLES2CreateContext(MojoHandle handle,
-                           const int32_t* attrib_list,
-                           MojoGLES2ContextLost lost_callback,
-                           void* closure,
-                           const MojoAsyncWaiter* async_waiter);
+MojoGLES2CreateContext(MojoHandle handle,
+                       const int32_t* attrib_list,
+                       MojoGLES2ContextLost lost_callback,
+                       void* closure);
 MOJO_GLES2_EXPORT void MojoGLES2DestroyContext(MojoGLES2Context context);
 MOJO_GLES2_EXPORT void MojoGLES2MakeCurrent(MojoGLES2Context context);
 MOJO_GLES2_EXPORT void MojoGLES2SwapBuffers(void);
diff --git a/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h b/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h
index 9230be3..5f048259 100644
--- a/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h
+++ b/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h
@@ -578,3 +578,9 @@
               GLint,
               (GLuint program, const char* name),
               (program, name))
+VISIT_GL_CALL(UniformMatrix4fvStreamTextureMatrixCHROMIUM,
+              void,
+              (GLint location,
+               GLboolean transpose,
+               const GLfloat* default_value),
+              (location, transpose, default_value))
diff --git a/mojo/public/platform/native/gles2_thunks.cc b/mojo/public/platform/native/gles2_thunks.cc
index 2350fce..6d84279 100644
--- a/mojo/public/platform/native/gles2_thunks.cc
+++ b/mojo/public/platform/native/gles2_thunks.cc
@@ -17,11 +17,10 @@
 MojoGLES2Context MojoGLES2CreateContext(MojoHandle handle,
                                         const int32_t* attrib_list,
                                         MojoGLES2ContextLost lost_callback,
-                                        void* closure,
-                                        const MojoAsyncWaiter* async_waiter) {
+                                        void* closure) {
   assert(g_control_thunks.GLES2CreateContext);
-  return g_control_thunks.GLES2CreateContext(
-      handle, attrib_list, lost_callback, closure, async_waiter);
+  return g_control_thunks.GLES2CreateContext(handle, attrib_list, lost_callback,
+                                             closure);
 }
 
 void MojoGLES2DestroyContext(MojoGLES2Context context) {
diff --git a/mojo/public/platform/native/gles2_thunks.h b/mojo/public/platform/native/gles2_thunks.h
index cd9cc75..4a565509 100644
--- a/mojo/public/platform/native/gles2_thunks.h
+++ b/mojo/public/platform/native/gles2_thunks.h
@@ -22,8 +22,7 @@
   MojoGLES2Context (*GLES2CreateContext)(MojoHandle handle,
                                          const int32_t* attrib_list,
                                          MojoGLES2ContextLost lost_callback,
-                                         void* closure,
-                                         const MojoAsyncWaiter* async_waiter);
+                                         void* closure);
   void (*GLES2DestroyContext)(MojoGLES2Context context);
   void (*GLES2MakeCurrent)(MojoGLES2Context context);
   void (*GLES2SwapBuffers)();
diff --git a/mojo/services/network/network_service_delegate.cc b/mojo/services/network/network_service_delegate.cc
index b1920f7..a3a0ea38 100644
--- a/mojo/services/network/network_service_delegate.cc
+++ b/mojo/services/network/network_service_delegate.cc
@@ -49,7 +49,7 @@
 }
 
 void NetworkServiceDelegate::Initialize(Shell* shell, const std::string& url,
-                                        uint32_t id) {
+                                        uint32_t id, uint32_t user_id) {
   shell_ = shell;
 
   // TODO(erg): Find everything else that writes to the filesystem and
diff --git a/mojo/services/network/network_service_delegate.h b/mojo/services/network/network_service_delegate.h
index 7890c22..678db5a 100644
--- a/mojo/services/network/network_service_delegate.h
+++ b/mojo/services/network/network_service_delegate.h
@@ -34,7 +34,8 @@
 
  private:
   // mojo::ShellClient implementation.
-  void Initialize(Shell* shell, const std::string& url, uint32_t id) override;
+  void Initialize(Shell* shell, const std::string& url,
+                  uint32_t id, uint32_t user_id) override;
   bool AcceptConnection(Connection* connection) override;
   bool ShellConnectionLost() override;
   void Quit() override;
diff --git a/mojo/services/package_manager/loader.cc b/mojo/services/package_manager/loader.cc
index c1bb53b1..6799e41 100644
--- a/mojo/services/package_manager/loader.cc
+++ b/mojo/services/package_manager/loader.cc
@@ -11,15 +11,17 @@
 namespace package_manager {
 
 Loader::Loader(base::TaskRunner* blocking_pool,
-               bool register_mojo_url_schemes)
+               bool register_mojo_url_schemes,
+               scoped_ptr<package_manager::ApplicationCatalogStore> app_catalog)
     : blocking_pool_(blocking_pool),
-      register_mojo_url_schemes_(register_mojo_url_schemes) {}
+      register_mojo_url_schemes_(register_mojo_url_schemes),
+      app_catalog_(std::move(app_catalog)) {}
 Loader::~Loader() {}
 
 void Loader::Load(const GURL& url,
                   mojo::shell::mojom::ShellClientRequest request) {
   client_.reset(new package_manager::PackageManager(
-      blocking_pool_, register_mojo_url_schemes_));
+      blocking_pool_, register_mojo_url_schemes_, std::move(app_catalog_)));
   connection_.reset(new mojo::ShellConnection(client_.get(),
                                               std::move(request)));
 }
diff --git a/mojo/services/package_manager/loader.h b/mojo/services/package_manager/loader.h
index 5bddd36f..58ee8f9 100644
--- a/mojo/services/package_manager/loader.h
+++ b/mojo/services/package_manager/loader.h
@@ -18,9 +18,13 @@
 
 namespace package_manager {
 
+class ApplicationCatalogStore;
+
 class Loader : public mojo::shell::ApplicationLoader {
  public:
-  Loader(base::TaskRunner* blocking_pool, bool register_mojo_url_schemes);
+  Loader(base::TaskRunner* blocking_pool,
+         bool register_mojo_url_schemes,
+         scoped_ptr<package_manager::ApplicationCatalogStore> app_catalog);
   ~Loader() override;
 
   // mojo::shell::ApplicationLoader:
@@ -30,6 +34,7 @@
  private:
   base::TaskRunner* blocking_pool_;
   bool register_mojo_url_schemes_;
+  scoped_ptr<package_manager::ApplicationCatalogStore> app_catalog_;
   scoped_ptr<mojo::ShellClient> client_;
   scoped_ptr<mojo::ShellConnection> connection_;
 
diff --git a/mojo/services/package_manager/main.cc b/mojo/services/package_manager/main.cc
index 596b994..be54ee334 100644
--- a/mojo/services/package_manager/main.cc
+++ b/mojo/services/package_manager/main.cc
@@ -29,7 +29,8 @@
         new base::SequencedWorkerPool(kMaxBlockingPoolThreads,
                                       "blocking_pool"));
     scoped_ptr<mojo::ShellClient> shell_client(
-        new package_manager::PackageManager(blocking_pool.get(), true));
+        new package_manager::PackageManager(blocking_pool.get(), true,
+                                            nullptr));
     mojo::ShellConnection connection(
         shell_client.get(), MakeRequest<mojo::shell::mojom::ShellClient>(
             MakeScopedHandle(MessagePipeHandle(shell_handle))));
diff --git a/mojo/services/package_manager/package_manager.cc b/mojo/services/package_manager/package_manager.cc
index 1ec443aa..ce6e1a69 100644
--- a/mojo/services/package_manager/package_manager.cc
+++ b/mojo/services/package_manager/package_manager.cc
@@ -38,10 +38,13 @@
 ApplicationInfo BuildApplicationInfoFromDictionary(
     const base::DictionaryValue& value) {
   ApplicationInfo info;
-  CHECK(value.GetString("url", &info.url));
-  CHECK(value.GetString("name", &info.name));
+  std::string url_string;
+  CHECK(value.GetString(ApplicationCatalogStore::kUrlKey, &url_string));
+  info.url = GURL(url_string);
+  CHECK(value.GetString(ApplicationCatalogStore::kNameKey, &info.name));
   const base::DictionaryValue* capabilities = nullptr;
-  CHECK(value.GetDictionary("capabilities", &capabilities));
+  CHECK(value.GetDictionary(ApplicationCatalogStore::kCapabilitiesKey,
+                            &capabilities));
   info.base_filter = BuildCapabilityFilterFromDictionary(*capabilities);
   return info;
 }
@@ -49,8 +52,8 @@
 void SerializeEntry(const ApplicationInfo& entry,
                     base::DictionaryValue** value) {
   *value = new base::DictionaryValue;
-  (*value)->SetString("url", entry.url);
-  (*value)->SetString("name", entry.name);
+  (*value)->SetString(ApplicationCatalogStore::kUrlKey, entry.url.spec());
+  (*value)->SetString(ApplicationCatalogStore::kNameKey, entry.name);
   base::DictionaryValue* capabilities = new base::DictionaryValue;
   for (const auto& pair : entry.base_filter) {
     scoped_ptr<base::ListValue> interfaces(new base::ListValue);
@@ -58,7 +61,8 @@
       interfaces->AppendString(iface_name);
     capabilities->Set(pair.first, std::move(interfaces));
   }
-  (*value)->Set("capabilities", make_scoped_ptr(capabilities));
+  (*value)->Set(ApplicationCatalogStore::kCapabilitiesKey,
+                make_scoped_ptr(capabilities));
 }
 
 scoped_ptr<base::Value> ReadManifest(const base::FilePath& manifest_path) {
@@ -72,15 +76,21 @@
 
 }  // namespace
 
+// static
+const char ApplicationCatalogStore::kUrlKey[] = "url";
+// static
+const char ApplicationCatalogStore::kNameKey[] = "name";
+// static
+const char ApplicationCatalogStore::kCapabilitiesKey[] = "capabilities";
+
 ApplicationInfo::ApplicationInfo() {}
 ApplicationInfo::~ApplicationInfo() {}
 
-ApplicationCatalogStore::~ApplicationCatalogStore() {}
-
 PackageManager::PackageManager(base::TaskRunner* blocking_pool,
-                               bool register_schemes)
+                               bool register_schemes,
+                               scoped_ptr<ApplicationCatalogStore> catalog)
     : blocking_pool_(blocking_pool),
-      catalog_store_(nullptr),
+      catalog_store_(std::move(catalog)),
       weak_factory_(this) {
   if (register_schemes)
     mojo::RegisterMojoSchemes();
@@ -92,11 +102,13 @@
       mojo::util::FilePathToFileURL(shell_dir).Resolve(std::string());
   system_package_dir_ =
       mojo::util::AddTrailingSlashIfNeeded(system_package_dir_);
+
+  DeserializeCatalog();
 }
 PackageManager::~PackageManager() {}
 
 void PackageManager::Initialize(mojo::Shell* shell, const std::string& url,
-                                uint32_t id) {}
+                                uint32_t id, uint32_t user_id) {}
 
 bool PackageManager::AcceptConnection(mojo::Connection* connection) {
   connection->AddInterface<mojom::Catalog>(this);
@@ -146,10 +158,10 @@
 void PackageManager::ResolveMojoURL(const mojo::String& mojo_url,
                                     const ResolveMojoURLCallback& callback) {
   GURL resolved_url = mojo_url.To<GURL>();
-  auto alias_iter = mojo_url_aliases_.find(mojo_url);
+  auto alias_iter = mojo_url_aliases_.find(resolved_url);
   std::string qualifier;
   if (alias_iter != mojo_url_aliases_.end()) {
-    resolved_url = GURL(alias_iter->second.first);
+    resolved_url = alias_iter->second.first;
     qualifier = alias_iter->second.second;
   } else {
     qualifier = resolved_url.host();
@@ -163,13 +175,14 @@
     const GetEntriesCallback& callback) {
   mojo::Map<mojo::String, mojom::CatalogEntryPtr> entries;
   std::vector<mojo::String> urls_vec = urls.PassStorage();
-  for (const auto& url : urls_vec) {
+  for (const std::string& url_string : urls_vec) {
+    const GURL url(url_string);
     if (catalog_.find(url) == catalog_.end())
       continue;
     const ApplicationInfo& info = catalog_[url];
     mojom::CatalogEntryPtr entry(mojom::CatalogEntry::New());
     entry->name = info.name;
-    entries[info.url] = std::move(entry);
+    entries[info.url.spec()] = std::move(entry);
   }
   callback.Run(std::move(entries));
 }
@@ -178,7 +191,7 @@
     const GURL& resolved_url,
     const std::string& qualifier,
     const ResolveMojoURLCallback& callback) {
-  auto info_iter = catalog_.find(resolved_url.spec());
+  auto info_iter = catalog_.find(resolved_url);
   CHECK(info_iter != catalog_.end());
 
   GURL file_url;
@@ -209,7 +222,7 @@
 }
 
 bool PackageManager::IsURLInCatalog(const GURL& url) const {
-  return catalog_.find(url.spec()) != catalog_.end();
+  return catalog_.find(url) != catalog_.end();
 }
 
 void PackageManager::EnsureURLInCatalog(
@@ -240,21 +253,18 @@
 }
 
 void PackageManager::DeserializeCatalog() {
-  ApplicationInfo info;
-  info.url = "mojo://shell/";
-  info.name = "Mojo Shell";
-  catalog_[info.url] = info;
-
   if (!catalog_store_)
     return;
-  base::ListValue* catalog = nullptr;
-  catalog_store_->GetStore(&catalog);
+  const base::ListValue* catalog = catalog_store_->GetStore();
   CHECK(catalog);
+  // TODO(sky): make this handle aliases.
   for (auto it = catalog->begin(); it != catalog->end(); ++it) {
     const base::DictionaryValue* dictionary = nullptr;
     const base::Value* v = *it;
     CHECK(v->GetAsDictionary(&dictionary));
-    DeserializeApplication(dictionary);
+    const ApplicationInfo app_info =
+        BuildApplicationInfoFromDictionary(*dictionary);
+    catalog_[app_info.url] = app_info;
   }
 }
 
@@ -283,7 +293,7 @@
         applications->GetDictionary(i, &child);
         const ApplicationInfo& child_info = DeserializeApplication(child);
         mojo_url_aliases_[child_info.url] =
-            std::make_pair(info.url, GURL(child_info.url).host());
+            std::make_pair(info.url, child_info.url.host());
       }
     }
   }
@@ -324,7 +334,7 @@
     DeserializeApplication(dictionary);
   } else {
     ApplicationInfo info;
-    info.url = url.spec();
+    info.url = url;
     info.name = url.spec();
     catalog_[info.url] = info;
   }
diff --git a/mojo/services/package_manager/package_manager.h b/mojo/services/package_manager/package_manager.h
index c311ce4..12597240 100644
--- a/mojo/services/package_manager/package_manager.h
+++ b/mojo/services/package_manager/package_manager.h
@@ -30,7 +30,7 @@
   ApplicationInfo();
   ~ApplicationInfo();
 
-  std::string url;
+  GURL url;
   std::string name;
   CapabilityFilter base_filter;
 };
@@ -40,15 +40,25 @@
 // of the contents of the store, so no one else must modify its contents.
 class ApplicationCatalogStore {
  public:
+  // Value is a string.
+  static const char kUrlKey[];
+  // Value is a string.
+  static const char kNameKey[];
+  // Value is a dictionary that maps from the filter to a list of string
+  // interfaces.
+  static const char kCapabilitiesKey[];
+
+  virtual ~ApplicationCatalogStore() {}
+
   // Called during initialization to construct the PackageManagerImpl's catalog.
-  virtual void GetStore(base::ListValue** store) = 0;
+  // Returns a serialized list of the apps. Each entry in the returned list
+  // corresponds to an app (as a dictionary). Each dictionary has a url, name
+  // and capabilities. The return value is owned by the caller.
+  virtual const base::ListValue* GetStore() = 0;
 
   // Write the catalog to the store. Called when the PackageManagerImpl learns
   // of a newly encountered application.
   virtual void UpdateStore(scoped_ptr<base::ListValue> store) = 0;
-
- protected:
-  virtual ~ApplicationCatalogStore();
 };
 
 class PackageManager : public mojo::ShellClient,
@@ -61,16 +71,17 @@
  public:
   // If |register_schemes| is true, mojo: and exe: schemes are registered as
   // "standard".
-  PackageManager(base::TaskRunner* blocking_pool, bool register_schemes);
+  PackageManager(base::TaskRunner* blocking_pool,
+                 bool register_schemes,
+                 scoped_ptr<ApplicationCatalogStore> catalog);
   ~PackageManager() override;
 
  private:
-  using MojoURLAliasMap =
-      std::map<std::string, std::pair<std::string, std::string>>;
+  using MojoURLAliasMap = std::map<GURL, std::pair<GURL, std::string>>;
 
   // mojo::ShellClient:
   void Initialize(mojo::Shell* shell, const std::string& url,
-                  uint32_t id) override;
+                  uint32_t id, uint32_t user_id) override;
   bool AcceptConnection(mojo::Connection* connection) override;
 
   // mojo::InterfaceFactory<mojom::Resolver>:
@@ -150,8 +161,8 @@
   mojo::WeakBindingSet<mojom::ShellResolver> shell_resolver_bindings_;
   mojo::WeakBindingSet<mojom::Catalog> catalog_bindings_;
 
-  ApplicationCatalogStore* catalog_store_;
-  std::map<std::string, ApplicationInfo> catalog_;
+  scoped_ptr<ApplicationCatalogStore> catalog_store_;
+  std::map<GURL, ApplicationInfo> catalog_;
 
   // Used when an app handles multiple urls. Maps from app (as url) to url of
   // app that is responsible for handling it. The value is a pair of the
diff --git a/mojo/services/test_service/test_request_tracker_application.cc b/mojo/services/test_service/test_request_tracker_application.cc
index 55246e6..73190b00 100644
--- a/mojo/services/test_service/test_request_tracker_application.cc
+++ b/mojo/services/test_service/test_request_tracker_application.cc
@@ -21,7 +21,8 @@
 
 void TestRequestTrackerApplication::Initialize(Shell* shell,
                                                const std::string& url,
-                                               uint32_t id) {
+                                               uint32_t id,
+                                               uint32_t user_id) {
   shell_ = shell;
 }
 
diff --git a/mojo/services/test_service/test_request_tracker_application.h b/mojo/services/test_service/test_request_tracker_application.h
index 8ace9ec1..22206f9e 100644
--- a/mojo/services/test_service/test_request_tracker_application.h
+++ b/mojo/services/test_service/test_request_tracker_application.h
@@ -26,7 +26,8 @@
   ~TestRequestTrackerApplication() override;
 
   // mojo::ShellClient methods:
-  void Initialize(Shell* shell, const std::string& url, uint32_t id) override;
+  void Initialize(Shell* shell, const std::string& url,
+                  uint32_t id, uint32_t user_id) override;
   bool AcceptConnection(Connection* connection) override;
 
   // InterfaceFactory<TestTimeService> methods:
diff --git a/mojo/services/test_service/test_service_application.cc b/mojo/services/test_service/test_service_application.cc
index 02e4421..a447c24 100644
--- a/mojo/services/test_service/test_service_application.cc
+++ b/mojo/services/test_service/test_service_application.cc
@@ -24,7 +24,7 @@
 }
 
 void TestServiceApplication::Initialize(Shell* shell, const std::string& url,
-                                        uint32_t id) {
+                                        uint32_t id, uint32_t user_id) {
   shell_ = shell;
 }
 
diff --git a/mojo/services/test_service/test_service_application.h b/mojo/services/test_service/test_service_application.h
index fd107fb..1c024c03 100644
--- a/mojo/services/test_service/test_service_application.h
+++ b/mojo/services/test_service/test_service_application.h
@@ -23,7 +23,8 @@
   ~TestServiceApplication() override;
 
   // mojo::ShellClient implementation.
-  void Initialize(Shell* shell, const std::string& url, uint32_t id) override;
+  void Initialize(Shell* shell, const std::string& url,
+                  uint32_t id, uint32_t user_id) override;
   bool AcceptConnection(Connection* connection) override;
 
   // InterfaceFactory<TestService> implementation.
diff --git a/mojo/shell/BUILD.gn b/mojo/shell/BUILD.gn
index b2d3ef6..2fbf078 100644
--- a/mojo/shell/BUILD.gn
+++ b/mojo/shell/BUILD.gn
@@ -33,6 +33,7 @@
     "identity.cc",
     "identity.h",
     "native_runner.h",
+    "native_runner_delegate.h",
     "switches.cc",
     "switches.h",
   ]
@@ -42,7 +43,6 @@
     "//base/third_party/dynamic_annotations",
     "//mojo/common",
     "//mojo/public/cpp/bindings",
-    "//mojo/services/package_manager:lib",
     "//mojo/services/package_manager/public/interfaces",
     "//mojo/shell/public/cpp:sources",
     "//mojo/shell/public/interfaces",
@@ -50,6 +50,11 @@
     "//url",
   ]
 
+  public_deps = [
+    # ApplicationManager exposes and uses PackageManager types in its header.
+    "//mojo/services/package_manager:lib",
+  ]
+
   # For mojo/shell/application_loader.h
   allow_circular_includes_from = [ "//mojo/services/package_manager:lib" ]
 }
diff --git a/mojo/shell/application_instance.cc b/mojo/shell/application_instance.cc
index 7923a764..df2cfb7 100644
--- a/mojo/shell/application_instance.cc
+++ b/mojo/shell/application_instance.cc
@@ -33,7 +33,7 @@
       queue_requests_(false),
       native_runner_(nullptr),
       pid_(base::kNullProcessId) {
-  DCHECK_NE(Shell::kInvalidApplicationID, id_);
+  DCHECK_NE(kInvalidApplicationID, id_);
 }
 
 ApplicationInstance::~ApplicationInstance() {
@@ -44,7 +44,7 @@
 
 void ApplicationInstance::InitializeApplication() {
   shell_client_->Initialize(binding_.CreateInterfacePtrAndBind(),
-                            identity_.url().spec(), id_);
+                            identity_.url().spec(), id_, identity_.user_id());
   binding_.set_connection_error_handler([this]() { OnConnectionError(); });
 }
 
@@ -67,8 +67,21 @@
 }
 
 // Shell implementation:
+void ApplicationInstance::GetConnector(mojom::ConnectorRequest request) {
+  connectors_.AddBinding(this, std::move(request));
+}
+
+void ApplicationInstance::QuitApplication() {
+  queue_requests_ = true;
+  shell_client_->OnQuitRequested(
+      base::Bind(&ApplicationInstance::OnQuitRequestedResult,
+                 base::Unretained(this)));
+}
+
+// Connector implementation:
 void ApplicationInstance::Connect(
     const String& app_url,
+    uint32_t user_id,
     shell::mojom::InterfaceProviderRequest remote_interfaces,
     shell::mojom::InterfaceProviderPtr local_interfaces,
     mojom::CapabilityFilterPtr filter,
@@ -86,8 +99,9 @@
       capability_filter = filter->filter.To<CapabilityFilter>();
 
     scoped_ptr<ConnectParams> params(new ConnectParams);
-    params->SetSource(this);
-    params->set_target(Identity(url, std::string(), capability_filter));
+    params->set_source(identity_);
+    params->set_target(
+        Identity(url, std::string(), user_id, capability_filter));
     params->set_remote_interfaces(std::move(remote_interfaces));
     params->set_local_interfaces(std::move(local_interfaces));
     params->set_connect_callback(callback);
@@ -99,11 +113,8 @@
   }
 }
 
-void ApplicationInstance::QuitApplication() {
-  queue_requests_ = true;
-  shell_client_->OnQuitRequested(
-      base::Bind(&ApplicationInstance::OnQuitRequestedResult,
-                 base::Unretained(this)));
+void ApplicationInstance::Clone(mojom::ConnectorRequest request) {
+  connectors_.AddBinding(this, std::move(request));
 }
 
 void ApplicationInstance::SetPID(uint32_t pid) {
@@ -112,9 +123,9 @@
 }
 
 uint32_t ApplicationInstance::GenerateUniqueID() const {
-  static uint32_t id = Shell::kInvalidApplicationID;
+  static uint32_t id = kInvalidApplicationID;
   ++id;
-  CHECK_NE(Shell::kInvalidApplicationID, id);
+  CHECK_NE(kInvalidApplicationID, id);
   return id;
 }
 
@@ -128,11 +139,11 @@
 
   ApplicationInstance* source =
       manager_->GetApplicationInstance(params->source());
-  uint32_t source_id = source ? source->id() : Shell::kInvalidApplicationID;
+  uint32_t source_id = source ? source->id() : kInvalidApplicationID;
   shell_client_->AcceptConnection(
-      params->source().url().spec(), source_id, params->TakeRemoteInterfaces(),
-      params->TakeLocalInterfaces(), Array<String>::From(interfaces),
-      params->target().url().spec());
+      params->source().url().spec(), params->source().user_id(), source_id,
+      params->TakeRemoteInterfaces(), params->TakeLocalInterfaces(),
+      Array<String>::From(interfaces), params->target().url().spec());
 }
 
 void ApplicationInstance::OnConnectionError() {
diff --git a/mojo/shell/application_instance.h b/mojo/shell/application_instance.h
index afe30e59..fb4d046 100644
--- a/mojo/shell/application_instance.h
+++ b/mojo/shell/application_instance.h
@@ -14,6 +14,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/process/process_handle.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/weak_binding_set.h"
 #include "mojo/shell/capability_filter.h"
 #include "mojo/shell/connect_params.h"
 #include "mojo/shell/identity.h"
@@ -31,6 +32,7 @@
 // Encapsulates a connection to an instance of an application, tracked by the
 // shell's ApplicationManager.
 class ApplicationInstance : public mojom::Shell,
+                            public mojom::Connector,
                             public mojom::PIDReceiver {
  public:
   ApplicationInstance(
@@ -56,12 +58,17 @@
 
  private:
   // Shell implementation:
+  void GetConnector(mojom::ConnectorRequest request) override;
+  void QuitApplication() override;
+
+  // Connector implementation:
   void Connect(const String& app_url,
+               uint32_t user_id,
                shell::mojom::InterfaceProviderRequest remote_interfaces,
                shell::mojom::InterfaceProviderPtr local_interfaces,
                mojom::CapabilityFilterPtr filter,
                const ConnectCallback& callback) override;
-  void QuitApplication() override;
+  void Clone(mojom::ConnectorRequest request) override;
 
   // PIDReceiver implementation:
   void SetPID(uint32_t pid) override;
@@ -86,6 +93,7 @@
   mojom::ShellClientPtr shell_client_;
   Binding<mojom::Shell> binding_;
   Binding<mojom::PIDReceiver> pid_receiver_binding_;
+  WeakBindingSet<mojom::Connector> connectors_;
   bool queue_requests_;
   std::vector<ConnectParams*> queued_client_requests_;
   NativeRunner* native_runner_;
diff --git a/mojo/shell/application_manager.cc b/mojo/shell/application_manager.cc
index 1ff5901..6f27b2b 100644
--- a/mojo/shell/application_manager.cc
+++ b/mojo/shell/application_manager.cc
@@ -29,29 +29,6 @@
 namespace mojo {
 namespace shell {
 
-namespace {
-
-class ShellApplicationLoader : public ApplicationLoader {
- public:
-  explicit ShellApplicationLoader(ApplicationManager* manager)
-      : manager_(manager) {}
-  ~ShellApplicationLoader() override {}
-
- private:
-  // Overridden from ApplicationLoader:
-  void Load(const GURL& url, mojom::ShellClientRequest request) override {
-    DCHECK(request.is_pending());
-    shell_connection_.reset(new ShellConnection(manager_, std::move(request)));
-  }
-
-  ApplicationManager* manager_;
-  scoped_ptr<ShellConnection> shell_connection_;
-
-  DISALLOW_COPY_AND_ASSIGN(ShellApplicationLoader);
-};
-
-}  // namespace
-
 // static
 ApplicationManager::TestAPI::TestAPI(ApplicationManager* manager)
     : manager_(manager) {
@@ -69,20 +46,19 @@
 ////////////////////////////////////////////////////////////////////////////////
 // ApplicationManager, public:
 
-ApplicationManager::ApplicationManager(bool register_mojo_url_schemes)
-    : ApplicationManager(nullptr, nullptr, register_mojo_url_schemes) {}
-
 ApplicationManager::ApplicationManager(
     scoped_ptr<NativeRunnerFactory> native_runner_factory,
-    base::TaskRunner* task_runner,
-    bool register_mojo_url_schemes)
-    : task_runner_(task_runner),
+    base::TaskRunner* file_task_runner,
+    bool register_mojo_url_schemes,
+    scoped_ptr<package_manager::ApplicationCatalogStore> app_catalog)
+    : file_task_runner_(file_task_runner),
       native_runner_factory_(std::move(native_runner_factory)),
       weak_ptr_factory_(this) {
-  SetLoaderForURL(make_scoped_ptr(new ShellApplicationLoader(this)),
-                  GURL("mojo://shell/"));
+  mojom::ShellClientRequest request;
+  CreateInstance(CreateShellIdentity(), &request);
+  shell_connection_.reset(new ShellConnection(this, std::move(request)));
 
-  InitPackageManager(register_mojo_url_schemes);
+  InitPackageManager(register_mojo_url_schemes, std::move(app_catalog));
 }
 
 ApplicationManager::~ApplicationManager() {
@@ -103,6 +79,15 @@
                        params->target().url().spec());
   DCHECK(params->target().url().is_valid());
 
+  if (params->target().user_id() == mojom::Connector::kUserInherit) {
+    ApplicationInstance* source = GetApplicationInstance(params->source());
+    Identity target = params->target();
+    // TODO(beng): we should CHECK source.
+    target.set_user_id(source ? source->identity().user_id()
+                              : mojom::Connector::kUserRoot);
+    params->set_target(target);
+  }
+
   // Connect to an existing matching instance, if possible.
   if (ConnectToExistingInstance(&params))
     return;
@@ -194,7 +179,9 @@
   // created instance is identified by |url| and may be subsequently reached by
   // client code using this identity.
   CapabilityFilter local_filter = filter->filter.To<CapabilityFilter>();
-  Identity target_id(url.To<GURL>(), std::string(), local_filter);
+  // TODO(beng): obtain userid from the inbound connection.
+  Identity target_id(url.To<GURL>(), std::string(),
+                     mojom::Connector::kUserInherit, local_filter);
   mojom::ShellClientRequest request;
   ApplicationInstance* instance = CreateInstance(target_id, &request);
   instance->BindPIDReceiver(std::move(pid_receiver));
@@ -218,9 +205,11 @@
 ////////////////////////////////////////////////////////////////////////////////
 // ApplicationManager, private:
 
-void ApplicationManager::InitPackageManager(bool register_mojo_url_schemes) {
-  scoped_ptr<ApplicationLoader> loader(
-      new package_manager::Loader(task_runner_, register_mojo_url_schemes));
+void ApplicationManager::InitPackageManager(
+    bool register_mojo_url_schemes,
+    scoped_ptr<package_manager::ApplicationCatalogStore> app_catalog) {
+  scoped_ptr<ApplicationLoader> loader(new package_manager::Loader(
+      file_task_runner_, register_mojo_url_schemes, std::move(app_catalog)));
 
   mojom::ShellClientRequest request;
   GURL url("mojo://package_manager/");
@@ -235,8 +224,12 @@
 bool ApplicationManager::ConnectToExistingInstance(
     scoped_ptr<ConnectParams>* params) {
   ApplicationInstance* instance = GetApplicationInstance((*params)->target());
-  if (!instance)
-    return false;
+  if (!instance) {
+    Identity root_identity = (*params)->target();
+    root_identity.set_user_id(mojom::Connector::kUserRoot);
+    instance = GetApplicationInstance(root_identity);
+    if (!instance) return false;
+  }
   instance->ConnectToClient(std::move(*params));
   return true;
 }
@@ -315,7 +308,8 @@
   // TODO(beng): this clobbers the filter passed via Connect().
   if (!base_filter.is_null())
     filter = base_filter->filter.To<CapabilityFilter>();
-  Identity target(params->target().url(), params->target().qualifier(), filter);
+  Identity target(params->target().url(), params->target().qualifier(),
+                  params->target().user_id(), filter);
 
   mojom::ShellClientRequest request;
   ApplicationInstance* instance = CreateInstance(target, &request);
@@ -332,13 +326,14 @@
     // from the original request rather than for the package itself, which will
     // always be the same.
     CreateShellClient(source,
-                      Identity(resolved_gurl, target.qualifier(), filter),
+                      Identity(resolved_gurl, target.qualifier(),
+                               target.user_id(), filter),
                       target.url(), std::move(request));
   } else {
     bool start_sandboxed = false;
     base::FilePath path = util::UrlToFilePath(file_url.To<GURL>());
     scoped_ptr<NativeRunner> runner = native_runner_factory_->Create(path);
-    runner->Start(path, start_sandboxed, std::move(request),
+    runner->Start(path, target, start_sandboxed, std::move(request),
                   base::Bind(&ApplicationManager::ApplicationPIDAvailable,
                              weak_ptr_factory_.GetWeakPtr(), instance->id()),
                   base::Bind(&ApplicationManager::CleanupRunner,
diff --git a/mojo/shell/application_manager.h b/mojo/shell/application_manager.h
index 83c1ad7..2757d92 100644
--- a/mojo/shell/application_manager.h
+++ b/mojo/shell/application_manager.h
@@ -13,6 +13,7 @@
 #include "base/memory/weak_ptr.h"
 #include "mojo/public/cpp/bindings/weak_binding_set.h"
 #include "mojo/public/cpp/bindings/weak_interface_ptr_set.h"
+#include "mojo/services/package_manager/package_manager.h"
 #include "mojo/services/package_manager/public/interfaces/shell_resolver.mojom.h"
 #include "mojo/shell/application_loader.h"
 #include "mojo/shell/capability_filter.h"
@@ -34,6 +35,7 @@
 }
 
 namespace mojo {
+class ShellConnection;
 namespace shell {
 
 class ApplicationInstance;
@@ -56,19 +58,19 @@
     DISALLOW_COPY_AND_ASSIGN(TestAPI);
   };
 
-  // Creates an ApplicationManager.
-  explicit ApplicationManager(bool register_mojo_url_schemes);
   // |native_runner_factory| is an instance of an object capable of vending
   // implementations of NativeRunner, e.g. for in or out-of-process execution.
   // See native_runner.h and RunNativeApplication().
-  // |task_runner| provides access to a thread to perform file copy operations
-  // on. This may be null only in testing environments where applications are
-  // loaded via ApplicationLoader implementations.
+  // |file_task_runner| provides access to a thread to perform file copy
+  // operations on. This may be null only in testing environments where
+  // applications are loaded via ApplicationLoader implementations.
   // When |register_mojo_url_schemes| is true, mojo: and exe: URL schems are
   // registered as "standard" which faciliates resolving.
-  ApplicationManager(scoped_ptr<NativeRunnerFactory> native_runner_factory,
-                     base::TaskRunner* task_runner,
-                     bool register_mojo_url_schemes);
+  ApplicationManager(
+      scoped_ptr<NativeRunnerFactory> native_runner_factory,
+      base::TaskRunner* file_task_runner,
+      bool register_mojo_url_schemes,
+      scoped_ptr<package_manager::ApplicationCatalogStore> app_catalog);
   ~ApplicationManager() override;
 
   // Provide a callback to be notified whenever an instance is destroyed.
@@ -121,7 +123,9 @@
                                mojom::PIDReceiverRequest pid_receiver) override;
   void AddListener(mojom::ApplicationManagerListenerPtr listener) override;
 
-  void InitPackageManager(bool register_mojo_url_schemes);
+  void InitPackageManager(
+      bool register_mojo_url_schemes,
+      scoped_ptr<package_manager::ApplicationCatalogStore> app_catalog);
 
   // Attempt to complete the connection requested by |params| by connecting to
   // an existing instance. If there is an existing instance, |params| is taken,
@@ -185,16 +189,17 @@
   WeakInterfacePtrSet<mojom::ApplicationManagerListener> listeners_;
 
   base::Callback<void(const Identity&)> instance_quit_callback_;
-  base::TaskRunner* task_runner_;
+  base::TaskRunner* file_task_runner_;
   scoped_ptr<NativeRunnerFactory> native_runner_factory_;
   std::vector<scoped_ptr<NativeRunner>> native_runners_;
+  scoped_ptr<ShellConnection> shell_connection_;
   WeakBindingSet<mojom::ApplicationManager> bindings_;
   base::WeakPtrFactory<ApplicationManager> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ApplicationManager);
 };
 
-mojom::Shell::ConnectCallback EmptyConnectCallback();
+mojom::Connector::ConnectCallback EmptyConnectCallback();
 
 }  // namespace shell
 }  // namespace mojo
diff --git a/mojo/shell/background/BUILD.gn b/mojo/shell/background/BUILD.gn
index b7e5ee3..fa83fae 100644
--- a/mojo/shell/background/BUILD.gn
+++ b/mojo/shell/background/BUILD.gn
@@ -18,6 +18,7 @@
   deps = [
     "//base",
     "//mojo/message_pump",
+    "//mojo/services/package_manager:lib",
     "//mojo/shell",
     "//mojo/shell/public/cpp:sources",
     "//mojo/shell/runner:init",
diff --git a/mojo/shell/background/background_shell.cc b/mojo/shell/background/background_shell.cc
index 0fdba197..5d8bdc51 100644
--- a/mojo/shell/background/background_shell.cc
+++ b/mojo/shell/background/background_shell.cc
@@ -12,6 +12,7 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/simple_thread.h"
 #include "mojo/message_pump/message_pump_mojo.h"
+#include "mojo/services/package_manager/package_manager.h"
 #include "mojo/shell/application_loader.h"
 #include "mojo/shell/application_manager.h"
 #include "mojo/shell/capability_filter.h"
@@ -72,10 +73,9 @@
 // Manages the thread to startup mojo.
 class BackgroundShell::MojoThread : public base::SimpleThread {
  public:
-  explicit MojoThread(
-      const std::vector<CommandLineSwitch>& command_line_switches)
+  explicit MojoThread(scoped_ptr<BackgroundShell::InitParams> init_params)
       : SimpleThread("mojo-background-shell"),
-        command_line_switches_(command_line_switches) {}
+        init_params_(std::move(init_params)) {}
   ~MojoThread() override {}
 
   void CreateShellClientRequest(base::WaitableEvent* signal,
@@ -121,13 +121,14 @@
 
     message_loop_->BindToCurrentThread();
 
-    base::FilePath shell_dir;
-    PathService::Get(base::DIR_MODULE, &shell_dir);
-
     scoped_ptr<Context> context(new Context);
     context_ = context.get();
-    context_->set_command_line_switches(command_line_switches_);
-    context_->Init(shell_dir);
+    scoped_ptr<mojo::shell::Context::InitParams> context_init_params(
+        new mojo::shell::Context::InitParams);
+    context_init_params->app_catalog = std::move(init_params_->app_catalog);
+    context_init_params->native_runner_delegate =
+        init_params_->native_runner_delegate;
+    context_->Init(std::move(context_init_params));
 
     message_loop_->Run();
 
@@ -156,21 +157,23 @@
   // Created in Run() on the background thread.
   Context* context_ = nullptr;
 
-  const std::vector<CommandLineSwitch> command_line_switches_;
+  scoped_ptr<BackgroundShell::InitParams> init_params_;
 
   DISALLOW_COPY_AND_ASSIGN(MojoThread);
 };
 
+BackgroundShell::InitParams::InitParams() {}
+BackgroundShell::InitParams::~InitParams() {}
+
 BackgroundShell::BackgroundShell() {}
 
 BackgroundShell::~BackgroundShell() {
   thread_->Stop();
 }
 
-void BackgroundShell::Init(
-    const std::vector<CommandLineSwitch>& command_line_switches) {
+void BackgroundShell::Init(scoped_ptr<InitParams> init_params) {
   DCHECK(!thread_);
-  thread_.reset(new MojoThread(command_line_switches));
+  thread_.reset(new MojoThread(std::move(init_params)));
   thread_->Start();
 }
 
@@ -178,7 +181,8 @@
     const GURL& url) {
   scoped_ptr<ConnectParams> params(new ConnectParams);
   params->set_target(
-      Identity(url, std::string(), GetPermissiveCapabilityFilter()));
+      Identity(url, std::string(), mojom::Connector::kUserRoot,
+               GetPermissiveCapabilityFilter()));
   mojom::ShellClientRequest request;
   base::WaitableEvent signal(true, false);
   thread_->message_loop()->task_runner()->PostTask(
diff --git a/mojo/shell/background/background_shell.h b/mojo/shell/background/background_shell.h
index d1e9c412..6226f89 100644
--- a/mojo/shell/background/background_shell.h
+++ b/mojo/shell/background/background_shell.h
@@ -10,14 +10,19 @@
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/services/package_manager/package_manager.h"
 #include "mojo/shell/public/interfaces/shell_client.mojom.h"
 
 class GURL;
 
+namespace package_manager {
+class ApplicationCatalogStore;
+}
+
 namespace mojo {
 namespace shell {
 
-struct CommandLineSwitch;
+class NativeRunnerDelegate;
 
 // BackgroundShell starts up the mojo shell on a background thread, and
 // destroys the thread in the destructor. Once created use CreateApplication()
@@ -25,12 +30,20 @@
 // then be bound to an ApplicationImpl.
 class BackgroundShell {
  public:
+  struct InitParams {
+    InitParams();
+    ~InitParams();
+
+    NativeRunnerDelegate* native_runner_delegate = nullptr;
+    scoped_ptr<package_manager::ApplicationCatalogStore> app_catalog;
+  };
+
   BackgroundShell();
   ~BackgroundShell();
 
   // Starts the background shell. |command_line_switches| are additional
   // switches applied to any processes spawned by this call.
-  void Init(const std::vector<CommandLineSwitch>& command_line_switches);
+  void Init(scoped_ptr<InitParams> init_params);
 
   // Obtains an InterfaceRequest for the specified url.
   InterfaceRequest<mojom::ShellClient> CreateShellClientRequest(
diff --git a/mojo/shell/background/tests/BUILD.gn b/mojo/shell/background/tests/BUILD.gn
new file mode 100644
index 0000000..b6037522
--- /dev/null
+++ b/mojo/shell/background/tests/BUILD.gn
@@ -0,0 +1,64 @@
+# Copyright 2016 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("//mojo/public/mojo_application.gni")
+import("//mojo/public/mojo_application_manifest.gni")
+import("//mojo/public/tools/bindings/mojom.gni")
+import("//testing/test.gni")
+
+source_set("test_support") {
+  sources = [
+    "test_application_catalog_store.cc",
+    "test_application_catalog_store.h",
+  ]
+
+  deps = [
+    "//base",
+    "//mojo/services/package_manager:lib",
+    "//url",
+  ]
+}
+
+source_set("unittests") {
+  testonly = true
+  sources = [
+    "background_shell_unittest.cc",
+  ]
+
+  deps = [
+    ":test_app_bindings",
+    ":test_support",
+    "//base",
+    "//mojo/shell/background:lib",
+    "//mojo/shell/background:main",
+    "//mojo/shell/public/cpp:sources",
+    "//testing/gtest",
+    "//url",
+  ]
+
+  data_deps = [
+    ":test_app",
+  ]
+}
+
+mojom("test_app_bindings") {
+  sources = [
+    "test.mojom",
+  ]
+}
+
+mojo_native_application("test_app") {
+  output_name = "background_shell_test_app"
+
+  sources = [
+    "test_service.cc",
+  ]
+
+  deps = [
+    ":test_app_bindings",
+    "//base",
+    "//mojo/shell/public/cpp:sources",
+    "//mojo/shell/public/interfaces",
+  ]
+}
diff --git a/mojo/shell/background/tests/background_shell_unittest.cc b/mojo/shell/background/tests/background_shell_unittest.cc
new file mode 100644
index 0000000..04ec802
--- /dev/null
+++ b/mojo/shell/background/tests/background_shell_unittest.cc
@@ -0,0 +1,70 @@
+// Copyright 2016 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 "mojo/shell/background/background_shell.h"
+
+#include "base/run_loop.h"
+#include "mojo/shell/background/tests/test.mojom.h"
+#include "mojo/shell/background/tests/test_application_catalog_store.h"
+#include "mojo/shell/public/cpp/shell_client.h"
+#include "mojo/shell/public/cpp/shell_connection.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace mojo {
+namespace shell {
+namespace {
+
+const char kTestUrl[] = "mojo:test-app";
+
+class ShellClientImpl : public ShellClient {
+ public:
+  ShellClientImpl() {}
+  ~ShellClientImpl() override {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ShellClientImpl);
+};
+
+scoped_ptr<TestApplicationCatalogStore> BuildTestApplicationCatalogStore() {
+  scoped_ptr<base::ListValue> apps(new base::ListValue);
+  apps->Append(BuildPermissiveSerializedAppInfo(GURL(kTestUrl), "test"));
+  return make_scoped_ptr(new TestApplicationCatalogStore(std::move(apps)));
+}
+
+}  // namespace
+
+// Uses BackgroundShell to start the shell in the background and connects to
+// background_shell_test_app, verifying we can send a message to the app.
+// An ApplicationCatalogStore is supplied to avoid using a manifest.
+TEST(BackgroundShellTest, Basic) {
+  base::MessageLoop message_loop;
+  BackgroundShell background_shell;
+  scoped_ptr<BackgroundShell::InitParams> init_params(
+      new BackgroundShell::InitParams);
+  scoped_ptr<TestApplicationCatalogStore> store_ptr =
+      BuildTestApplicationCatalogStore();
+  TestApplicationCatalogStore* store = store_ptr.get();
+  init_params->app_catalog = std::move(store_ptr);
+  background_shell.Init(std::move(init_params));
+  ShellClientImpl shell_client;
+  ShellConnection shell_connection(
+      &shell_client, background_shell.CreateShellClientRequest(GURL(kTestUrl)));
+  shell_connection.WaitForInitialize();
+  mojom::TestServicePtr test_service;
+  static_cast<Shell*>(&shell_connection)
+      ->ConnectToInterface("mojo:background_shell_test_app", &test_service);
+  base::RunLoop run_loop;
+  bool got_result = false;
+  test_service->Test([&run_loop, &got_result]() {
+    got_result = true;
+    run_loop.Quit();
+  });
+  run_loop.Run();
+  EXPECT_TRUE(got_result);
+  EXPECT_TRUE(store->get_store_called());
+}
+
+}  // namespace shell
+}  // namespace mojo
diff --git a/mojo/shell/background/tests/test.mojom b/mojo/shell/background/tests/test.mojom
new file mode 100644
index 0000000..a021d707
--- /dev/null
+++ b/mojo/shell/background/tests/test.mojom
@@ -0,0 +1,9 @@
+// Copyright 2016 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.
+
+module mojo.shell.mojom;
+
+interface TestService {
+  Test() => ();
+};
diff --git a/mojo/shell/background/tests/test_application_catalog_store.cc b/mojo/shell/background/tests/test_application_catalog_store.cc
new file mode 100644
index 0000000..7c0a2c9
--- /dev/null
+++ b/mojo/shell/background/tests/test_application_catalog_store.cc
@@ -0,0 +1,46 @@
+// Copyright 2016 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 "mojo/shell/background/tests/test_application_catalog_store.h"
+
+#include "url/gurl.h"
+
+using package_manager::ApplicationCatalogStore;
+
+namespace mojo {
+namespace shell {
+
+TestApplicationCatalogStore::TestApplicationCatalogStore(
+    scoped_ptr<base::ListValue> store)
+    : store_(std::move(store)) {}
+
+TestApplicationCatalogStore::~TestApplicationCatalogStore() {}
+
+const base::ListValue* TestApplicationCatalogStore::GetStore() {
+  get_store_called_ = true;
+  return store_.get();
+}
+
+void TestApplicationCatalogStore::UpdateStore(
+    scoped_ptr<base::ListValue> store) {}
+
+scoped_ptr<base::DictionaryValue> BuildPermissiveSerializedAppInfo(
+    const GURL& url,
+    const std::string& name) {
+  scoped_ptr<base::DictionaryValue> app(new base::DictionaryValue);
+  app->SetString(ApplicationCatalogStore::kUrlKey, url.spec());
+  app->SetString(ApplicationCatalogStore::kNameKey, name);
+
+  scoped_ptr<base::DictionaryValue> capabilities(new base::DictionaryValue);
+  scoped_ptr<base::ListValue> interfaces(new base::ListValue);
+  interfaces->AppendString("*");
+  capabilities->Set("*", std::move(interfaces));
+
+  app->Set(ApplicationCatalogStore::kCapabilitiesKey, std::move(capabilities));
+
+  return app;
+}
+
+}  // namespace shell
+}  // namespace mojo
diff --git a/mojo/shell/background/tests/test_application_catalog_store.h b/mojo/shell/background/tests/test_application_catalog_store.h
new file mode 100644
index 0000000..691df28
--- /dev/null
+++ b/mojo/shell/background/tests/test_application_catalog_store.h
@@ -0,0 +1,49 @@
+// Copyright 2016 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 MOJO_SHELL_BACKGROUND_TESTS_TEST_APPLICATION_CATALOG_STORE_H_
+#define MOJO_SHELL_BACKGROUND_TESTS_TEST_APPLICATION_CATALOG_STORE_H_
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "mojo/services/package_manager/package_manager.h"
+
+class GURL;
+
+namespace mojo {
+namespace shell {
+
+// ApplicationCatalogStore implementation that takes the ListValue to return
+// as store.
+class TestApplicationCatalogStore
+    : public package_manager::ApplicationCatalogStore {
+ public:
+  explicit TestApplicationCatalogStore(scoped_ptr<base::ListValue> store);
+  ~TestApplicationCatalogStore() override;
+
+  bool get_store_called() const { return get_store_called_; }
+
+  // ApplicationCatalogStore:
+  const base::ListValue* GetStore() override;
+  void UpdateStore(scoped_ptr<base::ListValue> store) override;
+
+ private:
+  bool get_store_called_ = false;
+  scoped_ptr<base::ListValue> store_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestApplicationCatalogStore);
+};
+
+// Returns a dictionary for an app with the specified url, name and a
+// permissive filter.
+scoped_ptr<base::DictionaryValue> BuildPermissiveSerializedAppInfo(
+    const GURL& url,
+    const std::string& name);
+
+}  // namespace shell
+}  // namespace mojo
+
+#endif  // MOJO_SHELL_BACKGROUND_TESTS_TEST_APPLICATION_CATALOG_STORE_H_
diff --git a/mojo/shell/background/tests/test_service.cc b/mojo/shell/background/tests/test_service.cc
new file mode 100644
index 0000000..3c9dbbd
--- /dev/null
+++ b/mojo/shell/background/tests/test_service.cc
@@ -0,0 +1,53 @@
+// Copyright 2016 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 "mojo/public/c/system/main.h"
+#include "mojo/public/cpp/bindings/weak_binding_set.h"
+#include "mojo/shell/background/tests/test.mojom.h"
+#include "mojo/shell/public/cpp/application_runner.h"
+#include "mojo/shell/public/cpp/connection.h"
+#include "mojo/shell/public/cpp/shell_client.h"
+
+namespace mojo {
+namespace shell {
+
+class TestClient : public ShellClient,
+                   public InterfaceFactory<mojom::TestService>,
+                   public mojom::TestService {
+ public:
+  TestClient() {}
+  ~TestClient() override {}
+
+ private:
+  // ShellClient:
+  void Initialize(Shell* shell,
+                  const std::string& url,
+                  uint32_t id,
+                  uint32_t user_id) override {}
+  bool AcceptConnection(Connection* connection) override {
+    connection->AddInterface(this);
+    return true;
+  }
+
+  // InterfaceFactory<mojom::TestService>:
+  void Create(Connection* connection,
+              InterfaceRequest<mojom::TestService> request) override {
+    bindings_.AddBinding(this, std::move(request));
+  }
+
+  // mojom::TestService
+  void Test(const TestCallback& callback) override { callback.Run(); }
+
+  WeakBindingSet<mojom::TestService> bindings_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestClient);
+};
+
+}  // namespace shell
+}  // namespace mojo
+
+MojoResult MojoMain(MojoHandle shell_handle) {
+  mojo::ApplicationRunner runner(new mojo::shell::TestClient);
+  return runner.Run(shell_handle);
+}
diff --git a/mojo/shell/connect_params.cc b/mojo/shell/connect_params.cc
index 92d1a87..215f705c 100644
--- a/mojo/shell/connect_params.cc
+++ b/mojo/shell/connect_params.cc
@@ -11,21 +11,13 @@
 namespace mojo {
 namespace shell {
 
-  ConnectParams::ConnectParams() {}
+ConnectParams::ConnectParams() {}
 
-  ConnectParams::~ConnectParams() {}
-
-  void ConnectParams::SetSource(ApplicationInstance* source) {
-  if (!source) {
-    source_ = Identity();
-    return;
-  }
-
-  source_ = source->identity();
-}
+ConnectParams::~ConnectParams() {}
 
 void ConnectParams::SetTargetURL(const GURL& target_url) {
-  target_ = Identity(target_url, target_.qualifier(), target_.filter());
+  target_ = Identity(target_url, target_.qualifier(),
+                     mojom::Connector::kUserInherit, target_.filter());
 }
 
 }  // namespace shell
diff --git a/mojo/shell/connect_params.h b/mojo/shell/connect_params.h
index 172df1f..af45214 100644
--- a/mojo/shell/connect_params.h
+++ b/mojo/shell/connect_params.h
@@ -28,9 +28,6 @@
    ConnectParams();
    ~ConnectParams();
 
-  // Sets |source_|. If |source| is null, |source_| is reset.
-  void SetSource(ApplicationInstance* source);
-
   // The following methods set both |target_| and |target_url_request_|.
   void SetTargetURL(const GURL& target_url);
 
@@ -53,10 +50,11 @@
     return std::move(local_interfaces_);
   }
 
-  void set_connect_callback(const shell::mojom::Shell::ConnectCallback& value) {
+  void set_connect_callback(
+      const shell::mojom::Connector::ConnectCallback& value) {
     connect_callback_ = value;
   }
-  const shell::mojom::Shell::ConnectCallback& connect_callback() const {
+  const shell::mojom::Connector::ConnectCallback& connect_callback() const {
     return connect_callback_;
   }
 
@@ -69,7 +67,7 @@
 
   shell::mojom::InterfaceProviderRequest remote_interfaces_;
   shell::mojom::InterfaceProviderPtr local_interfaces_;
-  shell::mojom::Shell::ConnectCallback connect_callback_;
+  shell::mojom::Connector::ConnectCallback connect_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(ConnectParams);
 };
diff --git a/mojo/shell/connect_util.h b/mojo/shell/connect_util.h
index 036ecde9..14c32077 100644
--- a/mojo/shell/connect_util.h
+++ b/mojo/shell/connect_util.h
@@ -10,6 +10,7 @@
 #include "mojo/public/cpp/bindings/interface_ptr.h"
 #include "mojo/public/cpp/system/handle.h"
 #include "mojo/shell/identity.h"
+#include "mojo/shell/public/interfaces/shell.mojom.h"
 
 class GURL;
 
@@ -44,7 +45,8 @@
                                InterfacePtr<Interface>* ptr) {
   ScopedMessagePipeHandle service_handle = ConnectToInterfaceByName(
       application_manager, source,
-      Identity(application_url, std::string(), GetPermissiveCapabilityFilter()),
+      Identity(application_url, std::string(), mojom::Connector::kUserInherit,
+               GetPermissiveCapabilityFilter()),
       Interface::Name_);
   ptr->Bind(InterfacePtrInfo<Interface>(std::move(service_handle), 0u));
 }
diff --git a/mojo/shell/identity.cc b/mojo/shell/identity.cc
index 2c05b3f..0a4169a 100644
--- a/mojo/shell/identity.cc
+++ b/mojo/shell/identity.cc
@@ -4,6 +4,8 @@
 
 #include "mojo/shell/identity.h"
 
+#include "mojo/shell/public/interfaces/shell.mojom.h"
+
 namespace mojo {
 namespace shell {
 namespace {
@@ -28,18 +30,17 @@
 Identity::Identity() {}
 
 Identity::Identity(const GURL& url)
-    : url_(url),
-      qualifier_(url_.spec()) {}
+    : Identity(url, url.spec(), mojom::Connector::kUserRoot) {}
 
-Identity::Identity(const GURL& url, const std::string& qualifier)
-    : url_(url),
-      qualifier_(qualifier.empty() ? url_.spec() : qualifier) {}
+Identity::Identity(const GURL& url, const std::string& qualifier,
+                   uint32_t user_id)
+    : Identity(url, qualifier, user_id, CapabilityFilter()) {}
 
-Identity::Identity(const GURL& url,
-                   const std::string& qualifier,
-                   CapabilityFilter filter)
+Identity::Identity(const GURL& url, const std::string& qualifier,
+                   uint32_t user_id, CapabilityFilter filter)
     : url_(url),
       qualifier_(qualifier.empty() ? url_.spec() : qualifier),
+      user_id_(user_id),
       filter_(CanonicalizeFilter(filter)) {}
 
 Identity::~Identity() {}
@@ -50,17 +51,19 @@
   // TODO(beng): figure out how it should work.
   if (url_ != other.url_)
     return url_ < other.url_;
-  return qualifier_ < other.qualifier_;
+  if (qualifier_ != other.qualifier_)
+    return qualifier_ < other.qualifier_;
+  return user_id_ < other.user_id_;
 }
 
 bool Identity::operator==(const Identity& other) const {
   return other.url_ == url_ && other.qualifier_ == qualifier_ &&
-    other.filter_ == filter_;
+    other.filter_ == filter_ && other.user_id_ == user_id_;
 }
 
 Identity CreateShellIdentity() {
   return Identity(GURL("mojo://shell/"), std::string(),
-                  GetPermissiveCapabilityFilter());
+                  mojom::Connector::kUserRoot, GetPermissiveCapabilityFilter());
 }
 
 }  // namespace shell
diff --git a/mojo/shell/identity.h b/mojo/shell/identity.h
index e5a349b6..16e9681 100644
--- a/mojo/shell/identity.h
+++ b/mojo/shell/identity.h
@@ -21,10 +21,15 @@
 class Identity {
  public:
   Identity();
+  // Assumes user = mojom::Connector::kUserRoot.
+  // Used in tests or for shell-initiated connections.
   explicit Identity(const GURL& in_url);
-  Identity(const GURL& in_url, const std::string& in_qualifier);
   Identity(const GURL& in_url,
            const std::string& in_qualifier,
+           uint32_t user_id);
+  Identity(const GURL& in_url,
+           const std::string& in_qualifier,
+           uint32_t user,
            CapabilityFilter filter);
   ~Identity();
 
@@ -33,6 +38,8 @@
   bool operator==(const Identity& other) const;
 
   const GURL& url() const { return url_; }
+  uint32_t user_id() const { return user_id_; }
+  void set_user_id(uint32_t user_id) { user_id_ = user_id; }
   const std::string& qualifier() const { return qualifier_; }
   const CapabilityFilter& filter() const { return filter_; }
 
@@ -40,6 +47,8 @@
   GURL url_;
   std::string qualifier_;
 
+  uint32_t user_id_;
+
   // TODO(beng): CapabilityFilter is not currently included in equivalence
   //             checks for Identity since we're not currently clear on the
   //             policy for instance disambiguation. Need to figure this out.
diff --git a/mojo/shell/native_runner.h b/mojo/shell/native_runner.h
index 6ab587b4..f2d4bc61 100644
--- a/mojo/shell/native_runner.h
+++ b/mojo/shell/native_runner.h
@@ -22,6 +22,8 @@
 namespace mojo {
 namespace shell {
 
+class Identity;
+
 // ApplicationManager requires implementations of NativeRunner and
 // NativeRunnerFactory to run native applications.
 class NativeRunner {
@@ -32,6 +34,7 @@
   // thread/process.
   virtual void Start(
       const base::FilePath& app_path,
+      const Identity& target,
       bool start_sandboxed,
       InterfaceRequest<mojom::ShellClient> request,
       const base::Callback<void(base::ProcessId)>& pid_available_callback,
diff --git a/mojo/shell/native_runner_delegate.h b/mojo/shell/native_runner_delegate.h
new file mode 100644
index 0000000..d2fe826
--- /dev/null
+++ b/mojo/shell/native_runner_delegate.h
@@ -0,0 +1,32 @@
+// Copyright 2016 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 MOJO_SHELL_NATIVE_RUNNER_DELEGATE_H_
+#define MOJO_SHELL_NATIVE_RUNNER_DELEGATE_H_
+
+namespace base {
+class CommandLine;
+}
+
+namespace mojo {
+namespace shell {
+
+class Identity;
+
+class NativeRunnerDelegate {
+ public:
+  // Called to adjust the commandline for launching the specified app.
+  // WARNING: this is called on a background thread.
+  virtual void AdjustCommandLineArgumentsForTarget(
+      const Identity& target,
+      base::CommandLine* command_line) = 0;
+
+ protected:
+  virtual ~NativeRunnerDelegate() {}
+};
+
+}  // namespace shell
+}  // namespace mojo
+
+#endif  // MOJO_SHELL_NATIVE_RUNNER_DELEGATE_H_
diff --git a/mojo/shell/public/cpp/BUILD.gn b/mojo/shell/public/cpp/BUILD.gn
index 2ebc220..1ad6892 100644
--- a/mojo/shell/public/cpp/BUILD.gn
+++ b/mojo/shell/public/cpp/BUILD.gn
@@ -23,6 +23,7 @@
     "application_runner.h",
     "connect.h",
     "connection.h",
+    "connector.h",
     "initialize_base_and_icu.cc",
     "interface_binder.h",
     "interface_factory.h",
@@ -31,6 +32,8 @@
     "lib/application_runner.cc",
     "lib/connection_impl.cc",
     "lib/connection_impl.h",
+    "lib/connector_impl.cc",
+    "lib/connector_impl.h",
     "lib/interface_factory_binder.h",
     "lib/interface_registry.cc",
     "lib/shell_client.cc",
diff --git a/mojo/shell/public/cpp/connection.h b/mojo/shell/public/cpp/connection.h
index e05243fc..39327a6 100644
--- a/mojo/shell/public/cpp/connection.h
+++ b/mojo/shell/public/cpp/connection.h
@@ -82,6 +82,9 @@
   // Returns the URL identifying the remote application on this connection.
   virtual const std::string& GetRemoteApplicationURL() = 0;
 
+  // Returns the User ID for the remote application.
+  virtual uint32_t GetRemoteUserID() const = 0;
+
   // Register a handler to receive an error notification on the pipe to the
   // remote application's InterfaceProvider.
   virtual void SetRemoteInterfaceProviderConnectionErrorHandler(
diff --git a/mojo/shell/public/cpp/connector.h b/mojo/shell/public/cpp/connector.h
new file mode 100644
index 0000000..7385e185
--- /dev/null
+++ b/mojo/shell/public/cpp/connector.h
@@ -0,0 +1,88 @@
+// Copyright 2016 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 MOJO_SHELL_PUBLIC_CPP_CONNECTOR_H_
+#define MOJO_SHELL_PUBLIC_CPP_CONNECTOR_H_
+
+#include "mojo/shell/public/cpp/connection.h"
+#include "mojo/shell/public/interfaces/shell.mojom.h"
+#include "url/gurl.h"
+
+namespace mojo {
+
+shell::mojom::CapabilityFilterPtr CreatePermissiveCapabilityFilter();
+
+// An interface that encapsulates the Mojo Shell's broker interface by which
+// connections between applications are established. Once Connect() is called,
+// this class is bound to the thread the call was made on and it cannot be
+// passed to another thread without calling Clone().
+// An instance of this class is created internally by ShellConnection for use
+// on the thread ShellConnection is instantiated on, and this interface is
+// wrapped by the Shell interface.
+// To use this interface on other threads, call Shell::CloneConnector() and
+// pass the result to another thread. To pass to subsequent threads, call
+// Clone() on instances of this object.
+// While instances of this object are owned by the caller, the underlying
+// connection with the shell is bound to the lifetime of the instance that
+// created it, i.e. when the application is terminated the Connector pipe is
+// closed.
+class Connector {
+ public:
+  class ConnectParams {
+   public:
+    explicit ConnectParams(const std::string& url);
+    ~ConnectParams();
+
+    const GURL& url() { return url_; }
+    shell::mojom::CapabilityFilterPtr TakeFilter() {
+      return std::move(filter_);
+    }
+    void set_filter(shell::mojom::CapabilityFilterPtr filter) {
+      filter_ = std::move(filter);
+    }
+    void set_user_id(uint32_t user_id) { user_id_ = user_id; }
+    uint32_t user_id() const { return user_id_; }
+
+   private:
+    GURL url_;
+    shell::mojom::CapabilityFilterPtr filter_;
+    uint32_t user_id_;
+
+    DISALLOW_COPY_AND_ASSIGN(ConnectParams);
+  };
+
+  // Requests a new connection to an application. Returns a pointer to the
+  // connection if the connection is permitted by this application's delegate,
+  // or nullptr otherwise. Caller takes ownership.
+  // Once this method is called, this object is bound to the thread on which the
+  // call took place. To pass to another thread, call Clone() and pass the
+  // result.
+  virtual scoped_ptr<Connection> Connect(const std::string& url) = 0;
+  virtual scoped_ptr<Connection> Connect(ConnectParams* params) = 0;
+
+  // Connect to application identified by |request->url| and connect to the
+  // service implementation of the interface identified by |Interface|.
+  template <typename Interface>
+  void ConnectToInterface(ConnectParams* params, InterfacePtr<Interface>* ptr) {
+    scoped_ptr<Connection> connection = Connect(params);
+    if (connection)
+      connection->GetInterface(ptr);
+  }
+  template <typename Interface>
+  void ConnectToInterface(const std::string& url,
+                          InterfacePtr<Interface>* ptr) {
+    ConnectParams params(url);
+    params.set_filter(CreatePermissiveCapabilityFilter());
+    return ConnectToInterface(&params, ptr);
+  }
+
+  // Creates a new instance of this class which may be passed to another thread.
+  // The returned object may be passed multiple times until Connect() is called,
+  // at which point this method must be called again to pass again.
+  virtual scoped_ptr<Connector> Clone() = 0;
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_SHELL_PUBLIC_CPP_CONNECTOR_H_
diff --git a/mojo/shell/public/cpp/lib/application_test_base.cc b/mojo/shell/public/cpp/lib/application_test_base.cc
index f9a726d..da56dbb 100644
--- a/mojo/shell/public/cpp/lib/application_test_base.cc
+++ b/mojo/shell/public/cpp/lib/application_test_base.cc
@@ -20,7 +20,8 @@
 namespace {
 // Share the application URL with multiple application tests.
 String g_url;
-uint32_t g_id = shell::mojom::Shell::kInvalidApplicationID;
+uint32_t g_id = shell::mojom::Connector::kInvalidApplicationID;
+uint32_t g_user_id = shell::mojom::Connector::kUserRoot;
 
 // ShellClient request handle passed from the shell in MojoMain, stored in
 // between SetUp()/TearDown() so we can (re-)intialize new ShellConnections.
@@ -45,15 +46,18 @@
   // shell::mojom::ShellClient implementation.
   void Initialize(shell::mojom::ShellPtr shell,
                   const mojo::String& url,
-                  uint32_t id) override {
+                  uint32_t id,
+                  uint32_t user_id) override {
     g_url = url;
     g_id = id;
+    g_user_id = user_id;
     g_shell_client_request = binding_.Unbind();
     g_shell = std::move(shell);
   }
 
   void AcceptConnection(
       const String& requestor_url,
+      uint32_t requestor_user_id,
       uint32_t requestor_id,
       shell::mojom::InterfaceProviderRequest local_interfaces,
       shell::mojom::InterfaceProviderPtr remote_interfaces,
@@ -121,7 +125,7 @@
       url_(g_url) {
   // Fake ShellClient initialization.
   shell::mojom::ShellClient* shell_client = shell_connection_.get();
-  shell_client->Initialize(std::move(g_shell), g_url, g_id);
+  shell_client->Initialize(std::move(g_shell), g_url, g_id, g_user_id);
 }
 
 TestHelper::~TestHelper() {
diff --git a/mojo/shell/public/cpp/lib/connection_impl.cc b/mojo/shell/public/cpp/lib/connection_impl.cc
index 47f9b9f5..4897bb3df 100644
--- a/mojo/shell/public/cpp/lib/connection_impl.cc
+++ b/mojo/shell/public/cpp/lib/connection_impl.cc
@@ -23,6 +23,7 @@
     const std::string& connection_url,
     const std::string& remote_url,
     uint32_t remote_id,
+    uint32_t remote_user_id,
     shell::mojom::InterfaceProviderPtr remote_interfaces,
     shell::mojom::InterfaceProviderRequest local_interfaces,
     const std::set<std::string>& allowed_interfaces)
@@ -30,6 +31,7 @@
       remote_url_(remote_url),
       remote_id_(remote_id),
       remote_ids_valid_(false),
+      remote_user_id_(remote_user_id),
       local_registry_(std::move(local_interfaces), this),
       remote_interfaces_(std::move(remote_interfaces)),
       allowed_interfaces_(allowed_interfaces),
@@ -38,7 +40,7 @@
       weak_factory_(this) {}
 
 ConnectionImpl::ConnectionImpl()
-    : remote_id_(shell::mojom::Shell::kInvalidApplicationID),
+    : remote_id_(shell::mojom::Connector::kInvalidApplicationID),
       remote_ids_valid_(false),
       local_registry_(shell::mojom::InterfaceProviderRequest(), this),
       allow_all_interfaces_(true),
@@ -46,7 +48,7 @@
 
 ConnectionImpl::~ConnectionImpl() {}
 
-shell::mojom::Shell::ConnectCallback ConnectionImpl::GetConnectCallback() {
+shell::mojom::Connector::ConnectCallback ConnectionImpl::GetConnectCallback() {
   return base::Bind(&ConnectionImpl::OnGotInstanceID,
                     weak_factory_.GetWeakPtr());
 }
@@ -62,6 +64,10 @@
   return remote_url_;
 }
 
+uint32_t ConnectionImpl::GetRemoteUserID() const {
+  return remote_user_id_;
+}
+
 void ConnectionImpl::SetRemoteInterfaceProviderConnectionErrorHandler(
     const Closure& handler) {
   remote_interfaces_.set_connection_error_handler(handler);
diff --git a/mojo/shell/public/cpp/lib/connection_impl.h b/mojo/shell/public/cpp/lib/connection_impl.h
index 4fc34e7..e2c407a 100644
--- a/mojo/shell/public/cpp/lib/connection_impl.h
+++ b/mojo/shell/public/cpp/lib/connection_impl.h
@@ -30,17 +30,19 @@
   ConnectionImpl(const std::string& connection_url,
                  const std::string& remote_url,
                  uint32_t remote_id,
+                 uint32_t remote_user_id,
                  shell::mojom::InterfaceProviderPtr remote_interfaces,
                  shell::mojom::InterfaceProviderRequest local_interfaces,
                  const std::set<std::string>& allowed_interfaces);
   ~ConnectionImpl() override;
 
-  shell::mojom::Shell::ConnectCallback GetConnectCallback();
+  shell::mojom::Connector::ConnectCallback GetConnectCallback();
 
  private:
   // Connection:
   const std::string& GetConnectionURL() override;
   const std::string& GetRemoteApplicationURL() override;
+  uint32_t GetRemoteUserID() const override;
   void SetRemoteInterfaceProviderConnectionErrorHandler(
       const Closure& handler) override;
   bool GetRemoteApplicationID(uint32_t* remote_id) const override;
@@ -58,6 +60,7 @@
   uint32_t remote_id_;
   bool remote_ids_valid_;
   std::vector<Closure> remote_id_callbacks_;
+  uint32_t remote_user_id_;
 
   InterfaceRegistry local_registry_;
   shell::mojom::InterfaceProviderPtr remote_interfaces_;
diff --git a/mojo/shell/public/cpp/lib/connector_impl.cc b/mojo/shell/public/cpp/lib/connector_impl.cc
new file mode 100644
index 0000000..989382e
--- /dev/null
+++ b/mojo/shell/public/cpp/lib/connector_impl.cc
@@ -0,0 +1,74 @@
+// Copyright 2016 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 "mojo/shell/public/cpp/lib/connector_impl.h"
+
+#include "mojo/shell/public/cpp/lib/connection_impl.h"
+
+namespace mojo {
+
+Connector::ConnectParams::ConnectParams(const std::string& url)
+    : url_(url),
+      filter_(shell::mojom::CapabilityFilter::New()),
+      user_id_(shell::mojom::Connector::kUserInherit) {
+  filter_->filter.SetToEmpty();
+}
+Connector::ConnectParams::~ConnectParams() {}
+
+ConnectorImpl::ConnectorImpl(shell::mojom::ConnectorPtrInfo unbound_state)
+    : unbound_state_(std::move(unbound_state)) {}
+ConnectorImpl::~ConnectorImpl() {}
+
+scoped_ptr<Connection> ConnectorImpl::Connect(const std::string& url) {
+  ConnectParams params(url);
+  params.set_filter(CreatePermissiveCapabilityFilter());
+  return Connect(&params);
+}
+
+scoped_ptr<Connection> ConnectorImpl::Connect(ConnectParams* params) {
+  // Bind this object to the current thread the first time it is used to
+  // connect.
+  if (!connector_.is_bound()) {
+    if (!unbound_state_.is_valid())
+      return nullptr;
+    connector_.Bind(std::move(unbound_state_));
+    thread_checker_.reset(new base::ThreadChecker);
+  }
+  DCHECK(thread_checker_->CalledOnValidThread());
+
+  DCHECK(params);
+  std::string application_url = params->url().spec();
+  // We allow all interfaces on outgoing connections since we are presumably in
+  // a position to know who we're talking to.
+  // TODO(beng): is this a valid assumption or do we need to figure some way to
+  //             filter here too?
+  std::set<std::string> allowed;
+  allowed.insert("*");
+  shell::mojom::InterfaceProviderPtr local_interfaces;
+  shell::mojom::InterfaceProviderRequest local_request =
+      GetProxy(&local_interfaces);
+  shell::mojom::InterfaceProviderPtr remote_interfaces;
+  shell::mojom::InterfaceProviderRequest remote_request =
+      GetProxy(&remote_interfaces);
+  scoped_ptr<internal::ConnectionImpl> registry(new internal::ConnectionImpl(
+      application_url, application_url,
+      shell::mojom::Connector::kInvalidApplicationID, params->user_id(),
+      std::move(remote_interfaces), std::move(local_request), allowed));
+  connector_->Connect(application_url,
+                      params->user_id(),
+                      std::move(remote_request),
+                      std::move(local_interfaces),
+                      params->TakeFilter(),
+                      registry->GetConnectCallback());
+  return std::move(registry);
+}
+
+scoped_ptr<Connector> ConnectorImpl::Clone() {
+  shell::mojom::ConnectorPtr connector;
+  connector_->Clone(GetProxy(&connector));
+  return make_scoped_ptr(
+      new ConnectorImpl(connector.PassInterface()));
+}
+
+}  // namespace mojo
diff --git a/mojo/shell/public/cpp/lib/connector_impl.h b/mojo/shell/public/cpp/lib/connector_impl.h
new file mode 100644
index 0000000..9782932
--- /dev/null
+++ b/mojo/shell/public/cpp/lib/connector_impl.h
@@ -0,0 +1,35 @@
+// Copyright 2016 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 MOJO_SHELL_PUBLIC_CPP_LIB_CONNECTOR_IMPL_H_
+#define MOJO_SHELL_PUBLIC_CPP_LIB_CONNECTOR_IMPL_H_
+
+#include "base/threading/thread_checker.h"
+#include "mojo/shell/public/cpp/connector.h"
+#include "mojo/shell/public/interfaces/shell.mojom.h"
+
+namespace mojo {
+
+class ConnectorImpl : public Connector {
+ public:
+  explicit ConnectorImpl(shell::mojom::ConnectorPtrInfo unbound_state);
+  ~ConnectorImpl();
+
+ private:
+  // Connector:
+  scoped_ptr<Connection> Connect(const std::string& url) override;
+  scoped_ptr<Connection> Connect(ConnectParams* params) override;
+  scoped_ptr<Connector> Clone() override;
+
+  shell::mojom::ConnectorPtrInfo unbound_state_;
+  shell::mojom::ConnectorPtr connector_;
+
+  scoped_ptr<base::ThreadChecker> thread_checker_;
+
+  DISALLOW_COPY_AND_ASSIGN(ConnectorImpl);
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_SHELL_PUBLIC_CPP_LIB_CONNECTOR_IMPL_H_
diff --git a/mojo/shell/public/cpp/lib/shell_client.cc b/mojo/shell/public/cpp/lib/shell_client.cc
index b3e83b5..6570068 100644
--- a/mojo/shell/public/cpp/lib/shell_client.cc
+++ b/mojo/shell/public/cpp/lib/shell_client.cc
@@ -10,7 +10,7 @@
 ShellClient::~ShellClient() {}
 
 void ShellClient::Initialize(Shell* app, const std::string& url,
-                                     uint32_t id) {
+                             uint32_t id, uint32_t user_id) {
 }
 
 bool ShellClient::AcceptConnection(Connection* connection) {
diff --git a/mojo/shell/public/cpp/lib/shell_connection.cc b/mojo/shell/public/cpp/lib/shell_connection.cc
index f9fca2f..1a3d398 100644
--- a/mojo/shell/public/cpp/lib/shell_connection.cc
+++ b/mojo/shell/public/cpp/lib/shell_connection.cc
@@ -9,7 +9,9 @@
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
 #include "mojo/public/cpp/bindings/interface_ptr.h"
+#include "mojo/shell/public/cpp/connector.h"
 #include "mojo/shell/public/cpp/lib/connection_impl.h"
+#include "mojo/shell/public/cpp/lib/connector_impl.h"
 #include "mojo/shell/public/cpp/shell_client.h"
 #include "mojo/shell/public/cpp/shell_connection.h"
 
@@ -84,13 +86,6 @@
   DISALLOW_COPY_AND_ASSIGN(AppRefCountImpl);
 };
 
-
-ShellConnection::ConnectParams::ConnectParams(const std::string& url)
-    : url_(url), filter_(shell::mojom::CapabilityFilter::New()) {
-  filter_->filter.SetToEmpty();
-}
-ShellConnection::ConnectParams::~ConnectParams() {}
-
 ////////////////////////////////////////////////////////////////////////////////
 // ShellConnection, public:
 
@@ -123,38 +118,16 @@
 // ShellConnection, Shell implementation:
 
 scoped_ptr<Connection> ShellConnection::Connect(const std::string& url) {
-  ConnectParams params(url);
-  params.set_filter(CreatePermissiveCapabilityFilter());
-  return Connect(&params);
+  return connector_->Connect(url);
 }
 
-scoped_ptr<Connection> ShellConnection::Connect(ConnectParams* params) {
-  if (!shell_)
-    return nullptr;
-  DCHECK(params);
-  std::string application_url = params->url().spec();
-  // We allow all interfaces on outgoing connections since we are presumably in
-  // a position to know who we're talking to.
-  // TODO(beng): is this a valid assumption or do we need to figure some way to
-  //             filter here too?
-  std::set<std::string> allowed;
-  allowed.insert("*");
-  shell::mojom::InterfaceProviderPtr local_interfaces;
-  shell::mojom::InterfaceProviderRequest local_request =
-      GetProxy(&local_interfaces);
-  shell::mojom::InterfaceProviderPtr remote_interfaces;
-  shell::mojom::InterfaceProviderRequest remote_request =
-      GetProxy(&remote_interfaces);
-  scoped_ptr<internal::ConnectionImpl> registry(new internal::ConnectionImpl(
-      application_url, application_url,
-      shell::mojom::Shell::kInvalidApplicationID, std::move(remote_interfaces),
-      std::move(local_request), allowed));
-  shell_->Connect(application_url,
-                  std::move(remote_request),
-                  std::move(local_interfaces),
-                  params->TakeFilter(),
-                  registry->GetConnectCallback());
-  return std::move(registry);
+scoped_ptr<Connection> ShellConnection::Connect(
+    Connector::ConnectParams* params) {
+  return connector_->Connect(params);
+}
+
+scoped_ptr<Connector> ShellConnection::CloneConnector() const {
+  return connector_->Clone();
 }
 
 void ShellConnection::Quit() {
@@ -179,22 +152,29 @@
 
 void ShellConnection::Initialize(shell::mojom::ShellPtr shell,
                                  const mojo::String& url,
-                                 uint32_t id) {
+                                 uint32_t id,
+                                 uint32_t user_id) {
   shell_ = std::move(shell);
   shell_.set_connection_error_handler([this]() { OnConnectionError(); });
-  client_->Initialize(this, url, id);
+
+  shell::mojom::ConnectorPtr connector;
+  shell_->GetConnector(GetProxy(&connector));
+  connector_.reset(new ConnectorImpl(connector.PassInterface()));
+
+  client_->Initialize(this, url, id, user_id);
 }
 
 void ShellConnection::AcceptConnection(
     const String& requestor_url,
     uint32_t requestor_id,
+    uint32_t requestor_user_id,
     shell::mojom::InterfaceProviderRequest local_interfaces,
     shell::mojom::InterfaceProviderPtr remote_interfaces,
     Array<String> allowed_interfaces,
     const String& url) {
   scoped_ptr<Connection> registry(new internal::ConnectionImpl(
-      url, requestor_url, requestor_id, std::move(remote_interfaces),
-      std::move(local_interfaces),
+      url, requestor_url, requestor_id, requestor_user_id,
+      std::move(remote_interfaces), std::move(local_interfaces),
       allowed_interfaces.To<std::set<std::string>>()));
   if (!client_->AcceptConnection(registry.get()))
     return;
diff --git a/mojo/shell/public/cpp/shell.h b/mojo/shell/public/cpp/shell.h
index 3b12cc9..d333acb 100644
--- a/mojo/shell/public/cpp/shell.h
+++ b/mojo/shell/public/cpp/shell.h
@@ -6,16 +6,12 @@
 #define MOJO_SHELL_PUBLIC_CPP_SHELL_H_
 
 #include "mojo/shell/public/cpp/connection.h"
+#include "mojo/shell/public/cpp/connector.h"
 #include "mojo/shell/public/interfaces/shell.mojom.h"
-#include "mojo/shell/public/interfaces/shell_client.mojom.h"
 #include "url/gurl.h"
 
 namespace mojo {
 
-shell::mojom::CapabilityFilterPtr CreatePermissiveCapabilityFilter();
-
-using ShellClientRequest = InterfaceRequest<shell::mojom::ShellClient>;
-
 // An interface implementation can keep this object as a member variable to
 // hold a reference to the ShellConnection, keeping it alive as long as the
 // bound implementation exists.
@@ -35,36 +31,17 @@
 // ShellConnection, this is the primary interface exposed to clients.
 class Shell {
  public:
-  class ConnectParams {
-   public:
-    explicit ConnectParams(const std::string& url);
-    ~ConnectParams();
-
-    const GURL& url() { return url_; }
-    shell::mojom::CapabilityFilterPtr TakeFilter() {
-      return std::move(filter_);
-    }
-    void set_filter(shell::mojom::CapabilityFilterPtr filter) {
-      filter_ = std::move(filter);
-    }
-
-   private:
-    GURL url_;
-    shell::mojom::CapabilityFilterPtr filter_;
-
-    DISALLOW_COPY_AND_ASSIGN(ConnectParams);
-  };
-
   // Requests a new connection to an application. Returns a pointer to the
   // connection if the connection is permitted by this application's delegate,
   // or nullptr otherwise. Caller takes ownership.
   virtual scoped_ptr<Connection> Connect(const std::string& url) = 0;
-  virtual scoped_ptr<Connection> Connect(ConnectParams* params) = 0;
+  virtual scoped_ptr<Connection> Connect(Connector::ConnectParams* params) = 0;
 
   // Connect to application identified by |request->url| and connect to the
   // service implementation of the interface identified by |Interface|.
   template <typename Interface>
-  void ConnectToInterface(ConnectParams* params, InterfacePtr<Interface>* ptr) {
+  void ConnectToInterface(Connector::ConnectParams* params,
+                          InterfacePtr<Interface>* ptr) {
     scoped_ptr<Connection> connection = Connect(params);
     if (connection)
       connection->GetInterface(ptr);
@@ -72,11 +49,15 @@
   template <typename Interface>
   void ConnectToInterface(const std::string& url,
                           InterfacePtr<Interface>* ptr) {
-    ConnectParams params(url);
+    Connector::ConnectParams params(url);
     params.set_filter(CreatePermissiveCapabilityFilter());
     return ConnectToInterface(&params, ptr);
   }
 
+  // Returns a clone of the ShellConnection's Connector that can be passed to
+  // other threads.
+  virtual scoped_ptr<Connector> CloneConnector() const = 0;
+
   // Initiate shutdown of this application. This may involve a round trip to the
   // Shell to ensure there are no inbound service requests.
   virtual void Quit() = 0;
diff --git a/mojo/shell/public/cpp/shell_client.h b/mojo/shell/public/cpp/shell_client.h
index 7bd12980..b7a8e0e 100644
--- a/mojo/shell/public/cpp/shell_client.h
+++ b/mojo/shell/public/cpp/shell_client.h
@@ -26,10 +26,15 @@
   virtual ~ShellClient();
 
   // Called once a bidirectional connection with the shell has been established.
-  // |url| is the URL used to start the application. |id| is a unique identifier
-  // the shell uses to identify this specific instance of the application.
+  // |url| is the URL used to start the application.
+  // |id| is a unique identifier the shell uses to identify this specific
+  // instance of the application.
+  // |user_id| identifies the user this instance is run as.
   // Called exactly once before any other method.
-  virtual void Initialize(Shell* shell, const std::string& url, uint32_t id);
+  virtual void Initialize(Shell* shell,
+                          const std::string& url,
+                          uint32_t id,
+                          uint32_t user_id = 0);
 
   // Called when a connection to this client is brokered by the shell. Override
   // to expose services to the remote application. Return true if the connection
diff --git a/mojo/shell/public/cpp/shell_connection.h b/mojo/shell/public/cpp/shell_connection.h
index d0e9b5c..ab24fd02 100644
--- a/mojo/shell/public/cpp/shell_connection.h
+++ b/mojo/shell/public/cpp/shell_connection.h
@@ -22,6 +22,7 @@
 namespace mojo {
 
 class AppRefCountImpl;
+class Connector;
 
 // Encapsulates a connection to the Mojo Shell in two parts:
 // - a bound InterfacePtr to mojo::shell::mojom::Shell, the primary mechanism
@@ -84,17 +85,20 @@
 
   // Shell:
   scoped_ptr<Connection> Connect(const std::string& url) override;
-  scoped_ptr<Connection> Connect(ConnectParams* params) override;
+  scoped_ptr<Connection> Connect(Connector::ConnectParams* params) override;
+  scoped_ptr<Connector> CloneConnector() const override;
   void Quit() override;
   scoped_ptr<AppRefCount> CreateAppRefCount() override;
 
   // shell::mojom::ShellClient:
   void Initialize(shell::mojom::ShellPtr shell,
                   const mojo::String& url,
-                  uint32_t id) override;
+                  uint32_t id,
+                  uint32_t user_id) override;
   void AcceptConnection(
       const String& requestor_url,
       uint32_t requestor_id,
+      uint32_t requestor_user_id,
       shell::mojom::InterfaceProviderRequest remote_interfaces,
       shell::mojom::InterfaceProviderPtr local_interfaces,
       Array<String> allowed_interfaces,
@@ -123,6 +127,7 @@
   mojo::ShellClient* client_;
   Binding<shell::mojom::ShellClient> binding_;
   shell::mojom::ShellPtr shell_;
+  scoped_ptr<Connector> connector_;
   Closure termination_closure_;
   bool quit_requested_;
   int ref_count_;
diff --git a/mojo/shell/public/interfaces/shell.mojom b/mojo/shell/public/interfaces/shell.mojom
index ed3cbd02..8c7f41b 100644
--- a/mojo/shell/public/interfaces/shell.mojom
+++ b/mojo/shell/public/interfaces/shell.mojom
@@ -20,43 +20,80 @@
   map<string, array<string>> filter;
 };
 
-// An interface through which a Mojo application may communicate with the Mojo
-// system and request connections to other applications.
-interface Shell {
+// Encapsulates establishing connections with other Mojo applications.
+interface Connector {
   const uint32 kInvalidApplicationID = 0;
+  const uint32 kUserRoot = 0;
+  const uint32 kUserInherit = 1;
 
-  // Establishes a connection with another application ("target application")
-  // (located at |url|) through which the calling application and the
-  // target application may request services from one another.
+  // Requests a connection with another application. The application originating
+  // the request is referred to as the "source" and the one receiving the
+  // "target".
   //
-  // If the calling application would like to request services from the target
-  // application, it should pass a valid interface request in the |services|
-  // parameter (i.e. one containing a valid message pipe endpoint). If the
-  // target application does not wish to offer services, it may either not bind
-  // an implementation to the interface request, or else bind an implementation
-  // that will reject some or all service requests.
+  // The connection is embodied by a pair of message pipes binding the
+  // InterfaceProvider interface, which allows both the source and target
+  // applications to export interfaces to one another. The interfaces bound via
+  // these InterfaceProviders are brokered by the shell according to the
+  // security policy defined by each application in its manifest .
   //
-  // If the calling application would like to offer services to the target
-  // application, it should pass a bound interface through the
-  // |exposed_services| parameter. The target application may then request
-  // services through that interface.
+  // If the target application is not running, the shell will run it, calling
+  // its Initialize() method before completing the connection.
   //
-  // At least one of |services| or |exposed_services| should be valid/bound in
-  // the call.
+  // Parameters:
   //
-  // If the |application_url| does not contain a domain, but is of the form
-  // "mojo:{service}", it is up to the Mojo shell to select an appropriate
-  // application for the service. Currently, the shell does this based on the
-  // value of its --origin flag.
+  //  url
+  //    A mojo: or exe: URL identifying the target application.
   //
-  // |filter| is a whitelist of application URLs and services that the target
-  // application is permitted to connect to. See documentation for
-  // CapabilityFilter above.
+  //  user_id
+  //    The user id of the target application instance to connect to. If no such
+  //    instance exists, the shell may start one. This user id will be passed
+  //    to the new instance via Initialize(). Applications must generally set
+  //    this to kUserInherit, and the shell will either connect to an existing
+  //    instance matching the caller's user id, create a new instance matching
+  //    the caller's user id, or connect to an existing instance running as
+  //    kUserRoot. By default, applications do not have the ability to pass
+  //    arbitrary values to this method, and doing so will result in a
+  //    connection error on the remote service provider. An application with
+  //    the ability to launch applications with arbitrary user ids (e.g. a login
+  //    app) may set this value to something meaningful to it.
+  //
+  //  remote_interfaces
+  //    Allows the source application access to interface implementations
+  //    exposed by the target application. The interfaces accessible via this
+  //    InterfaceParameter are filtered by the security policy described by the
+  //    source and target application manifests.
+  //
+  //  local_interfaces
+  //    Allows the remote application access to interface implementations
+  //    exposed by the source application. The interfaces accessible via this
+  //    InterfaceProvider are filtered by the security policy described by the
+  //    source and target application manifests.
+  //
+  //  filter
+  //    Deprecated, to be removed.
+  //
+  //  Response: (application_id)
+  //    The shell responds with a unique identifier for the instance that was
+  //    connected to.
+  //
   Connect(string url,
+          uint32 user_id,
           InterfaceProvider&? remote_interfaces,
           InterfaceProvider? local_interfaces,
           CapabilityFilter filter) => (uint32 application_id);
 
+  // Clones this Connector so it can be passed to another thread.
+  Clone(Connector& request);
+};
+
+// Wraps functionality exposed by the Shell to a Mojo application instance.
+interface Shell {
+  // Obtain a Connector that can be used to create connections with other
+  // applications. The connector is bound in the shell to the instance that
+  // vended this Shell interface, all connectors created and cloned frmo this
+  // one are bound to the lifetime of this instance.
+  GetConnector(Connector& connector);
+
   // When there are no more instantiated services in an application, it should
   // start its shutdown process by calling this method. Additionally, it should
   // keep track of any new service requests that come in. The shell will then
diff --git a/mojo/shell/public/interfaces/shell_client.mojom b/mojo/shell/public/interfaces/shell_client.mojom
index af0fcb6..575728df 100644
--- a/mojo/shell/public/interfaces/shell_client.mojom
+++ b/mojo/shell/public/interfaces/shell_client.mojom
@@ -7,63 +7,76 @@
 import "mojo/shell/public/interfaces/interface_provider.mojom";
 import "mojo/shell/public/interfaces/shell.mojom";
 
-// TODO(beng): rewrite these comments.
-// This is the primary interface implemented by every Mojo application. It
-// allows the application to receive its startup arguments from the shell, and
-// to be notified of events that occur during its execution.
-//
-// TODO(aa): It would be good to reorder the parameters once we have interface
-// versioning.
+// Implemented by something "known to" the Mojo Shell (e.g. an application or
+// service), for which an instance is tracked. It allows the implementor to
+// receive lifecycle events and service inbound connection attempts.
 interface ShellClient {
-  // Initializes the application with the specified arguments. This method is
-  // guaranteed to be called before any other method is called, and will only be
-  // called once.
+  // Called by the shell once an instance for this application has been created.
+  // This method will be called exactly once before any other method is called.
   //
-  // The |url| parameter is the identity of the application as far as the shell
-  // is concerned. This will be the URL the application was found at, after all
-  // mappings, resolution, and redirects. And it will not include the
-  // querystring, since the querystring is not part of an application's
-  // identity.
-  // 
-  // The |id| parameter is the identifier of the instance in the
-  // ApplicationManager. It can be passed to other shell interfaces that request
-  // an instance identifier.
-  Initialize(Shell shell, string url, uint32 id);
+  // Parameters:
+  //
+  //  shell
+  //    An interface back to the shell by which new connections may be
+  //    established.
+  //
+  //  url
+  //    The resolved URL used in the connection request that resulted in this
+  //    application being initialized.
+  //
+  //  id
+  //    A unique identifier used by the shell to identify this instance.
+  //
+  //  user_id
+  //    Identifies the user this instance is run as in the shell. This may
+  //    differ from the user the application that caused this application to be
+  //    instantiated is run as. This will always be a valid user id, never
+  //    Shell::kUserInherit.
+  //
+  Initialize(Shell shell, string url, uint32 id, uint32 user_id);
 
-  // Called when another application (identified by |requestor_url|) attempts to
-  // open a connection to this application.
+  // Called when another application attempts to open a connection to this
+  // application. An application implements this method to complete the exchange
+  // of interface implementations with the remote application. See also
+  // documentation in shell.mojom for Connect(). The application originating
+  // the request is referred to as the "source" and the one receiving the
+  // "target".
   //
-  // If the other application wants to request services from this application,
-  // it will have passed a valid interface request through the |services|
-  // parameter (i.e. one containing a valid message pipe endpoint). This
-  // application may then bind an implementation of |InterfaceProvider| to that
-  // request in order to make services available to the other application.
+  // Parameters:
   //
-  // If the other application wants to offer services to this application, it
-  // will have passed a bound interface through the |exposed_services|
-  // parameter. This application may then request services through that
-  // interface.
+  //  requestor_url
+  //    The URL of the source application.
   //
-  // It is possible that both parameters will be valid/bound if the other
-  // application wants to both request services from and offer services to this
-  // application.
+  //  requestor_id
+  //    A unique identifier used by the shell to identify the source
+  //    application's instance.
   //
-  // This application is free to ignore the |services| or |exposed_services|
-  // parameters if it does not wish to offer or request services.
+  //  requestor_user_id
+  //    An identifier for the user the source application is run as. This may
+  //    differ from the application the target is run as (i.e. the one received
+  //    via Initialize() above). This will always be a valid user id, never
+  //    Shell::kUserInherit.
   //
-  // |allowed_interfaces| is a set of interface names that the shell has
-  // determined can be exposed by this application to the connecting
-  // application. When this parameter is empty, this application should expose
-  // no services to the connecting application. When this parameter contains
-  // only the single string value "*" the application may expose all of its
-  // services to the connecting application.
+  //  local_interfaces
+  //    A request for an InterfaceProvider by which the source application may
+  //    seek to bind interface implementations exported by the target.
   //
-  // |resolved_url| is the URL that was requested to create this connection,
-  // after all mappings, resolutions, and redirects. This will include any
-  // querystring that was part of the request.
+  //  remote_interfaces
+  //    An InterfaceProvider by which the target application may bind interface
+  //    implementations exported by the source.
+  //
+  //  allowed_interfaces
+  //    A whitelist of interface names that should be exported to the source,
+  //    according to the security policy described by the source and target's
+  //    manifests. Attempts to bind interfaces not in this whitelist must not be
+  //    fulfilled.
+  //
+  //  resolved_url
+  //    The resolved URL used to complete this connection.
   //
   AcceptConnection(string requestor_url,
                    uint32 requestor_id,
+                   uint32 requestor_user_id,
                    InterfaceProvider&? local_interfaces,
                    InterfaceProvider? remote_interfaces,
                    array<string> allowed_interfaces,
diff --git a/mojo/shell/runner/child/native_apptest_target.cc b/mojo/shell/runner/child/native_apptest_target.cc
index 5f322d7d..d2747c5 100644
--- a/mojo/shell/runner/child/native_apptest_target.cc
+++ b/mojo/shell/runner/child/native_apptest_target.cc
@@ -29,7 +29,7 @@
  private:
   // mojo::ShellClient:
   void Initialize(mojo::Shell* shell, const std::string& url,
-                  uint32_t id) override {}
+                  uint32_t id, uint32_t user_id) override {}
   bool AcceptConnection(mojo::Connection* connection) override {
     connection->AddInterface<mojo::shell::test::TestNativeService>(this);
     return true;
diff --git a/mojo/shell/runner/child/test_native_main.cc b/mojo/shell/runner/child/test_native_main.cc
index db735ec..f8e4532e 100644
--- a/mojo/shell/runner/child/test_native_main.cc
+++ b/mojo/shell/runner/child/test_native_main.cc
@@ -57,7 +57,7 @@
 
     mojo::edk::InitIPCSupport(&process_delegate, io_thread.task_runner());
 
-    mojo::ShellClientRequest request;
+    mojom::ShellClientRequest request;
     scoped_ptr<mojo::shell::RunnerConnection> connection(
         mojo::shell::RunnerConnection::ConnectToRunner(
             &request, ScopedMessagePipeHandle()));
diff --git a/mojo/shell/runner/host/BUILD.gn b/mojo/shell/runner/host/BUILD.gn
index 0522d97..b4e38f7 100644
--- a/mojo/shell/runner/host/BUILD.gn
+++ b/mojo/shell/runner/host/BUILD.gn
@@ -61,7 +61,6 @@
     "child_process.h",
     "child_process_host.cc",
     "child_process_host.h",
-    "command_line_switch.h",
     "in_process_native_runner.cc",
     "in_process_native_runner.h",
     "out_of_process_native_runner.cc",
@@ -111,6 +110,7 @@
     "//base/test:test_support",
     "//mojo/edk/system",
     "//mojo/message_pump",
+    "//mojo/shell",
     "//mojo/shell/runner:init",
     "//mojo/shell/runner/common",
     "//testing/gtest",
diff --git a/mojo/shell/runner/host/child_process_host.cc b/mojo/shell/runner/host/child_process_host.cc
index ae79312..b9a1c1f 100644
--- a/mojo/shell/runner/host/child_process_host.cc
+++ b/mojo/shell/runner/host/child_process_host.cc
@@ -21,8 +21,8 @@
 #include "mojo/edk/embedder/embedder.h"
 #include "mojo/public/cpp/bindings/interface_ptr_info.h"
 #include "mojo/public/cpp/system/core.h"
+#include "mojo/shell/native_runner_delegate.h"
 #include "mojo/shell/runner/common/switches.h"
-#include "mojo/shell/runner/host/command_line_switch.h"
 
 #if defined(OS_LINUX) && !defined(OS_ANDROID)
 #include "sandbox/linux/services/namespace_sandbox.h"
@@ -35,16 +35,17 @@
 namespace mojo {
 namespace shell {
 
-ChildProcessHost::ChildProcessHost(
-    base::TaskRunner* launch_process_runner,
-    bool start_sandboxed,
-    const base::FilePath& app_path,
-    const std::vector<CommandLineSwitch>& command_line_switches)
+ChildProcessHost::ChildProcessHost(base::TaskRunner* launch_process_runner,
+                                   NativeRunnerDelegate* delegate,
+                                   bool start_sandboxed,
+                                   const Identity& target,
+                                   const base::FilePath& app_path)
     : launch_process_runner_(launch_process_runner),
+      delegate_(delegate),
       start_sandboxed_(start_sandboxed),
+      target_(target),
       app_path_(app_path),
       start_child_process_event_(false, false),
-      command_line_switches_(command_line_switches),
       weak_factory_(this) {
   node_channel_.reset(new edk::PlatformChannelPair);
   primordial_pipe_token_ = edk::GenerateRandomToken();
@@ -55,6 +56,7 @@
 
 ChildProcessHost::ChildProcessHost(ScopedHandle channel)
     : launch_process_runner_(nullptr),
+      delegate_(nullptr),
       start_sandboxed_(false),
       start_child_process_event_(false, false),
       weak_factory_(this) {
@@ -149,8 +151,10 @@
   child_command_line.AppendSwitchASCII(switches::kPrimordialPipeToken,
                                        primordial_pipe_token_);
 
-  for (const CommandLineSwitch& pair : command_line_switches_)
-    child_command_line.AppendSwitchASCII(pair.key, pair.value);
+  if (delegate_) {
+    delegate_->AdjustCommandLineArgumentsForTarget(target_,
+                                                   &child_command_line);
+  }
 
   base::LaunchOptions options;
 #if defined(OS_WIN)
diff --git a/mojo/shell/runner/host/child_process_host.h b/mojo/shell/runner/host/child_process_host.h
index 69e7e4fa..0cdbea33 100644
--- a/mojo/shell/runner/host/child_process_host.h
+++ b/mojo/shell/runner/host/child_process_host.h
@@ -19,6 +19,7 @@
 #include "base/synchronization/waitable_event.h"
 #include "mojo/edk/embedder/platform_channel_pair.h"
 #include "mojo/public/cpp/system/message_pipe.h"
+#include "mojo/shell/identity.h"
 #include "mojo/shell/runner/child/child_controller.mojom.h"
 #include "mojo/shell/runner/host/child_process_host.h"
 
@@ -29,7 +30,8 @@
 namespace mojo {
 namespace shell {
 
-struct CommandLineSwitch;
+class Identity;
+class NativeRunnerDelegate;
 
 // This class represents a "child process host". Handles launching and
 // connecting a platform-specific "pipe" to the child, and supports joining the
@@ -49,9 +51,10 @@
   // can be sandboxed if |start_sandboxed| is true. |app_path| is a path to the
   // mojo application we wish to start.
   ChildProcessHost(base::TaskRunner* launch_process_runner,
+                   NativeRunnerDelegate* delegate,
                    bool start_sandboxed,
-                   const base::FilePath& app_path,
-                   const std::vector<CommandLineSwitch>& switches);
+                   const Identity& target,
+                   const base::FilePath& app_path);
   // Allows a ChildProcessHost to be instantiated for an existing channel
   // created by someone else (e.g. an app that launched its own process).
   explicit ChildProcessHost(ScopedHandle channel);
@@ -79,7 +82,9 @@
   void AppCompleted(int32_t result);
 
   scoped_refptr<base::TaskRunner> launch_process_runner_;
+  NativeRunnerDelegate* delegate_;
   bool start_sandboxed_;
+  Identity target_;
   const base::FilePath app_path_;
   base::Process child_process_;
   // Used for the ChildController binding.
@@ -98,8 +103,6 @@
   // A token the child can use to connect a primordial pipe to the host.
   std::string primordial_pipe_token_;
 
-  const std::vector<CommandLineSwitch> command_line_switches_;
-
   base::WeakPtrFactory<ChildProcessHost> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ChildProcessHost);
diff --git a/mojo/shell/runner/host/child_process_host_unittest.cc b/mojo/shell/runner/host/child_process_host_unittest.cc
index 64a63fe..e14d2ac2 100644
--- a/mojo/shell/runner/host/child_process_host_unittest.cc
+++ b/mojo/shell/runner/host/child_process_host_unittest.cc
@@ -6,6 +6,8 @@
 
 #include "mojo/shell/runner/host/child_process_host.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/command_line.h"
@@ -18,7 +20,7 @@
 #include "mojo/edk/embedder/embedder.h"
 #include "mojo/edk/embedder/process_delegate.h"
 #include "mojo/message_pump/message_pump_mojo.h"
-#include "mojo/shell/runner/host/command_line_switch.h"
+#include "mojo/shell/native_runner_delegate.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace mojo {
@@ -40,6 +42,30 @@
   DISALLOW_COPY_AND_ASSIGN(ProcessDelegate);
 };
 
+class NativeRunnerDelegateImpl : public NativeRunnerDelegate {
+ public:
+  NativeRunnerDelegateImpl() {}
+  ~NativeRunnerDelegateImpl() override {}
+
+  size_t get_and_clear_adjust_count() {
+    size_t count = 0;
+    std::swap(count, adjust_count_);
+    return count;
+  }
+
+ private:
+  // NativeRunnerDelegate:
+  void AdjustCommandLineArgumentsForTarget(
+      const Identity& target,
+      base::CommandLine* command_line) override {
+    adjust_count_++;
+  }
+
+  size_t adjust_count_ = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(NativeRunnerDelegateImpl);
+};
+
 #if defined(OS_ANDROID)
 // TODO(qsr): Multiprocess shell tests are not supported on android.
 #define MAYBE_StartJoin DISABLED_StartJoin
@@ -64,9 +90,10 @@
   ProcessDelegate delegate;
   edk::InitIPCSupport(&delegate, io_thread.task_runner());
 
-  ChildProcessHost child_process_host(blocking_pool.get(), false,
-                                      base::FilePath(),
-                                      std::vector<CommandLineSwitch>());
+  NativeRunnerDelegateImpl native_runner_delegate;
+  ChildProcessHost child_process_host(blocking_pool.get(),
+                                      &native_runner_delegate, false,
+                                      Identity(), base::FilePath());
   base::RunLoop run_loop;
   child_process_host.Start(
       base::Bind(&ProcessReadyCallbackAdapater, run_loop.QuitClosure()));
@@ -78,6 +105,7 @@
   EXPECT_EQ(123, exit_code);
   blocking_pool->Shutdown();
   edk::ShutdownIPCSupport();
+  EXPECT_EQ(1u, native_runner_delegate.get_and_clear_adjust_count());
 }
 
 }  // namespace
diff --git a/mojo/shell/runner/host/command_line_switch.h b/mojo/shell/runner/host/command_line_switch.h
deleted file mode 100644
index 8e5224e2..0000000
--- a/mojo/shell/runner/host/command_line_switch.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2016 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 MOJO_SHELL_RUNNER_HOST_COMMAND_LINE_SWITCH_H_
-#define MOJO_SHELL_RUNNER_HOST_COMMAND_LINE_SWITCH_H_
-
-#include <string>
-
-namespace mojo {
-namespace shell {
-
-struct CommandLineSwitch {
-  CommandLineSwitch() : is_switch(true) {}
-
-  // If false only the key is used and the switch is treated as a single value.
-  bool is_switch;
-  std::string key;
-  std::string value;
-};
-
-}  // namespace shell
-}  // namespace mojo
-
-#endif  // MOJO_SHELL_RUNNER_HOST_COMMAND_LINE_SWITCH_H_
diff --git a/mojo/shell/runner/host/in_process_native_runner.cc b/mojo/shell/runner/host/in_process_native_runner.cc
index 69738a69..9dd19d0edf 100644
--- a/mojo/shell/runner/host/in_process_native_runner.cc
+++ b/mojo/shell/runner/host/in_process_native_runner.cc
@@ -12,7 +12,6 @@
 #include "base/task_runner.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/threading/platform_thread.h"
-#include "mojo/shell/runner/host/command_line_switch.h"
 #include "mojo/shell/runner/host/native_application_support.h"
 #include "mojo/shell/runner/host/out_of_process_native_runner.h"
 #include "mojo/shell/runner/init.h"
@@ -35,6 +34,7 @@
 
 void InProcessNativeRunner::Start(
     const base::FilePath& app_path,
+    const Identity& target,
     bool start_sandboxed,
     InterfaceRequest<mojom::ShellClient> request,
     const base::Callback<void(base::ProcessId)>& pid_available_callback,
@@ -83,8 +83,8 @@
     const base::FilePath& app_path) {
   // Non-Mojo apps are always run in a new process.
   if (!app_path.MatchesExtension(FILE_PATH_LITERAL(".mojo"))) {
-    return make_scoped_ptr(new OutOfProcessNativeRunner(
-        launch_process_runner_, std::vector<CommandLineSwitch>()));
+    return make_scoped_ptr(
+        new OutOfProcessNativeRunner(launch_process_runner_, nullptr));
   }
   return make_scoped_ptr(new InProcessNativeRunner);
 }
diff --git a/mojo/shell/runner/host/in_process_native_runner.h b/mojo/shell/runner/host/in_process_native_runner.h
index 93216b2..8e62172 100644
--- a/mojo/shell/runner/host/in_process_native_runner.h
+++ b/mojo/shell/runner/host/in_process_native_runner.h
@@ -32,6 +32,7 @@
   // NativeRunner:
   void Start(
       const base::FilePath& app_path,
+      const Identity& target,
       bool start_sandboxed,
       InterfaceRequest<mojom::ShellClient> request,
       const base::Callback<void(base::ProcessId)>& pid_available_callback,
diff --git a/mojo/shell/runner/host/out_of_process_native_runner.cc b/mojo/shell/runner/host/out_of_process_native_runner.cc
index 3ac446c5..cea56bc 100644
--- a/mojo/shell/runner/host/out_of_process_native_runner.cc
+++ b/mojo/shell/runner/host/out_of_process_native_runner.cc
@@ -14,7 +14,6 @@
 #include "base/logging.h"
 #include "base/task_runner.h"
 #include "mojo/shell/runner/host/child_process_host.h"
-#include "mojo/shell/runner/host/command_line_switch.h"
 #include "mojo/shell/runner/host/in_process_native_runner.h"
 
 namespace mojo {
@@ -22,9 +21,8 @@
 
 OutOfProcessNativeRunner::OutOfProcessNativeRunner(
     base::TaskRunner* launch_process_runner,
-    const std::vector<CommandLineSwitch>& command_line_switches)
-    : launch_process_runner_(launch_process_runner),
-      command_line_switches_(command_line_switches) {}
+    NativeRunnerDelegate* delegate)
+    : launch_process_runner_(launch_process_runner), delegate_(delegate) {}
 
 OutOfProcessNativeRunner::~OutOfProcessNativeRunner() {
   if (child_process_host_ && !app_path_.empty())
@@ -33,6 +31,7 @@
 
 void OutOfProcessNativeRunner::Start(
     const base::FilePath& app_path,
+    const Identity& target,
     bool start_sandboxed,
     InterfaceRequest<mojom::ShellClient> request,
     const base::Callback<void(base::ProcessId)>& pid_available_callback,
@@ -42,9 +41,8 @@
   DCHECK(app_completed_callback_.is_null());
   app_completed_callback_ = app_completed_callback;
 
-  child_process_host_.reset(new ChildProcessHost(launch_process_runner_,
-                                                 start_sandboxed, app_path,
-                                                 command_line_switches_));
+  child_process_host_.reset(new ChildProcessHost(
+      launch_process_runner_, delegate_, start_sandboxed, target, app_path));
   child_process_host_->Start(base::Bind(
       &OutOfProcessNativeRunner::OnProcessLaunched, base::Unretained(this),
       base::Passed(&request), pid_available_callback));
@@ -86,15 +84,14 @@
 
 OutOfProcessNativeRunnerFactory::OutOfProcessNativeRunnerFactory(
     base::TaskRunner* launch_process_runner,
-    const std::vector<CommandLineSwitch>& command_line_switches)
-    : launch_process_runner_(launch_process_runner),
-      command_line_switches_(command_line_switches) {}
+    NativeRunnerDelegate* delegate)
+    : launch_process_runner_(launch_process_runner), delegate_(delegate) {}
 OutOfProcessNativeRunnerFactory::~OutOfProcessNativeRunnerFactory() {}
 
 scoped_ptr<shell::NativeRunner> OutOfProcessNativeRunnerFactory::Create(
     const base::FilePath& app_path) {
-  return make_scoped_ptr(new OutOfProcessNativeRunner(launch_process_runner_,
-                                                      command_line_switches_));
+  return make_scoped_ptr(
+      new OutOfProcessNativeRunner(launch_process_runner_, delegate_));
 }
 
 }  // namespace shell
diff --git a/mojo/shell/runner/host/out_of_process_native_runner.h b/mojo/shell/runner/host/out_of_process_native_runner.h
index 0edb0aa..6b63c8ad 100644
--- a/mojo/shell/runner/host/out_of_process_native_runner.h
+++ b/mojo/shell/runner/host/out_of_process_native_runner.h
@@ -7,8 +7,6 @@
 
 #include <stdint.h>
 
-#include <vector>
-
 #include "base/callback.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
@@ -23,20 +21,20 @@
 namespace shell {
 
 class ChildProcessHost;
-struct CommandLineSwitch;
+class NativeRunnerDelegate;
 
 // An implementation of |NativeRunner| that loads/runs the given app (from the
 // file system) in a separate process (of its own).
 class OutOfProcessNativeRunner : public NativeRunner {
  public:
-  OutOfProcessNativeRunner(
-      base::TaskRunner* launch_process_runner,
-      const std::vector<CommandLineSwitch>& command_line_switches);
+  OutOfProcessNativeRunner(base::TaskRunner* launch_process_runner,
+                           NativeRunnerDelegate* delegate);
   ~OutOfProcessNativeRunner() override;
 
   // NativeRunner:
   void Start(
       const base::FilePath& app_path,
+      const Identity& identity,
       bool start_sandboxed,
       InterfaceRequest<mojom::ShellClient> request,
       const base::Callback<void(base::ProcessId)>& pid_available_callback,
@@ -56,12 +54,11 @@
       base::ProcessId pid);
 
   base::TaskRunner* const launch_process_runner_;
+  NativeRunnerDelegate* delegate_;
 
   base::FilePath app_path_;
   base::Closure app_completed_callback_;
 
-  std::vector<CommandLineSwitch> command_line_switches_;
-
   scoped_ptr<ChildProcessHost> child_process_host_;
 
   DISALLOW_COPY_AND_ASSIGN(OutOfProcessNativeRunner);
@@ -69,16 +66,15 @@
 
 class OutOfProcessNativeRunnerFactory : public NativeRunnerFactory {
  public:
-  OutOfProcessNativeRunnerFactory(
-      base::TaskRunner* launch_process_runner,
-      const std::vector<CommandLineSwitch>& command_line_switches);
+  OutOfProcessNativeRunnerFactory(base::TaskRunner* launch_process_runner,
+                                  NativeRunnerDelegate* delegate);
   ~OutOfProcessNativeRunnerFactory() override;
 
   scoped_ptr<NativeRunner> Create(const base::FilePath& app_path) override;
 
  private:
   base::TaskRunner* const launch_process_runner_;
-  std::vector<CommandLineSwitch> command_line_switches_;
+  NativeRunnerDelegate* delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(OutOfProcessNativeRunnerFactory);
 };
diff --git a/mojo/shell/standalone/BUILD.gn b/mojo/shell/standalone/BUILD.gn
index 46183b1..e9e62b4 100644
--- a/mojo/shell/standalone/BUILD.gn
+++ b/mojo/shell/standalone/BUILD.gn
@@ -37,6 +37,7 @@
     "//components/tracing:startup_tracing",
     "//mojo/edk/system",
     "//mojo/message_pump",
+    "//mojo/services/package_manager:lib",
     "//mojo/services/tracing/public/cpp",
     "//mojo/services/tracing/public/interfaces",
     "//mojo/shell",
@@ -45,11 +46,9 @@
     "//url",
   ]
 
-  if (!is_component_build) {
-    data_deps = [
-      "//mojo/services/tracing",
-    ]
-  }
+  data_deps = [
+    "//mojo/services/tracing",
+  ]
 
   # This target includes some files behind #ifdef OS... guards. Since gn is not
   # smart enough to understand preprocess includes, it does complains about
diff --git a/mojo/shell/standalone/context.cc b/mojo/shell/standalone/context.cc
index a04d259..72488e5 100644
--- a/mojo/shell/standalone/context.cc
+++ b/mojo/shell/standalone/context.cc
@@ -28,13 +28,13 @@
 #include "components/tracing/tracing_switches.h"
 #include "mojo/edk/embedder/embedder.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/services/package_manager/package_manager.h"
 #include "mojo/services/tracing/public/cpp/switches.h"
 #include "mojo/services/tracing/public/cpp/trace_provider_impl.h"
 #include "mojo/services/tracing/public/cpp/tracing_impl.h"
 #include "mojo/services/tracing/public/interfaces/tracing.mojom.h"
 #include "mojo/shell/application_loader.h"
 #include "mojo/shell/connect_params.h"
-#include "mojo/shell/runner/host/command_line_switch.h"
 #include "mojo/shell/runner/host/in_process_native_runner.h"
 #include "mojo/shell/runner/host/out_of_process_native_runner.h"
 #include "mojo/shell/standalone/tracer.h"
@@ -97,6 +97,9 @@
 
 }  // namespace
 
+Context::InitParams::InitParams() {}
+Context::InitParams::~InitParams() {}
+
 Context::Context()
     : io_thread_(CreateIOThread("io_thread")),
       main_entry_time_(base::Time::Now()) {}
@@ -112,7 +115,7 @@
   setup.Get();
 }
 
-void Context::Init(const base::FilePath& shell_file_root) {
+void Context::Init(scoped_ptr<InitParams> init_params) {
   TRACE_EVENT0("mojo_shell", "Context::Init");
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
@@ -144,20 +147,26 @@
     runner_factory.reset(
         new InProcessNativeRunnerFactory(blocking_pool_.get()));
   } else {
+    NativeRunnerDelegate* native_runner_delegate = init_params ?
+        init_params->native_runner_delegate : nullptr;
     runner_factory.reset(new OutOfProcessNativeRunnerFactory(
-        blocking_pool_.get(), command_line_switches_));
+        blocking_pool_.get(), native_runner_delegate));
   }
-  application_manager_.reset(new ApplicationManager(
-      std::move(runner_factory), blocking_pool_.get(), true));
+  scoped_ptr<package_manager::ApplicationCatalogStore> app_catalog;
+  if (init_params)
+    app_catalog = std::move(init_params->app_catalog);
+  application_manager_.reset(new ApplicationManager(std::move(runner_factory),
+                                                    blocking_pool_.get(), true,
+                                                    std::move(app_catalog)));
 
   shell::mojom::InterfaceProviderPtr tracing_remote_interfaces;
   shell::mojom::InterfaceProviderPtr tracing_local_interfaces;
   new TracingInterfaceProvider(&tracer_, GetProxy(&tracing_local_interfaces));
 
   scoped_ptr<ConnectParams> params(new ConnectParams);
-  params->set_source(Identity(GURL("mojo:shell"), std::string(),
-                              GetPermissiveCapabilityFilter()));
+  params->set_source(CreateShellIdentity());
   params->set_target(Identity(GURL("mojo:tracing"), std::string(),
+                              mojom::Connector::kUserInherit,
                               GetPermissiveCapabilityFilter()));
   params->set_remote_interfaces(GetProxy(&tracing_remote_interfaces));
   params->set_local_interfaces(std::move(tracing_local_interfaces));
@@ -227,8 +236,10 @@
   shell::mojom::InterfaceProviderPtr local_interfaces;
 
   scoped_ptr<ConnectParams> params(new ConnectParams);
+  params->set_source(CreateShellIdentity());
   params->set_target(
-      Identity(url, std::string(), GetPermissiveCapabilityFilter()));
+      Identity(url, std::string(), mojom::Connector::kUserRoot,
+               GetPermissiveCapabilityFilter()));
   params->set_remote_interfaces(GetProxy(&remote_interfaces));
   params->set_local_interfaces(std::move(local_interfaces));
   application_manager_->Connect(std::move(params));
diff --git a/mojo/shell/standalone/context.h b/mojo/shell/standalone/context.h
index 19df61a..b4e3768 100644
--- a/mojo/shell/standalone/context.h
+++ b/mojo/shell/standalone/context.h
@@ -5,8 +5,6 @@
 #ifndef MOJO_SHELL_STANDALONE_CONTEXT_H_
 #define MOJO_SHELL_STANDALONE_CONTEXT_H_
 
-#include <vector>
-
 #include "base/callback_forward.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -15,7 +13,6 @@
 #include "base/time/time.h"
 #include "mojo/edk/embedder/process_delegate.h"
 #include "mojo/shell/application_manager.h"
-#include "mojo/shell/runner/host/command_line_switch.h"
 #include "mojo/shell/standalone/tracer.h"
 #include "url/gurl.h"
 
@@ -23,26 +20,33 @@
 class SingleThreadTaskRunner;
 }
 
+namespace package_manager {
+class ApplicationCatalogStore;
+}
+
 namespace mojo {
 namespace shell {
-struct CommandLineSwitch;
+class NativeRunnerDelegate;
 
 // The "global" context for the shell's main process.
 class Context : public edk::ProcessDelegate {
  public:
+  struct InitParams {
+    InitParams();
+    ~InitParams();
+
+    NativeRunnerDelegate* native_runner_delegate = nullptr;
+    scoped_ptr<package_manager::ApplicationCatalogStore> app_catalog;
+  };
+
   Context();
   ~Context() override;
 
   static void EnsureEmbedderIsInitialized();
 
-  void set_command_line_switches(
-      const std::vector<CommandLineSwitch>& command_line_switches) {
-    command_line_switches_ = command_line_switches;
-  }
-
   // This must be called with a message loop set up for the current thread,
   // which must remain alive until after Shutdown() is called.
-  void Init(const base::FilePath& shell_file_root);
+  void Init(scoped_ptr<InitParams> init_params);
 
   // If Init() was called and succeeded, this must be called before destruction.
   void Shutdown();
@@ -70,7 +74,6 @@
   Tracer tracer_;
   scoped_ptr<ApplicationManager> application_manager_;
   base::Time main_entry_time_;
-  std::vector<CommandLineSwitch> command_line_switches_;
 
   DISALLOW_COPY_AND_ASSIGN(Context);
 };
diff --git a/mojo/shell/standalone/desktop/launcher_process.cc b/mojo/shell/standalone/desktop/launcher_process.cc
index efb6fd6f7..58309188 100644
--- a/mojo/shell/standalone/desktop/launcher_process.cc
+++ b/mojo/shell/standalone/desktop/launcher_process.cc
@@ -38,10 +38,8 @@
   Context shell_context;
   {
     base::MessageLoop message_loop;
-    base::FilePath shell_dir;
-    PathService::Get(base::DIR_MODULE, &shell_dir);
     CHECK(base::i18n::InitializeICU());
-    shell_context.Init(shell_dir);
+    shell_context.Init(nullptr);
 
     message_loop.PostTask(
         FROM_HERE,
diff --git a/mojo/shell/tests/BUILD.gn b/mojo/shell/tests/BUILD.gn
index 5ef1e7b..5c3ba44 100644
--- a/mojo/shell/tests/BUILD.gn
+++ b/mojo/shell/tests/BUILD.gn
@@ -37,16 +37,20 @@
   sources = [
     "application_manager_unittest.cc",
     "capability_filter_unittest.cc",
+    "run_all_unittests.cc",
   ]
 
   deps = [
     ":test_bindings",
     ":test_support",
     "//base",
-    "//mojo/edk/system:test_utils",
-    "//mojo/edk/test:run_all_unittests",
+    "//base/test:test_support",
+    "//mojo/edk/system",
     "//mojo/public/cpp/system",
     "//mojo/shell",
+    "//mojo/shell/background:lib",
+    "//mojo/shell/background:main",
+    "//mojo/shell/background/tests:unittests",
     "//mojo/shell/public/cpp",
     "//mojo/util:filename_util",
     "//testing/gtest",
diff --git a/mojo/shell/tests/application_manager_apptest.cc b/mojo/shell/tests/application_manager_apptest.cc
index 9a6b1691..9ebc076 100644
--- a/mojo/shell/tests/application_manager_apptest.cc
+++ b/mojo/shell/tests/application_manager_apptest.cc
@@ -30,7 +30,7 @@
       public CreateInstanceForHandleTest {
  public:
   ApplicationManagerAppTestDelegate()
-      : target_id_(mojom::Shell::kInvalidApplicationID),
+      : target_id_(mojom::Connector::kInvalidApplicationID),
         binding_(this) {}
   ~ApplicationManagerAppTestDelegate() override {}
 
@@ -38,7 +38,8 @@
 
  private:
   // mojo::ShellClient:
-  void Initialize(Shell* shell, const std::string& url, uint32_t id) override {}
+  void Initialize(Shell* shell, const std::string& url, uint32_t id,
+                  uint32_t user_id) override {}
   bool AcceptConnection(Connection* connection) override {
     connection->AddInterface<CreateInstanceForHandleTest>(this);
     return true;
@@ -175,9 +176,9 @@
   //    mojo:application_manager_apptests)
   base::MessageLoop::current()->Run();
 
-  uint32_t remote_id = mojom::Shell::kInvalidApplicationID;
+  uint32_t remote_id = mojom::Connector::kInvalidApplicationID;
   EXPECT_TRUE(connection->GetRemoteApplicationID(&remote_id));
-  EXPECT_NE(mojom::Shell::kInvalidApplicationID, remote_id);
+  EXPECT_NE(mojom::Connector::kInvalidApplicationID, remote_id);
 
   // 3. Validate that this test suite's URL was received from the application
   //    manager.
diff --git a/mojo/shell/tests/application_manager_apptest_driver.cc b/mojo/shell/tests/application_manager_apptest_driver.cc
index 39fe9ed1..aad9660 100644
--- a/mojo/shell/tests/application_manager_apptest_driver.cc
+++ b/mojo/shell/tests/application_manager_apptest_driver.cc
@@ -47,7 +47,7 @@
  private:
   // mojo::ShellClient:
   void Initialize(mojo::Shell* shell, const std::string& url,
-                  uint32_t id) override {
+                  uint32_t id, uint32_t user_id) override {
     shell_ = shell;
 
     base::FilePath target_path;
diff --git a/mojo/shell/tests/application_manager_apptest_target.cc b/mojo/shell/tests/application_manager_apptest_target.cc
index 5b5964f..5284553 100644
--- a/mojo/shell/tests/application_manager_apptest_target.cc
+++ b/mojo/shell/tests/application_manager_apptest_target.cc
@@ -24,7 +24,7 @@
  private:
   // mojo::ShellClient:
   void Initialize(mojo::Shell* shell, const std::string& url,
-                  uint32_t id) override {
+                  uint32_t id, uint32_t user_id) override {
     CreateInstanceForHandleTestPtr service;
     shell->ConnectToInterface("mojo:mojo_shell_apptests", &service);
     service->SetTargetID(id);
diff --git a/mojo/shell/tests/application_manager_unittest.cc b/mojo/shell/tests/application_manager_unittest.cc
index ac4133d9..d9f4473 100644
--- a/mojo/shell/tests/application_manager_unittest.cc
+++ b/mojo/shell/tests/application_manager_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/services/package_manager/package_manager.h"
 #include "mojo/shell/application_loader.h"
 #include "mojo/shell/connect_util.h"
 #include "mojo/shell/public/cpp/interface_factory.h"
@@ -397,7 +398,8 @@
   ~ApplicationManagerTest() override {}
 
   void SetUp() override {
-    application_manager_.reset(new ApplicationManager(true));
+    application_manager_.reset(
+        new ApplicationManager(nullptr, nullptr, true, nullptr));
     test_loader_ = new TestApplicationLoader(&context_);
     application_manager_->set_default_loader(
         scoped_ptr<ApplicationLoader>(test_loader_));
@@ -468,7 +470,7 @@
 
 TEST_F(ApplicationManagerTest, Deletes) {
   {
-    ApplicationManager am(true);
+    ApplicationManager am(nullptr, nullptr, true, nullptr);
     TestApplicationLoader* default_loader =
         new TestApplicationLoader(&context_);
     TestApplicationLoader* url_loader1 = new TestApplicationLoader(&context_);
@@ -600,7 +602,10 @@
 
   bool called = false;
   scoped_ptr<ConnectParams> params(new ConnectParams);
-  params->SetTargetURL(GURL("test:test"));
+  params->set_source(CreateShellIdentity());
+  params->set_target(
+      Identity(GURL("test:test"), "", mojom::Connector::kUserRoot,
+               GetPermissiveCapabilityFilter()));
   application_manager_->SetInstanceQuitCallback(
       base::Bind(&QuitClosure, params->target(), &called));
   application_manager_->Connect(std::move(params));
diff --git a/mojo/shell/tests/capability_filter_test.cc b/mojo/shell/tests/capability_filter_test.cc
index 9bce8923..57fb1f0 100644
--- a/mojo/shell/tests/capability_filter_test.cc
+++ b/mojo/shell/tests/capability_filter_test.cc
@@ -11,6 +11,7 @@
 #include "base/strings/stringprintf.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "mojo/public/cpp/bindings/weak_binding_set.h"
+#include "mojo/services/package_manager/package_manager.h"
 #include "mojo/shell/application_loader.h"
 #include "mojo/shell/public/cpp/connection.h"
 #include "mojo/shell/public/cpp/interface_factory.h"
@@ -115,7 +116,8 @@
 
  private:
   // Overridden from ShellClient:
-  void Initialize(Shell* shell, const std::string& url, uint32_t id) override {
+  void Initialize(Shell* shell, const std::string& url, uint32_t id,
+                  uint32_t user_id) override {
     shell_ = shell;
     // ServiceApplications have no capability filter and can thus connect
     // directly to the validator application.
@@ -162,7 +164,7 @@
 TestApplication::~TestApplication() {}
 
 void TestApplication::Initialize(Shell* shell, const std::string& url,
-                                 uint32_t id) {
+                                 uint32_t id, uint32_t user_id) {
   shell_ = shell;
   url_ = url;
 }
@@ -280,7 +282,8 @@
 
 
 void CapabilityFilterTest::SetUp() {
-  application_manager_.reset(new ApplicationManager(true));
+  application_manager_.reset(
+      new ApplicationManager(nullptr, nullptr, true, nullptr));
   application_manager_->SetInstanceQuitCallback(
       base::Bind(&CapabilityFilterTest::OnInstanceQuit,
                  base::Unretained(this)));
@@ -327,7 +330,9 @@
   shell::mojom::InterfaceProviderPtr local_interfaces;
   new InterfaceProviderImpl(GetProxy(&local_interfaces), validator_);
   scoped_ptr<ConnectParams> params(new ConnectParams);
-  params->set_target(Identity(GURL(url), std::string(), filter));
+  params->set_source(CreateShellIdentity());
+  params->set_target(Identity(GURL(url), std::string(),
+                              mojom::Connector::kUserInherit, filter));
   params->set_remote_interfaces(GetProxy(&remote_interfaces));
   params->set_local_interfaces(std::move(local_interfaces));
   quit_identities_.insert(params->target());
diff --git a/mojo/shell/tests/capability_filter_test.h b/mojo/shell/tests/capability_filter_test.h
index 0efc62c1..45a5fa8 100644
--- a/mojo/shell/tests/capability_filter_test.h
+++ b/mojo/shell/tests/capability_filter_test.h
@@ -29,7 +29,8 @@
 
  private:
   // Overridden from ShellClient:
-  void Initialize(Shell* shell, const std::string& url, uint32_t id) override;
+  void Initialize(Shell* shell, const std::string& url, uint32_t id,
+                  uint32_t user_id) override;
   bool AcceptConnection(Connection* connection) override;
 
   void ConnectionClosed(const std::string& service_url);
diff --git a/mojo/shell/tests/package_apptest.cc b/mojo/shell/tests/package_apptest.cc
index b29bc02..ecdb0d9a 100644
--- a/mojo/shell/tests/package_apptest.cc
+++ b/mojo/shell/tests/package_apptest.cc
@@ -44,7 +44,7 @@
     std::string root_name;
     root_service->GetName(base::Bind(&ReceiveName, &root_name, &run_loop));
     run_loop.Run();
-    uint32_t id = mojom::Shell::kInvalidApplicationID;
+    uint32_t id = mojom::Connector::kInvalidApplicationID;
     EXPECT_TRUE(connection->GetRemoteApplicationID(&id));
     ids.insert(id);
   }
@@ -60,7 +60,7 @@
     service_a->GetName(base::Bind(&ReceiveName, &a_name, &run_loop));
     run_loop.Run();
     EXPECT_EQ("A", a_name);
-    uint32_t id = mojom::Shell::kInvalidApplicationID;
+    uint32_t id = mojom::Connector::kInvalidApplicationID;
     EXPECT_TRUE(connection->GetRemoteApplicationID(&id));
     ids.insert(id);
   }
@@ -74,7 +74,7 @@
     service_b->GetName(base::Bind(&ReceiveName, &b_name, &run_loop));
     run_loop.Run();
     EXPECT_EQ("B", b_name);
-    uint32_t id = mojom::Shell::kInvalidApplicationID;
+    uint32_t id = mojom::Connector::kInvalidApplicationID;
     EXPECT_TRUE(connection->GetRemoteApplicationID(&id));
     ids.insert(id);
   }
diff --git a/mojo/shell/tests/package_test_package.cc b/mojo/shell/tests/package_test_package.cc
index 4a37ebe..a9defe4 100644
--- a/mojo/shell/tests/package_test_package.cc
+++ b/mojo/shell/tests/package_test_package.cc
@@ -49,7 +49,8 @@
 
  private:
   // mojo::ShellClient:
-  void Initialize(Shell* shell, const std::string& url, uint32_t id) override {
+  void Initialize(Shell* shell, const std::string& url,
+                  uint32_t id, uint32_t user_id) override {
     shell_ = shell;
     bindings_.set_connection_error_handler(
         base::Bind(&ProvidedShellClient::OnConnectionError,
@@ -104,7 +105,8 @@
 
  private:
   // mojo::ShellClient:
-  void Initialize(Shell* shell, const std::string& url, uint32_t id) override {
+  void Initialize(Shell* shell, const std::string& url,
+                  uint32_t id, uint32_t user_id) override {
     shell_ = shell;
     bindings_.set_connection_error_handler(
         base::Bind(&PackageTestShellClient::OnConnectionError,
diff --git a/mojo/shell/tests/run_all_unittests.cc b/mojo/shell/tests/run_all_unittests.cc
new file mode 100644
index 0000000..946d9c9
--- /dev/null
+++ b/mojo/shell/tests/run_all_unittests.cc
@@ -0,0 +1,18 @@
+// Copyright 2016 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 <signal.h>
+
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/shell/background/background_shell_main.h"
+
+int MasterProcessMain(int argc, char** argv) {
+  base::TestSuite test_suite(argc, argv);
+  mojo::edk::Init();
+  return base::LaunchUnitTests(
+      argc, argv,
+      base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
+}
diff --git a/native_client_sdk/src/tests/nacl_io_test/socket_test.cc b/native_client_sdk/src/tests/nacl_io_test/socket_test.cc
index 77b9fb1..259169a5 100644
--- a/native_client_sdk/src/tests/nacl_io_test/socket_test.cc
+++ b/native_client_sdk/src/tests/nacl_io_test/socket_test.cc
@@ -539,7 +539,7 @@
 
 }  // namespace
 
-TEST_F(UnixSocketMultithreadedTest, DISABLED_SendRecv) {
+TEST_F(UnixSocketMultithreadedTest, SendRecv) {
   pthread_t thread = CreateThread();
 
   uint8_t pattern[] = {0xA5, 0x00, 0xC3, 0xFF};
diff --git a/net/base/address_list.cc b/net/base/address_list.cc
index 5b4fe34..f065b35 100644
--- a/net/base/address_list.cc
+++ b/net/base/address_list.cc
@@ -9,7 +9,6 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/values.h"
-#include "net/base/net_util.h"
 #include "net/base/sys_addrinfo.h"
 
 namespace net {
diff --git a/net/base/escape.cc b/net/base/escape.cc
index 15de5e1..fc7d5cf0 100644
--- a/net/base/escape.cc
+++ b/net/base/escape.cc
@@ -290,7 +290,10 @@
            (first_byte == ' ' && (rules & UnescapeRule::SPACES)) ||
            // Allow any of the prohibited but non-control characters when
            // we're doing "special" chars.
-           (first_byte > ' ' && (rules & UnescapeRule::URL_SPECIAL_CHARS)) ||
+           ((first_byte == '/' || first_byte == '\\') &&
+            (rules & UnescapeRule::PATH_SEPARATORS)) ||
+           (first_byte > ' ' && first_byte != '/' && first_byte != '\\' &&
+            (rules & UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS)) ||
            // Additionally allow non-display characters if requested.
            (first_byte < ' ' &&
             (rules & UnescapeRule::SPOOFING_AND_CONTROL_CHARS)))) {
diff --git a/net/base/escape.h b/net/base/escape.h
index c31dcf9..759631a 100644
--- a/net/base/escape.h
+++ b/net/base/escape.h
@@ -78,20 +78,36 @@
     // just the absence of them). All other unescape rules imply "normal" in
     // addition to their special meaning. Things like escaped letters, digits,
     // and most symbols will get unescaped with this mode.
-    NORMAL = 1,
+    NORMAL = 1 << 0,
 
     // Convert %20 to spaces. In some places where we're showing URLs, we may
     // want this. In places where the URL may be copied and pasted out, then
     // you wouldn't want this since it might not be interpreted in one piece
     // by other applications.
-    SPACES = 2,
+    SPACES = 1 << 1,
+
+    // Unescapes '/' and '\\'. If these characters were unescaped, the resulting
+    // URL won't be the same as the source one. Moreover, they are dangerous to
+    // unescape in strings that will be used as file paths or names. This value
+    // should only be used when slashes don't have special meaning, like data
+    // URLs.
+    PATH_SEPARATORS = 1 << 2,
 
     // Unescapes various characters that will change the meaning of URLs,
-    // including '%', '+', '&', '/', '#'. If we unescaped these characters, the
-    // resulting URL won't be the same as the source one. This flag is used when
-    // generating final output like filenames for URLs where we won't be
-    // interpreting as a URL and want to do as much unescaping as possible.
-    URL_SPECIAL_CHARS = 4,
+    // including '%', '+', '&', '#'. Does not unescape path separators.
+    // If these characters were unescaped, the resulting URL won't be the same
+    // as the source one. This flag is used when generating final output like
+    // filenames for URLs where we won't be interpreting as a URL and want to do
+    // as much unescaping as possible.
+    URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS = 1 << 3,
+
+    // A combination of URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS and
+    // PATH_SEPARATORS. Warning about the use of PATH_SEPARATORS also apply
+    // here.
+    // TODO(mmenke):  Audit all uses of this and replace with the above values,
+    // as needed.
+    URL_SPECIAL_CHARS =
+        PATH_SEPARATORS | URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS,
 
     // Unescapes characters that can be used in spoofing attempts (such as LOCK)
     // and control characters (such as BiDi control characters and %01).  This
@@ -100,10 +116,10 @@
     //
     // DO NOT use SPOOFING_AND_CONTROL_CHARS if the URL is going to be displayed
     // in the UI for security reasons.
-    SPOOFING_AND_CONTROL_CHARS = 8,
+    SPOOFING_AND_CONTROL_CHARS = 1 << 4,
 
     // URL queries use "+" for space. This flag controls that replacement.
-    REPLACE_PLUS_WITH_SPACE = 16,
+    REPLACE_PLUS_WITH_SPACE = 1 << 5,
   };
 };
 
diff --git a/net/base/escape_unittest.cc b/net/base/escape_unittest.cc
index cec7f32..b828d80b 100644
--- a/net/base/escape_unittest.cc
+++ b/net/base/escape_unittest.cc
@@ -150,43 +150,55 @@
 
 TEST(EscapeTest, UnescapeURLComponentASCII) {
   const UnescapeURLCaseASCII unescape_cases[] = {
-    {"", UnescapeRule::NORMAL, ""},
-    {"%2", UnescapeRule::NORMAL, "%2"},
-    {"%%%%%%", UnescapeRule::NORMAL, "%%%%%%"},
-    {"Don't escape anything", UnescapeRule::NORMAL, "Don't escape anything"},
-    {"Invalid %escape %2", UnescapeRule::NORMAL, "Invalid %escape %2"},
-    {"Some%20random text %25%2dOK", UnescapeRule::NONE,
-     "Some%20random text %25%2dOK"},
-    {"Some%20random text %25%2dOK", UnescapeRule::NORMAL,
-     "Some%20random text %25-OK"},
-    {"Some%20random text %25%2dOK", UnescapeRule::SPACES,
-     "Some random text %25-OK"},
-    {"Some%20random text %25%2dOK", UnescapeRule::URL_SPECIAL_CHARS,
-     "Some%20random text %-OK"},
-    {"Some%20random text %25%2dOK",
-     UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS,
-     "Some random text %-OK"},
-    {"%A0%B1%C2%D3%E4%F5", UnescapeRule::NORMAL, "\xA0\xB1\xC2\xD3\xE4\xF5"},
-    {"%Aa%Bb%Cc%Dd%Ee%Ff", UnescapeRule::NORMAL, "\xAa\xBb\xCc\xDd\xEe\xFf"},
-    // Certain URL-sensitive characters should not be unescaped unless asked.
-    {"Hello%20%13%10world %23# %3F? %3D= %26& %25% %2B+", UnescapeRule::SPACES,
-     "Hello %13%10world %23# %3F? %3D= %26& %25% %2B+"},
-    {"Hello%20%13%10world %23# %3F? %3D= %26& %25% %2B+",
-     UnescapeRule::URL_SPECIAL_CHARS,
-     "Hello%20%13%10world ## ?? == && %% ++"},
-    // We can neither escape nor unescape '@' since some websites expect it to
-    // be preserved as either '@' or "%40".
-    // See http://b/996720 and http://crbug.com/23933 .
-    {"me@my%40example", UnescapeRule::NORMAL, "me@my%40example"},
-    // Control characters.
-    {"%01%02%03%04%05%06%07%08%09 %25", UnescapeRule::URL_SPECIAL_CHARS,
-     "%01%02%03%04%05%06%07%08%09 %"},
-    {"%01%02%03%04%05%06%07%08%09 %25",
-     UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
-     "\x01\x02\x03\x04\x05\x06\x07\x08\x09 %25"},
-    {"Hello%20%13%10%02", UnescapeRule::SPACES, "Hello %13%10%02"},
-    {"Hello%20%13%10%02", UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
-     "Hello%20\x13\x10\x02"},
+      {"", UnescapeRule::NORMAL, ""},
+      {"%2", UnescapeRule::NORMAL, "%2"},
+      {"%%%%%%", UnescapeRule::NORMAL, "%%%%%%"},
+      {"Don't escape anything", UnescapeRule::NORMAL, "Don't escape anything"},
+      {"Invalid %escape %2", UnescapeRule::NORMAL, "Invalid %escape %2"},
+      {"Some%20random text %25%2dOK", UnescapeRule::NONE,
+       "Some%20random text %25%2dOK"},
+      {"Some%20random text %25%2dOK", UnescapeRule::NORMAL,
+       "Some%20random text %25-OK"},
+      {"Some%20random text %25%2dOK", UnescapeRule::SPACES,
+       "Some random text %25-OK"},
+      {"Some%20random text %25%2dOK", UnescapeRule::PATH_SEPARATORS,
+       "Some%20random text %25-OK"},
+      {"Some%20random text %25%2dOK",
+       UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS,
+       "Some%20random text %-OK"},
+      {"Some%20random text %25%2dOK",
+       UnescapeRule::SPACES |
+           UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS,
+       "Some random text %-OK"},
+      {"%A0%B1%C2%D3%E4%F5", UnescapeRule::NORMAL, "\xA0\xB1\xC2\xD3\xE4\xF5"},
+      {"%Aa%Bb%Cc%Dd%Ee%Ff", UnescapeRule::NORMAL, "\xAa\xBb\xCc\xDd\xEe\xFf"},
+      // Certain URL-sensitive characters should not be unescaped unless asked.
+      {"Hello%20%13%10world %23# %3F? %3D= %26& %25% %2B+",
+       UnescapeRule::SPACES, "Hello %13%10world %23# %3F? %3D= %26& %25% %2B+"},
+      {"Hello%20%13%10world %23# %3F? %3D= %26& %25% %2B+",
+       UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS,
+       "Hello%20%13%10world ## ?? == && %% ++"},
+      // We can neither escape nor unescape '@' since some websites expect it to
+      // be preserved as either '@' or "%40".
+      // See http://b/996720 and http://crbug.com/23933 .
+      {"me@my%40example", UnescapeRule::NORMAL, "me@my%40example"},
+      // Control characters.
+      {"%01%02%03%04%05%06%07%08%09 %25",
+       UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS,
+       "%01%02%03%04%05%06%07%08%09 %"},
+      {"%01%02%03%04%05%06%07%08%09 %25",
+       UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
+       "\x01\x02\x03\x04\x05\x06\x07\x08\x09 %25"},
+      {"Hello%20%13%10%02", UnescapeRule::SPACES, "Hello %13%10%02"},
+      {"Hello%20%13%10%02", UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
+       "Hello%20\x13\x10\x02"},
+
+      // '/' and '\\' should only be unescaped by PATH_SEPARATORS.
+      {"%2F%5C", UnescapeRule::PATH_SEPARATORS, "/\\"},
+      {"%2F%5C", UnescapeRule::SPACES |
+                     UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS |
+                     UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
+       "%2F%5C"},
   };
 
   for (size_t i = 0; i < arraysize(unescape_cases); i++) {
@@ -218,126 +230,135 @@
 
 TEST(EscapeTest, UnescapeURLComponent) {
   const UnescapeURLCase unescape_cases[] = {
-    {L"", UnescapeRule::NORMAL, L""},
-    {L"%2", UnescapeRule::NORMAL, L"%2"},
-    {L"%%%%%%", UnescapeRule::NORMAL, L"%%%%%%"},
-    {L"Don't escape anything", UnescapeRule::NORMAL, L"Don't escape anything"},
-    {L"Invalid %escape %2", UnescapeRule::NORMAL, L"Invalid %escape %2"},
-    {L"Some%20random text %25%2dOK", UnescapeRule::NONE,
-     L"Some%20random text %25%2dOK"},
-    {L"Some%20random text %25%2dOK", UnescapeRule::NORMAL,
-     L"Some%20random text %25-OK"},
-    {L"Some%20random text %25%E2%80", UnescapeRule::NORMAL,
-     L"Some%20random text %25\xE2\x80"},
-    {L"Some%20random text %25%E2%80OK", UnescapeRule::NORMAL,
-     L"Some%20random text %25\xE2\x80OK"},
-    {L"Some%20random text %25%E2%80%84OK", UnescapeRule::NORMAL,
-     L"Some%20random text %25\xE2\x80\x84OK"},
+      {L"", UnescapeRule::NORMAL, L""},
+      {L"%2", UnescapeRule::NORMAL, L"%2"},
+      {L"%%%%%%", UnescapeRule::NORMAL, L"%%%%%%"},
+      {L"Don't escape anything", UnescapeRule::NORMAL,
+       L"Don't escape anything"},
+      {L"Invalid %escape %2", UnescapeRule::NORMAL, L"Invalid %escape %2"},
+      {L"Some%20random text %25%2dOK", UnescapeRule::NONE,
+       L"Some%20random text %25%2dOK"},
+      {L"Some%20random text %25%2dOK", UnescapeRule::NORMAL,
+       L"Some%20random text %25-OK"},
+      {L"Some%20random text %25%E2%80", UnescapeRule::NORMAL,
+       L"Some%20random text %25\xE2\x80"},
+      {L"Some%20random text %25%E2%80OK", UnescapeRule::NORMAL,
+       L"Some%20random text %25\xE2\x80OK"},
+      {L"Some%20random text %25%E2%80%84OK", UnescapeRule::NORMAL,
+       L"Some%20random text %25\xE2\x80\x84OK"},
 
-    // BiDi Control characters should not be unescaped unless explicity told to
-    // do so with UnescapeRule::SPOOFING_AND_CONTROL_CHARS
-    {L"Some%20random text %25%D8%9COK", UnescapeRule::NORMAL,
-     L"Some%20random text %25%D8%9COK"},
-    {L"Some%20random text %25%E2%80%8EOK", UnescapeRule::NORMAL,
-     L"Some%20random text %25%E2%80%8EOK"},
-    {L"Some%20random text %25%E2%80%8FOK", UnescapeRule::NORMAL,
-     L"Some%20random text %25%E2%80%8FOK"},
-    {L"Some%20random text %25%E2%80%AAOK", UnescapeRule::NORMAL,
-     L"Some%20random text %25%E2%80%AAOK"},
-    {L"Some%20random text %25%E2%80%ABOK", UnescapeRule::NORMAL,
-     L"Some%20random text %25%E2%80%ABOK"},
-    {L"Some%20random text %25%E2%80%AEOK", UnescapeRule::NORMAL,
-     L"Some%20random text %25%E2%80%AEOK"},
-    {L"Some%20random text %25%E2%81%A6OK", UnescapeRule::NORMAL,
-     L"Some%20random text %25%E2%81%A6OK"},
-    {L"Some%20random text %25%E2%81%A9OK", UnescapeRule::NORMAL,
-     L"Some%20random text %25%E2%81%A9OK"},
-    // UnescapeRule::SPOOFING_AND_CONTROL_CHARS should unescape BiDi Control
-    // characters.
-    {L"Some%20random text %25%D8%9COK",
-     UnescapeRule::NORMAL | UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
-     L"Some%20random text %25\xD8\x9COK"},
-    {L"Some%20random text %25%E2%80%8EOK",
-     UnescapeRule::NORMAL | UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
-     L"Some%20random text %25\xE2\x80\x8EOK"},
-    {L"Some%20random text %25%E2%80%8FOK",
-     UnescapeRule::NORMAL | UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
-     L"Some%20random text %25\xE2\x80\x8FOK"},
-    {L"Some%20random text %25%E2%80%AAOK",
-     UnescapeRule::NORMAL | UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
-     L"Some%20random text %25\xE2\x80\xAAOK"},
-    {L"Some%20random text %25%E2%80%ABOK",
-     UnescapeRule::NORMAL | UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
-     L"Some%20random text %25\xE2\x80\xABOK"},
-    {L"Some%20random text %25%E2%80%AEOK",
-     UnescapeRule::NORMAL | UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
-     L"Some%20random text %25\xE2\x80\xAEOK"},
-    {L"Some%20random text %25%E2%81%A6OK",
-     UnescapeRule::NORMAL | UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
-     L"Some%20random text %25\xE2\x81\xA6OK"},
-    {L"Some%20random text %25%E2%81%A9OK",
-     UnescapeRule::NORMAL | UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
-     L"Some%20random text %25\xE2\x81\xA9OK"},
+      // BiDi Control characters should not be unescaped unless explicity told
+      // to
+      // do so with UnescapeRule::SPOOFING_AND_CONTROL_CHARS
+      {L"Some%20random text %25%D8%9COK", UnescapeRule::NORMAL,
+       L"Some%20random text %25%D8%9COK"},
+      {L"Some%20random text %25%E2%80%8EOK", UnescapeRule::NORMAL,
+       L"Some%20random text %25%E2%80%8EOK"},
+      {L"Some%20random text %25%E2%80%8FOK", UnescapeRule::NORMAL,
+       L"Some%20random text %25%E2%80%8FOK"},
+      {L"Some%20random text %25%E2%80%AAOK", UnescapeRule::NORMAL,
+       L"Some%20random text %25%E2%80%AAOK"},
+      {L"Some%20random text %25%E2%80%ABOK", UnescapeRule::NORMAL,
+       L"Some%20random text %25%E2%80%ABOK"},
+      {L"Some%20random text %25%E2%80%AEOK", UnescapeRule::NORMAL,
+       L"Some%20random text %25%E2%80%AEOK"},
+      {L"Some%20random text %25%E2%81%A6OK", UnescapeRule::NORMAL,
+       L"Some%20random text %25%E2%81%A6OK"},
+      {L"Some%20random text %25%E2%81%A9OK", UnescapeRule::NORMAL,
+       L"Some%20random text %25%E2%81%A9OK"},
+      // UnescapeRule::SPOOFING_AND_CONTROL_CHARS should unescape BiDi Control
+      // characters.
+      {L"Some%20random text %25%D8%9COK",
+       UnescapeRule::NORMAL | UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
+       L"Some%20random text %25\xD8\x9COK"},
+      {L"Some%20random text %25%E2%80%8EOK",
+       UnescapeRule::NORMAL | UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
+       L"Some%20random text %25\xE2\x80\x8EOK"},
+      {L"Some%20random text %25%E2%80%8FOK",
+       UnescapeRule::NORMAL | UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
+       L"Some%20random text %25\xE2\x80\x8FOK"},
+      {L"Some%20random text %25%E2%80%AAOK",
+       UnescapeRule::NORMAL | UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
+       L"Some%20random text %25\xE2\x80\xAAOK"},
+      {L"Some%20random text %25%E2%80%ABOK",
+       UnescapeRule::NORMAL | UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
+       L"Some%20random text %25\xE2\x80\xABOK"},
+      {L"Some%20random text %25%E2%80%AEOK",
+       UnescapeRule::NORMAL | UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
+       L"Some%20random text %25\xE2\x80\xAEOK"},
+      {L"Some%20random text %25%E2%81%A6OK",
+       UnescapeRule::NORMAL | UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
+       L"Some%20random text %25\xE2\x81\xA6OK"},
+      {L"Some%20random text %25%E2%81%A9OK",
+       UnescapeRule::NORMAL | UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
+       L"Some%20random text %25\xE2\x81\xA9OK"},
 
-    // Certain banned characters should not be unescaped unless explicitly told
-    // to do so with UnescapeRule::SPOOFING_AND_CONTROL_CHARS.
-    // U+1F50F LOCK WITH INK PEN
-    {L"Some%20random text %25%F0%9F%94%8FOK", UnescapeRule::NORMAL,
-     L"Some%20random text %25%F0%9F%94%8FOK"},
-    // U+1F510 CLOSED LOCK WITH KEY
-    {L"Some%20random text %25%F0%9F%94%90OK", UnescapeRule::NORMAL,
-     L"Some%20random text %25%F0%9F%94%90OK"},
-    // U+1F512 LOCK
-    {L"Some%20random text %25%F0%9F%94%92OK", UnescapeRule::NORMAL,
-     L"Some%20random text %25%F0%9F%94%92OK"},
-    // U+1F513 OPEN LOCK
-    {L"Some%20random text %25%F0%9F%94%93OK", UnescapeRule::NORMAL,
-     L"Some%20random text %25%F0%9F%94%93OK"},
-    // UnescapeRule::SPOOFING_AND_CONTROL_CHARS should unescape banned
-    // characters.
-    {L"Some%20random text %25%F0%9F%94%8FOK",
-     UnescapeRule::NORMAL | UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
-     L"Some%20random text %25\xF0\x9F\x94\x8FOK"},
-    {L"Some%20random text %25%F0%9F%94%90OK",
-     UnescapeRule::NORMAL | UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
-     L"Some%20random text %25\xF0\x9F\x94\x90OK"},
-    {L"Some%20random text %25%F0%9F%94%92OK",
-     UnescapeRule::NORMAL | UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
-     L"Some%20random text %25\xF0\x9F\x94\x92OK"},
-    {L"Some%20random text %25%F0%9F%94%93OK",
-     UnescapeRule::NORMAL | UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
-     L"Some%20random text %25\xF0\x9F\x94\x93OK"},
+      // Certain banned characters should not be unescaped unless explicitly
+      // told
+      // to do so with UnescapeRule::SPOOFING_AND_CONTROL_CHARS.
+      // U+1F50F LOCK WITH INK PEN
+      {L"Some%20random text %25%F0%9F%94%8FOK", UnescapeRule::NORMAL,
+       L"Some%20random text %25%F0%9F%94%8FOK"},
+      // U+1F510 CLOSED LOCK WITH KEY
+      {L"Some%20random text %25%F0%9F%94%90OK", UnescapeRule::NORMAL,
+       L"Some%20random text %25%F0%9F%94%90OK"},
+      // U+1F512 LOCK
+      {L"Some%20random text %25%F0%9F%94%92OK", UnescapeRule::NORMAL,
+       L"Some%20random text %25%F0%9F%94%92OK"},
+      // U+1F513 OPEN LOCK
+      {L"Some%20random text %25%F0%9F%94%93OK", UnescapeRule::NORMAL,
+       L"Some%20random text %25%F0%9F%94%93OK"},
+      // UnescapeRule::SPOOFING_AND_CONTROL_CHARS should unescape banned
+      // characters.
+      {L"Some%20random text %25%F0%9F%94%8FOK",
+       UnescapeRule::NORMAL | UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
+       L"Some%20random text %25\xF0\x9F\x94\x8FOK"},
+      {L"Some%20random text %25%F0%9F%94%90OK",
+       UnescapeRule::NORMAL | UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
+       L"Some%20random text %25\xF0\x9F\x94\x90OK"},
+      {L"Some%20random text %25%F0%9F%94%92OK",
+       UnescapeRule::NORMAL | UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
+       L"Some%20random text %25\xF0\x9F\x94\x92OK"},
+      {L"Some%20random text %25%F0%9F%94%93OK",
+       UnescapeRule::NORMAL | UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
+       L"Some%20random text %25\xF0\x9F\x94\x93OK"},
 
-    {L"Some%20random text %25%2dOK", UnescapeRule::SPACES,
-     L"Some random text %25-OK"},
-    {L"Some%20random text %25%2dOK", UnescapeRule::URL_SPECIAL_CHARS,
-     L"Some%20random text %-OK"},
-    {L"Some%20random text %25%2dOK",
-     UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS,
-     L"Some random text %-OK"},
-    {L"%A0%B1%C2%D3%E4%F5", UnescapeRule::NORMAL, L"\xA0\xB1\xC2\xD3\xE4\xF5"},
-    {L"%Aa%Bb%Cc%Dd%Ee%Ff", UnescapeRule::NORMAL, L"\xAa\xBb\xCc\xDd\xEe\xFf"},
-    // Certain URL-sensitive characters should not be unescaped unless asked.
-    {L"Hello%20%13%10world %23# %3F? %3D= %26& %25% %2B+", UnescapeRule::SPACES,
-     L"Hello %13%10world %23# %3F? %3D= %26& %25% %2B+"},
-    {L"Hello%20%13%10world %23# %3F? %3D= %26& %25% %2B+",
-     UnescapeRule::URL_SPECIAL_CHARS,
-     L"Hello%20%13%10world ## ?? == && %% ++"},
-    // We can neither escape nor unescape '@' since some websites expect it to
-    // be preserved as either '@' or "%40".
-    // See http://b/996720 and http://crbug.com/23933 .
-    {L"me@my%40example", UnescapeRule::NORMAL, L"me@my%40example"},
-    // Control characters.
-    {L"%01%02%03%04%05%06%07%08%09 %25", UnescapeRule::URL_SPECIAL_CHARS,
-     L"%01%02%03%04%05%06%07%08%09 %"},
-    {L"%01%02%03%04%05%06%07%08%09 %25",
-     UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
-     L"\x01\x02\x03\x04\x05\x06\x07\x08\x09 %25"},
-    {L"Hello%20%13%10%02", UnescapeRule::SPACES, L"Hello %13%10%02"},
-    {L"Hello%20%13%10%02", UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
-     L"Hello%20\x13\x10\x02"},
-    {L"Hello\x9824\x9827", UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
-     L"Hello\x9824\x9827"},
+      {L"Some%20random text %25%2dOK", UnescapeRule::SPACES,
+       L"Some random text %25-OK"},
+      {L"Some%20random text %25%2dOK",
+       UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS,
+       L"Some%20random text %-OK"},
+      {L"Some%20random text %25%2dOK",
+       UnescapeRule::SPACES |
+           UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS,
+       L"Some random text %-OK"},
+      {L"%A0%B1%C2%D3%E4%F5", UnescapeRule::NORMAL,
+       L"\xA0\xB1\xC2\xD3\xE4\xF5"},
+      {L"%Aa%Bb%Cc%Dd%Ee%Ff", UnescapeRule::NORMAL,
+       L"\xAa\xBb\xCc\xDd\xEe\xFf"},
+      // Certain URL-sensitive characters should not be unescaped unless asked.
+      {L"Hello%20%13%10world %23# %3F? %3D= %26& %25% %2B+",
+       UnescapeRule::SPACES,
+       L"Hello %13%10world %23# %3F? %3D= %26& %25% %2B+"},
+      {L"Hello%20%13%10world %23# %3F? %3D= %26& %25% %2B+",
+       UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS,
+       L"Hello%20%13%10world ## ?? == && %% ++"},
+      // We can neither escape nor unescape '@' since some websites expect it to
+      // be preserved as either '@' or "%40".
+      // See http://b/996720 and http://crbug.com/23933 .
+      {L"me@my%40example", UnescapeRule::NORMAL, L"me@my%40example"},
+      // Control characters.
+      {L"%01%02%03%04%05%06%07%08%09 %25",
+       UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS,
+       L"%01%02%03%04%05%06%07%08%09 %"},
+      {L"%01%02%03%04%05%06%07%08%09 %25",
+       UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
+       L"\x01\x02\x03\x04\x05\x06\x07\x08\x09 %25"},
+      {L"Hello%20%13%10%02", UnescapeRule::SPACES, L"Hello %13%10%02"},
+      {L"Hello%20%13%10%02", UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
+       L"Hello%20\x13\x10\x02"},
+      {L"Hello\x9824\x9827", UnescapeRule::SPOOFING_AND_CONTROL_CHARS,
+       L"Hello\x9824\x9827"},
   };
 
   for (size_t i = 0; i < arraysize(unescape_cases); i++) {
diff --git a/net/base/filename_util.cc b/net/base/filename_util.cc
index 0969f715..153ce43d 100644
--- a/net/base/filename_util.cc
+++ b/net/base/filename_util.cc
@@ -98,7 +98,8 @@
 
   // GURL stores strings as percent-encoded 8-bit, this will undo if possible.
   path = UnescapeURLComponent(
-      path, UnescapeRule::SPACES | UnescapeRule::URL_SPECIAL_CHARS);
+      path, UnescapeRule::SPACES |
+                UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS);
 
 #if defined(OS_WIN)
   if (base::IsStringUTF8(path)) {
diff --git a/net/base/filename_util_unittest.cc b/net/base/filename_util_unittest.cc
index 5e3fb7e1..4ca7f02c 100644
--- a/net/base/filename_util_unittest.cc
+++ b/net/base/filename_util_unittest.cc
@@ -239,6 +239,9 @@
     {L"\\\\foo\\bar.txt", "file:/foo/bar.txt"},
     {L"\\\\foo\\bar.txt", "file://foo\\bar.txt"},
     {L"C:\\foo\\bar.txt", "file:\\\\\\c:/foo/bar.txt"},
+    // %2f ('/') and %5c ('\\') are left alone by both GURL and
+    // FileURLToFilePath.
+    {L"C:\\foo%2f..%5cbar", "file:///C:\\foo%2f..%5cbar"},
 #elif defined(OS_POSIX)
     {L"/c:/foo/bar.txt", "file:/c:/foo/bar.txt"},
     {L"/c:/foo/bar.txt", "file:///c:/foo/bar.txt"},
@@ -253,6 +256,9 @@
     {L"/foo/bar.txt", "file:////foo////bar.txt"},
     {L"/c:/foo/bar.txt", "file:\\\\\\c:/foo/bar.txt"},
     {L"/c:/foo/bar.txt", "file:c:/foo/bar.txt"},
+    // %2f ('/') and %5c ('\\') are left alone by both GURL and
+    // FileURLToFilePath.
+    {L"/foo%2f..%5cbar", "file:///foo%2f..%5cbar"},
 //  We get these wrong because GURL turns back slashes into forward
 //  slashes.
 //  {L"/foo%5Cbar.txt", "file://foo\\bar.txt"},
diff --git a/net/base/ip_address.cc b/net/base/ip_address.cc
index 4076460..f9565e5ad 100644
--- a/net/base/ip_address.cc
+++ b/net/base/ip_address.cc
@@ -20,6 +20,14 @@
 IPAddress::IPAddress(const uint8_t* address, size_t address_len)
     : ip_address_(address, address + address_len) {}
 
+IPAddress::IPAddress(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3) {
+  ip_address_.reserve(4);
+  ip_address_.push_back(b0);
+  ip_address_.push_back(b1);
+  ip_address_.push_back(b2);
+  ip_address_.push_back(b3);
+}
+
 IPAddress::~IPAddress() {}
 
 bool IPAddress::IsIPv4() const {
diff --git a/net/base/ip_address.h b/net/base/ip_address.h
index 3969f02..f46eadb 100644
--- a/net/base/ip_address.h
+++ b/net/base/ip_address.h
@@ -39,6 +39,10 @@
   // parameter. The input is expected to be in network byte order.
   IPAddress(const uint8_t* address, size_t address_len);
 
+  // Initializes |ip_address_| from the 4 bX bytes. The bytes are expected to be
+  // in network byte order.
+  IPAddress(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3);
+
   ~IPAddress();
 
   // Returns true if the IP has |kIPv4AddressSize| elements.
diff --git a/net/base/ip_address_number_unittest.cc b/net/base/ip_address_number_unittest.cc
index 93e6d907..67d9f312 100644
--- a/net/base/ip_address_number_unittest.cc
+++ b/net/base/ip_address_number_unittest.cc
@@ -7,7 +7,6 @@
 #include "base/format_macros.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
-#include "net/base/net_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace net {
diff --git a/net/base/net_util.cc b/net/base/net_util.cc
deleted file mode 100644
index 92db80c1..0000000
--- a/net/base/net_util.cc
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) 2012 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 "net/base/net_util.h"
-
-#include "build/build_config.h"
-
-#if defined(OS_POSIX)
-#include <netinet/in.h>
-#elif defined(OS_WIN)
-#include <ws2tcpip.h>
-#endif
-
-#include "base/logging.h"
-#include "net/base/ip_address_number.h"
-#include "net/base/url_util.h"
-
-namespace net {
-
-bool IsLocalhost(base::StringPiece host) {
-  if (IsLocalHostname(host, nullptr))
-    return true;
-
-  IPAddressNumber ip_number;
-  if (ParseIPLiteralToNumber(host, &ip_number)) {
-    size_t size = ip_number.size();
-    switch (size) {
-      case kIPv4AddressSize: {
-        IPAddressNumber localhost_prefix;
-        localhost_prefix.push_back(127);
-        for (int i = 0; i < 3; ++i) {
-          localhost_prefix.push_back(0);
-        }
-        return IPNumberMatchesPrefix(ip_number, localhost_prefix, 8);
-      }
-
-      case kIPv6AddressSize: {
-        struct in6_addr sin6_addr;
-        memcpy(&sin6_addr, &ip_number[0], kIPv6AddressSize);
-        return !!IN6_IS_ADDR_LOOPBACK(&sin6_addr);
-      }
-
-      default:
-        NOTREACHED();
-    }
-  }
-
-  return false;
-}
-
-}  // namespace net
diff --git a/net/base/net_util.h b/net/base/net_util.h
deleted file mode 100644
index 329a008..0000000
--- a/net/base/net_util.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2012 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 NET_BASE_NET_UTIL_H_
-#define NET_BASE_NET_UTIL_H_
-
-#include "base/strings/string_piece.h"
-#include "net/base/net_export.h"
-
-namespace net {
-
-// Returns true if |host| is one of the local hostnames
-// (e.g. "localhost") or IP addresses (IPv4 127.0.0.0/8 or IPv6 ::1).
-//
-// Note that this function does not check for IP addresses other than
-// the above, although other IP addresses may point to the local
-// machine.
-NET_EXPORT bool IsLocalhost(base::StringPiece host);
-
-}  // namespace net
-
-#endif  // NET_BASE_NET_UTIL_H_
diff --git a/net/base/net_util_unittest.cc b/net/base/net_util_unittest.cc
deleted file mode 100644
index 4e2d476..0000000
--- a/net/base/net_util_unittest.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) 2012 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 "net/base/net_util.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-TEST(NetUtilTest, IsLocalhost) {
-  EXPECT_TRUE(IsLocalhost("localhost"));
-  EXPECT_TRUE(IsLocalhost("localHosT"));
-  EXPECT_TRUE(IsLocalhost("localhost."));
-  EXPECT_TRUE(IsLocalhost("localHost."));
-  EXPECT_TRUE(IsLocalhost("localhost.localdomain"));
-  EXPECT_TRUE(IsLocalhost("localhost.localDOMain"));
-  EXPECT_TRUE(IsLocalhost("localhost.localdomain."));
-  EXPECT_TRUE(IsLocalhost("localhost6"));
-  EXPECT_TRUE(IsLocalhost("localhost6."));
-  EXPECT_TRUE(IsLocalhost("localhost6.localdomain6"));
-  EXPECT_TRUE(IsLocalhost("localhost6.localdomain6."));
-  EXPECT_TRUE(IsLocalhost("127.0.0.1"));
-  EXPECT_TRUE(IsLocalhost("127.0.1.0"));
-  EXPECT_TRUE(IsLocalhost("127.1.0.0"));
-  EXPECT_TRUE(IsLocalhost("127.0.0.255"));
-  EXPECT_TRUE(IsLocalhost("127.0.255.0"));
-  EXPECT_TRUE(IsLocalhost("127.255.0.0"));
-  EXPECT_TRUE(IsLocalhost("::1"));
-  EXPECT_TRUE(IsLocalhost("0:0:0:0:0:0:0:1"));
-  EXPECT_TRUE(IsLocalhost("foo.localhost"));
-  EXPECT_TRUE(IsLocalhost("foo.localhost."));
-  EXPECT_TRUE(IsLocalhost("foo.localhoST"));
-  EXPECT_TRUE(IsLocalhost("foo.localhoST."));
-
-  EXPECT_FALSE(IsLocalhost("localhostx"));
-  EXPECT_FALSE(IsLocalhost("localhost.x"));
-  EXPECT_FALSE(IsLocalhost("foo.localdomain"));
-  EXPECT_FALSE(IsLocalhost("foo.localdomain.x"));
-  EXPECT_FALSE(IsLocalhost("localhost6x"));
-  EXPECT_FALSE(IsLocalhost("localhost.localdomain6"));
-  EXPECT_FALSE(IsLocalhost("localhost6.localdomain"));
-  EXPECT_FALSE(IsLocalhost("127.0.0.1.1"));
-  EXPECT_FALSE(IsLocalhost(".127.0.0.255"));
-  EXPECT_FALSE(IsLocalhost("::2"));
-  EXPECT_FALSE(IsLocalhost("::1:1"));
-  EXPECT_FALSE(IsLocalhost("0:0:0:0:1:0:0:1"));
-  EXPECT_FALSE(IsLocalhost("::1:1"));
-  EXPECT_FALSE(IsLocalhost("0:0:0:0:0:0:0:0:1"));
-  EXPECT_FALSE(IsLocalhost("foo.localhost.com"));
-  EXPECT_FALSE(IsLocalhost("foo.localhoste"));
-  EXPECT_FALSE(IsLocalhost("foo.localhos"));
-}
-
-}  // namespace net
diff --git a/net/base/network_change_notifier.cc b/net/base/network_change_notifier.cc
index 52e5ce34..17c91f59 100644
--- a/net/base/network_change_notifier.cc
+++ b/net/base/network_change_notifier.cc
@@ -12,9 +12,9 @@
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
 #include "build/build_config.h"
-#include "net/base/net_util.h"
 #include "net/base/network_change_notifier_factory.h"
 #include "net/base/network_interfaces.h"
+#include "net/base/url_util.h"
 #include "net/dns/dns_config_service.h"
 #include "net/url_request/url_request.h"
 #include "url/gurl.h"
diff --git a/net/base/network_interfaces_linux.cc b/net/base/network_interfaces_linux.cc
index 8aea321..4601487b 100644
--- a/net/base/network_interfaces_linux.cc
+++ b/net/base/network_interfaces_linux.cc
@@ -26,7 +26,6 @@
 #include "net/base/escape.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/network_interfaces_posix.h"
 #include "url/gurl.h"
 
diff --git a/net/base/network_interfaces_mac.cc b/net/base/network_interfaces_mac.cc
index 2357cd6..66385acc 100644
--- a/net/base/network_interfaces_mac.cc
+++ b/net/base/network_interfaces_mac.cc
@@ -20,7 +20,6 @@
 #include "net/base/escape.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/network_interfaces_posix.h"
 #include "url/gurl.h"
 
diff --git a/net/base/network_interfaces_unittest.cc b/net/base/network_interfaces_unittest.cc
index 6f27e1f..c4b72df 100644
--- a/net/base/network_interfaces_unittest.cc
+++ b/net/base/network_interfaces_unittest.cc
@@ -19,7 +19,6 @@
 #include "base/sys_byteorder.h"
 #include "base/time/time.h"
 #include "net/base/ip_endpoint.h"
-#include "net/base/net_util.h"
 
 #if !defined(OS_NACL) && !defined(OS_WIN)
 #include <net/if.h>
diff --git a/net/base/network_interfaces_win.cc b/net/base/network_interfaces_win.cc
index ac79391..fd11994 100644
--- a/net/base/network_interfaces_win.cc
+++ b/net/base/network_interfaces_win.cc
@@ -21,7 +21,6 @@
 #include "net/base/escape.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "url/gurl.h"
 
 namespace net {
diff --git a/net/base/network_quality_estimator.cc b/net/base/network_quality_estimator.cc
index 37cbcc0..e0a10cfc 100644
--- a/net/base/network_quality_estimator.cc
+++ b/net/base/network_quality_estimator.cc
@@ -18,8 +18,8 @@
 #include "build/build_config.h"
 #include "net/base/load_flags.h"
 #include "net/base/load_timing_info.h"
-#include "net/base/net_util.h"
 #include "net/base/network_interfaces.h"
+#include "net/base/url_util.h"
 #include "net/url_request/url_request.h"
 #include "url/gurl.h"
 
diff --git a/net/base/url_util.cc b/net/base/url_util.cc
index 797d1c8..86a6108 100644
--- a/net/base/url_util.cc
+++ b/net/base/url_util.cc
@@ -4,6 +4,14 @@
 
 #include "net/base/url_util.h"
 
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+#include <netinet/in.h>
+#elif defined(OS_WIN)
+#include <ws2tcpip.h>
+#endif
+
 #include "base/logging.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -343,6 +351,37 @@
                   registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
 }
 
+bool IsLocalhost(base::StringPiece host) {
+  if (IsLocalHostname(host, nullptr))
+    return true;
+
+  IPAddressNumber ip_number;
+  if (ParseIPLiteralToNumber(host, &ip_number)) {
+    size_t size = ip_number.size();
+    switch (size) {
+      case kIPv4AddressSize: {
+        IPAddressNumber localhost_prefix;
+        localhost_prefix.push_back(127);
+        for (int i = 0; i < 3; ++i) {
+          localhost_prefix.push_back(0);
+        }
+        return IPNumberMatchesPrefix(ip_number, localhost_prefix, 8);
+      }
+
+      case kIPv6AddressSize: {
+        struct in6_addr sin6_addr;
+        memcpy(&sin6_addr, &ip_number[0], kIPv6AddressSize);
+        return !!IN6_IS_ADDR_LOOPBACK(&sin6_addr);
+      }
+
+      default:
+        NOTREACHED();
+    }
+  }
+
+  return false;
+}
+
 GURL SimplifyUrlForRequest(const GURL& url) {
   DCHECK(url.is_valid());
   GURL::Replacements replacements;
diff --git a/net/base/url_util.h b/net/base/url_util.h
index 517aaa3..75f7b62 100644
--- a/net/base/url_util.h
+++ b/net/base/url_util.h
@@ -142,6 +142,14 @@
 // that falls in an IANA-reserved range.
 NET_EXPORT bool IsHostnameNonUnique(const std::string& hostname);
 
+// Returns true if |host| is one of the local hostnames
+// (e.g. "localhost") or IP addresses (IPv4 127.0.0.0/8 or IPv6 ::1).
+//
+// Note that this function does not check for IP addresses other than
+// the above, although other IP addresses may point to the local
+// machine.
+NET_EXPORT bool IsLocalhost(base::StringPiece host);
+
 // Strip the portions of |url| that aren't core to the network request.
 //   - user name / password
 //   - reference section
diff --git a/net/base/url_util_unittest.cc b/net/base/url_util_unittest.cc
index b670165a..3a7a1b4 100644
--- a/net/base/url_util_unittest.cc
+++ b/net/base/url_util_unittest.cc
@@ -387,6 +387,50 @@
 INSTANTIATE_TEST_CASE_P(, UrlUtilNonUniqueNameTest,
                         testing::ValuesIn(kNonUniqueNameTestData));
 
+TEST(UrlUtilTest, IsLocalhost) {
+  EXPECT_TRUE(IsLocalhost("localhost"));
+  EXPECT_TRUE(IsLocalhost("localHosT"));
+  EXPECT_TRUE(IsLocalhost("localhost."));
+  EXPECT_TRUE(IsLocalhost("localHost."));
+  EXPECT_TRUE(IsLocalhost("localhost.localdomain"));
+  EXPECT_TRUE(IsLocalhost("localhost.localDOMain"));
+  EXPECT_TRUE(IsLocalhost("localhost.localdomain."));
+  EXPECT_TRUE(IsLocalhost("localhost6"));
+  EXPECT_TRUE(IsLocalhost("localhost6."));
+  EXPECT_TRUE(IsLocalhost("localhost6.localdomain6"));
+  EXPECT_TRUE(IsLocalhost("localhost6.localdomain6."));
+  EXPECT_TRUE(IsLocalhost("127.0.0.1"));
+  EXPECT_TRUE(IsLocalhost("127.0.1.0"));
+  EXPECT_TRUE(IsLocalhost("127.1.0.0"));
+  EXPECT_TRUE(IsLocalhost("127.0.0.255"));
+  EXPECT_TRUE(IsLocalhost("127.0.255.0"));
+  EXPECT_TRUE(IsLocalhost("127.255.0.0"));
+  EXPECT_TRUE(IsLocalhost("::1"));
+  EXPECT_TRUE(IsLocalhost("0:0:0:0:0:0:0:1"));
+  EXPECT_TRUE(IsLocalhost("foo.localhost"));
+  EXPECT_TRUE(IsLocalhost("foo.localhost."));
+  EXPECT_TRUE(IsLocalhost("foo.localhoST"));
+  EXPECT_TRUE(IsLocalhost("foo.localhoST."));
+
+  EXPECT_FALSE(IsLocalhost("localhostx"));
+  EXPECT_FALSE(IsLocalhost("localhost.x"));
+  EXPECT_FALSE(IsLocalhost("foo.localdomain"));
+  EXPECT_FALSE(IsLocalhost("foo.localdomain.x"));
+  EXPECT_FALSE(IsLocalhost("localhost6x"));
+  EXPECT_FALSE(IsLocalhost("localhost.localdomain6"));
+  EXPECT_FALSE(IsLocalhost("localhost6.localdomain"));
+  EXPECT_FALSE(IsLocalhost("127.0.0.1.1"));
+  EXPECT_FALSE(IsLocalhost(".127.0.0.255"));
+  EXPECT_FALSE(IsLocalhost("::2"));
+  EXPECT_FALSE(IsLocalhost("::1:1"));
+  EXPECT_FALSE(IsLocalhost("0:0:0:0:1:0:0:1"));
+  EXPECT_FALSE(IsLocalhost("::1:1"));
+  EXPECT_FALSE(IsLocalhost("0:0:0:0:0:0:0:0:1"));
+  EXPECT_FALSE(IsLocalhost("foo.localhost.com"));
+  EXPECT_FALSE(IsLocalhost("foo.localhoste"));
+  EXPECT_FALSE(IsLocalhost("foo.localhos"));
+}
+
 TEST(UrlUtilTest, SimplifyUrlForRequest) {
   struct {
     const char* const input_url;
diff --git a/net/cert/ct_policy_enforcer_unittest.cc b/net/cert/ct_policy_enforcer_unittest.cc
index c6c61b3..18a82e1 100644
--- a/net/cert/ct_policy_enforcer_unittest.cc
+++ b/net/cert/ct_policy_enforcer_unittest.cc
@@ -66,14 +66,12 @@
     non_google_log_id_.assign(crypto::kSHA256Length, 'A');
   }
 
-  // TODO(eranm): Remove the use of CTVerifyResult in this file and just
-  // use lists of verified SCTs. https://crbug.com/587921
-  void FillResultWithSCTsOfOrigin(
+  void FillListWithSCTsOfOrigin(
       ct::SignedCertificateTimestamp::Origin desired_origin,
       size_t num_scts,
       const std::vector<std::string>& desired_log_keys,
       bool timestamp_past_enforcement_date,
-      ct::CTVerifyResult* result) {
+      ct::SCTList* verified_scts) {
     for (size_t i = 0; i < num_scts; ++i) {
       scoped_refptr<ct::SignedCertificateTimestamp> sct(
           new ct::SignedCertificateTimestamp());
@@ -90,29 +88,29 @@
         sct->timestamp =
             base::Time::FromUTCExploded({2015, 6, 0, 15, 0, 0, 0, 0});
 
-      result->verified_scts.push_back(sct);
+      verified_scts->push_back(sct);
     }
   }
 
-  void FillResultWithSCTsOfOrigin(
+  void FillListWithSCTsOfOrigin(
       ct::SignedCertificateTimestamp::Origin desired_origin,
       size_t num_scts,
-      ct::CTVerifyResult* result) {
+      ct::SCTList* verified_scts) {
     std::vector<std::string> desired_log_ids;
     desired_log_ids.push_back(google_log_id_);
-    FillResultWithSCTsOfOrigin(desired_origin, num_scts, desired_log_ids, true,
-                               result);
+    FillListWithSCTsOfOrigin(desired_origin, num_scts, desired_log_ids, true,
+                             verified_scts);
   }
 
-  void FillResultWithRepeatedLogID(const std::string& desired_id,
-                                   size_t num_scts,
-                                   bool timestamp_past_enforcement_date,
-                                   ct::CTVerifyResult* result) {
+  void FillSCTListWithRepeatedLogID(const std::string& desired_id,
+                                    size_t num_scts,
+                                    bool timestamp_past_enforcement_date,
+                                    ct::SCTList* verified_scts) {
     std::vector<std::string> desired_log_ids(num_scts, desired_id);
 
-    FillResultWithSCTsOfOrigin(
+    FillListWithSCTsOfOrigin(
         ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION, num_scts,
-        desired_log_ids, timestamp_past_enforcement_date, result);
+        desired_log_ids, timestamp_past_enforcement_date, verified_scts);
   }
 
   void CheckCertificateCompliesWithExactNumberOfEmbeddedSCTs(
@@ -121,24 +119,24 @@
       size_t required_scts) {
     scoped_refptr<X509Certificate> cert(
         new X509Certificate("subject", "issuer", start, end));
-    ct::CTVerifyResult result;
+    ct::SCTList scts;
 
     for (size_t i = 0; i < required_scts - 1; ++i) {
-      FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED,
-                                 1, std::vector<std::string>(), false, &result);
+      FillListWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 1,
+                               std::vector<std::string>(), false, &scts);
       EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS,
-                policy_enforcer_->DoesConformToCTEVPolicy(
-                    cert.get(), nullptr, result.verified_scts, BoundNetLog()))
+                policy_enforcer_->DoesConformToCTEVPolicy(cert.get(), nullptr,
+                                                          scts, BoundNetLog()))
           << " for: " << (end - start).InDays() << " and " << required_scts
-          << " scts=" << result.verified_scts.size() << " i=" << i;
+          << " scts=" << scts.size() << " i=" << i;
     }
-    FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 1,
-                               std::vector<std::string>(), false, &result);
+    FillListWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 1,
+                             std::vector<std::string>(), false, &scts);
     EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS,
-              policy_enforcer_->DoesConformToCTEVPolicy(
-                  cert.get(), nullptr, result.verified_scts, BoundNetLog()))
+              policy_enforcer_->DoesConformToCTEVPolicy(cert.get(), nullptr,
+                                                        scts, BoundNetLog()))
         << " for: " << (end - start).InDays() << " and " << required_scts
-        << " scts=" << result.verified_scts.size();
+        << " scts=" << scts.size();
   }
 
  protected:
@@ -150,52 +148,52 @@
 
 TEST_F(CTPolicyEnforcerTest,
        DoesNotConformToCTEVPolicyNotEnoughDiverseSCTsAllGoogle) {
-  ct::CTVerifyResult result;
-  FillResultWithRepeatedLogID(google_log_id_, 2, true, &result);
+  ct::SCTList scts;
+  FillSCTListWithRepeatedLogID(google_log_id_, 2, true, &scts);
 
   EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_DIVERSE_SCTS,
-            policy_enforcer_->DoesConformToCTEVPolicy(
-                chain_.get(), nullptr, result.verified_scts, BoundNetLog()));
+            policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr,
+                                                      scts, BoundNetLog()));
 }
 
 TEST_F(CTPolicyEnforcerTest,
        DoesNotConformToCTEVPolicyNotEnoughDiverseSCTsAllNonGoogle) {
-  ct::CTVerifyResult result;
-  FillResultWithRepeatedLogID(non_google_log_id_, 2, true, &result);
+  ct::SCTList scts;
+  FillSCTListWithRepeatedLogID(non_google_log_id_, 2, true, &scts);
 
   EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_DIVERSE_SCTS,
-            policy_enforcer_->DoesConformToCTEVPolicy(
-                chain_.get(), nullptr, result.verified_scts, BoundNetLog()));
+            policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr,
+                                                      scts, BoundNetLog()));
 }
 
 TEST_F(CTPolicyEnforcerTest, ConformsToCTEVPolicyIfSCTBeforeEnforcementDate) {
-  ct::CTVerifyResult result;
-  FillResultWithRepeatedLogID(non_google_log_id_, 2, false, &result);
+  ct::SCTList scts;
+  FillSCTListWithRepeatedLogID(non_google_log_id_, 2, false, &scts);
 
   EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS,
-            policy_enforcer_->DoesConformToCTEVPolicy(
-                chain_.get(), nullptr, result.verified_scts, BoundNetLog()));
+            policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr,
+                                                      scts, BoundNetLog()));
 }
 
 TEST_F(CTPolicyEnforcerTest, ConformsToCTEVPolicyWithNonEmbeddedSCTs) {
-  ct::CTVerifyResult result;
-  FillResultWithSCTsOfOrigin(
-      ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION, 2, &result);
+  ct::SCTList scts;
+  FillListWithSCTsOfOrigin(
+      ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION, 2, &scts);
 
   EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS,
-            policy_enforcer_->DoesConformToCTEVPolicy(
-                chain_.get(), nullptr, result.verified_scts, BoundNetLog()));
+            policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr,
+                                                      scts, BoundNetLog()));
 }
 
 TEST_F(CTPolicyEnforcerTest, ConformsToCTEVPolicyWithEmbeddedSCTs) {
   // This chain_ is valid for 10 years - over 121 months - so requires 5 SCTs.
-  ct::CTVerifyResult result;
-  FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 5,
-                             &result);
+  ct::SCTList scts;
+  FillListWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 5,
+                           &scts);
 
   EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS,
-            policy_enforcer_->DoesConformToCTEVPolicy(
-                chain_.get(), nullptr, result.verified_scts, BoundNetLog()));
+            policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr,
+                                                      scts, BoundNetLog()));
 }
 
 TEST_F(CTPolicyEnforcerTest, DoesNotConformToCTEVPolicyNotEnoughSCTs) {
@@ -204,41 +202,38 @@
   // This chain_ is valid for 10 years - over 121 months - so requires 5 SCTs.
   // However, as there are only two logs, two SCTs will be required - supply one
   // to guarantee the test fails.
-  ct::CTVerifyResult result;
-  FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 1,
-                             &result);
+  ct::SCTList scts;
+  FillListWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 1,
+                           &scts);
 
-  EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS,
-            policy_enforcer_->DoesConformToCTEVPolicy(
-                chain_.get(), non_including_whitelist.get(),
-                result.verified_scts, BoundNetLog()));
+  EXPECT_EQ(
+      ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS,
+      policy_enforcer_->DoesConformToCTEVPolicy(
+          chain_.get(), non_including_whitelist.get(), scts, BoundNetLog()));
 
   // ... but should be OK if whitelisted.
   scoped_refptr<ct::EVCertsWhitelist> whitelist(
       new DummyEVCertsWhitelist(true, true));
-  EXPECT_EQ(
-      ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_WHITELIST,
-      policy_enforcer_->DoesConformToCTEVPolicy(
-          chain_.get(), whitelist.get(), result.verified_scts, BoundNetLog()));
+  EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_WHITELIST,
+            policy_enforcer_->DoesConformToCTEVPolicy(
+                chain_.get(), whitelist.get(), scts, BoundNetLog()));
 }
 
 TEST_F(CTPolicyEnforcerTest, DoesNotConformToPolicyInvalidDates) {
   scoped_refptr<X509Certificate> no_valid_dates_cert(new X509Certificate(
       "subject", "issuer", base::Time(), base::Time::Now()));
-  ct::CTVerifyResult result;
-  FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 5,
-                             &result);
+  ct::SCTList scts;
+  FillListWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 5,
+                           &scts);
   EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS,
             policy_enforcer_->DoesConformToCTEVPolicy(
-                no_valid_dates_cert.get(), nullptr, result.verified_scts,
-                BoundNetLog()));
+                no_valid_dates_cert.get(), nullptr, scts, BoundNetLog()));
   // ... but should be OK if whitelisted.
   scoped_refptr<ct::EVCertsWhitelist> whitelist(
       new DummyEVCertsWhitelist(true, true));
-  EXPECT_EQ(
-      ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_WHITELIST,
-      policy_enforcer_->DoesConformToCTEVPolicy(
-          chain_.get(), whitelist.get(), result.verified_scts, BoundNetLog()));
+  EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_WHITELIST,
+            policy_enforcer_->DoesConformToCTEVPolicy(
+                chain_.get(), whitelist.get(), scts, BoundNetLog()));
 }
 
 TEST_F(CTPolicyEnforcerTest,
@@ -289,35 +284,33 @@
   scoped_refptr<ct::EVCertsWhitelist> whitelist(
       new DummyEVCertsWhitelist(true, true));
 
-  ct::CTVerifyResult result;
-  FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 1,
-                             &result);
-  EXPECT_EQ(
-      ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_WHITELIST,
-      policy_enforcer_->DoesConformToCTEVPolicy(
-          chain_.get(), whitelist.get(), result.verified_scts, BoundNetLog()));
+  ct::SCTList scts;
+  FillListWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 1,
+                           &scts);
+  EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_WHITELIST,
+            policy_enforcer_->DoesConformToCTEVPolicy(
+                chain_.get(), whitelist.get(), scts, BoundNetLog()));
 }
 
 TEST_F(CTPolicyEnforcerTest, IgnoresInvalidEVWhitelist) {
   scoped_refptr<ct::EVCertsWhitelist> whitelist(
       new DummyEVCertsWhitelist(false, true));
 
-  ct::CTVerifyResult result;
-  FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 1,
-                             &result);
-  EXPECT_EQ(
-      ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS,
-      policy_enforcer_->DoesConformToCTEVPolicy(
-          chain_.get(), whitelist.get(), result.verified_scts, BoundNetLog()));
+  ct::SCTList scts;
+  FillListWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 1,
+                           &scts);
+  EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS,
+            policy_enforcer_->DoesConformToCTEVPolicy(
+                chain_.get(), whitelist.get(), scts, BoundNetLog()));
 }
 
 TEST_F(CTPolicyEnforcerTest, IgnoresNullEVWhitelist) {
-  ct::CTVerifyResult result;
-  FillResultWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 1,
-                             &result);
+  ct::SCTList scts;
+  FillListWithSCTsOfOrigin(ct::SignedCertificateTimestamp::SCT_EMBEDDED, 1,
+                           &scts);
   EXPECT_EQ(ct::EVPolicyCompliance::EV_POLICY_NOT_ENOUGH_SCTS,
-            policy_enforcer_->DoesConformToCTEVPolicy(
-                chain_.get(), nullptr, result.verified_scts, BoundNetLog()));
+            policy_enforcer_->DoesConformToCTEVPolicy(chain_.get(), nullptr,
+                                                      scts, BoundNetLog()));
 }
 
 }  // namespace
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index 82029e7..30cf5ff 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -318,22 +318,6 @@
     // DELETE_COOKIE_LAST_ENTRY
     {CookieMonsterDelegate::CHANGE_COOKIE_EXPLICIT, false}};
 
-std::string BuildCookieLine(const CanonicalCookieVector& cookies) {
-  std::string cookie_line;
-  for (CanonicalCookieVector::const_iterator it = cookies.begin();
-       it != cookies.end(); ++it) {
-    if (it != cookies.begin())
-      cookie_line += "; ";
-    // In Mozilla if you set a cookie like AAAA, it will have an empty token
-    // and a value of AAAA.  When it sends the cookie back, it will send AAAA,
-    // so we need to avoid sending =AAAA for a blank token value.
-    if (!(*it)->Name().empty())
-      cookie_line += (*it)->Name() + "=";
-    cookie_line += (*it)->Value();
-  }
-  return cookie_line;
-}
-
 void RunAsync(scoped_refptr<base::TaskRunner> proxy,
               const CookieStore::CookieChangedCallback& callback,
               const CanonicalCookie& cookie,
@@ -522,14 +506,13 @@
   }
 }
 
-// Task class for GetCookieListForURLWithOptionsAsync call.
-class CookieMonster::GetCookieListForURLWithOptionsTask
-    : public CookieMonsterTask {
+// Task class for GetCookieListWithOptionsAsync call.
+class CookieMonster::GetCookieListWithOptionsTask : public CookieMonsterTask {
  public:
-  GetCookieListForURLWithOptionsTask(CookieMonster* cookie_monster,
-                                     const GURL& url,
-                                     const CookieOptions& options,
-                                     const GetCookieListCallback& callback)
+  GetCookieListWithOptionsTask(CookieMonster* cookie_monster,
+                               const GURL& url,
+                               const CookieOptions& options,
+                               const GetCookieListCallback& callback)
       : CookieMonsterTask(cookie_monster),
         url_(url),
         options_(options),
@@ -539,20 +522,20 @@
   void Run() override;
 
  protected:
-  ~GetCookieListForURLWithOptionsTask() override {}
+  ~GetCookieListWithOptionsTask() override {}
 
  private:
   GURL url_;
   CookieOptions options_;
   GetCookieListCallback callback_;
 
-  DISALLOW_COPY_AND_ASSIGN(GetCookieListForURLWithOptionsTask);
+  DISALLOW_COPY_AND_ASSIGN(GetCookieListWithOptionsTask);
 };
 
-void CookieMonster::GetCookieListForURLWithOptionsTask::Run() {
+void CookieMonster::GetCookieListWithOptionsTask::Run() {
   if (!callback_.is_null()) {
     CookieList cookies =
-        this->cookie_monster()->GetCookieListForURLWithOptions(url_, options_);
+        this->cookie_monster()->GetCookieListWithOptions(url_, options_);
     this->InvokeCallback(base::Bind(&GetCookieListCallback::Run,
                                     base::Unretained(&callback_), cookies));
   }
@@ -905,16 +888,6 @@
   DoCookieTaskForURL(task, url);
 }
 
-void CookieMonster::GetCookieListForURLWithOptionsAsync(
-    const GURL& url,
-    const CookieOptions& options,
-    const GetCookieListCallback& callback) {
-  scoped_refptr<GetCookieListForURLWithOptionsTask> task =
-      new GetCookieListForURLWithOptionsTask(this, url, options, callback);
-
-  DoCookieTaskForURL(task, url);
-}
-
 void CookieMonster::FlushStore(const base::Closure& callback) {
   base::AutoLock autolock(lock_);
   if (initialized_ && store_.get())
@@ -956,15 +929,12 @@
   DoCookieTaskForURL(task, url);
 }
 
-void CookieMonster::GetAllCookiesForURLAsync(
+void CookieMonster::GetCookieListWithOptionsAsync(
     const GURL& url,
+    const CookieOptions& options,
     const GetCookieListCallback& callback) {
-  CookieOptions options;
-  options.set_include_httponly();
-  options.set_include_same_site();
-  options.set_do_not_update_access_time();
-  scoped_refptr<GetCookieListForURLWithOptionsTask> task =
-      new GetCookieListForURLWithOptionsTask(this, url, options, callback);
+  scoped_refptr<GetCookieListWithOptionsTask> task =
+      new GetCookieListWithOptionsTask(this, url, options, callback);
 
   DoCookieTaskForURL(task, url);
 }
@@ -1160,16 +1130,19 @@
   return cookie_list;
 }
 
-CookieList CookieMonster::GetCookieListForURLWithOptions(
+CookieList CookieMonster::GetCookieListWithOptions(
     const GURL& url,
     const CookieOptions& options) {
   base::AutoLock autolock(lock_);
 
+  CookieList cookies;
+  if (!HasCookieableScheme(url))
+    return cookies;
+
   std::vector<CanonicalCookie*> cookie_ptrs;
   FindCookiesForHostAndDomain(url, options, &cookie_ptrs);
   std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
 
-  CookieList cookies;
   cookies.reserve(cookie_ptrs.size());
   for (std::vector<CanonicalCookie*>::const_iterator it = cookie_ptrs.begin();
        it != cookie_ptrs.end(); it++)
diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h
index 87acb9a..14633c7 100644
--- a/net/cookies/cookie_monster.h
+++ b/net/cookies/cookie_monster.h
@@ -148,16 +148,6 @@
                 CookieMonsterDelegate* delegate,
                 int last_access_threshold_milliseconds);
 
-  // Returns all the cookies, for use in management UI, etc. Filters results
-  // using given url scheme, host / domain and path and options. This does not
-  // mark the cookies as having been accessed.
-  // The returned cookies are ordered by longest path, then earliest
-  // creation date.
-  void GetCookieListForURLWithOptionsAsync(
-      const GURL& url,
-      const CookieOptions& options,
-      const GetCookieListCallback& callback);
-
   // Replaces all the cookies by |list|. This method does not flush the backend.
   void SetAllCookiesAsync(const CookieList& list,
                           const SetCookiesCallback& callback);
@@ -184,8 +174,10 @@
   void GetCookiesWithOptionsAsync(const GURL& url,
                                   const CookieOptions& options,
                                   const GetCookiesCallback& callback) override;
-  void GetAllCookiesForURLAsync(const GURL& url,
-                                const GetCookieListCallback& callback) override;
+  void GetCookieListWithOptionsAsync(
+      const GURL& url,
+      const CookieOptions& options,
+      const GetCookieListCallback& callback) override;
   void GetAllCookiesAsync(const GetCookieListCallback& callback) override;
   void DeleteCookieAsync(const GURL& url,
                          const std::string& cookie_name,
@@ -241,6 +233,7 @@
   class GetCookieListForURLWithOptionsTask;
   class GetAllCookiesTask;
   class GetCookiesWithOptionsTask;
+  class GetCookieListWithOptionsTask;
   class SetAllCookiesTask;
   class SetCookieWithDetailsTask;
   class SetCookieWithOptionsTask;
@@ -418,8 +411,8 @@
 
   CookieList GetAllCookies();
 
-  CookieList GetCookieListForURLWithOptions(const GURL& url,
-                                            const CookieOptions& options);
+  CookieList GetCookieListWithOptions(const GURL& url,
+                                      const CookieOptions& options);
 
   int DeleteAllCreatedBetween(const base::Time& delete_begin,
                               const base::Time& delete_end);
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc
index eab8b75..7871c91 100644
--- a/net/cookies/cookie_monster_unittest.cc
+++ b/net/cookies/cookie_monster_unittest.cc
@@ -126,7 +126,7 @@
                                             const CookieOptions& options) {
     DCHECK(cm);
     GetCookieListCallback callback;
-    cm->GetCookieListForURLWithOptionsAsync(
+    cm->GetCookieListWithOptionsAsync(
         url, options,
         base::Bind(&GetCookieListCallback::Run, base::Unretained(&callback)));
     callback.WaitUntilDone();
@@ -827,8 +827,8 @@
 }
 
 ACTION_P3(GetCookieListForUrlWithOptionsAction, cookie_monster, url, callback) {
-  cookie_monster->GetCookieListForURLWithOptionsAsync(url, CookieOptions(),
-                                                      callback->AsCallback());
+  cookie_monster->GetCookieListWithOptionsAsync(url, CookieOptions(),
+                                                callback->AsCallback());
 }
 
 ACTION_P3(GetAllCookiesForUrlAction, cookie_monster, url, callback) {
@@ -2492,7 +2492,7 @@
                                           const GURL& url,
                                           const CookieOptions& options,
                                           GetCookieListCallback* callback) {
-    cm->GetCookieListForURLWithOptionsAsync(
+    cm->GetCookieListWithOptionsAsync(
         url, options,
         base::Bind(&GetCookieListCallback::Run, base::Unretained(callback)));
   }
diff --git a/net/cookies/cookie_store.cc b/net/cookies/cookie_store.cc
index 64338e6..780a292 100644
--- a/net/cookies/cookie_store.cc
+++ b/net/cookies/cookie_store.cc
@@ -12,6 +12,38 @@
 
 CookieStore::~CookieStore() {}
 
+std::string CookieStore::BuildCookieLine(
+    const std::vector<CanonicalCookie>& cookies) {
+  std::string cookie_line;
+  for (const auto& cookie : cookies) {
+    if (!cookie_line.empty())
+      cookie_line += "; ";
+    // In Mozilla, if you set a cookie like "AAA", it will have an empty token
+    // and a value of "AAA". When it sends the cookie back, it will send "AAA",
+    // so we need to avoid sending "=AAA" for a blank token value.
+    if (!cookie.Name().empty())
+      cookie_line += cookie.Name() + "=";
+    cookie_line += cookie.Value();
+  }
+  return cookie_line;
+}
+
+std::string CookieStore::BuildCookieLine(
+    const std::vector<CanonicalCookie*>& cookies) {
+  std::string cookie_line;
+  for (const auto& cookie : cookies) {
+    if (!cookie_line.empty())
+      cookie_line += "; ";
+    // In Mozilla, if you set a cookie like "AAA", it will have an empty token
+    // and a value of "AAA". When it sends the cookie back, it will send "AAA",
+    // so we need to avoid sending "=AAA" for a blank token value.
+    if (!cookie->Name().empty())
+      cookie_line += cookie->Name() + "=";
+    cookie_line += cookie->Value();
+  }
+  return cookie_line;
+}
+
 void CookieStore::DeleteAllAsync(const DeleteCallback& callback) {
   DeleteAllCreatedBetweenAsync(base::Time(), base::Time::Max(), callback);
 }
@@ -20,4 +52,14 @@
   // By default, do nothing.
 }
 
+void CookieStore::GetAllCookiesForURLAsync(
+    const GURL& url,
+    const GetCookieListCallback& callback) {
+  CookieOptions options;
+  options.set_include_httponly();
+  options.set_include_same_site();
+  options.set_do_not_update_access_time();
+  GetCookieListWithOptionsAsync(url, options, callback);
+}
+
 }  // namespace net
diff --git a/net/cookies/cookie_store.h b/net/cookies/cookie_store.h
index 21c586bc..c007001 100644
--- a/net/cookies/cookie_store.h
+++ b/net/cookies/cookie_store.h
@@ -43,6 +43,16 @@
       CookieChangedCallbackList;
   typedef CookieChangedCallbackList::Subscription CookieChangedSubscription;
 
+  // Returns the cookie line (e.g. "cookie1=value1; cookie2=value2") represented
+  // by |cookies|. The string is built in the same order as the given list.
+  //
+  // TODO(mkwst): We really should standardize on either
+  // 'std::vector<CanonicalCookie>' or 'std::vector<CanonicalCookie*>'.
+  static std::string BuildCookieLine(
+      const std::vector<CanonicalCookie>& cookies);
+  static std::string BuildCookieLine(
+      const std::vector<CanonicalCookie*>& cookies);
+
   // Sets the cookies specified by |cookie_list| returned from |url|
   // with options |options| in effect.  Expects a cookie line, like
   // "a=1; domain=b.com".
@@ -93,17 +103,31 @@
   //
   // The returned cookies are ordered by longest path, then earliest
   // creation date.
+  //
+  // TODO(mkwst): This method is deprecated; callsites should be updated to
+  // use 'GetCookieListWithOptionsAsync'.
   virtual void GetCookiesWithOptionsAsync(
       const GURL& url,
       const CookieOptions& options,
       const GetCookiesCallback& callback) = 0;
 
+  // Obtains a CookieList for the given |url| and |options|. The returned
+  // cookies are passed into |callback|, ordered by longest path, then earliest
+  // creation date.
+  virtual void GetCookieListWithOptionsAsync(
+      const GURL& url,
+      const CookieOptions& options,
+      const GetCookieListCallback& callback) = 0;
+
   // Returns all cookies associated with |url|, including http-only, and
   // same-site cookies. The returned cookies are ordered by longest path, then
   // by earliest creation date, and are not marked as having been accessed.
-  virtual void GetAllCookiesForURLAsync(
-      const GURL& url,
-      const GetCookieListCallback& callback) = 0;
+  //
+  // TODO(mkwst): This method is deprecated, and should be removed, either by
+  // updating callsites to use 'GetCookieListWithOptionsAsync' with an explicit
+  // CookieOptions, or by changing CookieOptions' defaults.
+  void GetAllCookiesForURLAsync(const GURL& url,
+                                const GetCookieListCallback& callback);
 
   // Returns all the cookies, for use in management UI, etc. This does not mark
   // the cookies as having been accessed. The returned cookies are ordered by
diff --git a/net/cookies/cookie_store_test_helpers.cc b/net/cookies/cookie_store_test_helpers.cc
index 1cfee78..b4876ff 100644
--- a/net/cookies/cookie_store_test_helpers.cc
+++ b/net/cookies/cookie_store_test_helpers.cc
@@ -53,6 +53,12 @@
   did_run_ = true;
 }
 
+void DelayedCookieMonster::GetCookieListWithOptionsInternalCallback(
+    const CookieList& cookie_list) {
+  cookie_list_ = cookie_list;
+  did_run_ = true;
+}
+
 void DelayedCookieMonster::SetCookieWithOptionsAsync(
     const GURL& url,
     const std::string& cookie_line,
@@ -105,10 +111,21 @@
       base::TimeDelta::FromMilliseconds(kDelayedTime));
 }
 
-void DelayedCookieMonster::GetAllCookiesForURLAsync(
+void DelayedCookieMonster::GetCookieListWithOptionsAsync(
     const GURL& url,
-    const GetCookieListCallback& callback) {
-  cookie_monster_->GetAllCookiesForURLAsync(url, callback);
+    const CookieOptions& options,
+    const CookieMonster::GetCookieListCallback& callback) {
+  did_run_ = false;
+  cookie_monster_->GetCookieListWithOptionsAsync(
+      url, options,
+      base::Bind(
+          &DelayedCookieMonster::GetCookieListWithOptionsInternalCallback,
+          base::Unretained(this)));
+  DCHECK_EQ(did_run_, true);
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::Bind(&DelayedCookieMonster::InvokeGetCookieListCallback,
+                            base::Unretained(this), callback),
+      base::TimeDelta::FromMilliseconds(kDelayedTime));
 }
 
 void DelayedCookieMonster::GetAllCookiesAsync(
@@ -128,6 +145,12 @@
     callback.Run(cookie_);
 }
 
+void DelayedCookieMonster::InvokeGetCookieListCallback(
+    const CookieMonster::GetCookieListCallback& callback) {
+  if (!callback.is_null())
+    callback.Run(cookie_list_);
+}
+
 bool DelayedCookieMonster::SetCookieWithOptions(
     const GURL& url,
     const std::string& cookie_line,
diff --git a/net/cookies/cookie_store_test_helpers.h b/net/cookies/cookie_store_test_helpers.h
index c63c278..f43dec1 100644
--- a/net/cookies/cookie_store_test_helpers.h
+++ b/net/cookies/cookie_store_test_helpers.h
@@ -49,8 +49,10 @@
       const CookieOptions& options,
       const CookieMonster::GetCookiesCallback& callback) override;
 
-  void GetAllCookiesForURLAsync(const GURL& url,
-                                const GetCookieListCallback& callback) override;
+  void GetCookieListWithOptionsAsync(
+      const GURL& url,
+      const CookieOptions& options,
+      const GetCookieListCallback& callback) override;
 
   void GetAllCookiesAsync(const GetCookieListCallback& callback) override;
 
@@ -97,6 +99,7 @@
   void SetCookiesInternalCallback(bool result);
 
   void GetCookiesWithOptionsInternalCallback(const std::string& cookie);
+  void GetCookieListWithOptionsInternalCallback(const CookieList& cookie);
 
   // Invoke the original callbacks.
 
@@ -106,6 +109,9 @@
   void InvokeGetCookieStringCallback(
       const CookieMonster::GetCookiesCallback& callback);
 
+  void InvokeGetCookieListCallback(
+      const CookieMonster::GetCookieListCallback& callback);
+
   friend class base::RefCountedThreadSafe<DelayedCookieMonster>;
   ~DelayedCookieMonster() override;
 
@@ -115,6 +121,7 @@
   bool result_;
   std::string cookie_;
   std::string cookie_line_;
+  CookieList cookie_list_;
 };
 
 class CookieURLHelper {
diff --git a/net/cookies/cookie_store_unittest.cc b/net/cookies/cookie_store_unittest.cc
new file mode 100644
index 0000000..73933659
--- /dev/null
+++ b/net/cookies/cookie_store_unittest.cc
@@ -0,0 +1,65 @@
+// Copyright (c) 2016 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 <vector>
+
+#include "base/time/time.h"
+#include "net/cookies/cookie_store.h"
+#include "base/memory/scoped_ptr.h"
+#include "net/cookies/canonical_cookie.h"
+#include "net/cookies/cookie_options.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace net {
+
+namespace {
+
+// Helper for testing BuildCookieLine
+void MatchCookieLineToVector(
+    const std::string& line,
+    const std::vector<scoped_ptr<CanonicalCookie>>& cookies) {
+  // Test the std::vector<CanonicalCookie> variant
+  // ('CookieMonster::CookieList'):
+  std::vector<CanonicalCookie> list;
+  for (const auto& cookie : cookies)
+    list.push_back(*cookie);
+  EXPECT_EQ(line, CookieStore::BuildCookieLine(list));
+
+  // Test the std::vector<CanonicalCookie*> variant
+  // ('CookieMonster::CanonicalCookieVector' (yes, this is absurd)):
+  std::vector<CanonicalCookie*> ptr_list;
+  for (const auto& cookie : cookies)
+    ptr_list.push_back(cookie.get());
+  EXPECT_EQ(line, CookieStore::BuildCookieLine(ptr_list));
+}
+
+} // namespace
+
+TEST(CookieStoreBaseTest, BuildCookieLine) {
+  std::vector<scoped_ptr<CanonicalCookie>> cookies;
+  GURL url("https://example.com/");
+  CookieOptions options;
+  base::Time now = base::Time::Now();
+  MatchCookieLineToVector("", cookies);
+
+  cookies.push_back(CanonicalCookie::Create(url, "A=B", now, options));
+  MatchCookieLineToVector("A=B", cookies);
+  // Nameless cookies are sent back without a prefixed '='.
+  cookies.push_back(CanonicalCookie::Create(url, "C", now, options));
+  MatchCookieLineToVector("A=B; C", cookies);
+  // Cookies separated by ';'.
+  cookies.push_back(CanonicalCookie::Create(url, "D=E", now, options));
+  MatchCookieLineToVector("A=B; C; D=E", cookies);
+  // BuildCookieLine doesn't reorder the list, it relies on the caller to do so.
+  cookies.push_back(CanonicalCookie::Create(
+      url, "F=G", now - base::TimeDelta::FromSeconds(1), options));
+  MatchCookieLineToVector("A=B; C; D=E; F=G", cookies);
+  // BuildCookieLine doesn't deduplicate.
+  cookies.push_back(CanonicalCookie::Create(
+      url, "D=E", now - base::TimeDelta::FromSeconds(2), options));
+  MatchCookieLineToVector("A=B; C; D=E; F=G; D=E", cookies);
+}
+
+}  // namespace net
diff --git a/net/cookies/cookie_store_unittest.h b/net/cookies/cookie_store_unittest.h
index 2847438..0dfa2cb 100644
--- a/net/cookies/cookie_store_unittest.h
+++ b/net/cookies/cookie_store_unittest.h
@@ -104,25 +104,31 @@
     CookieOptions options;
     if (!CookieStoreTestTraits::supports_http_only)
       options.set_include_httponly();
-    StringResultCookieCallback callback;
-    cs->GetCookiesWithOptionsAsync(
-        url, options,
-        base::Bind(&StringResultCookieCallback::Run,
-                   base::Unretained(&callback)));
-    callback.WaitUntilDone();
-    return callback.result();
+    return GetCookiesWithOptions(cs, url, options);
   }
 
   std::string GetCookiesWithOptions(CookieStore* cs,
                                     const GURL& url,
                                     const CookieOptions& options) {
     DCHECK(cs);
-    StringResultCookieCallback callback;
-    cs->GetCookiesWithOptionsAsync(
-        url, options, base::Bind(&StringResultCookieCallback::Run,
-                                 base::Unretained(&callback)));
+    GetCookieListCallback callback;
+    cs->GetCookieListWithOptionsAsync(
+        url, options,
+        base::Bind(&GetCookieListCallback::Run, base::Unretained(&callback)));
     callback.WaitUntilDone();
-    return callback.result();
+    return CookieStore::BuildCookieLine(callback.cookies());
+  }
+
+  CookieList GetCookieListWithOptions(CookieStore* cs,
+                                      const GURL& url,
+                                      const CookieOptions& options) {
+    DCHECK(cs);
+    GetCookieListCallback callback;
+    cs->GetCookieListWithOptionsAsync(
+        url, options,
+        base::Bind(&GetCookieListCallback::Run, base::Unretained(&callback)));
+    callback.WaitUntilDone();
+    return callback.cookies();
   }
 
   CookieList GetAllCookiesForURL(CookieStore* cs, const GURL& url) {
@@ -380,8 +386,17 @@
       base::Time(), base::Time(), base::Time(), false, false, false,
       COOKIE_PRIORITY_DEFAULT));
 
-  CookieList cookies =
-      this->GetAllCookiesForURL(cs.get(), this->www_google_foo_.url());
+  // Get all the cookies for a given URL, regardless of properties. This 'get()'
+  // operation shouldn't update the access time, as the test checks that the
+  // access time is set properly upon creation. Updating the access time would
+  // make that difficult.
+  CookieOptions options;
+  options.set_include_httponly();
+  options.set_include_same_site();
+  options.set_do_not_update_access_time();
+
+  CookieList cookies = this->GetCookieListWithOptions(
+      cs.get(), this->www_google_foo_.url(), options);
   CookieList::iterator it = cookies.begin();
 
   ASSERT_TRUE(it != cookies.end());
@@ -402,7 +417,18 @@
 
   ASSERT_TRUE(++it == cookies.end());
 
-  cookies = this->GetAllCookiesForURL(cs.get(), this->www_google_bar_.url());
+  // Verify that the cookie was set as 'httponly' by passing in a CookieOptions
+  // that excludes them and getting an empty result.
+  if (TypeParam::supports_http_only) {
+    cookies = this->GetCookieListWithOptions(
+        cs.get(), this->www_google_bar_.url(), CookieOptions());
+    it = cookies.begin();
+    ASSERT_TRUE(it == cookies.end());
+  }
+
+  // Get the cookie using the wide open |options|:
+  cookies = this->GetCookieListWithOptions(
+      cs.get(), this->www_google_bar_.url(), options);
   it = cookies.begin();
 
   ASSERT_TRUE(it != cookies.end());
@@ -420,7 +446,8 @@
 
   EXPECT_TRUE(++it == cookies.end());
 
-  cookies = this->GetAllCookiesForURL(cs.get(), this->https_www_google_.url());
+  cookies = this->GetCookieListWithOptions(
+      cs.get(), this->https_www_google_.url(), options);
   it = cookies.begin();
 
   ASSERT_TRUE(it != cookies.end());
@@ -811,6 +838,9 @@
                               kValidDomainCookieLine));
   this->MatchCookieLines(std::string(),
                          this->GetCookies(cs.get(), this->ftp_google_.url()));
+  EXPECT_EQ(0U, this->GetCookieListWithOptions(
+                        cs.get(), this->ftp_google_.url(), CookieOptions())
+                    .size());
 }
 
 TYPED_TEST_P(CookieStoreTest, PathTest) {
@@ -1221,6 +1251,28 @@
   EXPECT_EQ("d=1; a=4; e=1; b=1; c=1",
             this->GetCookies(cs.get(),
                              GURL("http://d.c.b.a.google.com/aa/bb/cc/dd")));
+
+  CookieOptions options;
+  CookieList cookies = this->GetCookieListWithOptions(
+      cs.get(), GURL("http://d.c.b.a.google.com/aa/bb/cc/dd"), options);
+  CookieList::const_iterator it = cookies.begin();
+
+  ASSERT_TRUE(it != cookies.end());
+  EXPECT_EQ("d", it->Name());
+
+  ASSERT_TRUE(++it != cookies.end());
+  EXPECT_EQ("a", it->Name());
+
+  ASSERT_TRUE(++it != cookies.end());
+  EXPECT_EQ("e", it->Name());
+
+  ASSERT_TRUE(++it != cookies.end());
+  EXPECT_EQ("b", it->Name());
+
+  ASSERT_TRUE(++it != cookies.end());
+  EXPECT_EQ("c", it->Name());
+
+  EXPECT_TRUE(++it == cookies.end());
 }
 
 // Check that GetAllCookiesAsync returns cookies from multiple domains, in the
@@ -1272,8 +1324,8 @@
   EXPECT_EQ("A=C", this->GetCookies(cs.get(), this->www_google_bar_.url()));
 
   // Delete the "/foo" cookie, and make sure only it was deleted.
-  CookieList cookies =
-      this->GetAllCookiesForURL(cs.get(), this->www_google_foo_.url());
+  CookieList cookies = this->GetCookieListWithOptions(
+      cs.get(), this->www_google_foo_.url(), CookieOptions());
   ASSERT_EQ(1u, cookies.size());
   EXPECT_EQ(1, this->DeleteCanonicalCookie(cs.get(), cookies[0]));
   EXPECT_EQ(1u, this->GetAllCookies(cs.get()).size());
@@ -1284,7 +1336,8 @@
   EXPECT_EQ(0, this->DeleteCanonicalCookie(cs.get(), cookies[0]));
 
   // Try to delete the "/bar" cookie after overwriting it with a new cookie.
-  cookies = this->GetAllCookiesForURL(cs.get(), this->www_google_bar_.url());
+  cookies = this->GetCookieListWithOptions(
+      cs.get(), this->www_google_bar_.url(), CookieOptions());
   ASSERT_EQ(1u, cookies.size());
   EXPECT_TRUE(
       this->SetCookie(cs.get(), this->http_www_google_.url(), "A=D;Path=/bar"));
@@ -1293,7 +1346,8 @@
   EXPECT_EQ("A=D", this->GetCookies(cs.get(), this->www_google_bar_.url()));
 
   // Delete the new "/bar" cookie.
-  cookies = this->GetAllCookiesForURL(cs.get(), this->www_google_bar_.url());
+  cookies = this->GetCookieListWithOptions(
+      cs.get(), this->www_google_bar_.url(), CookieOptions());
   ASSERT_EQ(1u, cookies.size());
   EXPECT_EQ(1, this->DeleteCanonicalCookie(cs.get(), cookies[0]));
   EXPECT_EQ(0u, this->GetAllCookies(cs.get()).size());
diff --git a/net/disk_cache/backend_unittest.cc b/net/disk_cache/backend_unittest.cc
index f826995..ebd2f57 100644
--- a/net/disk_cache/backend_unittest.cc
+++ b/net/disk_cache/backend_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/files/file_util.h"
 #include "base/metrics/field_trial.h"
 #include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -136,6 +137,8 @@
   void BackendDisable3();
   void BackendDisable4();
   void BackendDisabledAPI();
+
+  void BackendEviction();
 };
 
 int DiskCacheBackendTest::GeneratePendingIO(net::TestCompletionCallback* cb) {
@@ -2901,6 +2904,49 @@
   BackendDisabledAPI();
 }
 
+// Test that some eviction of some kind happens.
+void DiskCacheBackendTest::BackendEviction() {
+  const int kMaxSize = 200 * 1024;
+  const int kMaxEntryCount = 20;
+  const int kWriteSize = kMaxSize / kMaxEntryCount;
+
+  const int kWriteEntryCount = kMaxEntryCount * 2;
+
+  static_assert(kWriteEntryCount * kWriteSize > kMaxSize,
+                "must write more than MaxSize");
+
+  SetMaxSize(kMaxSize);
+  InitSparseCache(nullptr, nullptr);
+
+  scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kWriteSize));
+  CacheTestFillBuffer(buffer->data(), kWriteSize, false);
+
+  std::string key_prefix("prefix");
+  for (int i = 0; i < kWriteEntryCount; ++i) {
+    AddDelay();
+    disk_cache::Entry* entry = NULL;
+    ASSERT_EQ(net::OK, CreateEntry(key_prefix + base::IntToString(i), &entry));
+    disk_cache::ScopedEntryPtr entry_closer(entry);
+    EXPECT_EQ(kWriteSize,
+              WriteData(entry, 1, 0, buffer.get(), kWriteSize, false));
+  }
+
+  int size = CalculateSizeOfAllEntries();
+  EXPECT_GT(kMaxSize, size);
+}
+
+TEST_F(DiskCacheBackendTest, BackendEviction) {
+  BackendEviction();
+}
+
+TEST_F(DiskCacheBackendTest, MemoryOnlyBackendEviction) {
+  SetMemoryOnlyMode();
+  BackendEviction();
+}
+
+// TODO(gavinp): Enable BackendEviction test for simple cache after performance
+// problems are addressed. See crbug.com/588184 for more information.
+
 TEST_F(DiskCacheTest, Backend_UsageStatsTimer) {
   MessageLoopHelper helper;
 
diff --git a/net/disk_cache/entry_unittest.cc b/net/disk_cache/entry_unittest.cc
index ea58049..22f793bb 100644
--- a/net/disk_cache/entry_unittest.cc
+++ b/net/disk_cache/entry_unittest.cc
@@ -1633,7 +1633,7 @@
     ++count;
     disk_cache::MemEntryImpl* mem_entry =
         reinterpret_cast<disk_cache::MemEntryImpl*>(entry);
-    EXPECT_EQ(disk_cache::MemEntryImpl::kParentEntry, mem_entry->type());
+    EXPECT_EQ(disk_cache::MemEntryImpl::PARENT_ENTRY, mem_entry->type());
     mem_entry->Close();
   }
   EXPECT_EQ(1, count);
diff --git a/net/disk_cache/memory/mem_backend_impl.cc b/net/disk_cache/memory/mem_backend_impl.cc
index 5b37ca9..028c022 100644
--- a/net/disk_cache/memory/mem_backend_impl.cc
+++ b/net/disk_cache/memory/mem_backend_impl.cc
@@ -4,6 +4,8 @@
 
 #include "net/disk_cache/memory/mem_backend_impl.h"
 
+#include <algorithm>
+#include <functional>
 #include <utility>
 
 #include "base/logging.h"
@@ -14,36 +16,39 @@
 
 using base::Time;
 
+namespace disk_cache {
+
 namespace {
 
 const int kDefaultInMemoryCacheSize = 10 * 1024 * 1024;
-const int kCleanUpMargin = 1024 * 1024;
+const int kDefaultEvictionSize = kDefaultInMemoryCacheSize / 10;
 
-int LowWaterAdjust(int high_water) {
-  if (high_water < kCleanUpMargin)
-    return 0;
-
-  return high_water - kCleanUpMargin;
+bool CheckLRUListOrder(const base::LinkedList<MemEntryImpl>& lru_list) {
+  // TODO(gavinp): Check MemBackendImpl::current_size_ here as well.
+  base::Time previous_last_use_time;
+  for (base::LinkNode<MemEntryImpl>* node = lru_list.head();
+       node != lru_list.end(); node = node->next()) {
+    if (node->value()->GetLastUsed() < previous_last_use_time)
+      return false;
+    previous_last_use_time = node->value()->GetLastUsed();
+  }
+  return true;
 }
 
 }  // namespace
 
-namespace disk_cache {
-
 MemBackendImpl::MemBackendImpl(net::NetLog* net_log)
     : max_size_(0), current_size_(0), net_log_(net_log), weak_factory_(this) {
 }
 
 MemBackendImpl::~MemBackendImpl() {
-  EntryMap::iterator it = entries_.begin();
-  while (it != entries_.end()) {
-    it->second->Doom();
-    it = entries_.begin();
-  }
+  DCHECK(CheckLRUListOrder(lru_list_));
+  while (!entries_.empty())
+    entries_.begin()->second->Doom();
   DCHECK(!current_size_);
 }
 
-// Static.
+// static
 scoped_ptr<Backend> MemBackendImpl::CreateBackend(int max_bytes,
                                                   net::NetLog* net_log) {
   scoped_ptr<MemBackendImpl> cache(new MemBackendImpl(net_log));
@@ -67,7 +72,7 @@
   }
 
   // We want to use up to 2% of the computer's memory, with a limit of 50 MB,
-  // reached on systemd with more than 2.5 GB of RAM.
+  // reached on system with more than 2.5 GB of RAM.
   total_memory = total_memory * 2 / 100;
   if (total_memory > kDefaultInMemoryCacheSize * 5)
     max_size_ = kDefaultInMemoryCacheSize * 5;
@@ -91,41 +96,33 @@
   return true;
 }
 
-void MemBackendImpl::InternalDoomEntry(MemEntryImpl* entry) {
-  // Only parent entries can be passed into this method.
-  DCHECK(entry->type() == MemEntryImpl::kParentEntry);
-
-  rankings_.Remove(entry);
-  EntryMap::iterator it = entries_.find(entry->GetKey());
-  if (it != entries_.end())
-    entries_.erase(it);
-  else
-    NOTREACHED();
-
-  entry->InternalDoom();
-}
-
-void MemBackendImpl::UpdateRank(MemEntryImpl* node) {
-  rankings_.UpdateRank(node);
-}
-
-void MemBackendImpl::ModifyStorageSize(int32_t old_size, int32_t new_size) {
-  if (old_size >= new_size)
-    SubstractStorageSize(old_size - new_size);
-  else
-    AddStorageSize(new_size - old_size);
-}
-
 int MemBackendImpl::MaxFileSize() const {
   return max_size_ / 8;
 }
 
-void MemBackendImpl::InsertIntoRankingList(MemEntryImpl* entry) {
-  rankings_.Insert(entry);
+void MemBackendImpl::OnEntryInserted(MemEntryImpl* entry) {
+  lru_list_.Append(entry);
 }
 
-void MemBackendImpl::RemoveFromRankingList(MemEntryImpl* entry) {
-  rankings_.Remove(entry);
+void MemBackendImpl::OnEntryUpdated(MemEntryImpl* entry) {
+  DCHECK(CheckLRUListOrder(lru_list_));
+  // LinkedList<>::RemoveFromList() removes |entry| from |lru_list_|.
+  entry->RemoveFromList();
+  lru_list_.Append(entry);
+}
+
+void MemBackendImpl::OnEntryDoomed(MemEntryImpl* entry) {
+  DCHECK(CheckLRUListOrder(lru_list_));
+  if (entry->type() == MemEntryImpl::PARENT_ENTRY)
+    entries_.erase(entry->key());
+  // LinkedList<>::RemoveFromList() removes |entry| from |lru_list_|.
+  entry->RemoveFromList();
+}
+
+void MemBackendImpl::ModifyStorageSize(int32_t delta) {
+  current_size_ += delta;
+  if (delta > 0)
+    EvictIfNeeded();
 }
 
 net::CacheType MemBackendImpl::GetCacheType() const {
@@ -136,52 +133,71 @@
   return static_cast<int32_t>(entries_.size());
 }
 
-int MemBackendImpl::OpenEntry(const std::string& key, Entry** entry,
+int MemBackendImpl::OpenEntry(const std::string& key,
+                              Entry** entry,
                               const CompletionCallback& callback) {
-  if (OpenEntry(key, entry))
-    return net::OK;
+  EntryMap::iterator it = entries_.find(key);
+  if (it == entries_.end())
+    return net::ERR_FAILED;
 
-  return net::ERR_FAILED;
+  it->second->Open();
+
+  *entry = it->second;
+  return net::OK;
 }
 
-int MemBackendImpl::CreateEntry(const std::string& key, Entry** entry,
+int MemBackendImpl::CreateEntry(const std::string& key,
+                                Entry** entry,
                                 const CompletionCallback& callback) {
-  if (CreateEntry(key, entry))
-    return net::OK;
+  std::pair<EntryMap::iterator, bool> create_result =
+      entries_.insert(EntryMap::value_type(key, nullptr));
+  const bool did_insert = create_result.second;
+  if (!did_insert)
+    return net::ERR_FAILED;
 
-  return net::ERR_FAILED;
+  MemEntryImpl* cache_entry = new MemEntryImpl(this, key, net_log_);
+  create_result.first->second = cache_entry;
+  *entry = cache_entry;
+  return net::OK;
 }
 
 int MemBackendImpl::DoomEntry(const std::string& key,
                               const CompletionCallback& callback) {
-  if (DoomEntry(key))
-    return net::OK;
+  EntryMap::iterator it = entries_.find(key);
+  if (it == entries_.end())
+    return net::ERR_FAILED;
 
-  return net::ERR_FAILED;
+  it->second->Doom();
+  return net::OK;
 }
 
 int MemBackendImpl::DoomAllEntries(const CompletionCallback& callback) {
-  if (DoomAllEntries())
-    return net::OK;
-
-  return net::ERR_FAILED;
+  return DoomEntriesBetween(Time(), Time(), callback);
 }
 
-int MemBackendImpl::DoomEntriesBetween(const base::Time initial_time,
-                                       const base::Time end_time,
+int MemBackendImpl::DoomEntriesBetween(Time initial_time,
+                                       Time end_time,
                                        const CompletionCallback& callback) {
-  if (DoomEntriesBetween(initial_time, end_time))
-    return net::OK;
+  if (end_time.is_null())
+    end_time = Time::Max();
 
-  return net::ERR_FAILED;
+  DCHECK_GE(end_time, initial_time);
+
+  base::LinkNode<MemEntryImpl>* node = lru_list_.head();
+  while (node != lru_list_.end() && node->value()->GetLastUsed() < initial_time)
+    node = node->next();
+  while (node != lru_list_.end() && node->value()->GetLastUsed() < end_time) {
+    MemEntryImpl* to_doom = node->value();
+    node = node->next();
+    to_doom->Doom();
+  }
+
+  return net::OK;
 }
 
-int MemBackendImpl::DoomEntriesSince(const base::Time initial_time,
+int MemBackendImpl::DoomEntriesSince(Time initial_time,
                                      const CompletionCallback& callback) {
-  if (DoomEntriesSince(initial_time))
-    return net::OK;
-
-  return net::ERR_FAILED;
+  return DoomEntriesBetween(initial_time, Time::Max(), callback);
 }
 
 int MemBackendImpl::CalculateSizeOfAllEntries(
@@ -189,35 +205,41 @@
   return current_size_;
 }
 
-class MemBackendImpl::MemIterator : public Backend::Iterator {
+class MemBackendImpl::MemIterator final : public Backend::Iterator {
  public:
   explicit MemIterator(base::WeakPtr<MemBackendImpl> backend)
-      : backend_(backend), current_(NULL) {
-  }
+      : backend_(backend), current_(nullptr) {}
 
   int OpenNextEntry(Entry** next_entry,
                     const CompletionCallback& callback) override {
     if (!backend_)
       return net::ERR_FAILED;
 
-    MemEntryImpl* node = backend_->rankings_.GetNext(current_);
+    // Iterate using |lru_list_|, from most recently used to least recently
+    // used, for compatibility with the unit tests that assume this behaviour.
+    // Consider the last element if we are beginning an iteration, otherwise
+    // progressively move earlier in the LRU list.
+    current_ = current_ ? current_->previous() : backend_->lru_list_.tail();
+
     // We should never return a child entry so iterate until we hit a parent
     // entry.
-    while (node && node->type() != MemEntryImpl::kParentEntry)
-      node = backend_->rankings_.GetNext(node);
-    *next_entry = node;
-    current_ = node;
-
-    if (node) {
-      node->Open();
-      return net::OK;
+    while (current_ != backend_->lru_list_.end() &&
+           current_->value()->type() != MemEntryImpl::PARENT_ENTRY) {
+      current_ = current_->previous();
     }
-    return net::ERR_FAILED;
+    if (current_ == backend_->lru_list_.end()) {
+      *next_entry = nullptr;
+      return net::ERR_FAILED;
+    }
+
+    current_->value()->Open();
+    *next_entry = current_->value();
+    return net::OK;
   }
 
  private:
   base::WeakPtr<MemBackendImpl> backend_;
-  MemEntryImpl* current_;
+  base::LinkNode<MemEntryImpl>* current_;
 };
 
 scoped_ptr<Backend::Iterator> MemBackendImpl::CreateIterator() {
@@ -227,127 +249,23 @@
 
 void MemBackendImpl::OnExternalCacheHit(const std::string& key) {
   EntryMap::iterator it = entries_.find(key);
-  if (it != entries_.end()) {
-    UpdateRank(it->second);
-  }
-}
-
-bool MemBackendImpl::OpenEntry(const std::string& key, Entry** entry) {
-  EntryMap::iterator it = entries_.find(key);
-  if (it == entries_.end())
-    return false;
-
-  it->second->Open();
-
-  *entry = it->second;
-  return true;
-}
-
-bool MemBackendImpl::CreateEntry(const std::string& key, Entry** entry) {
-  EntryMap::iterator it = entries_.find(key);
   if (it != entries_.end())
-    return false;
-
-  MemEntryImpl* cache_entry = new MemEntryImpl(this);
-  if (!cache_entry->CreateEntry(key, net_log_)) {
-    delete entry;
-    return false;
-  }
-
-  rankings_.Insert(cache_entry);
-  entries_[key] = cache_entry;
-
-  *entry = cache_entry;
-  return true;
+    it->second->UpdateStateOnUse(MemEntryImpl::ENTRY_WAS_NOT_MODIFIED);
 }
 
-bool MemBackendImpl::DoomEntry(const std::string& key) {
-  Entry* entry;
-  if (!OpenEntry(key, &entry))
-    return false;
-
-  entry->Doom();
-  entry->Close();
-  return true;
-}
-
-bool MemBackendImpl::DoomAllEntries() {
-  TrimCache(true);
-  return true;
-}
-
-bool MemBackendImpl::DoomEntriesBetween(const Time initial_time,
-                                        const Time end_time) {
-  if (end_time.is_null())
-    return DoomEntriesSince(initial_time);
-
-  DCHECK(end_time >= initial_time);
-
-  MemEntryImpl* node = rankings_.GetNext(NULL);
-  // Last valid entry before |node|.
-  // Note, that entries after |node| may become invalid during |node| doom in
-  // case when they are child entries of it. It is guaranteed that
-  // parent node will go prior to it childs in ranking list (see
-  // InternalReadSparseData and InternalWriteSparseData).
-  MemEntryImpl* last_valid = NULL;
-
-  // rankings_ is ordered by last used, this will descend through the cache
-  // and start dooming items before the end_time, and will stop once it reaches
-  // an item used before the initial time.
-  while (node) {
-    if (node->GetLastUsed() < initial_time)
-      break;
-
-    if (node->GetLastUsed() < end_time)
-      node->Doom();
-    else
-      last_valid = node;
-    node = rankings_.GetNext(last_valid);
-  }
-
-  return true;
-}
-
-bool MemBackendImpl::DoomEntriesSince(const Time initial_time) {
-  for (;;) {
-    // Get the entry in the front.
-    Entry* entry = rankings_.GetNext(NULL);
-
-    // Break the loop when there are no more entries or the entry is too old.
-    if (!entry || entry->GetLastUsed() < initial_time)
-      return true;
-    entry->Doom();
-  }
-}
-
-void MemBackendImpl::TrimCache(bool empty) {
-  MemEntryImpl* next = rankings_.GetPrev(NULL);
-  if (!next)
+void MemBackendImpl::EvictIfNeeded() {
+  if (current_size_ <= max_size_)
     return;
 
-  int target_size = empty ? 0 : LowWaterAdjust(max_size_);
-  while (current_size_ > target_size && next) {
-    MemEntryImpl* node = next;
-    next = rankings_.GetPrev(next);
-    if (!node->InUse() || empty) {
-      node->Doom();
-    }
+  int target_size = std::max(0, max_size_ - kDefaultEvictionSize);
+
+  base::LinkNode<MemEntryImpl>* entry = lru_list_.head();
+  while (current_size_ > target_size && entry != lru_list_.end()) {
+    MemEntryImpl* to_doom = entry->value();
+    entry = entry->next();
+    if (!to_doom->InUse())
+      to_doom->Doom();
   }
-
-  return;
-}
-
-void MemBackendImpl::AddStorageSize(int32_t bytes) {
-  current_size_ += bytes;
-  DCHECK_GE(current_size_, 0);
-
-  if (current_size_ > max_size_)
-    TrimCache(false);
-}
-
-void MemBackendImpl::SubstractStorageSize(int32_t bytes) {
-  current_size_ -= bytes;
-  DCHECK_GE(current_size_, 0);
 }
 
 }  // namespace disk_cache
diff --git a/net/disk_cache/memory/mem_backend_impl.h b/net/disk_cache/memory/mem_backend_impl.h
index e2a9f1a..8abcca5 100644
--- a/net/disk_cache/memory/mem_backend_impl.h
+++ b/net/disk_cache/memory/mem_backend_impl.h
@@ -9,13 +9,17 @@
 
 #include <stdint.h>
 
+#include <string>
+
 #include "base/compiler_specific.h"
 #include "base/containers/hash_tables.h"
+#include "base/containers/linked_list.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string_split.h"
+#include "base/time/time.h"
 #include "net/disk_cache/disk_cache.h"
-#include "net/disk_cache/memory/mem_rankings.h"
+#include "net/disk_cache/memory/mem_entry_impl.h"
 
 namespace net {
 class NetLog;
@@ -23,11 +27,9 @@
 
 namespace disk_cache {
 
-class MemEntryImpl;
-
 // This class implements the Backend interface. An object of this class handles
 // the operations of the cache without writing to disk.
-class NET_EXPORT_PRIVATE MemBackendImpl : public Backend {
+class NET_EXPORT_PRIVATE MemBackendImpl final : public Backend {
  public:
   explicit MemBackendImpl(net::NetLog* net_log);
   ~MemBackendImpl() override;
@@ -45,26 +47,29 @@
   // Sets the maximum size for the total amount of data stored by this instance.
   bool SetMaxSize(int max_bytes);
 
-  // Permanently deletes an entry.
-  void InternalDoomEntry(MemEntryImpl* entry);
-
-  // Updates the ranking information for an entry.
-  void UpdateRank(MemEntryImpl* node);
-
-  // A user data block is being created, extended or truncated.
-  void ModifyStorageSize(int32_t old_size, int32_t new_size);
-
   // Returns the maximum size for a file to reside on the cache.
   int MaxFileSize() const;
 
-  // Insert an MemEntryImpl into the ranking list. This method is only called
-  // from MemEntryImpl to insert child entries. The reference can be removed
-  // by calling RemoveFromRankingList(|entry|).
-  void InsertIntoRankingList(MemEntryImpl* entry);
+  // These next methods (before the implementation of the Backend interface) are
+  // called by MemEntryImpl to update the state of the backend during the entry
+  // lifecycle.
 
-  // Remove |entry| from ranking list. This method is only called from
-  // MemEntryImpl to remove a child entry from the ranking list.
-  void RemoveFromRankingList(MemEntryImpl* entry);
+  // Signals that new entry has been created, and should be placed in
+  // |lru_list_| so that it is eligable for eviction.
+  void OnEntryInserted(MemEntryImpl* entry);
+
+  // Signals that an entry has been updated, and thus should be moved to the end
+  // of |lru_list_|.
+  void OnEntryUpdated(MemEntryImpl* entry);
+
+  // Signals that an entry has been doomed, and so it should be removed from the
+  // list of active entries as appropriate, as well as removed from the
+  // |lru_list_|.
+  void OnEntryDoomed(MemEntryImpl* entry);
+
+  // Adjust the current size of this backend by |delta|. This is used to
+  // determine if eviction is neccessary and when eviction is finished.
+  void ModifyStorageSize(int32_t delta);
 
   // Backend interface.
   net::CacheType GetCacheType() const override;
@@ -94,26 +99,15 @@
 
   typedef base::hash_map<std::string, MemEntryImpl*> EntryMap;
 
-  // Old Backend interface.
-  bool OpenEntry(const std::string& key, Entry** entry);
-  bool CreateEntry(const std::string& key, Entry** entry);
-  bool DoomEntry(const std::string& key);
-  bool DoomAllEntries();
-  bool DoomEntriesBetween(const base::Time initial_time,
-                          const base::Time end_time);
-  bool DoomEntriesSince(const base::Time initial_time);
-
   // Deletes entries from the cache until the current size is below the limit.
-  // If empty is true, the whole cache will be trimmed, regardless of being in
-  // use.
-  void TrimCache(bool empty);
-
-  // Handles the used storage count.
-  void AddStorageSize(int32_t bytes);
-  void SubstractStorageSize(int32_t bytes);
+  void EvictIfNeeded();
 
   EntryMap entries_;
-  MemRankings rankings_;  // Rankings to be able to trim the cache.
+
+  // Stored in increasing order of last use time, from least recently used to
+  // most recently used.
+  base::LinkedList<MemEntryImpl> lru_list_;
+
   int32_t max_size_;      // Maximum data size for this instance.
   int32_t current_size_;
 
diff --git a/net/disk_cache/memory/mem_entry_impl.cc b/net/disk_cache/memory/mem_entry_impl.cc
index 6925518..c28a7fab 100644
--- a/net/disk_cache/memory/mem_entry_impl.cc
+++ b/net/disk_cache/memory/mem_entry_impl.cc
@@ -4,6 +4,7 @@
 
 #include "net/disk_cache/memory/mem_entry_impl.h"
 
+#include <algorithm>
 #include <utility>
 
 #include "base/bind.h"
@@ -17,6 +18,8 @@
 
 using base::Time;
 
+namespace disk_cache {
+
 namespace {
 
 const int kSparseData = 1;
@@ -28,12 +31,12 @@
 const int kMaxSparseEntrySize = 1 << kMaxSparseEntryBits;
 
 // Convert global offset to child index.
-inline int ToChildIndex(int64_t offset) {
+int ToChildIndex(int64_t offset) {
   return static_cast<int>(offset >> kMaxSparseEntryBits);
 }
 
 // Convert global offset to offset in child entry.
-inline int ToChildOffset(int64_t offset) {
+int ToChildOffset(int64_t offset) {
   return static_cast<int>(offset & (kMaxSparseEntrySize - 1));
 }
 
@@ -45,129 +48,110 @@
   return base::StringPrintf("Range_%s:%i", base_name.c_str(), child_id);
 }
 
-// Returns NetLog parameters for the creation of a child MemEntryImpl.  Separate
-// function needed because child entries don't suppport GetKey().
-scoped_ptr<base::Value> NetLogChildEntryCreationCallback(
-    const disk_cache::MemEntryImpl* parent,
-    int child_id,
+// Returns NetLog parameters for the creation of a MemEntryImpl. A separate
+// function is needed because child entries don't store their key().
+scoped_ptr<base::Value> NetLogEntryCreationCallback(
+    const MemEntryImpl* entry,
     net::NetLogCaptureMode /* capture_mode */) {
   scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-  dict->SetString("key", GenerateChildName(parent->GetKey(), child_id));
+  std::string key;
+  switch (entry->type()) {
+    case MemEntryImpl::PARENT_ENTRY:
+      key = entry->key();
+      break;
+    case MemEntryImpl::CHILD_ENTRY:
+      key = GenerateChildName(entry->parent()->key(), entry->child_id());
+      break;
+  }
+  dict->SetString("key", key);
   dict->SetBoolean("created", true);
   return std::move(dict);
 }
 
 }  // namespace
 
-namespace disk_cache {
-
-MemEntryImpl::MemEntryImpl(MemBackendImpl* backend) {
-  doomed_ = false;
-  backend_ = backend;
-  ref_count_ = 0;
-  parent_ = NULL;
-  child_id_ = 0;
-  child_first_pos_ = 0;
-  next_ = NULL;
-  prev_ = NULL;
-  for (int i = 0; i < NUM_STREAMS; i++)
-    data_size_[i] = 0;
-}
-
-// ------------------------------------------------------------------------
-
-bool MemEntryImpl::CreateEntry(const std::string& key, net::NetLog* net_log) {
-  key_ = key;
-  Time current = Time::Now();
-  last_modified_ = current;
-  last_used_ = current;
-
-  net_log_ = net::BoundNetLog::Make(net_log,
-                                    net::NetLog::SOURCE_MEMORY_CACHE_ENTRY);
-  // Must be called after |key_| is set, so GetKey() works.
-  net_log_.BeginEvent(
-      net::NetLog::TYPE_DISK_CACHE_MEM_ENTRY_IMPL,
-      CreateNetLogEntryCreationCallback(this, true));
-
+MemEntryImpl::MemEntryImpl(MemBackendImpl* backend,
+                           const std::string& key,
+                           net::NetLog* net_log)
+    : MemEntryImpl(backend,
+                   key,
+                   0,        // child_id
+                   nullptr,  // parent
+                   net_log) {
   Open();
-  backend_->ModifyStorageSize(0, static_cast<int32_t>(key.size()));
-  return true;
+  backend_->ModifyStorageSize(GetStorageSize());
 }
 
-void MemEntryImpl::InternalDoom() {
-  net_log_.AddEvent(net::NetLog::TYPE_ENTRY_DOOM);
-  doomed_ = true;
-  if (!ref_count_) {
-    if (type() == kParentEntry) {
-      // If this is a parent entry, we need to doom all the child entries.
-      if (children_.get()) {
-        EntryMap children;
-        children.swap(*children_);
-        for (EntryMap::iterator i = children.begin();
-             i != children.end(); ++i) {
-          // Since a pointer to this object is also saved in the map, avoid
-          // dooming it.
-          if (i->second != this)
-            i->second->Doom();
-        }
-        DCHECK(children_->empty());
-      }
-    } else {
-      // If this is a child entry, detach it from the parent.
-      parent_->DetachChild(child_id_);
-    }
-    delete this;
-  }
+MemEntryImpl::MemEntryImpl(MemBackendImpl* backend,
+                           int child_id,
+                           MemEntryImpl* parent,
+                           net::NetLog* net_log)
+    : MemEntryImpl(backend,
+                   std::string(),  // key
+                   child_id,
+                   parent,
+                   net_log) {
+  (*parent_->children_)[child_id] = this;
 }
 
 void MemEntryImpl::Open() {
   // Only a parent entry can be opened.
-  // TODO(hclam): make sure it's correct to not apply the concept of ref
-  // counting to child entry.
-  DCHECK(type() == kParentEntry);
-  ref_count_++;
-  DCHECK_GE(ref_count_, 0);
+  DCHECK_EQ(PARENT_ENTRY, type());
+  ++ref_count_;
+  DCHECK_GE(ref_count_, 1);
   DCHECK(!doomed_);
 }
 
-bool MemEntryImpl::InUse() {
-  if (type() == kParentEntry) {
+bool MemEntryImpl::InUse() const {
+  if (type() == PARENT_ENTRY) {
     return ref_count_ > 0;
   } else {
-    // A child entry is always not in use. The consequence is that a child entry
-    // can always be evicted while the associated parent entry is currently in
-    // used (i.e. opened).
+    // TODO(gavinp): Can't this just be a DCHECK? How would ref_count_ not be
+    // zero?
+
+    // A child entry is never in use. Thus one can always be evicted, even while
+    // its parent entry is open and in use.
     return false;
   }
 }
 
-// ------------------------------------------------------------------------
+int MemEntryImpl::GetStorageSize() const {
+  int storage_size = static_cast<int32_t>(key_.size());
+  for (const auto& i : data_)
+    storage_size += i.size();
+  return storage_size;
+}
+
+void MemEntryImpl::UpdateStateOnUse(EntryModified modified_enum) {
+  if (!doomed_)
+    backend_->OnEntryUpdated(this);
+
+  last_used_ = Time::Now();
+  if (modified_enum == ENTRY_WAS_MODIFIED)
+    last_modified_ = last_used_;
+}
 
 void MemEntryImpl::Doom() {
-  if (doomed_)
-    return;
-  if (type() == kParentEntry) {
-    // Perform internal doom from the backend if this is a parent entry.
-    backend_->InternalDoomEntry(this);
-  } else {
-    // Manually detach from the backend and perform internal doom.
-    backend_->RemoveFromRankingList(this);
-    InternalDoom();
+  if (!doomed_) {
+    doomed_ = true;
+    backend_->OnEntryDoomed(this);
+    net_log_.AddEvent(net::NetLog::TYPE_ENTRY_DOOM);
   }
+  if (!ref_count_)
+    delete this;
 }
 
 void MemEntryImpl::Close() {
-  // Only a parent entry can be closed.
-  DCHECK(type() == kParentEntry);
-  ref_count_--;
+  DCHECK_EQ(PARENT_ENTRY, type());
+  --ref_count_;
   DCHECK_GE(ref_count_, 0);
   if (!ref_count_ && doomed_)
-    InternalDoom();
+    delete this;
 }
 
 std::string MemEntryImpl::GetKey() const {
   // A child entry doesn't have key so this method should not be called.
-  DCHECK(type() == kParentEntry);
+  DCHECK_EQ(PARENT_ENTRY, type());
   return key_;
 }
 
@@ -180,9 +164,9 @@
 }
 
 int32_t MemEntryImpl::GetDataSize(int index) const {
-  if (index < 0 || index >= NUM_STREAMS)
+  if (index < 0 || index >= kNumStreams)
     return 0;
-  return data_size_[index];
+  return data_[index].size();
 }
 
 int MemEntryImpl::ReadData(int index, int offset, IOBuffer* buf, int buf_len,
@@ -260,7 +244,7 @@
         net::NetLog::TYPE_SPARSE_GET_RANGE,
         CreateNetLogSparseOperationCallback(offset, len));
   }
-  int result = GetAvailableRange(offset, len, start);
+  int result = InternalGetAvailableRange(offset, len, start);
   if (net_log_.IsCapturing()) {
     net_log_.EndEvent(
         net::NetLog::TYPE_SPARSE_GET_RANGE,
@@ -270,8 +254,8 @@
 }
 
 bool MemEntryImpl::CouldBeSparse() const {
-  DCHECK_EQ(kParentEntry, type());
-  return (children_.get() != NULL);
+  DCHECK_EQ(PARENT_ENTRY, type());
+  return (children_.get() != nullptr);
 }
 
 int MemEntryImpl::ReadyForSparseIO(const CompletionCallback& callback) {
@@ -280,41 +264,73 @@
 
 // ------------------------------------------------------------------------
 
+MemEntryImpl::MemEntryImpl(MemBackendImpl* backend,
+                           const ::std::string& key,
+                           int child_id,
+                           MemEntryImpl* parent,
+                           net::NetLog* net_log)
+    : key_(key),
+      ref_count_(0),
+      child_id_(child_id),
+      child_first_pos_(0),
+      parent_(parent),
+      last_modified_(Time::Now()),
+      last_used_(last_modified_),
+      backend_(backend),
+      doomed_(false) {
+  backend_->OnEntryInserted(this);
+  net_log_ =
+      net::BoundNetLog::Make(net_log, net::NetLog::SOURCE_MEMORY_CACHE_ENTRY);
+  net_log_.BeginEvent(net::NetLog::TYPE_DISK_CACHE_MEM_ENTRY_IMPL,
+                      base::Bind(&NetLogEntryCreationCallback, this));
+}
+
 MemEntryImpl::~MemEntryImpl() {
-  for (int i = 0; i < NUM_STREAMS; i++)
-    backend_->ModifyStorageSize(data_size_[i], 0);
-  backend_->ModifyStorageSize(static_cast<int32_t>(key_.size()), 0);
+  backend_->ModifyStorageSize(-GetStorageSize());
+
+  if (type() == PARENT_ENTRY) {
+    if (children_) {
+      EntryMap children;
+      children_->swap(children);
+
+      for (auto& it : children) {
+        // Since |this| is stored in the map, it should be guarded against
+        // double dooming, which will result in double destruction.
+        if (it.second != this)
+          it.second->Doom();
+      }
+    }
+  } else {
+    parent_->children_->erase(child_id_);
+  }
   net_log_.EndEvent(net::NetLog::TYPE_DISK_CACHE_MEM_ENTRY_IMPL);
 }
 
 int MemEntryImpl::InternalReadData(int index, int offset, IOBuffer* buf,
                                    int buf_len) {
-  DCHECK(type() == kParentEntry || index == kSparseData);
+  DCHECK(type() == PARENT_ENTRY || index == kSparseData);
 
-  if (index < 0 || index >= NUM_STREAMS)
+  if (index < 0 || index >= kNumStreams || buf_len < 0)
     return net::ERR_INVALID_ARGUMENT;
 
-  int entry_size = GetDataSize(index);
+  int entry_size = data_[index].size();
   if (offset >= entry_size || offset < 0 || !buf_len)
     return 0;
 
-  if (buf_len < 0)
-    return net::ERR_INVALID_ARGUMENT;
-
   if (offset + buf_len > entry_size)
     buf_len = entry_size - offset;
 
-  UpdateRank(false);
-
-  memcpy(buf->data(), &(data_[index])[offset], buf_len);
+  UpdateStateOnUse(ENTRY_WAS_NOT_MODIFIED);
+  std::copy(data_[index].begin() + offset,
+            data_[index].begin() + offset + buf_len, buf->data());
   return buf_len;
 }
 
 int MemEntryImpl::InternalWriteData(int index, int offset, IOBuffer* buf,
                                     int buf_len, bool truncate) {
-  DCHECK(type() == kParentEntry || index == kSparseData);
+  DCHECK(type() == PARENT_ENTRY || index == kSparseData);
 
-  if (index < 0 || index >= NUM_STREAMS)
+  if (index < 0 || index >= kNumStreams)
     return net::ERR_INVALID_ARGUMENT;
 
   if (offset < 0 || buf_len < 0)
@@ -328,34 +344,32 @@
     return net::ERR_FAILED;
   }
 
-  // Read the size at this point.
-  int entry_size = GetDataSize(index);
+  int old_data_size = data_[index].size();
+  if (truncate || old_data_size < offset + buf_len) {
+    data_[index].resize(offset + buf_len);
 
-  PrepareTarget(index, offset, buf_len);
-
-  if (entry_size < offset + buf_len) {
-    backend_->ModifyStorageSize(entry_size, offset + buf_len);
-    data_size_[index] = offset + buf_len;
-  } else if (truncate) {
-    if (entry_size > offset + buf_len) {
-      backend_->ModifyStorageSize(entry_size, offset + buf_len);
-      data_size_[index] = offset + buf_len;
+    // Zero fill any hole.
+    if (old_data_size < offset) {
+      std::fill(data_[index].begin() + old_data_size,
+                data_[index].begin() + offset, 0);
     }
+
+    backend_->ModifyStorageSize(data_[index].size() - old_data_size);
   }
 
-  UpdateRank(true);
+  UpdateStateOnUse(ENTRY_WAS_MODIFIED);
 
   if (!buf_len)
     return 0;
 
-  memcpy(&(data_[index])[offset], buf->data(), buf_len);
+  std::copy(buf->data(), buf->data() + buf_len, data_[index].begin() + offset);
   return buf_len;
 }
 
 int MemEntryImpl::InternalReadSparseData(int64_t offset,
                                          IOBuffer* buf,
                                          int buf_len) {
-  DCHECK(type() == kParentEntry);
+  DCHECK_EQ(PARENT_ENTRY, type());
 
   if (!InitSparseInfo())
     return net::ERR_CACHE_OPERATION_NOT_SUPPORTED;
@@ -369,7 +383,7 @@
 
   // Iterate until we have read enough.
   while (io_buf->BytesRemaining()) {
-    MemEntryImpl* child = OpenChild(offset + io_buf->BytesConsumed(), false);
+    MemEntryImpl* child = GetChild(offset + io_buf->BytesConsumed(), false);
 
     // No child present for that offset.
     if (!child)
@@ -385,7 +399,7 @@
     if (net_log_.IsCapturing()) {
       net_log_.BeginEvent(
           net::NetLog::TYPE_SPARSE_READ_CHILD_DATA,
-          CreateNetLogSparseReadWriteCallback(child->net_log().source(),
+          CreateNetLogSparseReadWriteCallback(child->net_log_.source(),
                                               io_buf->BytesRemaining()));
     }
     int ret = child->ReadData(kSparseData, child_offset, io_buf.get(),
@@ -405,15 +419,14 @@
     io_buf->DidConsume(ret);
   }
 
-  UpdateRank(false);
-
+  UpdateStateOnUse(ENTRY_WAS_NOT_MODIFIED);
   return io_buf->BytesConsumed();
 }
 
 int MemEntryImpl::InternalWriteSparseData(int64_t offset,
                                           IOBuffer* buf,
                                           int buf_len) {
-  DCHECK(type() == kParentEntry);
+  DCHECK_EQ(PARENT_ENTRY, type());
 
   if (!InitSparseInfo())
     return net::ERR_CACHE_OPERATION_NOT_SUPPORTED;
@@ -429,7 +442,7 @@
   // child entry until all |buf_len| bytes are written. The write operation can
   // start in the middle of an entry.
   while (io_buf->BytesRemaining()) {
-    MemEntryImpl* child = OpenChild(offset + io_buf->BytesConsumed(), true);
+    MemEntryImpl* child = GetChild(offset + io_buf->BytesConsumed(), true);
     int child_offset = ToChildOffset(offset + io_buf->BytesConsumed());
 
     // Find the right amount to write, this evaluates the remaining bytes to
@@ -441,10 +454,9 @@
     int data_size = child->GetDataSize(kSparseData);
 
     if (net_log_.IsCapturing()) {
-      net_log_.BeginEvent(
-          net::NetLog::TYPE_SPARSE_WRITE_CHILD_DATA,
-          CreateNetLogSparseReadWriteCallback(child->net_log().source(),
-                                              write_len));
+      net_log_.BeginEvent(net::NetLog::TYPE_SPARSE_WRITE_CHILD_DATA,
+                          CreateNetLogSparseReadWriteCallback(
+                              child->net_log_.source(), write_len));
     }
 
     // Always writes to the child entry. This operation may overwrite data
@@ -472,13 +484,14 @@
     io_buf->DidConsume(ret);
   }
 
-  UpdateRank(true);
-
+  UpdateStateOnUse(ENTRY_WAS_MODIFIED);
   return io_buf->BytesConsumed();
 }
 
-int MemEntryImpl::GetAvailableRange(int64_t offset, int len, int64_t* start) {
-  DCHECK(type() == kParentEntry);
+int MemEntryImpl::InternalGetAvailableRange(int64_t offset,
+                                            int len,
+                                            int64_t* start) {
+  DCHECK_EQ(PARENT_ENTRY, type());
   DCHECK(start);
 
   if (!InitSparseInfo())
@@ -487,7 +500,7 @@
   if (offset < 0 || len < 0 || !start)
     return net::ERR_INVALID_ARGUMENT;
 
-  MemEntryImpl* current_child = NULL;
+  MemEntryImpl* current_child = nullptr;
 
   // Find the first child and record the number of empty bytes.
   int empty = FindNextChild(offset, len, &current_child);
@@ -521,38 +534,10 @@
   return 0;
 }
 
-void MemEntryImpl::PrepareTarget(int index, int offset, int buf_len) {
-  int entry_size = GetDataSize(index);
-
-  if (entry_size >= offset + buf_len)
-    return;  // Not growing the stored data.
-
-  if (static_cast<int>(data_[index].size()) < offset + buf_len)
-    data_[index].resize(offset + buf_len);
-
-  if (offset <= entry_size)
-    return;  // There is no "hole" on the stored data.
-
-  // Cleanup the hole not written by the user. The point is to avoid returning
-  // random stuff later on.
-  memset(&(data_[index])[entry_size], 0, offset - entry_size);
-}
-
-void MemEntryImpl::UpdateRank(bool modified) {
-  Time current = Time::Now();
-  last_used_ = current;
-
-  if (modified)
-    last_modified_ = current;
-
-  if (!doomed_)
-    backend_->UpdateRank(this);
-}
-
 bool MemEntryImpl::InitSparseInfo() {
-  DCHECK(type() == kParentEntry);
+  DCHECK_EQ(PARENT_ENTRY, type());
 
-  if (!children_.get()) {
+  if (!children_) {
     // If we already have some data in sparse stream but we are being
     // initialized as a sparse entry, we should fail.
     if (GetDataSize(kSparseData))
@@ -566,52 +551,27 @@
   return true;
 }
 
-bool MemEntryImpl::InitChildEntry(MemEntryImpl* parent, int child_id,
-                                  net::NetLog* net_log) {
-  DCHECK(!parent_);
-  DCHECK(!child_id_);
-
-  net_log_ = net::BoundNetLog::Make(net_log,
-                                    net::NetLog::SOURCE_MEMORY_CACHE_ENTRY);
-  net_log_.BeginEvent(
-      net::NetLog::TYPE_DISK_CACHE_MEM_ENTRY_IMPL,
-      base::Bind(&NetLogChildEntryCreationCallback, parent, child_id_));
-
-  parent_ = parent;
-  child_id_ = child_id;
-  Time current = Time::Now();
-  last_modified_ = current;
-  last_used_ = current;
-  // Insert this to the backend's ranking list.
-  backend_->InsertIntoRankingList(this);
-  return true;
-}
-
-MemEntryImpl* MemEntryImpl::OpenChild(int64_t offset, bool create) {
-  DCHECK(type() == kParentEntry);
+MemEntryImpl* MemEntryImpl::GetChild(int64_t offset, bool create) {
+  DCHECK_EQ(PARENT_ENTRY, type());
   int index = ToChildIndex(offset);
   EntryMap::iterator i = children_->find(index);
-  if (i != children_->end()) {
+  if (i != children_->end())
     return i->second;
-  } else if (create) {
-    MemEntryImpl* child = new MemEntryImpl(backend_);
-    child->InitChildEntry(this, index, net_log_.net_log());
-    (*children_)[index] = child;
-    return child;
-  }
-  return NULL;
+  if (create)
+    return new MemEntryImpl(backend_, index, this, net_log_.net_log());
+  return nullptr;
 }
 
 int MemEntryImpl::FindNextChild(int64_t offset, int len, MemEntryImpl** child) {
   DCHECK(child);
-  *child = NULL;
+  *child = nullptr;
   int scanned_len = 0;
 
   // This loop tries to find the first existing child.
   while (scanned_len < len) {
     // This points to the current offset in the child.
     int current_child_offset = ToChildOffset(offset + scanned_len);
-    MemEntryImpl* current_child = OpenChild(offset + scanned_len, false);
+    MemEntryImpl* current_child = GetChild(offset + scanned_len, false);
     if (current_child) {
       int child_first_pos = current_child->child_first_pos_;
 
@@ -634,8 +594,4 @@
   return scanned_len;
 }
 
-void MemEntryImpl::DetachChild(int child_id) {
-  children_->erase(child_id);
-}
-
 }  // namespace disk_cache
diff --git a/net/disk_cache/memory/mem_entry_impl.h b/net/disk_cache/memory/mem_entry_impl.h
index 52a1696f..11634e6a 100644
--- a/net/disk_cache/memory/mem_entry_impl.h
+++ b/net/disk_cache/memory/mem_entry_impl.h
@@ -7,9 +7,15 @@
 
 #include <stdint.h>
 
+#include <string>
+#include <vector>
+
 #include "base/containers/hash_tables.h"
+#include "base/containers/linked_list.h"
+#include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
 #include "net/disk_cache/disk_cache.h"
 #include "net/log/net_log.h"
 
@@ -18,8 +24,8 @@
 class MemBackendImpl;
 
 // This class implements the Entry interface for the memory-only cache. An
-// object of this class represents a single entry on the cache. We use two
-// types of entries, parent and child to support sparse caching.
+// object of this class represents a single entry on the cache. We use two types
+// of entries, parent and child to support sparse caching.
 //
 // A parent entry is non-sparse until a sparse method is invoked (i.e.
 // ReadSparseData, WriteSparseData, GetAvailableRange) when sparse information
@@ -31,64 +37,62 @@
 // ReadData and WriteData cannot be applied to them. The lifetime of a child
 // entry is managed by the parent entry that created it except that the entry
 // can be evicted independently. A child entry does not have a key and it is not
-// registered in the backend's entry map. It is registered in the backend's
-// ranking list to enable eviction of a partial content.
+// registered in the backend's entry map.
 //
-// A sparse entry has a fixed maximum size and can be partially filled. There
-// can only be one continous filled region in a sparse entry, as illustrated by
-// the following example:
+// A sparse child entry has a fixed maximum size and can be partially
+// filled. There can only be one continous filled region in a sparse entry, as
+// illustrated by the following example:
 // | xxx ooooo |
 // x = unfilled region
 // o = filled region
-// It is guranteed that there is at most one unfilled region and one filled
+// It is guaranteed that there is at most one unfilled region and one filled
 // region, and the unfilled region (if there is one) is always before the filled
 // region. The book keeping for filled region in a sparse entry is done by using
-// the variable |child_first_pos_| (inclusive).
+// the variable |child_first_pos_|.
 
-class MemEntryImpl : public Entry {
+class NET_EXPORT_PRIVATE MemEntryImpl final
+    : public Entry,
+      public base::LinkNode<MemEntryImpl> {
  public:
   enum EntryType {
-    kParentEntry,
-    kChildEntry,
+    PARENT_ENTRY,
+    CHILD_ENTRY,
   };
 
-  explicit MemEntryImpl(MemBackendImpl* backend);
+  // Provided to better document calls to |UpdateStateOnUse()|.
+  enum EntryModified {
+    ENTRY_WAS_NOT_MODIFIED,
+    ENTRY_WAS_MODIFIED,
+  };
 
-  // Performs the initialization of a EntryImpl that will be added to the
-  // cache.
-  bool CreateEntry(const std::string& key, net::NetLog* net_log);
+  // Constructor for parent entries.
+  MemEntryImpl(MemBackendImpl* backend,
+               const std::string& key,
+               net::NetLog* net_log);
 
-  // Permanently destroys this entry.
-  void InternalDoom();
+  // Constructor for child entries.
+  MemEntryImpl(MemBackendImpl* backend,
+               int child_id,
+               MemEntryImpl* parent,
+               net::NetLog* net_log);
 
   void Open();
-  bool InUse();
+  bool InUse() const;
 
-  MemEntryImpl* next() const {
-    return next_;
-  }
+  EntryType type() const { return parent_ ? CHILD_ENTRY : PARENT_ENTRY; }
+  const std::string& key() const { return key_; }
+  const MemEntryImpl* parent() const { return parent_; }
+  int child_id() const { return child_id_; }
+  base::Time last_used() const { return last_used_; }
 
-  MemEntryImpl* prev() const {
-    return prev_;
-  }
+  // The in-memory size of this entry to use for the purposes of eviction.
+  int GetStorageSize() const;
 
-  void set_next(MemEntryImpl* next) {
-    next_ = next;
-  }
+  // Update an entry's position in the backend LRU list and set |last_used_|. If
+  // the entry was modified, also update |last_modified_|.
+  void UpdateStateOnUse(EntryModified modified_enum);
 
-  void set_prev(MemEntryImpl* prev) {
-    prev_ = prev;
-  }
-
-  EntryType type() const {
-    return parent_ ? kChildEntry : kParentEntry;
-  }
-
-  const net::BoundNetLog& net_log() {
-    return net_log_;
-  }
-
-  // Entry interface.
+  // From disk_cache::Entry:
   void Doom() override;
   void Close() override;
   std::string GetKey() const override;
@@ -123,11 +127,15 @@
   int ReadyForSparseIO(const CompletionCallback& callback) override;
 
  private:
+  MemEntryImpl(MemBackendImpl* backend,
+               const std::string& key,
+               int child_id,
+               MemEntryImpl* parent,
+               net::NetLog* net_log);
+
   typedef base::hash_map<int, MemEntryImpl*> EntryMap;
 
-  enum {
-    NUM_STREAMS = 3
-  };
+  static const int kNumStreams = 3;
 
   ~MemEntryImpl() override;
 
@@ -138,53 +146,35 @@
                         bool truncate);
   int InternalReadSparseData(int64_t offset, IOBuffer* buf, int buf_len);
   int InternalWriteSparseData(int64_t offset, IOBuffer* buf, int buf_len);
-
-  // Old Entry interface.
-  int GetAvailableRange(int64_t offset, int len, int64_t* start);
-
-  // Grows and cleans up the data buffer.
-  void PrepareTarget(int index, int offset, int buf_len);
-
-  // Updates ranking information.
-  void UpdateRank(bool modified);
+  int InternalGetAvailableRange(int64_t offset, int len, int64_t* start);
 
   // Initializes the children map and sparse info. This method is only called
   // on a parent entry.
   bool InitSparseInfo();
 
-  // Performs the initialization of a MemEntryImpl as a child entry.
-  // |parent| is the pointer to the parent entry. |child_id| is the ID of
-  // the new child.
-  bool InitChildEntry(MemEntryImpl* parent, int child_id, net::NetLog* net_log);
-
   // Returns an entry responsible for |offset|. The returned entry can be a
   // child entry or this entry itself if |offset| points to the first range.
   // If such entry does not exist and |create| is true, a new child entry is
   // created.
-  MemEntryImpl* OpenChild(int64_t offset, bool create);
+  MemEntryImpl* GetChild(int64_t offset, bool create);
 
   // Finds the first child located within the range [|offset|, |offset + len|).
   // Returns the number of bytes ahead of |offset| to reach the first available
   // bytes in the entry. The first child found is output to |child|.
   int FindNextChild(int64_t offset, int len, MemEntryImpl** child);
 
-  // Removes child indexed by |child_id| from the children map.
-  void DetachChild(int child_id);
-
   std::string key_;
-  std::vector<char> data_[NUM_STREAMS];  // User data.
-  int32_t data_size_[NUM_STREAMS];
+  std::vector<char> data_[kNumStreams];  // User data.
   int ref_count_;
 
   int child_id_;              // The ID of a child entry.
   int child_first_pos_;       // The position of the first byte in a child
                               // entry.
-  MemEntryImpl* next_;        // Pointers for the LRU list.
-  MemEntryImpl* prev_;
-  MemEntryImpl* parent_;      // Pointer to the parent entry.
+  // Pointer to the parent entry, or nullptr if this entry is a parent entry.
+  MemEntryImpl* parent_;
   scoped_ptr<EntryMap> children_;
 
-  base::Time last_modified_;  // LRU information.
+  base::Time last_modified_;
   base::Time last_used_;
   MemBackendImpl* backend_;   // Back pointer to the cache.
   bool doomed_;               // True if this entry was removed from the cache.
diff --git a/net/disk_cache/memory/mem_rankings.cc b/net/disk_cache/memory/mem_rankings.cc
deleted file mode 100644
index ba5e00b..0000000
--- a/net/disk_cache/memory/mem_rankings.cc
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright (c) 2006-2008 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 "net/disk_cache/memory/mem_rankings.h"
-
-#include "base/logging.h"
-#include "net/disk_cache/memory/mem_entry_impl.h"
-
-namespace disk_cache {
-
-MemRankings::~MemRankings() {
-  DCHECK(!head_ && !tail_);
-}
-
-void MemRankings::Insert(MemEntryImpl* node) {
-  if (head_)
-    head_->set_prev(node);
-
-  if (!tail_)
-    tail_ = node;
-
-  node->set_prev(NULL);
-  node->set_next(head_);
-  head_ = node;
-}
-
-void MemRankings::Remove(MemEntryImpl* node) {
-  MemEntryImpl* prev = node->prev();
-  MemEntryImpl* next = node->next();
-
-  if (head_ == node)
-    head_ = next;
-
-  if (tail_ == node)
-    tail_ = prev;
-
-  if (prev)
-    prev->set_next(next);
-
-  if (next)
-    next->set_prev(prev);
-
-  node->set_next(NULL);
-  node->set_prev(NULL);
-}
-
-void MemRankings::UpdateRank(MemEntryImpl* node) {
-  Remove(node);
-  Insert(node);
-}
-
-MemEntryImpl* MemRankings::GetNext(MemEntryImpl* node) {
-  if (!node)
-    return head_;
-
-  return node->next();
-}
-
-MemEntryImpl* MemRankings::GetPrev(MemEntryImpl* node) {
-  if (!node)
-    return tail_;
-
-  return node->prev();
-}
-
-}  // namespace disk_cache
diff --git a/net/disk_cache/memory/mem_rankings.h b/net/disk_cache/memory/mem_rankings.h
deleted file mode 100644
index d660cab..0000000
--- a/net/disk_cache/memory/mem_rankings.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2010 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.
-
-// See net/disk_cache/disk_cache.h for the public interface.
-
-#ifndef NET_DISK_CACHE_MEMORY_MEM_RANKINGS_H_
-#define NET_DISK_CACHE_MEMORY_MEM_RANKINGS_H_
-
-#include "base/macros.h"
-
-namespace disk_cache {
-
-class MemEntryImpl;
-
-// This class handles the ranking information for the memory-only cache.
-class MemRankings {
- public:
-  MemRankings() : head_(NULL), tail_(NULL) {}
-  ~MemRankings();
-
-  // Inserts a given entry at the head of the queue.
-  void Insert(MemEntryImpl* node);
-
-  // Removes a given entry from the LRU list.
-  void Remove(MemEntryImpl* node);
-
-  // Moves a given entry to the head.
-  void UpdateRank(MemEntryImpl* node);
-
-  // Iterates through the list.
-  MemEntryImpl* GetNext(MemEntryImpl* node);
-  MemEntryImpl* GetPrev(MemEntryImpl* node);
-
- private:
-  MemEntryImpl* head_;
-  MemEntryImpl* tail_;
-
-  DISALLOW_COPY_AND_ASSIGN(MemRankings);
-};
-
-}  // namespace disk_cache
-
-#endif  // NET_DISK_CACHE_MEMORY_MEM_RANKINGS_H_
diff --git a/net/dns/address_sorter_posix_unittest.cc b/net/dns/address_sorter_posix_unittest.cc
index 1212978..d464babd 100644
--- a/net/dns/address_sorter_posix_unittest.cc
+++ b/net/dns/address_sorter_posix_unittest.cc
@@ -8,7 +8,6 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/test_completion_callback.h"
 #include "net/socket/client_socket_factory.h"
 #include "net/socket/ssl_client_socket.h"
diff --git a/net/dns/address_sorter_unittest.cc b/net/dns/address_sorter_unittest.cc
index 0c2be88..5038b4f 100644
--- a/net/dns/address_sorter_unittest.cc
+++ b/net/dns/address_sorter_unittest.cc
@@ -11,7 +11,6 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "net/base/address_list.h"
-#include "net/base/net_util.h"
 #include "net/base/test_completion_callback.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/net/dns/dns_config_service_posix.cc b/net/dns/dns_config_service_posix.cc
index 92d7dff..ab84b22 100644
--- a/net/dns/dns_config_service_posix.cc
+++ b/net/dns/dns_config_service_posix.cc
@@ -19,7 +19,6 @@
 #include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "net/base/ip_endpoint.h"
-#include "net/base/net_util.h"
 #include "net/dns/dns_hosts.h"
 #include "net/dns/dns_protocol.h"
 #include "net/dns/notify_watcher_mac.h"
diff --git a/net/dns/dns_config_service_unittest.cc b/net/dns/dns_config_service_unittest.cc
index 40796ad..aa4b3c8 100644
--- a/net/dns/dns_config_service_unittest.cc
+++ b/net/dns/dns_config_service_unittest.cc
@@ -13,7 +13,6 @@
 #include "base/strings/string_split.h"
 #include "base/test/test_timeouts.h"
 #include "base/thread_task_runner_handle.h"
-#include "net/base/net_util.h"
 #include "net/dns/dns_protocol.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/net/dns/dns_config_service_win.cc b/net/dns/dns_config_service_win.cc
index a08feb5..1bdbb59 100644
--- a/net/dns/dns_config_service_win.cc
+++ b/net/dns/dns_config_service_win.cc
@@ -26,7 +26,6 @@
 #include "base/win/registry.h"
 #include "base/win/scoped_handle.h"
 #include "base/win/windows_version.h"
-#include "net/base/net_util.h"
 #include "net/base/network_change_notifier.h"
 #include "net/dns/dns_hosts.h"
 #include "net/dns/dns_protocol.h"
diff --git a/net/dns/dns_response_unittest.cc b/net/dns/dns_response_unittest.cc
index e701c9a..46f50ed 100644
--- a/net/dns/dns_response_unittest.cc
+++ b/net/dns/dns_response_unittest.cc
@@ -7,7 +7,6 @@
 #include "base/time/time.h"
 #include "net/base/address_list.h"
 #include "net/base/io_buffer.h"
-#include "net/base/net_util.h"
 #include "net/dns/dns_protocol.h"
 #include "net/dns/dns_query.h"
 #include "net/dns/dns_test_util.h"
diff --git a/net/dns/host_resolver_impl_unittest.cc b/net/dns/host_resolver_impl_unittest.cc
index c4e863c..3d30dbe 100644
--- a/net/dns/host_resolver_impl_unittest.cc
+++ b/net/dns/host_resolver_impl_unittest.cc
@@ -27,7 +27,6 @@
 #include "base/time/time.h"
 #include "net/base/address_list.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/dns/dns_client.h"
 #include "net/dns/dns_test_util.h"
 #include "net/dns/mock_host_resolver.h"
diff --git a/net/dns/mapped_host_resolver.cc b/net/dns/mapped_host_resolver.cc
index 97461148..5474cc3 100644
--- a/net/dns/mapped_host_resolver.cc
+++ b/net/dns/mapped_host_resolver.cc
@@ -10,7 +10,6 @@
 #include "base/values.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 
 namespace net {
 
diff --git a/net/dns/mapped_host_resolver_unittest.cc b/net/dns/mapped_host_resolver_unittest.cc
index 002a988..dd772ac4 100644
--- a/net/dns/mapped_host_resolver_unittest.cc
+++ b/net/dns/mapped_host_resolver_unittest.cc
@@ -8,7 +8,6 @@
 
 #include "net/base/address_list.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/test_completion_callback.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/log/net_log.h"
diff --git a/net/dns/mdns_client.cc b/net/dns/mdns_client.cc
index 04f995b3..109a836 100644
--- a/net/dns/mdns_client.cc
+++ b/net/dns/mdns_client.cc
@@ -5,7 +5,6 @@
 #include "net/dns/mdns_client.h"
 
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/network_interfaces.h"
 #include "net/dns/dns_protocol.h"
 #include "net/dns/mdns_client_impl.h"
diff --git a/net/dns/mock_host_resolver.cc b/net/dns/mock_host_resolver.cc
index 42ec6b9a..b97c51b 100644
--- a/net/dns/mock_host_resolver.cc
+++ b/net/dns/mock_host_resolver.cc
@@ -19,7 +19,6 @@
 #include "base/threading/platform_thread.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/test_completion_callback.h"
 #include "net/dns/host_cache.h"
 
diff --git a/net/dns/mojo_host_resolver_impl_unittest.cc b/net/dns/mojo_host_resolver_impl_unittest.cc
index 543a172..6816a6b8 100644
--- a/net/dns/mojo_host_resolver_impl_unittest.cc
+++ b/net/dns/mojo_host_resolver_impl_unittest.cc
@@ -14,7 +14,6 @@
 #include "mojo/public/cpp/bindings/interface_request.h"
 #include "net/base/address_list.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/dns/mojo_host_type_converters.h"
 #include "net/log/net_log.h"
diff --git a/net/dns/mojo_host_type_converters.cc b/net/dns/mojo_host_type_converters.cc
index 4d0eabf..2e404e0 100644
--- a/net/dns/mojo_host_type_converters.cc
+++ b/net/dns/mojo_host_type_converters.cc
@@ -8,7 +8,6 @@
 
 #include "mojo/public/cpp/bindings/type_converter.h"
 #include "net/base/address_list.h"
-#include "net/base/net_util.h"
 
 namespace net {
 namespace {
diff --git a/net/ftp/ftp_network_transaction_unittest.cc b/net/ftp/ftp_network_transaction_unittest.cc
index ec1dc200..c1b98c8 100644
--- a/net/ftp/ftp_network_transaction_unittest.cc
+++ b/net/ftp/ftp_network_transaction_unittest.cc
@@ -13,7 +13,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/io_buffer.h"
-#include "net/base/net_util.h"
 #include "net/base/test_completion_callback.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/ftp/ftp_request_info.h"
diff --git a/net/http/http_auth_gssapi_posix.cc b/net/http/http_auth_gssapi_posix.cc
index 1c3352c9..d70d884 100644
--- a/net/http/http_auth_gssapi_posix.cc
+++ b/net/http/http_auth_gssapi_posix.cc
@@ -16,7 +16,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_restrictions.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/http/http_auth_multi_round_parse.h"
 
 // These are defined for the GSSAPI library:
diff --git a/net/http/http_auth_handler_ntlm_win.cc b/net/http/http_auth_handler_ntlm_win.cc
index 7aca5f0..58e563b 100644
--- a/net/http/http_auth_handler_ntlm_win.cc
+++ b/net/http/http_auth_handler_ntlm_win.cc
@@ -11,7 +11,6 @@
 
 #include "base/strings/string_util.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/http/http_auth_preferences.h"
 #include "net/http/http_auth_sspi_win.h"
 
diff --git a/net/http/http_content_disposition.cc b/net/http/http_content_disposition.cc
index bef2d44a..90d051d 100644
--- a/net/http/http_content_disposition.cc
+++ b/net/http/http_content_disposition.cc
@@ -12,7 +12,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "net/base/escape.h"
 #include "net/base/net_string_util.h"
-#include "net/base/net_util.h"
 #include "net/http/http_util.h"
 
 namespace net {
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index cef8d77..94361dac 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -74,15 +74,16 @@
 void ProcessAlternativeServices(HttpNetworkSession* session,
                                 const HttpResponseHeaders& headers,
                                 const HostPortPair& http_host_port_pair) {
-  if (session->params().parse_alternative_services &&
-      headers.HasHeader(kAlternativeServiceHeader)) {
-    std::string alternative_service_str;
-    headers.GetNormalizedHeader(kAlternativeServiceHeader,
-                                &alternative_service_str);
-    session->http_stream_factory()->ProcessAlternativeService(
-        session->http_server_properties(), alternative_service_str,
-        http_host_port_pair, *session);
-    // If there is an "Alt-Svc" header, then ignore "Alternate-Protocol".
+  if (session->params().parse_alternative_services) {
+    if (headers.HasHeader(kAlternativeServiceHeader)) {
+      std::string alternative_service_str;
+      headers.GetNormalizedHeader(kAlternativeServiceHeader,
+                                  &alternative_service_str);
+      session->http_stream_factory()->ProcessAlternativeService(
+          session->http_server_properties(), alternative_service_str,
+          http_host_port_pair, *session);
+    }
+    // If "Alt-Svc" is enabled, then ignore "Alternate-Protocol".
     return;
   }
 
@@ -1436,61 +1437,31 @@
     return OK;
   }
 
+  // TODO(davidben): Remove this code once the dedicated error code is no
+  // longer needed and the flags to re-enable the fallback expire.
   bool should_fallback = false;
   uint16_t version_max = server_ssl_config_.version_max;
 
   switch (error) {
+    // This could be a TLS-intolerant server or a server that chose a
+    // cipher suite defined only for higher protocol versions (such as
+    // an TLS 1.1 server that chose a TLS-1.2-only cipher suite).  Fall
+    // back to the next lower version and retry.
     case ERR_CONNECTION_CLOSED:
     case ERR_SSL_PROTOCOL_ERROR:
     case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
-      if (version_max >= SSL_PROTOCOL_VERSION_TLS1 &&
-          version_max > server_ssl_config_.version_min) {
-        // This could be a TLS-intolerant server or a server that chose a
-        // cipher suite defined only for higher protocol versions (such as
-        // an SSL 3.0 server that chose a TLS-only cipher suite).  Fall
-        // back to the next lower version and retry.
-        // NOTE: if the SSLClientSocket class doesn't support TLS 1.1,
-        // specifying TLS 1.1 in version_max will result in a TLS 1.0
-        // handshake, so falling back from TLS 1.1 to TLS 1.0 will simply
-        // repeat the TLS 1.0 handshake. To avoid this problem, the default
-        // version_max should match the maximum protocol version supported
-        // by the SSLClientSocket class.
-        version_max--;
-
-        // Fallback to the lower SSL version.
-        // While SSL 3.0 fallback should be eliminated because of security
-        // reasons, there is a high risk of breaking the servers if this is
-        // done in general.
-        should_fallback = true;
-      }
-      break;
+    // Some servers trigger the TLS 1.1 fallback with ERR_CONNECTION_RESET
+    // (https://crbug.com/433406).
     case ERR_CONNECTION_RESET:
-      if (version_max >= SSL_PROTOCOL_VERSION_TLS1_1 &&
-          version_max > server_ssl_config_.version_min) {
-        // Some network devices that inspect application-layer packets seem to
-        // inject TCP reset packets to break the connections when they see TLS
-        // 1.1 in ClientHello or ServerHello. See http://crbug.com/130293.
-        //
-        // Only allow ERR_CONNECTION_RESET to trigger a fallback from TLS 1.1 or
-        // 1.2. We don't lose much in this fallback because the explicit IV for
-        // CBC mode in TLS 1.1 is approximated by record splitting in TLS
-        // 1.0. The fallback will be more painful for TLS 1.2 when we have GCM
-        // support.
-        //
-        // ERR_CONNECTION_RESET is a common network error, so we don't want it
-        // to trigger a version fallback in general, especially the TLS 1.0 ->
-        // SSL 3.0 fallback, which would drop TLS extensions.
-        version_max--;
-        should_fallback = true;
-      }
-      break;
+    // This was added for the TLS 1.0 fallback (https://crbug.com/260358) which
+    // has since been removed, but other servers may be relying on it for the
+    // TLS 1.1 fallback. It will be removed with the remainder of the fallback.
     case ERR_SSL_BAD_RECORD_MAC_ALERT:
-      if (version_max >= SSL_PROTOCOL_VERSION_TLS1_1 &&
+      // Fallback down to a TLS 1.1 ClientHello. By default, this is rejected
+      // but surfaces ERR_SSL_FALLBACK_BEYOND_MINIMUM_VERSION to help diagnose
+      // server bugs.
+      if (version_max >= SSL_PROTOCOL_VERSION_TLS1_2 &&
           version_max > server_ssl_config_.version_min) {
-        // Some broken SSL devices negotiate TLS 1.0 when sent a TLS 1.1 or
-        // 1.2 ClientHello, but then return a bad_record_mac alert. See
-        // crbug.com/260358. In order to make the fallback as minimal as
-        // possible, this fallback is only triggered for >= TLS 1.1.
         version_max--;
         should_fallback = true;
       }
diff --git a/net/http/http_network_transaction_ssl_unittest.cc b/net/http/http_network_transaction_ssl_unittest.cc
index 51f3406..d856996 100644
--- a/net/http/http_network_transaction_ssl_unittest.cc
+++ b/net/http/http_network_transaction_ssl_unittest.cc
@@ -7,7 +7,6 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "net/base/net_util.h"
 #include "net/base/request_priority.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/http/http_auth_handler_mock.h"
@@ -115,7 +114,7 @@
 };
 
 // Tests that HttpNetworkTransaction attempts to fallback from
-// TLS 1.2 to TLS 1.1, then from TLS 1.1 to TLS 1.0.
+// TLS 1.2 to TLS 1.1.
 TEST_F(HttpNetworkTransactionSSLTest, SSLFallback) {
   ssl_config_service_ = new TLS12SSLConfigService;
   session_params_.ssl_config_service = ssl_config_service_.get();
@@ -134,19 +133,11 @@
   StaticSocketDataProvider data2(NULL, 0, NULL, 0);
   mock_socket_factory_.AddSocketDataProvider(&data2);
 
-  // |ssl_data3| contains the handshake result for a TLS 1.0
-  // handshake which will be attempted after the TLS 1.1
-  // handshake fails.
-  SSLSocketDataProvider ssl_data3(ASYNC, ERR_SSL_PROTOCOL_ERROR);
-  mock_socket_factory_.AddSSLSocketDataProvider(&ssl_data3);
-  StaticSocketDataProvider data3(NULL, 0, NULL, 0);
-  mock_socket_factory_.AddSocketDataProvider(&data3);
-
   HttpNetworkSession session(session_params_);
   HttpNetworkTransaction trans(DEFAULT_PRIORITY, &session);
 
   TestCompletionCallback callback;
-  // This will consume |ssl_data1|, |ssl_data2| and |ssl_data3|.
+  // This will consume |ssl_data1| and |ssl_data2|.
   int rv =
       callback.GetResult(trans.Start(GetRequestInfo("https://www.paypal.com/"),
                                      callback.callback(), BoundNetLog()));
@@ -154,12 +145,12 @@
 
   SocketDataProviderArray<SocketDataProvider>& mock_data =
       mock_socket_factory_.mock_data();
-  // Confirms that |ssl_data1|, |ssl_data2| and |ssl_data3| are consumed.
-  EXPECT_EQ(3u, mock_data.next_index());
+  // Confirms that |ssl_data1| and |ssl_data2| are consumed.
+  EXPECT_EQ(2u, mock_data.next_index());
 
   SSLConfig& ssl_config = GetServerSSLConfig(&trans);
-  // |version_max| fallbacks to TLS 1.0.
-  EXPECT_EQ(SSL_PROTOCOL_VERSION_TLS1, ssl_config.version_max);
+  // |version_max| falls back to TLS 1.1.
+  EXPECT_EQ(SSL_PROTOCOL_VERSION_TLS1_1, ssl_config.version_max);
   EXPECT_TRUE(ssl_config.version_fallback);
 }
 
@@ -217,4 +208,3 @@
 #endif  // !defined(OS_IOS)
 
 }  // namespace net
-
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 3f92da8..bc7f7b3 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -9971,7 +9971,7 @@
 }
 
 TEST_P(HttpNetworkTransactionTest, EmptyAlternateProtocolHeader) {
-  session_deps_.parse_alternative_services = true;
+  session_deps_.parse_alternative_services = false;
   session_deps_.enable_alternative_service_with_different_host = false;
 
   MockRead data_reads[] = {
@@ -10660,7 +10660,7 @@
 }
 
 TEST_P(HttpNetworkTransactionTest, UseAlternateProtocolForNpnSpdy) {
-  session_deps_.parse_alternative_services = true;
+  session_deps_.parse_alternative_services = false;
   session_deps_.enable_alternative_service_with_different_host = false;
 
   HttpRequestInfo request;
@@ -10748,7 +10748,7 @@
 }
 
 TEST_P(HttpNetworkTransactionTest, AlternateProtocolWithSpdyLateBinding) {
-  session_deps_.parse_alternative_services = true;
+  session_deps_.parse_alternative_services = false;
   session_deps_.enable_alternative_service_with_different_host = false;
 
   HttpRequestInfo request;
@@ -10869,7 +10869,7 @@
 }
 
 TEST_P(HttpNetworkTransactionTest, StallAlternateProtocolForNpnSpdy) {
-  session_deps_.parse_alternative_services = true;
+  session_deps_.parse_alternative_services = false;
   session_deps_.enable_alternative_service_with_different_host = false;
 
   HttpRequestInfo request;
@@ -10998,7 +10998,7 @@
 
 TEST_P(HttpNetworkTransactionTest,
        UseAlternateProtocolForTunneledNpnSpdy) {
-  session_deps_.parse_alternative_services = true;
+  session_deps_.parse_alternative_services = false;
   session_deps_.enable_alternative_service_with_different_host = false;
 
   ProxyConfig proxy_config;
@@ -11122,7 +11122,7 @@
 
 TEST_P(HttpNetworkTransactionTest,
        UseAlternateProtocolForNpnSpdyWithExistingSpdySession) {
-  session_deps_.parse_alternative_services = true;
+  session_deps_.parse_alternative_services = false;
   session_deps_.enable_alternative_service_with_different_host = false;
 
   HttpRequestInfo request;
@@ -11946,7 +11946,7 @@
 // This test ensures that the URL passed into the proxy is upgraded to https
 // when doing an Alternate Protocol upgrade.
 TEST_P(HttpNetworkTransactionTest, SpdyAlternateProtocolThroughProxy) {
-  session_deps_.parse_alternative_services = true;
+  session_deps_.parse_alternative_services = false;
   session_deps_.enable_alternative_service_with_different_host = false;
 
   session_deps_.proxy_service =
diff --git a/net/http/http_proxy_client_socket.cc b/net/http/http_proxy_client_socket.cc
index 562bff36..a5f710730 100644
--- a/net/http/http_proxy_client_socket.cc
+++ b/net/http/http_proxy_client_socket.cc
@@ -13,7 +13,6 @@
 #include "net/base/auth.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/io_buffer.h"
-#include "net/base/net_util.h"
 #include "net/base/proxy_delegate.h"
 #include "net/http/http_basic_stream.h"
 #include "net/http/http_network_session.h"
diff --git a/net/http/http_proxy_client_socket_wrapper.cc b/net/http/http_proxy_client_socket_wrapper.cc
index d1595187d..8184a7d 100644
--- a/net/http/http_proxy_client_socket_wrapper.cc
+++ b/net/http/http_proxy_client_socket_wrapper.cc
@@ -12,7 +12,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/profiler/scoped_tracker.h"
 #include "base/values.h"
-#include "net/base/net_util.h"
 #include "net/base/proxy_delegate.h"
 #include "net/http/http_proxy_client_socket.h"
 #include "net/http/http_response_info.h"
diff --git a/net/http/http_server_properties_impl_unittest.cc b/net/http/http_server_properties_impl_unittest.cc
index 73c5c39..d06574f 100644
--- a/net/http/http_server_properties_impl_unittest.cc
+++ b/net/http/http_server_properties_impl_unittest.cc
@@ -1283,8 +1283,7 @@
   EXPECT_FALSE(impl_.GetSupportsQuic(&address));
   EXPECT_TRUE(address.empty());
 
-  IPAddress actual_address;
-  CHECK(actual_address.AssignFromIPLiteral("127.0.0.1"));
+  IPAddress actual_address(127, 0, 0, 1);
   impl_.SetSupportsQuic(true, actual_address);
 
   EXPECT_TRUE(impl_.GetSupportsQuic(&address));
diff --git a/net/http/http_server_properties_manager_unittest.cc b/net/http/http_server_properties_manager_unittest.cc
index 3d6f6c7..5471fd1 100644
--- a/net/http/http_server_properties_manager_unittest.cc
+++ b/net/http/http_server_properties_manager_unittest.cc
@@ -820,8 +820,7 @@
   IPAddress address;
   EXPECT_FALSE(http_server_props_manager_->GetSupportsQuic(&address));
 
-  IPAddress actual_address;
-  CHECK(actual_address.AssignFromIPLiteral("127.0.0.1"));
+  IPAddress actual_address(127, 0, 0, 1);
   http_server_props_manager_->SetSupportsQuic(true, actual_address);
   // ExpectScheduleUpdatePrefsOnNetworkThread() should be called only once.
   http_server_props_manager_->SetSupportsQuic(true, actual_address);
@@ -888,8 +887,7 @@
   AlternativeService alternative_service(NPN_HTTP_2, "mail.google.com", 1234);
   http_server_props_manager_->SetAlternativeService(
       spdy_server_mail, alternative_service, 1.0, one_day_from_now_);
-  IPAddress actual_address;
-  CHECK(actual_address.AssignFromIPLiteral("127.0.0.1"));
+  IPAddress actual_address(127, 0, 0, 1);
   http_server_props_manager_->SetSupportsQuic(true, actual_address);
   ServerNetworkStats stats;
   stats.srtt = base::TimeDelta::FromMicroseconds(10);
@@ -1078,8 +1076,7 @@
                                                 quic_server_info1);
 
   // Set SupportsQuic.
-  IPAddress actual_address;
-  CHECK(actual_address.AssignFromIPLiteral("127.0.0.1"));
+  IPAddress actual_address(127, 0, 0, 1);
   http_server_props_manager_->SetSupportsQuic(true, actual_address);
 
   // Update cache.
diff --git a/net/http/http_stream_factory_impl.cc b/net/http/http_stream_factory_impl.cc
index 4931e9aa..962f513 100644
--- a/net/http/http_stream_factory_impl.cc
+++ b/net/http/http_stream_factory_impl.cc
@@ -9,7 +9,6 @@
 #include "base/logging.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
-#include "net/base/net_util.h"
 #include "net/http/http_network_session.h"
 #include "net/http/http_server_properties.h"
 #include "net/http/http_stream_factory_impl_job.h"
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc
index f4fbca1d..1d09da79 100644
--- a/net/http/http_stream_factory_impl_job.cc
+++ b/net/http/http_stream_factory_impl_job.cc
@@ -24,7 +24,6 @@
 #include "base/values.h"
 #include "build/build_config.h"
 #include "net/base/connection_type_histograms.h"
-#include "net/base/net_util.h"
 #include "net/base/port_util.h"
 #include "net/cert/cert_verifier.h"
 #include "net/http/http_basic_stream.h"
diff --git a/net/http/http_transaction_test_util.cc b/net/http/http_transaction_test_util.cc
index 0e027a2..2298efd0 100644
--- a/net/http/http_transaction_test_util.cc
+++ b/net/http/http_transaction_test_util.cc
@@ -390,8 +390,7 @@
 }
 
 bool MockNetworkTransaction::GetRemoteEndpoint(IPEndPoint* endpoint) const {
-  IPAddress ip_address;
-  CHECK(ip_address.AssignFromIPLiteral("127.0.0.1"));
+  IPAddress ip_address(127, 0, 0, 1);
   *endpoint = IPEndPoint(ip_address, 80);
   return true;
 }
diff --git a/net/http/proxy_client_socket.cc b/net/http/proxy_client_socket.cc
index 3b36ed8..3a7947c 100644
--- a/net/http/proxy_client_socket.cc
+++ b/net/http/proxy_client_socket.cc
@@ -8,7 +8,6 @@
 #include "base/strings/stringprintf.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/http/http_auth_controller.h"
 #include "net/http/http_request_info.h"
 #include "net/http/http_response_headers.h"
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index ee914e7..0adc8f1 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -8013,7 +8013,623 @@
     { "name": "windscribe.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "wlaws.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "xolphin.nl", "include_subdomains": true, "mode": "force-https" },
-    { "name": "zellari.ru", "include_subdomains": true, "mode": "force-https" }
+    { "name": "zellari.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "123plons.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "1cover.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "1xcess.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "2carpros.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "3r.org.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "91tianmi.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "aaron-gustafson.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "abilitynet.org.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "abmgood.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "aboutmyproperty.ca", "include_subdomains": true, "mode": "force-https" },
+    { "name": "acheconcursos.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "acnpacific.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "acuve.jp", "include_subdomains": true, "mode": "force-https" },
+    { "name": "addaxpetroleum.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "adigitali.biz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "adquisitio.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "adquisitio.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "adquisitio.es", "include_subdomains": true, "mode": "force-https" },
+    { "name": "adquisitio.fr", "include_subdomains": true, "mode": "force-https" },
+    { "name": "adquisitio.it", "include_subdomains": true, "mode": "force-https" },
+    { "name": "aemoria.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "aeon.co", "include_subdomains": true, "mode": "force-https" },
+    { "name": "affiliateroyale.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "aficotroceni.ro", "include_subdomains": true, "mode": "force-https" },
+    { "name": "agenda-loto.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ahd.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "airsoft.ch", "include_subdomains": true, "mode": "force-https" },
+    { "name": "akelius.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "alastyr.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "aldes.co.za", "include_subdomains": true, "mode": "force-https" },
+    { "name": "alexandra-schulze.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "all-subtitles.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "all4os.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ama.ne.jp", "include_subdomains": true, "mode": "force-https" },
+    { "name": "amateri.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "amerigroup.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "anghami.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "animesfusion.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "anook.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "apeasternpower.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "applez.xyz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "attorney.org.il", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ausschreibungen-suedtirol.it", "include_subdomains": true, "mode": "force-https" },
+    { "name": "babysaying.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "baiyangliu.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bankersonline.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "banqingdiao.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bbdos.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bcdonadio.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bedabox.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "belcompany.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "benhartmann.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "benmatthews.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "beryl.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "betcafearena.ro", "include_subdomains": true, "mode": "force-https" },
+    { "name": "betpamm.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bevinsco.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "beyondpricing.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bfi.wien", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bhuntr.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bierbaumer.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "billin.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "billpro.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bilrom.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bimbo.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bimbobakeriesusa.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "biofam.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bip.gov.sa", "include_subdomains": true, "mode": "force-https" },
+    { "name": "birkman.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bismarck.moe", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bit8.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bitshaker.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bittersweetcandybowl.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "blinkenlight.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "blinkenlight.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bluechilli.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "boilesen.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bookmein.in", "include_subdomains": true, "mode": "force-https" },
+    { "name": "boomerang.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "brd.ro", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bunsenlabs.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cabusar.fr", "include_subdomains": true, "mode": "force-https" },
+    { "name": "caizx.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "calix.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cando.eu", "include_subdomains": true, "mode": "force-https" },
+    { "name": "capitalquadatv.org.nz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cardstream.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "celec.gob.ec", "include_subdomains": true, "mode": "force-https" },
+    { "name": "centennialrewards.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "centerpereezd.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "centillien.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "centralpoint.be", "include_subdomains": true, "mode": "force-https" },
+    { "name": "centralpoint.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "centralstatecu.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "centrobill.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cerfrance.fr", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ceu.edu", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cgbilling.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "chamilo.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "chargejuice.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "charlierogers.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "checkyourmath.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "chepaofen.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "christianbargon.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cienbeaute-lidl.fr", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cigarterminal.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cittadesign.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "citya.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "clickenergy.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "clockworksms.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cmscafe.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "coffee-mamenoki.jp", "include_subdomains": true, "mode": "force-https" },
+    { "name": "coinessa.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "coloringnotebook.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "comfortticket.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "comparamejor.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "compareandrecycle.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "comparetravelinsurance.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "compuscan.co.za", "include_subdomains": true, "mode": "force-https" },
+    { "name": "connectingconcepts.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "constructdigital.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "contarkos.xyz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cookinglife.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cookmedical.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "coryadum.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "countybankdel.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "crazydomains.ae", "include_subdomains": true, "mode": "force-https" },
+    { "name": "crazydomains.co.nz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "crazydomains.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "crazydomains.in", "include_subdomains": true, "mode": "force-https" },
+    { "name": "crazyhotseeds.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "criena.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "crowdsupply.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cryptobin.co", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cryptocon.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cryptolab.tk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cselzer.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "csvape.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cutorrent.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "dalfiume.it", "include_subdomains": true, "mode": "force-https" },
+    { "name": "dargasia.is", "include_subdomains": true, "mode": "force-https" },
+    { "name": "darkshop.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "datacalle.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "datacandy.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "datarank.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "datewon.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "datortipsen.se", "include_subdomains": true, "mode": "force-https" },
+    { "name": "deer.team", "include_subdomains": true, "mode": "force-https" },
+    { "name": "detutorial.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "developmentaid.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "digminecraft.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "dijkmanmuziek.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "diodeled.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "divegearexpress.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "diybook.at", "include_subdomains": true, "mode": "force-https" },
+    { "name": "diycc.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "dndtools.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "donnons.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "dpd.com.pl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "drakefortreasurer.sexy", "include_subdomains": true, "mode": "force-https" },
+    { "name": "dreamtechie.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "dreizwosechs.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "drumbe.at", "include_subdomains": true, "mode": "force-https" },
+    { "name": "dunea.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "dycontrol.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ebankcbt.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ebp2p.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ecco-verde.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "edati.lv", "include_subdomains": true, "mode": "force-https" },
+    { "name": "educationunlimited.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "educator-one.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "eimacs.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "einheizpreis.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ekzarta.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "electricianforum.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "elenoon.ir", "include_subdomains": true, "mode": "force-https" },
+    { "name": "elglobo.com.mx", "include_subdomains": true, "mode": "force-https" },
+    { "name": "emaily.eu", "include_subdomains": true, "mode": "force-https" },
+    { "name": "emilyshepherd.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "energiekeurplus.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "englishforums.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "enviam.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ericdiao.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "escapees.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "estilos.com.pe", "include_subdomains": true, "mode": "force-https" },
+    { "name": "eternitylove.us", "include_subdomains": true, "mode": "force-https" },
+    { "name": "euroshop.or.at", "include_subdomains": true, "mode": "force-https" },
+    { "name": "everythingkitchens.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "expo-asia.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "extracobanks.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "factuursturen.be", "include_subdomains": true, "mode": "force-https" },
+    { "name": "factuursturen.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "faktura.pl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "familiegrottendieck.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "fashion.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "feard.space", "include_subdomains": true, "mode": "force-https" },
+    { "name": "fexco.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "fillmysuitca.se", "include_subdomains": true, "mode": "force-https" },
+    { "name": "finalgear.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "firecore.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "firexarxa.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "flaemig42.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "flanco.ro", "include_subdomains": true, "mode": "force-https" },
+    { "name": "flexport.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "fly.moe", "include_subdomains": true, "mode": "force-https" },
+    { "name": "fnb-griffinonline.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "forextimes.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "formationseeker.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "fossewaygardencentre.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "freelance.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "freesitemapgenerator.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "frezbo.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "fugle.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "functions-online.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "funnyang.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "funrun.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "g2a.co", "include_subdomains": true, "mode": "force-https" },
+    { "name": "gamoloco.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "gcsepod.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "gfhgiro.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "gifzilla.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "glubbforum.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "godesigner.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "goerner.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "goldmark.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "graciousmay.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "greatnet.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "grunex.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "grytics.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "gtlfsonlinepay.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "gunwatch.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "halo.fr", "include_subdomains": true, "mode": "force-https" },
+    { "name": "harmoney.co.nz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "harrisonsdirect.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "hashnode.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "haxo.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "hdfgroup.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "hellenicaward.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "helpmebuild.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "highseer.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "hilti.co.jp", "include_subdomains": true, "mode": "force-https" },
+    { "name": "hilti.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "hilti.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "hilti.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "hilti.com.hk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "hilti.com.sg", "include_subdomains": true, "mode": "force-https" },
+    { "name": "hilti.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "hilti.es", "include_subdomains": true, "mode": "force-https" },
+    { "name": "hilti.fi", "include_subdomains": true, "mode": "force-https" },
+    { "name": "hilti.fr", "include_subdomains": true, "mode": "force-https" },
+    { "name": "hilti.it", "include_subdomains": true, "mode": "force-https" },
+    { "name": "hilti.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "homehunting.pt", "include_subdomains": true, "mode": "force-https" },
+    { "name": "homeyou.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "hostedbgp.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "hotelmap.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "htmlacademy.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "humpteedumptee.in", "include_subdomains": true, "mode": "force-https" },
+    { "name": "huren.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "idlekernel.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "igotoffer.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ikeyless.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ilrg.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "imedikament.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "imeds.pl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "immigrationdirect.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "imusic.dk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "indusfastremit-us.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "indusfastremit.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "insighti.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "insighti.eu", "include_subdomains": true, "mode": "force-https" },
+    { "name": "insighti.sk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "iprice.co.id", "include_subdomains": true, "mode": "force-https" },
+    { "name": "iprice.hk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "iprice.my", "include_subdomains": true, "mode": "force-https" },
+    { "name": "iprice.ph", "include_subdomains": true, "mode": "force-https" },
+    { "name": "iprice.sg", "include_subdomains": true, "mode": "force-https" },
+    { "name": "iprice.vn", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ipricethailand.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "iprim.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "islandhosting.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "iterror.co", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ivpn.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "jabber.at", "include_subdomains": true, "mode": "force-https" },
+    { "name": "jackf.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "jamesburton.london", "include_subdomains": true, "mode": "force-https" },
+    { "name": "japaniac.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "jelly.cz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "jennybeaned.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "jr5proxdoug.xyz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "juhakoho.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kairion.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kaisers.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "karmaplatform.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "katekligys.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kefaloniatoday.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kenners.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kernl.us", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kerrfrequencycombs.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kgxtech.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kornersafe.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "krachtinverbinding.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kriegt.es", "include_subdomains": true, "mode": "force-https" },
+    { "name": "krizek.cc", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kubik-rubik.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kum.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kuponrazzi.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kynastonwedding.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "lacentral.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ldarby.me.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "leatherfurnitureexpo.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "leopotamgroup.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "libscode.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "lifeinitsownway.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "linkenheil.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "linkmaker.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "linkonaut.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "linpx.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "liquidcomm.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "loadingdeck.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "locomotive.ca", "include_subdomains": true, "mode": "force-https" },
+    { "name": "loony.info", "include_subdomains": true, "mode": "force-https" },
+    { "name": "lovemomiji.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "lpak.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "lufthansaexperts.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "lynkos.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "m.nu", "include_subdomains": true, "mode": "force-https" },
+    { "name": "madebymagnitude.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "madtec.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mail4you.in", "include_subdomains": true, "mode": "force-https" },
+    { "name": "malwaretips.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "manueli.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "marbogardenlidkoping.se", "include_subdomains": true, "mode": "force-https" },
+    { "name": "masterhaus.bg", "include_subdomains": true, "mode": "force-https" },
+    { "name": "matthewprenger.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "maxserver.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mbilker.us", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mcdonalds.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mealgoo.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "memberpress.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mhertel.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mhict.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "michel-wein.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mightysounds.cz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mikeybot.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "miku.be", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mitnetz-strom.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mmonit.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mobal.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "monobank.no", "include_subdomains": true, "mode": "force-https" },
+    { "name": "morganino.eu", "include_subdomains": true, "mode": "force-https" },
+    { "name": "moveek.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "movember.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mpac.ca", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mtg-tutor.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mtnz.co.za", "include_subdomains": true, "mode": "force-https" },
+    { "name": "multibit.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mutuelle.fr", "include_subdomains": true, "mode": "force-https" },
+    { "name": "myclientsplus.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "myconan.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mysmelly.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "myworkinfo.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "myzone.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "nagelfam.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "namacindia.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "natuurbehangnederland.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "navstevnik.sk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "nct.org.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ndbt.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "netmagik.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "neuwal.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "nfo.so", "include_subdomains": true, "mode": "force-https" },
+    { "name": "nohats.ca", "include_subdomains": true, "mode": "force-https" },
+    { "name": "northcutt.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "nos-medias.fr", "include_subdomains": true, "mode": "force-https" },
+    { "name": "notjustbitchy.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "novatrucking.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "novelfeed.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "nshost.ro", "include_subdomains": true, "mode": "force-https" },
+    { "name": "numberoneshoes.co.nz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "nyiad.edu", "include_subdomains": true, "mode": "force-https" },
+    { "name": "nyip.edu", "include_subdomains": true, "mode": "force-https" },
+    { "name": "oaic.gov.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "olafnorge.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "onmarketbookbuilds.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ono.es", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ononpay.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "oost.io", "include_subdomains": true, "mode": "force-https" },
+    { "name": "openvz.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "opium.io", "include_subdomains": true, "mode": "force-https" },
+    { "name": "optumrxhealthstore.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "orcamoney.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "orionfcu.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "orlives.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "osmosis.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "outdoorproducts.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "overthinkingit.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "oxynux.fr", "include_subdomains": true, "mode": "force-https" },
+    { "name": "pagewizz.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "panamaequity.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "parkingpoint.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "particonpsplus.it", "include_subdomains": true, "mode": "force-https" },
+    { "name": "passwordrevelator.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "payment-network.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "payoff.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "paytm.in", "include_subdomains": true, "mode": "force-https" },
+    { "name": "payupay.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "pcforum.sk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "pedicureduiven.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "pedroventura.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "penablog.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "pensiunealido.ro", "include_subdomains": true, "mode": "force-https" },
+    { "name": "peoplesbankal.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "pepperworldhotshop.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "pethub.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "pharmgkb.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "philadelphia.com.mx", "include_subdomains": true, "mode": "force-https" },
+    { "name": "picoauto.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "picotech.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "picscare.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "pincha.com.tw", "include_subdomains": true, "mode": "force-https" },
+    { "name": "pinkcasino.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "pisexy.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "pixelminers.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "plainjs.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "planete-cocoon.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "plexusmd.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "politologos.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "polypet.com.sg", "include_subdomains": true, "mode": "force-https" },
+    { "name": "posylka.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ppro.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "prezola.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "pro-link.eu", "include_subdomains": true, "mode": "force-https" },
+    { "name": "projectarmy.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "punknews.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "pvcvoordeel.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "qewc.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "quera.ir", "include_subdomains": true, "mode": "force-https" },
+    { "name": "quire.io", "include_subdomains": true, "mode": "force-https" },
+    { "name": "racius.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "redit.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "reezer.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "regenbogenwald.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "renrenche.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "retrofitlab.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "rheuma-online.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "rhymix.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "riaucybersolution.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "rk6.cz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "roundtheme.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "royzez.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "rtd.uk.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "runtondev.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "safcstore.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sakaserver.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "salesmachine.io", "include_subdomains": true, "mode": "force-https" },
+    { "name": "salon.io", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sampoznay.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sandviks.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sardegnatirocini.it", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sat4all.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "schont.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "schwarzkopfforyou.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "selectorders.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "serveradminz.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "shawnh.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "shoplandia.co", "include_subdomains": true, "mode": "force-https" },
+    { "name": "siriuspup.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sitsy.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sixt.ch", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sixt.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sixt.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sixt.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sixt.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "skyway.capital", "include_subdomains": true, "mode": "force-https" },
+    { "name": "slotboss.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "smartsparrow.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "smittix.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "smove.sg", "include_subdomains": true, "mode": "force-https" },
+    { "name": "snelwerk.be", "include_subdomains": true, "mode": "force-https" },
+    { "name": "snoqualmiefiber.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sofort.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sofortueberweisung.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sosaka.ml", "include_subdomains": true, "mode": "force-https" },
+    { "name": "soundgasm.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "souyidai.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "spectrosoftware.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sperrstun.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "spiegels.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "stalker-shop.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "stephanierxo.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "stocktrader.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "stoffelen.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "stolina.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "stormyyd.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "strom.family", "include_subdomains": true, "mode": "force-https" },
+    { "name": "studentskydenik.cz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sudo.ws", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sunbritetv.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "suneilpatel.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "supcro.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "superbshare.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "supersalescontest.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "svijet-medija.hr", "include_subdomains": true, "mode": "force-https" },
+    { "name": "swimming.ca", "include_subdomains": true, "mode": "force-https" },
+    { "name": "swite.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "syncmylife.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tablotv.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "talentcast.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tasmansecurity.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "teachercreatedmaterials.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "teamtouring.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "terrastaffinggroup.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "textburst.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "texter-linz.at", "include_subdomains": true, "mode": "force-https" },
+    { "name": "thebikeinsurer.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "thecandidforum.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "thedisc.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "theinitium.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "theseed.io", "include_subdomains": true, "mode": "force-https" },
+    { "name": "theseletarmall.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "thiswebhost.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "thomasbreads.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "thomashunter.name", "include_subdomains": true, "mode": "force-https" },
+    { "name": "thomaskliszowski.fr", "include_subdomains": true, "mode": "force-https" },
+    { "name": "threedpro.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tiendschuurstraat.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tiplanet.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tkarstens.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tmprod.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tomeara.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "top-stage.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "toysperiod.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "trabbel.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "trackchair.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tradeacademy.in", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tradedesk.co.za", "include_subdomains": true, "mode": "force-https" },
+    { "name": "transformify.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "trell.co.in", "include_subdomains": true, "mode": "force-https" },
+    { "name": "trineco.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "trineco.fi", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tssouthernpower.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tuxz.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "u-blox.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "uangteman.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ui8.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "umassfive.coop", "include_subdomains": true, "mode": "force-https" },
+    { "name": "unicef.pl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "unicredit.ba", "include_subdomains": true, "mode": "force-https" },
+    { "name": "unicredit.ro", "include_subdomains": true, "mode": "force-https" },
+    { "name": "unicreditbank.hu", "include_subdomains": true, "mode": "force-https" },
+    { "name": "unicreditbank.rs", "include_subdomains": true, "mode": "force-https" },
+    { "name": "unicreditbank.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "unseen.tw", "include_subdomains": true, "mode": "force-https" },
+    { "name": "unyq.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "uplinklabs.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "uptic.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "us-immigration.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "uscitizenship.info", "include_subdomains": true, "mode": "force-https" },
+    { "name": "usd.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "useresponse.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "userify.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "usimmigration.us", "include_subdomains": true, "mode": "force-https" },
+    { "name": "usitcolours.bg", "include_subdomains": true, "mode": "force-https" },
+    { "name": "usparklodging.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "validbrands.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "veggiesbourg.fr", "include_subdomains": true, "mode": "force-https" },
+    { "name": "velasense.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "verifikatorindonesia.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "versia.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "veryhax.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "viaprinto.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "vide-greniers.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "vinilosdecorativos.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "vitta.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "vivaldi.club", "include_subdomains": true, "mode": "force-https" },
+    { "name": "vivatv.com.tw", "include_subdomains": true, "mode": "force-https" },
+    { "name": "vizeat.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "vorodevops.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "vpn.ht", "include_subdomains": true, "mode": "force-https" },
+    { "name": "vulners.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "wail.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "walkingforhealth.org.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "weather-and-climate.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "web.cc", "include_subdomains": true, "mode": "force-https" },
+    { "name": "webtobesocial.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "webzanem.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "weekdone.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "weekly-residence.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "weisse-liste.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "wellacapability.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "werally.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "westsuburbanbank.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "wftda.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "wideboxmacau.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "wienholding.at", "include_subdomains": true, "mode": "force-https" },
+    { "name": "wind.moe", "include_subdomains": true, "mode": "force-https" },
+    { "name": "winshiplending.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "wizzley.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "wkv.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "wnu.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "word-grabber.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "wunderkarten.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ximage.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "xmerak.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "xotika.tv", "include_subdomains": true, "mode": "force-https" },
+    { "name": "xtronics.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "yosemo.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "yufan.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "zadroweb.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "zberger.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "zizoo.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "zju.tv", "include_subdomains": true, "mode": "force-https" },
+    { "name": "zjubtv.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "zoe.vc", "include_subdomains": true, "mode": "force-https" },
+    { "name": "zoznamrealit.sk", "include_subdomains": true, "mode": "force-https" }
   ],
 
   // |ReportUMAOnPinFailure| uses these to report which domain was associated
diff --git a/net/net.gyp b/net/net.gyp
index 06b080a..7fe7e3d8 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -791,6 +791,18 @@
       ],
     },
     {
+      'target_name': 'cachetool',
+      'type': 'executable',
+      'dependencies': [
+        '../base/base.gyp:base',
+        'net',
+        'net_test_support',
+      ],
+      'sources': [
+        'tools/cachetool/cachetool.cc',
+      ],
+    },
+    {
       'target_name': 'dump_cache',
       'type': 'executable',
       'dependencies': [
diff --git a/net/net.gypi b/net/net.gypi
index 2f7fd9e..450e9b7 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -47,8 +47,6 @@
       'base/net_module.cc',
       'base/net_module.h',
       'base/net_string_util.h',
-      'base/net_util.cc',
-      'base/net_util.h',
       'base/network_interfaces.cc',
       'base/network_interfaces.h',
       'base/network_interfaces_posix.cc',
@@ -726,8 +724,6 @@
       'disk_cache/memory/mem_backend_impl.h',
       'disk_cache/memory/mem_entry_impl.cc',
       'disk_cache/memory/mem_entry_impl.h',
-      'disk_cache/memory/mem_rankings.cc',
-      'disk_cache/memory/mem_rankings.h',
       'disk_cache/net_log_parameters.cc',
       'disk_cache/net_log_parameters.h',
       'disk_cache/simple/simple_backend_impl.cc',
@@ -1337,7 +1333,6 @@
       'base/lookup_string_in_fixed_set_unittest.cc',
       'base/mime_sniffer_unittest.cc',
       'base/mime_util_unittest.cc',
-      'base/net_util_unittest.cc',
       'base/network_activity_monitor_unittest.cc',
       'base/network_change_notifier_unittest.cc',
       'base/network_change_notifier_win_unittest.cc',
@@ -1353,7 +1348,7 @@
       'base/static_cookie_policy_unittest.cc',
       'base/test_completion_callback_unittest.cc',
       'base/test_proxy_delegate.cc',
-      'base/test_proxy_delegate.h',      
+      'base/test_proxy_delegate.h',
       'base/upload_bytes_element_reader_unittest.cc',
       'base/upload_file_element_reader_unittest.cc',
       'base/url_util_unittest.cc',
@@ -1396,6 +1391,7 @@
       'cookies/canonical_cookie_unittest.cc',
       'cookies/cookie_constants_unittest.cc',
       'cookies/cookie_monster_unittest.cc',
+      'cookies/cookie_store_unittest.cc',
       'cookies/cookie_util_unittest.cc',
       'cookies/parsed_cookie_unittest.cc',
       'der/input_unittest.cc',
diff --git a/net/quic/p2p/quic_p2p_session.cc b/net/quic/p2p/quic_p2p_session.cc
index 0c1be86..e198399 100644
--- a/net/quic/p2p/quic_p2p_session.cc
+++ b/net/quic/p2p/quic_p2p_session.cc
@@ -31,9 +31,7 @@
   // ToString() to format addresses for logging and ToString() is not allowed
   // for empty addresses.
   // TODO(sergeyu): Fix QuicConnection and remove SetSelfAddress() call below.
-  net::IPAddress ip;
-  bool success = ip.AssignFromIPLiteral("0.0.0.0");
-  DCHECK(success);
+  net::IPAddress ip(0, 0, 0, 0);
   this->connection()->SetSelfAddress(net::IPEndPoint(ip, 0));
 }
 
diff --git a/net/quic/p2p/quic_p2p_session_test.cc b/net/quic/p2p/quic_p2p_session_test.cc
index 75d1f2c8..88dc76c 100644
--- a/net/quic/p2p/quic_p2p_session_test.cc
+++ b/net/quic/p2p/quic_p2p_session_test.cc
@@ -228,8 +228,7 @@
                                               Perspective perspective) {
     net::QuicChromiumPacketWriter* writer =
         new net::QuicChromiumPacketWriter(socket.get());
-    net::IPAddress ip;
-    EXPECT_TRUE(ip.AssignFromIPLiteral("0.0.0.0"));
+    net::IPAddress ip(0, 0, 0, 0);
     scoped_ptr<QuicConnection> quic_connection1(new QuicConnection(
         0, net::IPEndPoint(ip, 0), &quic_helper_, writer,
         true /* owns_writer */, perspective, QuicSupportedVersions()));
diff --git a/net/quic/quic_address_mismatch_test.cc b/net/quic/quic_address_mismatch_test.cc
index 3bb9472..1946baf 100644
--- a/net/quic/quic_address_mismatch_test.cc
+++ b/net/quic/quic_address_mismatch_test.cc
@@ -5,7 +5,6 @@
 #include "net/quic/quic_address_mismatch.h"
 
 #include "net/base/ip_endpoint.h"
-#include "net/base/net_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace net {
diff --git a/net/quic/quic_end_to_end_unittest.cc b/net/quic/quic_end_to_end_unittest.cc
index b35021e..10cfc97 100644
--- a/net/quic/quic_end_to_end_unittest.cc
+++ b/net/quic/quic_end_to_end_unittest.cc
@@ -167,8 +167,7 @@
 
   // Starts the QUIC server listening on a random port.
   void StartServer() {
-    IPAddress ip;
-    CHECK(ip.AssignFromIPLiteral("127.0.0.1"));
+    IPAddress ip(127, 0, 0, 1);
     server_address_ = IPEndPoint(ip, 0);
     server_config_.SetInitialStreamFlowControlWindowToSend(
         kInitialStreamFlowControlWindowForTest);
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index 16cc99c8..01796c4 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -143,8 +143,7 @@
         stream_id_(kClientDataStreamId1),
         maker_(GetParam(), connection_id_, &clock_, kDefaultServerHostName),
         random_generator_(0) {
-    IPAddress ip;
-    CHECK(ip.AssignFromIPLiteral("192.0.2.33"));
+    IPAddress ip(192, 0, 2, 33);
     peer_addr_ = IPEndPoint(ip, 443);
     self_addr_ = IPEndPoint(ip, 8435);
     clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(20));
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index c6b4527..b5a8d6d 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -204,6 +204,9 @@
     request_.load_flags = 0;
     clock_->AdvanceTime(QuicTime::Delta::FromMilliseconds(20));
 
+    params_.parse_alternative_services = true;
+    params_.enable_alternative_service_with_different_host = true;
+
     scoped_refptr<X509Certificate> cert(
         ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
     verify_details_.cert_verify_result.verified_cert = cert;
@@ -407,15 +410,9 @@
         packet_number, stream_id, should_include_version, fin, headers, offset);
   }
 
-  void CreateSession() { CreateSessionWithFactory(&socket_factory_, false); }
+  void CreateSession() { CreateSessionWithFactory(&socket_factory_); }
 
-  void CreateSessionWithNextProtos() {
-    CreateSessionWithFactory(&socket_factory_, true);
-  }
-
-  // If |use_next_protos| is true, enables SPDY and QUIC.
-  void CreateSessionWithFactory(ClientSocketFactory* socket_factory,
-                                bool use_next_protos) {
+  void CreateSessionWithFactory(ClientSocketFactory* socket_factory) {
     params_.enable_quic = true;
     params_.quic_clock = clock_;
     params_.quic_random = &random_generator_;
@@ -441,11 +438,6 @@
 
     test_network_quality_estimator_->AddRTTObserver(&rtt_observer_);
 
-    if (use_next_protos) {
-      params_.parse_alternative_services = true;
-      params_.enable_alternative_service_with_different_host = true;
-    }
-
     session_.reset(new HttpNetworkSession(params_));
     session_->quic_stream_factory()->set_require_confirmation(false);
     ASSERT_EQ(params_.quic_socket_receive_buffer_size,
@@ -634,6 +626,8 @@
   // the alternate-protocol job will "win".
   AddHangingNonAlternateProtocolSocketData();
 
+  params_.parse_alternative_services = false;
+  params_.enable_alternative_service_with_different_host = false;
   CreateSession();
 
   EXPECT_FALSE(rtt_observer_.rtt_notification_received());
@@ -703,6 +697,8 @@
   // no attempt will be made to speak to the proxy over TCP.
 
   request_.url = GURL("http://mail.example.org/");
+  params_.parse_alternative_services = false;
+  params_.enable_alternative_service_with_different_host = false;
   CreateSession();
 
   SendRequestAndExpectQuicResponseFromProxyOnPort("hello!", 70);
@@ -750,7 +746,7 @@
 
   request_.url = GURL("http://" + origin_host);
   AddHangingNonAlternateProtocolSocketData();
-  CreateSessionWithNextProtos();
+  CreateSession();
   AddQuicAlternateProtocolMapping(MockCryptoClientStream::CONFIRM_HANDSHAKE);
   SendRequestAndExpectQuicResponseFromProxyOnPort("hello!", 70);
 }
@@ -792,7 +788,7 @@
   AddQuicRemoteAlternativeServiceMapping(
       MockCryptoClientStream::CONFIRM_HANDSHAKE, alternative);
   AddHangingNonAlternateProtocolSocketData();
-  CreateSessionWithNextProtos();
+  CreateSession();
 
   SendRequestAndExpectQuicResponse("hello!");
 }
@@ -812,6 +808,8 @@
   mock_quic_data1.AddSocketDataToFactory(&socket_factory_);
   mock_quic_data2.AddSocketDataToFactory(&socket_factory_);
 
+  params_.parse_alternative_services = false;
+  params_.enable_alternative_service_with_different_host = false;
   CreateSession();
 
   EXPECT_EQ(0U, test_network_quality_estimator_->watcher_count());
@@ -841,6 +839,8 @@
   SSLSocketDataProvider ssl(ASYNC, OK);
   socket_factory_.AddSSLSocketDataProvider(&ssl);
 
+  params_.parse_alternative_services = false;
+  params_.enable_alternative_service_with_different_host = false;
   CreateSession();
 
   SendRequestAndExpectHttpResponse("hello world");
@@ -874,7 +874,7 @@
   mock_quic_data.AddSocketDataToFactory(&socket_factory_);
 
   AddHangingNonAlternateProtocolSocketData();
-  CreateSessionWithNextProtos();
+  CreateSession();
 
   SendRequestAndExpectHttpResponse("hello world");
   SendRequestAndExpectQuicResponse("hello!");
@@ -909,7 +909,7 @@
   mock_quic_data.AddSocketDataToFactory(&socket_factory_);
 
   AddHangingNonAlternateProtocolSocketData();
-  CreateSessionWithNextProtos();
+  CreateSession();
 
   SendRequestAndExpectHttpResponse("hello world");
   SendRequestAndExpectQuicResponse("hello!");
@@ -932,7 +932,7 @@
   socket_factory_.AddSocketDataProvider(&http_data);
   socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
 
-  CreateSessionWithNextProtos();
+  CreateSession();
 
   SendRequestAndExpectHttpResponse("hello world");
   SendRequestAndExpectHttpResponse("hello world");
@@ -993,7 +993,7 @@
   mock_quic_data.AddSocketDataToFactory(&socket_factory_);
 
   AddHangingNonAlternateProtocolSocketData();
-  CreateSessionWithNextProtos();
+  CreateSession();
 
   SendRequestAndExpectHttpResponse("hello world");
 
@@ -1083,7 +1083,7 @@
 
   AddHangingNonAlternateProtocolSocketData();
 
-  CreateSessionWithNextProtos();
+  CreateSession();
 
   SendRequestAndExpectHttpResponse("hello world");
   SendRequestAndExpectQuicResponseOnPort("hello from foo!", 443);
@@ -1160,7 +1160,7 @@
   mock_quic_data.AddSocketDataToFactory(&socket_factory_);
   AddHangingNonAlternateProtocolSocketData();
 
-  CreateSessionWithNextProtos();
+  CreateSession();
 
   // Send two HTTP requests, responses set up alt-svc lists for the origins.
   request_.url = GURL("https://www.example.org/");
@@ -1256,7 +1256,7 @@
   mock_quic_data2.AddSocketDataToFactory(&socket_factory_);
   AddHangingNonAlternateProtocolSocketData();
 
-  CreateSessionWithNextProtos();
+  CreateSession();
 
   // Send HTTP requests, responses set up the alt-svc lists for the origins.
   SendRequestAndExpectHttpResponse("hello world from mail.example.org");
@@ -1301,7 +1301,7 @@
   mock_quic_data.AddSocketDataToFactory(&socket_factory_);
 
   AddHangingNonAlternateProtocolSocketData();
-  CreateSessionWithNextProtos();
+  CreateSession();
 
   SendRequestAndExpectHttpResponse("hello world");
   SendRequestAndExpectQuicResponseOnPort("hello!", 137);
@@ -1334,7 +1334,7 @@
   mock_quic_data.AddSocketDataToFactory(&socket_factory_);
 
   AddHangingNonAlternateProtocolSocketData();
-  CreateSessionWithNextProtos();
+  CreateSession();
 
   AlternativeService alternative_service(QUIC,
                                          HostPortPair::FromURL(request_.url));
@@ -1380,7 +1380,7 @@
 
   AddHangingNonAlternateProtocolSocketData();
   params_.alternative_service_probability_threshold = 0.25;
-  CreateSessionWithNextProtos();
+  CreateSession();
 
   SendRequestAndExpectHttpResponse("hello world");
   SendRequestAndExpectQuicResponse("hello!");
@@ -1402,7 +1402,7 @@
   socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
 
   params_.alternative_service_probability_threshold = 0.75;
-  CreateSessionWithNextProtos();
+  CreateSession();
 
   SendRequestAndExpectHttpResponse("hello world");
   SendRequestAndExpectHttpResponse("hello world");
@@ -1424,7 +1424,7 @@
   socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
 
   params_.alternative_service_probability_threshold = 0.75;
-  CreateSessionWithNextProtos();
+  CreateSession();
 
   SendRequestAndExpectHttpResponse("hello world");
   SendRequestAndExpectHttpResponse("hello world");
@@ -1456,7 +1456,7 @@
   mock_quic_data.AddSocketDataToFactory(&socket_factory_);
 
   AddHangingNonAlternateProtocolSocketData();
-  CreateSessionWithNextProtos();
+  CreateSession();
 
   // TODO(rtenneti): Test QUIC over HTTPS, GetSSLInfo().
   SendRequestAndExpectHttpResponse("hello world");
@@ -1492,7 +1492,9 @@
   // the alternate-protocol job will "win".
   AddHangingNonAlternateProtocolSocketData();
 
-  CreateSessionWithNextProtos();
+  params_.parse_alternative_services = false;
+  params_.parse_alternative_services = false;
+  CreateSession();
 
   SendRequestAndExpectHttpResponse("hello world");
   SendRequestAndExpectQuicResponse("hello!");
@@ -1529,7 +1531,8 @@
   // the alternate-protocol job will "win".
   AddHangingNonAlternateProtocolSocketData();
 
-  CreateSessionWithNextProtos();
+  params_.parse_alternative_services = false;
+  CreateSession();
 
   SendRequestAndExpectHttpResponse("hello world");
   SendRequestAndExpectQuicResponseOnPort("hello!", 137);
@@ -1565,7 +1568,8 @@
   // the alternate-protocol job will "win".
   AddHangingNonAlternateProtocolSocketData();
 
-  CreateSessionWithNextProtos();
+  params_.parse_alternative_services = false;
+  CreateSession();
 
   AlternativeService alternative_service(QUIC,
                                          HostPortPair::FromURL(request_.url));
@@ -1584,6 +1588,7 @@
 }
 
 TEST_P(QuicNetworkTransactionTest, UseAlternateProtocolProbabilityForQuic) {
+  params_.parse_alternative_services = false;
   MockRead http_reads[] = {
       MockRead("HTTP/1.1 200 OK\r\n"),
       MockRead(kQuicAlternateProtocol50pctHeader), MockRead("hello world"),
@@ -1613,13 +1618,15 @@
   AddHangingNonAlternateProtocolSocketData();
 
   params_.alternative_service_probability_threshold = .25;
-  CreateSessionWithNextProtos();
+  params_.parse_alternative_services = false;
+  CreateSession();
 
   SendRequestAndExpectHttpResponse("hello world");
   SendRequestAndExpectQuicResponse("hello!");
 }
 
 TEST_P(QuicNetworkTransactionTest, DontUseAlternateProtocolProbabilityForQuic) {
+  params_.parse_alternative_services = false;
   MockRead http_reads[] = {
       MockRead("HTTP/1.1 200 OK\r\n"),
       MockRead(kQuicAlternateProtocol50pctHeader), MockRead("hello world"),
@@ -1634,7 +1641,7 @@
   socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
 
   params_.alternative_service_probability_threshold = .75;
-  CreateSessionWithNextProtos();
+  CreateSession();
 
   SendRequestAndExpectHttpResponse("hello world");
   SendRequestAndExpectHttpResponse("hello world");
@@ -1642,6 +1649,7 @@
 
 TEST_P(QuicNetworkTransactionTest,
        DontUseAlternateProtocolWithBadProbabilityForQuic) {
+  params_.parse_alternative_services = false;
   MockRead http_reads[] = {
       MockRead("HTTP/1.1 200 OK\r\n"),
       MockRead("Alternate-Protocol: 443:quic,p=2\r\n\r\n"),
@@ -1657,13 +1665,14 @@
   socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
 
   params_.alternative_service_probability_threshold = .75;
-  CreateSessionWithNextProtos();
+  CreateSession();
 
   SendRequestAndExpectHttpResponse("hello world");
   SendRequestAndExpectHttpResponse("hello world");
 }
 
 TEST_P(QuicNetworkTransactionTest, UseAlternateProtocolForQuicForHttps) {
+  params_.parse_alternative_services = false;
   MockRead http_reads[] = {
       MockRead("HTTP/1.1 200 OK\r\n"), MockRead(kQuicAlternateProtocolHeader),
       MockRead("hello world"),
@@ -1692,7 +1701,7 @@
   // the alternate-protocol job will "win".
   AddHangingNonAlternateProtocolSocketData();
 
-  CreateSessionWithNextProtos();
+  CreateSession();
 
   // TODO(rtenneti): Test QUIC over HTTPS, GetSSLInfo().
   SendRequestAndExpectHttpResponse("hello world");
@@ -1744,7 +1753,7 @@
     refused_data.set_connect_data(refused_connect);
     socket_factory_.AddSocketDataProvider(&refused_data);
 
-    CreateSessionWithNextProtos();
+    CreateSession();
     AlternativeService alternative_service(QUIC, alternative);
     base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
     session_->http_server_properties()->SetAlternativeService(
@@ -1781,6 +1790,7 @@
 }
 
 TEST_P(QuicNetworkTransactionTest, HungAlternateProtocol) {
+  params_.parse_alternative_services = false;
   crypto_client_stream_factory_.set_handshake_mode(
       MockCryptoClientStream::COLD_START);
 
@@ -1816,7 +1826,7 @@
   socket_factory.AddSocketDataProvider(&http_data2);
   socket_factory.AddSSLSocketDataProvider(&ssl_data_);
 
-  CreateSessionWithFactory(&socket_factory, true);
+  CreateSessionWithFactory(&socket_factory);
 
   // Run the first request.
   SendRequestAndExpectHttpResponse("hello world");
@@ -1852,7 +1862,7 @@
   // the alternate-protocol job will "win".
   AddHangingNonAlternateProtocolSocketData();
 
-  CreateSessionWithNextProtos();
+  CreateSession();
   AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
   SendRequestAndExpectQuicResponse("hello!");
 }
@@ -1882,7 +1892,7 @@
   host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(),
                          nullptr, net_log_.bound());
 
-  CreateSessionWithNextProtos();
+  CreateSession();
   AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
   SendRequestAndExpectQuicResponse("hello!");
 }
@@ -1917,7 +1927,7 @@
                          nullptr, net_log_.bound());
 
   request_.url = GURL("http://mail.example.org/");
-  CreateSessionWithNextProtos();
+  CreateSession();
   AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
   SendRequestAndExpectHttpResponse("hello world");
 }
@@ -1952,7 +1962,7 @@
   host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(),
                          nullptr, net_log_.bound());
 
-  CreateSessionWithNextProtos();
+  CreateSession();
   session_->quic_stream_factory()->set_require_confirmation(true);
   AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
 
@@ -1998,7 +2008,7 @@
   host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(),
                          nullptr, net_log_.bound());
 
-  CreateSessionWithNextProtos();
+  CreateSession();
   session_->quic_stream_factory()->set_require_confirmation(true);
   AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
 
@@ -2053,7 +2063,7 @@
   host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(),
                          nullptr, net_log_.bound());
 
-  CreateSessionWithNextProtos();
+  CreateSession();
   session_->quic_stream_factory()->set_require_confirmation(true);
   AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
 
@@ -2096,7 +2106,7 @@
   socket_factory_.AddSocketDataProvider(&http_data);
   socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
 
-  CreateSessionWithNextProtos();
+  CreateSession();
   AddQuicAlternateProtocolMapping(MockCryptoClientStream::COLD_START);
   SendRequestAndExpectHttpResponse("hello from http");
   ExpectBrokenAlternateProtocolMapping();
@@ -2122,7 +2132,7 @@
   socket_factory_.AddSocketDataProvider(&http_data);
   socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
 
-  CreateSessionWithNextProtos();
+  CreateSession();
 
   AddQuicAlternateProtocolMapping(MockCryptoClientStream::COLD_START);
   SendRequestAndExpectHttpResponse("hello from http");
@@ -2149,7 +2159,7 @@
   socket_factory_.AddSocketDataProvider(&http_data);
   socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
 
-  CreateSessionWithNextProtos();
+  CreateSession();
 
   AddQuicAlternateProtocolMapping(MockCryptoClientStream::COLD_START);
   scoped_ptr<HttpNetworkTransaction> trans(
@@ -2188,7 +2198,7 @@
   socket_factory_.AddSocketDataProvider(&http_data);
   socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
 
-  CreateSessionWithNextProtos();
+  CreateSession();
 
   AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
 
@@ -2219,7 +2229,7 @@
                                      0);
   socket_factory_.AddSocketDataProvider(&http_data);
 
-  CreateSessionWithNextProtos();
+  CreateSession();
 
   AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
 
@@ -2244,7 +2254,7 @@
   socket_factory_.AddSocketDataProvider(&http_data);
   socket_factory_.AddSSLSocketDataProvider(&ssl_data_);
 
-  CreateSessionWithNextProtos();
+  CreateSession();
   AddQuicAlternateProtocolMapping(MockCryptoClientStream::COLD_START);
   SendRequestAndExpectHttpResponse("hello from http");
 
@@ -2283,7 +2293,7 @@
   host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address, CompletionCallback(),
                          nullptr, net_log_.bound());
 
-  CreateSessionWithNextProtos();
+  CreateSession();
   AddQuicAlternateProtocolMapping(MockCryptoClientStream::ZERO_RTT);
   SendRequestAndExpectHttpResponse("hello world");
 }
@@ -2305,7 +2315,7 @@
 
   request_.url = GURL("https://www.example.org:443");
   AddHangingNonAlternateProtocolSocketData();
-  CreateSessionWithNextProtos();
+  CreateSession();
   AddQuicAlternateProtocolMapping(MockCryptoClientStream::CONFIRM_HANDSHAKE);
   SendRequestAndExpectQuicResponse("hello!");
   EXPECT_TRUE(rtt_observer_.rtt_notification_received());
@@ -2325,6 +2335,8 @@
   // the alternate-protocol job will "win".
   AddHangingNonAlternateProtocolSocketData();
 
+  params_.parse_alternative_services = false;
+  params_.enable_alternative_service_with_different_host = false;
   CreateSession();
   request_.method = "POST";
   ChunkedUploadDataStream upload_data(0);
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index eed392cf..c94b092 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -449,9 +449,7 @@
 }
 
 IPAddress Loopback4() {
-  IPAddress addr;
-  CHECK(addr.AssignFromIPLiteral("127.0.0.1"));
-  return addr;
+  return IPAddress(127, 0, 0, 1);
 }
 
 IPAddress Loopback6() {
@@ -461,9 +459,7 @@
 }
 
 IPAddress Any4() {
-  IPAddress any4;
-  CHECK(any4.AssignFromIPLiteral("0.0.0.0"));
-  return any4;
+  return IPAddress(0, 0, 0, 0);
 }
 
 void GenerateBody(string* body, int length) {
diff --git a/net/server/http_server_unittest.cc b/net/server/http_server_unittest.cc
index bda95d11..545cf33 100644
--- a/net/server/http_server_unittest.cc
+++ b/net/server/http_server_unittest.cc
@@ -30,7 +30,6 @@
 #include "net/base/io_buffer.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/test_completion_callback.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_util.h"
diff --git a/net/socket/socket_net_log_params.cc b/net/socket/socket_net_log_params.cc
index 37be0a6..347644a 100644
--- a/net/socket/socket_net_log_params.cc
+++ b/net/socket/socket_net_log_params.cc
@@ -10,7 +10,6 @@
 #include "base/values.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/ip_endpoint.h"
-#include "net/base/net_util.h"
 
 namespace net {
 
diff --git a/net/socket/socks5_client_socket.cc b/net/socket/socks5_client_socket.cc
index 20baaf2..bcc4259 100644
--- a/net/socket/socks5_client_socket.cc
+++ b/net/socket/socks5_client_socket.cc
@@ -13,7 +13,6 @@
 #include "base/sys_byteorder.h"
 #include "base/trace_event/trace_event.h"
 #include "net/base/io_buffer.h"
-#include "net/base/net_util.h"
 #include "net/log/net_log.h"
 #include "net/socket/client_socket_handle.h"
 
diff --git a/net/socket/socks_client_socket.cc b/net/socket/socks_client_socket.cc
index 633f12e3..ce5daac 100644
--- a/net/socket/socks_client_socket.cc
+++ b/net/socket/socks_client_socket.cc
@@ -11,7 +11,6 @@
 #include "base/compiler_specific.h"
 #include "base/sys_byteorder.h"
 #include "net/base/io_buffer.h"
-#include "net/base/net_util.h"
 #include "net/log/net_log.h"
 #include "net/socket/client_socket_handle.h"
 
diff --git a/net/socket/tcp_client_socket.cc b/net/socket/tcp_client_socket.cc
index 700fa1c..d52f08c4 100644
--- a/net/socket/tcp_client_socket.cc
+++ b/net/socket/tcp_client_socket.cc
@@ -14,7 +14,6 @@
 #include "net/base/io_buffer.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 
 namespace net {
 
diff --git a/net/socket/tcp_client_socket_unittest.cc b/net/socket/tcp_client_socket_unittest.cc
index 5e0d948c..04c0a59 100644
--- a/net/socket/tcp_client_socket_unittest.cc
+++ b/net/socket/tcp_client_socket_unittest.cc
@@ -10,7 +10,6 @@
 
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/test_completion_callback.h"
 #include "net/socket/tcp_server_socket.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/net/socket/transport_client_socket_pool_test_util.cc b/net/socket/transport_client_socket_pool_test_util.cc
index 0140c255e..37333db 100644
--- a/net/socket/transport_client_socket_pool_test_util.cc
+++ b/net/socket/transport_client_socket_pool_test_util.cc
@@ -18,7 +18,6 @@
 #include "net/base/ip_endpoint.h"
 #include "net/base/load_timing_info.h"
 #include "net/base/load_timing_info_test_util.h"
-#include "net/base/net_util.h"
 #include "net/socket/client_socket_handle.h"
 #include "net/socket/ssl_client_socket.h"
 #include "net/udp/datagram_client_socket.h"
diff --git a/net/socket/transport_client_socket_pool_unittest.cc b/net/socket/transport_client_socket_pool_unittest.cc
index aeab2b1..5fa1dec 100644
--- a/net/socket/transport_client_socket_pool_unittest.cc
+++ b/net/socket/transport_client_socket_pool_unittest.cc
@@ -14,7 +14,6 @@
 #include "net/base/load_timing_info.h"
 #include "net/base/load_timing_info_test_util.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/test_completion_callback.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/log/test_net_log.h"
diff --git a/net/socket/unix_domain_server_socket_posix.cc b/net/socket/unix_domain_server_socket_posix.cc
index e76dbfe..b6ba35c6 100644
--- a/net/socket/unix_domain_server_socket_posix.cc
+++ b/net/socket/unix_domain_server_socket_posix.cc
@@ -67,6 +67,14 @@
   return ERR_NOT_IMPLEMENTED;
 }
 
+int UnixDomainServerSocket::ListenWithAddressAndPort(
+    const std::string& address_string,
+    uint16_t port,
+    int backlog) {
+  NOTIMPLEMENTED();
+  return ERR_NOT_IMPLEMENTED;
+}
+
 int UnixDomainServerSocket::BindAndListen(const std::string& socket_path,
                                           int backlog) {
   DCHECK(!listen_socket_);
diff --git a/net/socket/unix_domain_server_socket_posix.h b/net/socket/unix_domain_server_socket_posix.h
index ad9cf15d..536074c4 100644
--- a/net/socket/unix_domain_server_socket_posix.h
+++ b/net/socket/unix_domain_server_socket_posix.h
@@ -52,6 +52,9 @@
 
   // ServerSocket implementation.
   int Listen(const IPEndPoint& address, int backlog) override;
+  int ListenWithAddressAndPort(const std::string& address_string,
+                               uint16_t port,
+                               int backlog) override;
   int GetLocalAddress(IPEndPoint* address) const override;
   int Accept(scoped_ptr<StreamSocket>* socket,
              const CompletionCallback& callback) override;
diff --git a/net/socket/unix_domain_server_socket_posix_unittest.cc b/net/socket/unix_domain_server_socket_posix_unittest.cc
index d76a288d..be472c0 100644
--- a/net/socket/unix_domain_server_socket_posix_unittest.cc
+++ b/net/socket/unix_domain_server_socket_posix_unittest.cc
@@ -118,6 +118,21 @@
   EXPECT_FALSE(accepted_socket);
 }
 
+TEST_F(UnixDomainServerSocketTest, UnimplementedMethodsFail) {
+  const bool kUseAbstractNamespace = false;
+  UnixDomainServerSocket server_socket(CreateAuthCallback(true),
+                                       kUseAbstractNamespace);
+
+  IPEndPoint ep;
+  EXPECT_EQ(ERR_NOT_IMPLEMENTED, server_socket.Listen(ep, 0));
+  EXPECT_EQ(ERR_NOT_IMPLEMENTED,
+      server_socket.ListenWithAddressAndPort(kInvalidSocketPath,
+                                             0,
+                                             /*backlog=*/1));
+
+  EXPECT_EQ(ERR_ADDRESS_INVALID, server_socket.GetLocalAddress(&ep));
+}
+
 // Normal cases including read/write are tested by UnixDomainClientSocketTest.
 
 }  // namespace
diff --git a/net/socket/websocket_transport_client_socket_pool_unittest.cc b/net/socket/websocket_transport_client_socket_pool_unittest.cc
index e45dcc2a..bbc9de80 100644
--- a/net/socket/websocket_transport_client_socket_pool_unittest.cc
+++ b/net/socket/websocket_transport_client_socket_pool_unittest.cc
@@ -21,7 +21,6 @@
 #include "net/base/load_timing_info.h"
 #include "net/base/load_timing_info_test_util.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/test_completion_callback.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/log/test_net_log.h"
diff --git a/net/spdy/spdy_http_stream.cc b/net/spdy/spdy_http_stream.cc
index 9e07d84..5a3a0cb 100644
--- a/net/spdy/spdy_http_stream.cc
+++ b/net/spdy/spdy_http_stream.cc
@@ -17,7 +17,6 @@
 #include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "net/base/host_port_pair.h"
-#include "net/base/net_util.h"
 #include "net/base/upload_data_stream.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_request_info.h"
diff --git a/net/spdy/spdy_proxy_client_socket.cc b/net/spdy/spdy_proxy_client_socket.cc
index 013c9f6..39ef8f0 100644
--- a/net/spdy/spdy_proxy_client_socket.cc
+++ b/net/spdy/spdy_proxy_client_socket.cc
@@ -18,7 +18,6 @@
 #include "base/values.h"
 #include "net/base/auth.h"
 #include "net/base/io_buffer.h"
-#include "net/base/net_util.h"
 #include "net/http/http_auth_cache.h"
 #include "net/http/http_auth_handler_factory.h"
 #include "net/http/http_request_info.h"
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
index 697ce7ca..ed5f16d9 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -29,7 +29,6 @@
 #include "crypto/ec_private_key.h"
 #include "crypto/ec_signature_creator.h"
 #include "net/base/connection_type_histograms.h"
-#include "net/base/net_util.h"
 #include "net/base/proxy_delegate.h"
 #include "net/cert/asn1_util.h"
 #include "net/cert/cert_verify_result.h"
diff --git a/net/ssl/ssl_config.cc b/net/ssl/ssl_config.cc
index e3ced671..be87ed0 100644
--- a/net/ssl/ssl_config.cc
+++ b/net/ssl/ssl_config.cc
@@ -12,7 +12,7 @@
 
 const uint16_t kDefaultSSLVersionMax = SSL_PROTOCOL_VERSION_TLS1_2;
 
-const uint16_t kDefaultSSLVersionFallbackMin = SSL_PROTOCOL_VERSION_TLS1_1;
+const uint16_t kDefaultSSLVersionFallbackMin = SSL_PROTOCOL_VERSION_TLS1_2;
 
 SSLConfig::CertAndStatus::CertAndStatus() : cert_status(0) {}
 
diff --git a/net/tools/cachetool/cachetool.cc b/net/tools/cachetool/cachetool.cc
new file mode 100644
index 0000000..8ae4115
--- /dev/null
+++ b/net/tools/cachetool/cachetool.cc
@@ -0,0 +1,227 @@
+// Copyright 2016 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 <iostream>
+
+#include "base/at_exit.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "net/base/io_buffer.h"
+#include "net/base/test_completion_callback.h"
+#include "net/disk_cache/disk_cache.h"
+#include "net/disk_cache/simple/simple_backend_impl.h"
+#include "net/http/http_cache.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_util.h"
+
+using disk_cache::Backend;
+using disk_cache::Entry;
+using disk_cache::SimpleBackendImpl;
+
+namespace {
+
+base::MessageLoopForIO* g_message_loop = nullptr;
+
+scoped_ptr<SimpleBackendImpl> CreateSimpleBackend(
+    const base::FilePath& cache_path) {
+  scoped_ptr<SimpleBackendImpl> cache_backend(new SimpleBackendImpl(
+      cache_path, 0, net::DISK_CACHE, g_message_loop->task_runner(), NULL));
+
+  net::TestCompletionCallback cb;
+  int rv = cache_backend->Init(cb.callback());
+  if (cb.GetResult(rv) != net::OK)
+    return nullptr;
+  return cache_backend;
+}
+
+// Print all of a cache's keys to stdout.
+bool ListKeys(Backend* cache_backend) {
+  scoped_ptr<Backend::Iterator> entry_iterator =
+      cache_backend->CreateIterator();
+  Entry* entry = nullptr;
+  net::TestCompletionCallback cb;
+  int rv = entry_iterator->OpenNextEntry(&entry, cb.callback());
+  while (cb.GetResult(rv) == net::OK) {
+    std::string url = entry->GetKey();
+    std::cout << url << std::endl;
+    entry->Close();
+    entry = nullptr;
+    rv = entry_iterator->OpenNextEntry(&entry, cb.callback());
+  }
+  return true;
+}
+
+// Print a key's stream to stdout.
+bool GetKeyStream(Backend* cache_backend, const std::string& key, int index) {
+  if (index < 0 || index > 2) {
+    std::cerr << "Invalid stream index." << std::endl;
+    return false;
+  }
+
+  Entry* cache_entry;
+  net::TestCompletionCallback cb;
+  int rv = cache_backend->OpenEntry(key, &cache_entry, cb.callback());
+  if (cb.GetResult(rv) != net::OK) {
+    std::cerr << "Couldn't find key's entry." << std::endl;
+    return false;
+  }
+
+  const int kInitBufferSize = 8192;
+  scoped_refptr<net::GrowableIOBuffer> buffer(new net::GrowableIOBuffer());
+  buffer->SetCapacity(kInitBufferSize);
+  while (true) {
+    rv = cache_entry->ReadData(index, buffer->offset(), buffer.get(),
+                               buffer->capacity() - buffer->offset(),
+                               cb.callback());
+    rv = cb.GetResult(rv);
+    if (rv < 0) {
+      cache_entry->Close();
+      std::cerr << "Stream read error." << std::endl;
+      return false;
+    }
+    buffer->set_offset(buffer->offset() + rv);
+    if (rv == 0)
+      break;
+    buffer->SetCapacity(buffer->offset() * 2);
+  }
+  cache_entry->Close();
+  if (index == 0) {
+    net::HttpResponseInfo response_info;
+    bool truncated_response_info = false;
+    net::HttpCache::ParseResponseInfo(buffer->StartOfBuffer(), buffer->offset(),
+                                      &response_info, &truncated_response_info);
+    if (truncated_response_info) {
+      std::cerr << "Truncated HTTP response." << std::endl;
+      return false;
+    }
+    std::cout << net::HttpUtil::ConvertHeadersBackToHTTPResponse(
+        response_info.headers->raw_headers());
+  } else {
+    std::cout.write(buffer->StartOfBuffer(), buffer->offset());
+  }
+  return true;
+}
+
+// Delete a specified key from the cache.
+bool DeleteKey(Backend* cache_backend, const std::string& key) {
+  net::TestCompletionCallback cb;
+  int rv = cache_backend->DoomEntry(key, cb.callback());
+  if (cb.GetResult(rv) != net::OK) {
+    std::cerr << "Couldn't delete key." << std::endl;
+    return false;
+  }
+  return true;
+}
+
+// Print the command line help.
+void PrintHelp() {
+  std::cout << "cachetool <cache_path> <cache_backend_type> <subcommand> ..."
+            << std::endl
+            << std::endl;
+  std::cout << "Available cache back-end types: simple";
+  std::cout << "Available subcommands:" << std::endl;
+  std::cout << "  validate: Verify that the cache can be opened and return, "
+            << "confirming the cache exists and is of the right type."
+            << std::endl;
+  std::cout << "  list_keys: List all keys in the cache." << std::endl;
+  std::cout << "  get_stream <key> <index>: Print a particular stream for a"
+            << " given key." << std::endl;
+  std::cout << "  delete_key <key>: Delete key from cache." << std::endl;
+  std::cout << "Expected values of <index> are:" << std::endl;
+  std::cout << "  0 (HTTP response headers)" << std::endl;
+  std::cout << "  1 (transport encoded content)" << std::endl;
+  std::cout << "  2 (compiled content)" << std::endl;
+}
+
+}  // namespace
+
+int main(int argc, char* argv[]) {
+  base::AtExitManager at_exit_manager;
+  base::MessageLoopForIO message_loop;
+  base::CommandLine::Init(argc, argv);
+  const base::CommandLine& command_line =
+      *base::CommandLine::ForCurrentProcess();
+
+#if defined(OS_WIN)
+  std::vector<std::string> args;
+  base::CommandLine::StringVector wide_args = command_line.GetArgs();
+  for (const auto& arg : wide_args) {
+    args.push_back(base::WideToUTF8(arg));
+  }
+#else
+  base::CommandLine::StringVector args = command_line.GetArgs();
+#endif
+  if (args.size() < 3U) {
+    PrintHelp();
+    return 1;
+  }
+
+#if defined(OS_WIN)
+  base::FilePath cache_path(wide_args[0]);
+#else
+  base::FilePath cache_path(args[0]);
+#endif
+  std::string cache_backend_type(args[1]);
+  std::string subcommand(args[2]);
+
+  g_message_loop = &message_loop;
+  scoped_ptr<Backend> cache_backend;
+  if (cache_backend_type == "simple") {
+    cache_backend = CreateSimpleBackend(cache_path);
+  } else {
+    std::cerr << "Unknown cache type." << std::endl;
+    PrintHelp();
+    return 1;
+  }
+
+  if (!cache_backend) {
+    std::cerr << "Invalid cache." << std::endl;
+    PrintHelp();
+    return 1;
+  }
+
+  bool successful_command = false;
+  if (subcommand == "validate") {
+    if (args.size() != 3) {
+      PrintHelp();
+      return 1;
+    }
+    successful_command = true;
+  } else if (subcommand == "list_keys") {
+    if (args.size() != 3) {
+      PrintHelp();
+      return 1;
+    }
+    successful_command = ListKeys(cache_backend.get());
+  } else if (subcommand == "get_stream") {
+    if (args.size() != 5) {
+      PrintHelp();
+      return 1;
+    }
+    std::string key(args[3]);
+    int index = 0;
+    if (!base::StringToInt(args[4], &index)) {
+      std::cerr << "<index> must be an integer." << std::endl;
+      PrintHelp();
+      return 1;
+    }
+    successful_command = GetKeyStream(cache_backend.get(), key, index);
+  } else if (subcommand == "delete_key") {
+    if (args.size() != 4) {
+      PrintHelp();
+      return 1;
+    }
+    std::string key(args[3]);
+    successful_command = DeleteKey(cache_backend.get(), key);
+  } else {
+    std::cerr << "Unknown subcommand." << std::endl;
+    PrintHelp();
+  }
+  return !successful_command;
+}
diff --git a/net/tools/flip_server/sm_connection.cc b/net/tools/flip_server/sm_connection.cc
index b5c77d8b..9c232f9 100644
--- a/net/tools/flip_server/sm_connection.cc
+++ b/net/tools/flip_server/sm_connection.cc
@@ -103,7 +103,7 @@
     server_ip_ = server_ip;
     server_port_ = server_port;
     int ret = CreateTCPClientSocket(
-        &fd_, server_ip, server_port, true, acceptor_->disable_nagle_);
+        server_ip, server_port, true, acceptor_->disable_nagle_, &fd_);
 
     if (ret < 0) {
       LOG(ERROR) << "-1 Could not create connected socket";
diff --git a/net/tools/flip_server/tcp_socket_util.cc b/net/tools/flip_server/tcp_socket_util.cc
index c7dbf8ec..b10698e 100644
--- a/net/tools/flip_server/tcp_socket_util.cc
+++ b/net/tools/flip_server/tcp_socket_util.cc
@@ -209,11 +209,11 @@
   return 0;
 }
 
-int CreateTCPClientSocket(int* connect_fd,
-                          const std::string& host,
+int CreateTCPClientSocket(const std::string& host,
                           const std::string& port,
                           bool is_numeric_host_address,
-                          bool disable_nagle) {
+                          bool disable_nagle,
+                          int* connect_fd) {
   const char* node = NULL;
   const char* service = NULL;
 
diff --git a/net/tools/flip_server/tcp_socket_util.h b/net/tools/flip_server/tcp_socket_util.h
index 6e05b21..e29a926 100644
--- a/net/tools/flip_server/tcp_socket_util.h
+++ b/net/tools/flip_server/tcp_socket_util.h
@@ -51,11 +51,11 @@
                           bool disable_nagle,
                           int* listen_fd);
 
-int CreateTCPClientSocket(int* connect_fd,
-                          const std::string& host,
+int CreateTCPClientSocket(const std::string& host,
                           const std::string& port,
                           bool is_numeric_host_address,
-                          bool disable_nagle);
+                          bool disable_nagle,
+                          int* connect_fd);
 
 }  // namespace net
 
diff --git a/net/tools/flip_server/url_to_filename_encoder.cc b/net/tools/flip_server/url_to_filename_encoder.cc
index b3d80e4b5..b5a01d18 100644
--- a/net/tools/flip_server/url_to_filename_encoder.cc
+++ b/net/tools/flip_server/url_to_filename_encoder.cc
@@ -8,7 +8,6 @@
 
 #include "base/logging.h"
 #include "base/strings/string_util.h"
-#include "net/base/net_util.h"
 
 using std::string;
 
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index a2786aa..19ca2c0 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -1453,8 +1453,7 @@
 class WrongAddressWriter : public QuicPacketWriterWrapper {
  public:
   WrongAddressWriter() {
-    IPAddress ip;
-    CHECK(ip.AssignFromIPLiteral("127.0.0.2"));
+    IPAddress ip(127, 0, 0, 2);
     self_address_ = IPEndPoint(ip, 0);
   }
 
@@ -1483,8 +1482,7 @@
   IPAddress old_host = client_->client()->GetLatestClientAddress().address();
 
   // Migrate socket to the new IP address.
-  IPAddress new_host;
-  CHECK(new_host.AssignFromIPLiteral("127.0.0.2"));
+  IPAddress new_host(127, 0, 0, 2);
   EXPECT_NE(old_host, new_host);
   ASSERT_TRUE(client_->client()->MigrateSocket(new_host));
 
diff --git a/net/tools/quic/quic_client.cc b/net/tools/quic/quic_client.cc
index 14f412e..8c2c8e8 100644
--- a/net/tools/quic/quic_client.cc
+++ b/net/tools/quic/quic_client.cc
@@ -164,8 +164,7 @@
   if (bind_to_address_.size() != 0) {
     client_address = IPEndPoint(bind_to_address_, local_port_);
   } else if (address_family == AF_INET) {
-    IPAddress any4;
-    CHECK(any4.AssignFromIPLiteral("0.0.0.0"));
+    IPAddress any4(0, 0, 0, 0);
     client_address = IPEndPoint(any4, local_port_);
   } else {
     IPAddress any6;
diff --git a/net/tools/quic/quic_client.h b/net/tools/quic/quic_client.h
index e5a72bf..5dff8cfe 100644
--- a/net/tools/quic/quic_client.h
+++ b/net/tools/quic/quic_client.h
@@ -161,9 +161,11 @@
   // Otherwise, return -1.
   int GetLatestFD() const;
 
-  void set_bind_to_address(IPAddress address) { bind_to_address_ = address; }
+  void set_bind_to_address(const IPAddress& address) {
+    bind_to_address_ = address;
+  }
 
-  IPAddress bind_to_address() const { return bind_to_address_; }
+  const IPAddress& bind_to_address() const { return bind_to_address_; }
 
   void set_local_port(int local_port) { local_port_ = local_port; }
 
diff --git a/net/tools/quic/quic_simple_client.cc b/net/tools/quic/quic_simple_client.cc
index 9378ae29..25bd93d 100644
--- a/net/tools/quic/quic_simple_client.cc
+++ b/net/tools/quic/quic_simple_client.cc
@@ -107,8 +107,7 @@
   if (bind_to_address_.size() != 0) {
     client_address_ = IPEndPoint(bind_to_address_, local_port_);
   } else if (address_family == AF_INET) {
-    IPAddress any4;
-    CHECK(any4.AssignFromIPLiteral("0.0.0.0"));
+    IPAddress any4(0, 0, 0, 0);
     client_address_ = IPEndPoint(any4, local_port_);
   } else {
     IPAddress any6;
diff --git a/net/tools/quic/quic_simple_client.h b/net/tools/quic/quic_simple_client.h
index 5cdff0d..0ac0087 100644
--- a/net/tools/quic/quic_simple_client.h
+++ b/net/tools/quic/quic_simple_client.h
@@ -142,9 +142,11 @@
   // Otherwise, deletes the data.  Takes ownerership of |data_to_resend|.
   void MaybeAddQuicDataToResend(QuicDataToResend* data_to_resend);
 
-  void set_bind_to_address(IPAddress address) { bind_to_address_ = address; }
+  void set_bind_to_address(const IPAddress& address) {
+    bind_to_address_ = address;
+  }
 
-  IPAddress bind_to_address() const { return bind_to_address_; }
+  const IPAddress& bind_to_address() const { return bind_to_address_; }
 
   void set_local_port(int local_port) { local_port_ = local_port; }
 
diff --git a/net/tools/quic/quic_socket_utils.cc b/net/tools/quic/quic_socket_utils.cc
index 356cec3..36c5fb4 100644
--- a/net/tools/quic/quic_socket_utils.cc
+++ b/net/tools/quic/quic_socket_utils.cc
@@ -152,24 +152,28 @@
 
 size_t QuicSocketUtils::SetIpInfoInCmsg(const IPAddress& self_address,
                                         cmsghdr* cmsg) {
-  if (GetAddressFamily(self_address) == ADDRESS_FAMILY_IPV4) {
+  if (self_address.IsIPv4()) {
     cmsg->cmsg_len = CMSG_LEN(sizeof(in_pktinfo));
     cmsg->cmsg_level = IPPROTO_IP;
     cmsg->cmsg_type = IP_PKTINFO;
     in_pktinfo* pktinfo = reinterpret_cast<in_pktinfo*>(CMSG_DATA(cmsg));
     memset(pktinfo, 0, sizeof(in_pktinfo));
     pktinfo->ipi_ifindex = 0;
-    memcpy(&pktinfo->ipi_spec_dst, &self_address.bytes()[0],
+    memcpy(&pktinfo->ipi_spec_dst, self_address.bytes().data(),
            self_address.size());
     return sizeof(in_pktinfo);
-  } else {
+  } else if (self_address.IsIPv6()) {
     cmsg->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo));
     cmsg->cmsg_level = IPPROTO_IPV6;
     cmsg->cmsg_type = IPV6_PKTINFO;
     in6_pktinfo* pktinfo = reinterpret_cast<in6_pktinfo*>(CMSG_DATA(cmsg));
     memset(pktinfo, 0, sizeof(in6_pktinfo));
-    memcpy(&pktinfo->ipi6_addr, &self_address.bytes()[0], self_address.size());
+    memcpy(&pktinfo->ipi6_addr, self_address.bytes().data(),
+           self_address.size());
     return sizeof(in6_pktinfo);
+  } else {
+    NOTREACHED() << "Unrecognized IPAddress";
+    return 0;
   }
 }
 
diff --git a/net/tools/quic/quic_socket_utils.h b/net/tools/quic/quic_socket_utils.h
index fc6d3c32..8a0e4420 100644
--- a/net/tools/quic/quic_socket_utils.h
+++ b/net/tools/quic/quic_socket_utils.h
@@ -23,8 +23,7 @@
 class QuicSocketUtils {
  public:
   // If the msghdr contains IP_PKTINFO or IPV6_PKTINFO, this will return the
-  // IPAddress in that header.  Returns an uninitialized IPAddress on
-  // failure.
+  // IPAddress in that header.  Returns an empty IPAddress on failure.
   static IPAddress GetAddressFromMsghdr(struct msghdr* hdr);
 
   // If the msghdr contains an SO_RXQ_OVFL entry, this will set dropped_packets
diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc
index b1bf3a9..7e6d413 100644
--- a/net/tools/quic/test_tools/quic_test_client.cc
+++ b/net/tools/quic/test_tools/quic_test_client.cc
@@ -628,7 +628,7 @@
   return client_->bind_to_address();
 }
 
-void QuicTestClient::set_bind_to_address(IPAddress address) {
+void QuicTestClient::set_bind_to_address(const IPAddress& address) {
   client_->set_bind_to_address(address);
 }
 
diff --git a/net/tools/quic/test_tools/quic_test_client.h b/net/tools/quic/test_tools/quic_test_client.h
index 7bfa0b51..df38ad5 100644
--- a/net/tools/quic/test_tools/quic_test_client.h
+++ b/net/tools/quic/test_tools/quic_test_client.h
@@ -131,7 +131,7 @@
   void MigrateSocket(const IPAddress& new_host) override;
   std::string SerializeMessage(const HTTPMessage& message) override;
   IPAddress bind_to_address() const override;
-  void set_bind_to_address(IPAddress address) override;
+  void set_bind_to_address(const IPAddress& address) override;
   const IPEndPoint& address() const override;
   size_t requests_sent() const override;
 
diff --git a/net/tools/quic/test_tools/simple_client.h b/net/tools/quic/test_tools/simple_client.h
index ad9c00e..3c5d02c 100644
--- a/net/tools/quic/test_tools/simple_client.h
+++ b/net/tools/quic/test_tools/simple_client.h
@@ -105,7 +105,7 @@
   // called in advance. If it's set to uninitialized IPAddress, default loopback
   // address will be used.
   virtual IPAddress bind_to_address() const = 0;
-  virtual void set_bind_to_address(IPAddress address) = 0;
+  virtual void set_bind_to_address(const IPAddress& address) = 0;
 
   // Returns true if the headers have been processed and are available.
   virtual bool response_headers_complete() const = 0;
diff --git a/net/udp/udp_socket_perftest.cc b/net/udp/udp_socket_perftest.cc
index 066ec28b..26c14cf 100644
--- a/net/udp/udp_socket_perftest.cc
+++ b/net/udp/udp_socket_perftest.cc
@@ -10,7 +10,6 @@
 #include "net/base/io_buffer.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/test_completion_callback.h"
 #include "net/test/net_test_suite.h"
 #include "net/udp/udp_client_socket.h"
diff --git a/net/udp/udp_socket_unittest.cc b/net/udp/udp_socket_unittest.cc
index 4bd8a9e..2782ba9 100644
--- a/net/udp/udp_socket_unittest.cc
+++ b/net/udp/udp_socket_unittest.cc
@@ -18,7 +18,6 @@
 #include "net/base/io_buffer.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/base/test_completion_callback.h"
 #include "net/log/test_net_log.h"
 #include "net/log/test_net_log_entry.h"
diff --git a/net/url_request/url_request_file_job_unittest.cc b/net/url_request/url_request_file_job_unittest.cc
index d8e0691..da43aab 100644
--- a/net/url_request/url_request_file_job_unittest.cc
+++ b/net/url_request/url_request_file_job_unittest.cc
@@ -13,7 +13,6 @@
 #include "base/thread_task_runner_handle.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "net/base/filename_util.h"
-#include "net/base/net_util.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/net/url_request/url_request_ftp_job.cc b/net/url_request/url_request_ftp_job.cc
index fd59e45..9d8dd49 100644
--- a/net/url_request/url_request_ftp_job.cc
+++ b/net/url_request/url_request_ftp_job.cc
@@ -13,7 +13,6 @@
 #include "net/base/host_port_pair.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/ftp/ftp_auth_cache.h"
 #include "net/ftp/ftp_response_info.h"
 #include "net/ftp/ftp_transaction_factory.h"
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 99cec66c..6204faa 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -261,8 +261,8 @@
       (request_info_.load_flags & LOAD_DO_NOT_SEND_COOKIES) ||
       (request_info_.load_flags & LOAD_DO_NOT_SAVE_COOKIES) ||
       CanEnablePrivacyMode();
-  // Privacy mode could still be disabled in OnCookiesLoaded if we are going
-  // to send previously saved cookies.
+  // Privacy mode could still be disabled in SetCookieHeaderAndStart if we are
+  // going to send previously saved cookies.
   request_info_.privacy_mode = enable_privacy_mode ?
       PRIVACY_MODE_ENABLED : PRIVACY_MODE_DISABLED;
 
@@ -667,51 +667,37 @@
 
   CookieStore* cookie_store = request_->context()->cookie_store();
   if (cookie_store && !(request_info_.load_flags & LOAD_DO_NOT_SEND_COOKIES)) {
-    cookie_store->GetAllCookiesForURLAsync(
-        request_->url(),
-        base::Bind(&URLRequestHttpJob::CheckCookiePolicyAndLoad,
+    CookieOptions options;
+    options.set_include_httponly();
+
+    // TODO(mkwst): If same-site cookies aren't enabled, pretend the request is
+    // same-site regardless, in order to include all cookies. Drop this check
+    // once we decide whether or not we're shipping this feature:
+    // https://crbug.com/459154
+    url::Origin requested_origin(request_->url());
+    if (!network_delegate() ||
+        !network_delegate()->AreExperimentalCookieFeaturesEnabled()) {
+      options.set_include_same_site();
+    } else if (requested_origin.IsSameOriginWith(
+                   url::Origin(request_->first_party_for_cookies())) &&
+               (IsMethodSafe(request_->method()) ||
+                requested_origin.IsSameOriginWith(request_->initiator()))) {
+      options.set_include_same_site();
+    }
+
+    cookie_store->GetCookieListWithOptionsAsync(
+        request_->url(), options,
+        base::Bind(&URLRequestHttpJob::SetCookieHeaderAndStart,
                    weak_factory_.GetWeakPtr()));
   } else {
     DoStartTransaction();
   }
 }
 
-void URLRequestHttpJob::DoLoadCookies() {
-  CookieOptions options;
-  options.set_include_httponly();
-
-  // TODO(mkwst): If same-site cookies aren't enabled, pretend the request is
-  // same-site regardless, in order to include all cookies. Drop this check once
-  // we decide whether or not we're shipping this feature:
-  // https://crbug.com/459154
-  url::Origin requested_origin(request_->url());
-  if (!network_delegate() ||
-      !network_delegate()->AreExperimentalCookieFeaturesEnabled()) {
-    options.set_include_same_site();
-  } else if (requested_origin.IsSameOriginWith(
-                 url::Origin(request_->first_party_for_cookies())) &&
-             (IsMethodSafe(request_->method()) ||
-              requested_origin.IsSameOriginWith(request_->initiator()))) {
-    options.set_include_same_site();
-  }
-
-  request_->context()->cookie_store()->GetCookiesWithOptionsAsync(
-      request_->url(), options, base::Bind(&URLRequestHttpJob::OnCookiesLoaded,
-                                           weak_factory_.GetWeakPtr()));
-}
-
-void URLRequestHttpJob::CheckCookiePolicyAndLoad(
-    const CookieList& cookie_list) {
-  if (CanGetCookies(cookie_list))
-    DoLoadCookies();
-  else
-    DoStartTransaction();
-}
-
-void URLRequestHttpJob::OnCookiesLoaded(const std::string& cookie_line) {
-  if (!cookie_line.empty()) {
+void URLRequestHttpJob::SetCookieHeaderAndStart(const CookieList& cookie_list) {
+  if (cookie_list.size() && CanGetCookies(cookie_list)) {
     request_info_.extra_headers.SetHeader(
-        HttpRequestHeaders::kCookie, cookie_line);
+        HttpRequestHeaders::kCookie, CookieStore::BuildCookieLine(cookie_list));
     // Disable privacy mode as we are sending cookies anyway.
     request_info_.privacy_mode = PRIVACY_MODE_DISABLED;
   }
diff --git a/net/url_request/url_request_http_job.h b/net/url_request/url_request_http_job.h
index 97965dab..56051fcc 100644
--- a/net/url_request/url_request_http_job.h
+++ b/net/url_request/url_request_http_job.h
@@ -162,9 +162,7 @@
   void DoneWithRequest(CompletionCause reason);
 
   // Callback functions for Cookie Monster
-  void DoLoadCookies();
-  void CheckCookiePolicyAndLoad(const CookieList& cookie_list);
-  void OnCookiesLoaded(const std::string& cookie_line);
+  void SetCookieHeaderAndStart(const CookieList& cookie_list);
   void DoStartTransaction();
 
   // Some servers send the body compressed, but specify the content length as
diff --git a/net/url_request/url_request_throttler_manager.cc b/net/url_request/url_request_throttler_manager.cc
index 3f08e9e1..a36f0c9 100644
--- a/net/url_request/url_request_throttler_manager.cc
+++ b/net/url_request/url_request_throttler_manager.cc
@@ -6,7 +6,7 @@
 
 #include "base/logging.h"
 #include "base/strings/string_util.h"
-#include "net/base/net_util.h"
+#include "net/base/url_util.h"
 #include "net/log/net_log.h"
 
 namespace net {
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 55f5235..2b6f11f 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -8725,21 +8725,33 @@
       SpawnedTestServer::SSLOptions::TLS_INTOLERANT_TLS1_1;
 
   ASSERT_NO_FATAL_FAILURE(DoFallbackTest(ssl_options));
-  ExpectFailure(ERR_SSL_FALLBACK_BEYOND_MINIMUM_VERSION);
+  ExpectFailure(ERR_SSL_VERSION_OR_CIPHER_MISMATCH);
 }
 
-// Tests the TLS 1.1 fallback.
-TEST_F(HTTPSFallbackTest, TLSv1_1Fallback) {
+// Tests the TLS 1.1 fallback doesn't happen but 1.2-intolerance is detected.
+TEST_F(HTTPSFallbackTest, TLSv1_1NoFallback) {
   SpawnedTestServer::SSLOptions ssl_options(
       SpawnedTestServer::SSLOptions::CERT_OK);
   ssl_options.tls_intolerant =
       SpawnedTestServer::SSLOptions::TLS_INTOLERANT_TLS1_2;
 
   ASSERT_NO_FATAL_FAILURE(DoFallbackTest(ssl_options));
+  ExpectFailure(ERR_SSL_FALLBACK_BEYOND_MINIMUM_VERSION);
+}
+
+// Tests the TLS 1.1 fallback when explicitly enabled.
+TEST_F(HTTPSFallbackTest, TLSv1_1Fallback) {
+  SpawnedTestServer::SSLOptions ssl_options(
+      SpawnedTestServer::SSLOptions::CERT_OK);
+  ssl_options.tls_intolerant =
+      SpawnedTestServer::SSLOptions::TLS_INTOLERANT_TLS1_2;
+
+  set_fallback_min_version(SSL_PROTOCOL_VERSION_TLS1_1);
+  ASSERT_NO_FATAL_FAILURE(DoFallbackTest(ssl_options));
   ExpectConnection(SSL_CONNECTION_VERSION_TLS1_1);
 }
 
-// Tests that the TLS 1.1 fallback triggers on closed connections.
+// Tests that the TLS 1.1 fallback, if enabled, triggers on closed connections.
 TEST_F(HTTPSFallbackTest, TLSv1_1FallbackClosed) {
   SpawnedTestServer::SSLOptions ssl_options(
       SpawnedTestServer::SSLOptions::CERT_OK);
@@ -8748,6 +8760,7 @@
   ssl_options.tls_intolerance_type =
       SpawnedTestServer::SSLOptions::TLS_INTOLERANCE_CLOSE;
 
+  set_fallback_min_version(SSL_PROTOCOL_VERSION_TLS1_1);
   ASSERT_NO_FATAL_FAILURE(DoFallbackTest(ssl_options));
   ExpectConnection(SSL_CONNECTION_VERSION_TLS1_1);
 }
@@ -8755,7 +8768,7 @@
 // This test is disabled on Android because the remote test server doesn't cause
 // a TCP reset.
 #if !defined(OS_ANDROID)
-// Tests fallback to TLS 1.1 on connection reset.
+// Tests fallback to TLS 1.1, if enabled, on connection reset.
 TEST_F(HTTPSFallbackTest, TLSv1_1FallbackReset) {
   SpawnedTestServer::SSLOptions ssl_options(
       SpawnedTestServer::SSLOptions::CERT_OK);
@@ -8764,13 +8777,15 @@
   ssl_options.tls_intolerance_type =
       SpawnedTestServer::SSLOptions::TLS_INTOLERANCE_RESET;
 
+  set_fallback_min_version(SSL_PROTOCOL_VERSION_TLS1_1);
   ASSERT_NO_FATAL_FAILURE(DoFallbackTest(ssl_options));
   ExpectConnection(SSL_CONNECTION_VERSION_TLS1_1);
 }
 #endif  // !OS_ANDROID
 
-// Tests that we don't fallback on handshake failure with servers that implement
-// TLS_FALLBACK_SCSV. Also ensure that the original error code is reported.
+// Tests that we don't fallback, even if enabled, on handshake failure with
+// servers that implement TLS_FALLBACK_SCSV. Also ensure that the original error
+// code is reported.
 TEST_F(HTTPSFallbackTest, FallbackSCSV) {
   SpawnedTestServer::SSLOptions ssl_options(
       SpawnedTestServer::SSLOptions::CERT_OK);
@@ -8782,6 +8797,7 @@
   // connections are rejected.
   ssl_options.fallback_scsv_enabled = true;
 
+  set_fallback_min_version(SSL_PROTOCOL_VERSION_TLS1_1);
   ASSERT_NO_FATAL_FAILURE(DoFallbackTest(ssl_options));
 
   // ERR_SSL_VERSION_OR_CIPHER_MISMATCH is how the server simulates version
@@ -8791,8 +8807,9 @@
   ExpectFailure(ERR_SSL_VERSION_OR_CIPHER_MISMATCH);
 }
 
-// Tests that we don't fallback on connection closed with servers that implement
-// TLS_FALLBACK_SCSV. Also ensure that the original error code is reported.
+// Tests that we don't fallback, even if enabled, on connection closed with
+// servers that implement TLS_FALLBACK_SCSV. Also ensure that the original error
+// code is reported.
 TEST_F(HTTPSFallbackTest, FallbackSCSVClosed) {
   SpawnedTestServer::SSLOptions ssl_options(
       SpawnedTestServer::SSLOptions::CERT_OK);
@@ -8806,6 +8823,7 @@
   // connections are rejected.
   ssl_options.fallback_scsv_enabled = true;
 
+  set_fallback_min_version(SSL_PROTOCOL_VERSION_TLS1_1);
   ASSERT_NO_FATAL_FAILURE(DoFallbackTest(ssl_options));
 
   // The original error should be replayed on rejected fallback.
@@ -8817,7 +8835,7 @@
   SpawnedTestServer::SSLOptions ssl_options(
       SpawnedTestServer::SSLOptions::CERT_OK);
   ssl_options.tls_intolerant =
-      SpawnedTestServer::SSLOptions::TLS_INTOLERANT_TLS1_1;
+      SpawnedTestServer::SSLOptions::TLS_INTOLERANT_TLS1_2;
   ssl_options.tls_intolerance_type =
       SpawnedTestServer::SSLOptions::TLS_INTOLERANCE_CLOSE;
   ssl_options.record_resume = true;
@@ -8830,14 +8848,13 @@
 
   SSLClientSocket::ClearSessionCache();
 
-  // Make a connection that does a probe fallback to TLSv1 but fails because
-  // TLSv1 fallback is disabled. We don't wish a session for this connection to
-  // be inserted locally.
+  // Make a connection that does a probe fallback to TLSv1.1 but fails because
+  // fallback is disabled. We don't wish a session for this connection to be
+  // inserted locally.
   {
     TestDelegate delegate;
     FallbackTestURLRequestContext context(true);
 
-    context.set_fallback_min_version(SSL_PROTOCOL_VERSION_TLS1_2);
     context.Init();
     scoped_ptr<URLRequest> request(context.CreateRequest(
         test_server.GetURL("/"), DEFAULT_PRIORITY, &delegate));
@@ -8852,11 +8869,11 @@
               request->status().error());
   }
 
-  // Now allow TLSv1 fallback connections and request the session cache log.
+  // Now allow TLSv1.1 fallback connections and request the session cache log.
   {
     TestDelegate delegate;
     FallbackTestURLRequestContext context(true);
-    context.set_fallback_min_version(SSL_PROTOCOL_VERSION_TLS1);
+    context.set_fallback_min_version(SSL_PROTOCOL_VERSION_TLS1_1);
 
     context.Init();
     scoped_ptr<URLRequest> request(context.CreateRequest(
@@ -8868,7 +8885,7 @@
     EXPECT_EQ(1, delegate.response_started_count());
     EXPECT_NE(0, delegate.bytes_received());
     EXPECT_EQ(
-        SSL_CONNECTION_VERSION_TLS1,
+        SSL_CONNECTION_VERSION_TLS1_1,
         SSLConnectionStatusToVersion(request->ssl_info().connection_status));
     EXPECT_TRUE(request->ssl_info().connection_status &
                 SSL_CONNECTION_VERSION_FALLBACK);
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index 2b59214..3899e0e 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -518,8 +518,8 @@
 }
 
 void ShutdownSDK() {
-  TearDownV8();
   FPDF_DestroyLibrary();
+  TearDownV8();
 }
 
 PDFEngine* PDFEngine::Create(PDFEngine::Client* client) {
diff --git a/remoting/host/daemon_process.cc b/remoting/host/daemon_process.cc
index 880d7248..b874426e 100644
--- a/remoting/host/daemon_process.cc
+++ b/remoting/host/daemon_process.cc
@@ -16,7 +16,6 @@
 #include "base/location.h"
 #include "base/single_thread_task_runner.h"
 #include "ipc/attachment_broker_privileged.h"
-#include "net/base/net_util.h"
 #include "remoting/base/auto_thread_task_runner.h"
 #include "remoting/host/branding.h"
 #include "remoting/host/chromoting_messages.h"
diff --git a/remoting/host/desktop_process_main.cc b/remoting/host/desktop_process_main.cc
index 794128c..7116580 100644
--- a/remoting/host/desktop_process_main.cc
+++ b/remoting/host/desktop_process_main.cc
@@ -32,7 +32,7 @@
       command_line->GetSwitchValueASCII(kDaemonPipeSwitchName);
 
   if (channel_name.empty())
-    return kUsageExitCode;
+    return kInvalidCommandLineExitCode;
 
   base::MessageLoopForUI message_loop;
   base::RunLoop run_loop;
diff --git a/remoting/host/host_exit_codes.cc b/remoting/host/host_exit_codes.cc
index 4e206a5..5d1a13c 100644
--- a/remoting/host/host_exit_codes.cc
+++ b/remoting/host/host_exit_codes.cc
@@ -13,6 +13,7 @@
 const NameMapElement<HostExitCodes> kHostExitCodeStrings[] = {
   { kSuccessExitCode, "SUCCESS_EXIT" },
   { kInitializationFailed, "INITIALIZATION_FAILED" },
+  { kInvalidCommandLineExitCode, "INVALID_COMMAND_LINE" },
   { kInvalidHostConfigurationExitCode, "INVALID_HOST_CONFIGURATION" },
   { kInvalidHostIdExitCode, "INVALID_HOST_ID" },
   { kInvalidOauthCredentialsExitCode, "INVALID_OAUTH_CREDENTIALS" },
diff --git a/remoting/host/host_exit_codes.h b/remoting/host/host_exit_codes.h
index 81f19edb..becefae 100644
--- a/remoting/host/host_exit_codes.h
+++ b/remoting/host/host_exit_codes.h
@@ -17,7 +17,7 @@
   kSuccessExitCode = 0,
   kReservedForX11ExitCode = 1,
   kInitializationFailed = 2,
-  kUsageExitCode = 3,
+  kInvalidCommandLineExitCode = 3,
 
   // Error codes that do indicate a permanent error condition.
   kInvalidHostConfigurationExitCode = 100,
diff --git a/remoting/host/host_main.cc b/remoting/host/host_main.cc
index 961f36c..6501fb74 100644
--- a/remoting/host/host_main.cc
+++ b/remoting/host/host_main.cc
@@ -202,7 +202,7 @@
     fprintf(stderr, "Unknown process type '%s' specified.",
             process_type.c_str());
     Usage(command_line->GetProgram());
-    return kUsageExitCode;
+    return kInvalidCommandLineExitCode;
   }
 
   // Required to find the ICU data file, used by some file_util routines.
@@ -212,7 +212,7 @@
 
   // Invoke the entry point.
   int exit_code = main_routine();
-  if (exit_code == kUsageExitCode) {
+  if (exit_code == kInvalidCommandLineExitCode) {
     Usage(command_line->GetProgram());
   }
 
diff --git a/remoting/host/host_mock_objects.h b/remoting/host/host_mock_objects.h
index 9c374af..2df17fc 100644
--- a/remoting/host/host_mock_objects.h
+++ b/remoting/host/host_mock_objects.h
@@ -25,6 +25,7 @@
 #include "third_party/webrtc/modules/desktop_capture/mouse_cursor_monitor.h"
 
 namespace base {
+class TimeDelta;
 class SingleThreadTaskRunner;
 }  // namespace base
 
@@ -148,6 +149,8 @@
   MOCK_METHOD2(SendClientResponse,
                void(int connection_id, const std::string& response));
   MOCK_METHOD1(SendErrorAndCloseConnection, void(int connection_id));
+  MOCK_CONST_METHOD0(GetActiveConnectionCountForTest, size_t());
+  MOCK_METHOD1(SetRequestTimeoutForTest, void(const base::TimeDelta& timeout));
 
   void SetSendMessageCallback(
       const GnubbyAuthHandler::SendMessageCallback& callback) override;
diff --git a/remoting/host/it2me/it2me_native_messaging_host_unittest.cc b/remoting/host/it2me/it2me_native_messaging_host_unittest.cc
index 7b541a65..0a5ede1 100644
--- a/remoting/host/it2me/it2me_native_messaging_host_unittest.cc
+++ b/remoting/host/it2me/it2me_native_messaging_host_unittest.cc
@@ -18,7 +18,6 @@
 #include "base/strings/stringize_macros.h"
 #include "base/values.h"
 #include "net/base/file_stream.h"
-#include "net/base/net_util.h"
 #include "remoting/base/auto_thread_task_runner.h"
 #include "remoting/host/chromoting_host_context.h"
 #include "remoting/host/native_messaging/log_message_handler.h"
diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc
index ebea38f6..180c15b 100644
--- a/remoting/host/remoting_me2me_host.cc
+++ b/remoting/host/remoting_me2me_host.cc
@@ -864,9 +864,7 @@
 
   if (!InitWithCommandLine(base::CommandLine::ForCurrentProcess())) {
     // Shutdown the host if the command line is invalid.
-    context_->network_task_runner()->PostTask(
-        FROM_HERE, base::Bind(&HostProcess::ShutdownHost, this,
-                              kUsageExitCode));
+    ShutdownOnUiThread();
     return;
   }
 
diff --git a/remoting/host/security_key/gnubby_auth_handler.h b/remoting/host/security_key/gnubby_auth_handler.h
index 1c2f5642..4c7ed25 100644
--- a/remoting/host/security_key/gnubby_auth_handler.h
+++ b/remoting/host/security_key/gnubby_auth_handler.h
@@ -12,6 +12,7 @@
 
 namespace base {
 class FilePath;
+class TimeDelta;
 }  // namespace base
 
 namespace remoting {
@@ -53,6 +54,12 @@
 
   // Closes the gnubby connection represented by |gnubby_connection_id|.
   virtual void SendErrorAndCloseConnection(int gnubby_connection_id) = 0;
+
+  // Returns the number of active gnubby connections.
+  virtual size_t GetActiveConnectionCountForTest() const = 0;
+
+  // Sets the timeout used when waiting for a gnubby response.
+  virtual void SetRequestTimeoutForTest(const base::TimeDelta& timeout) = 0;
 };
 
 }  // namespace remoting
diff --git a/remoting/host/security_key/gnubby_auth_handler_linux.cc b/remoting/host/security_key/gnubby_auth_handler_linux.cc
index 8a50686..f036434 100644
--- a/remoting/host/security_key/gnubby_auth_handler_linux.cc
+++ b/remoting/host/security_key/gnubby_auth_handler_linux.cc
@@ -1,9 +1,6 @@
 // Copyright 2016 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 "remoting/host/security_key/gnubby_auth_handler_linux.h"
-
 #include <stdint.h>
 #include <unistd.h>
 
@@ -11,12 +8,17 @@
 #include "base/files/file_util.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/stl_util.h"
+#include "base/threading/thread_checker.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/values.h"
+#include "net/base/completion_callback.h"
 #include "net/base/net_errors.h"
+#include "net/socket/stream_socket.h"
 #include "net/socket/unix_domain_server_socket_posix.h"
 #include "remoting/base/logging.h"
+#include "remoting/host/security_key/gnubby_auth_handler.h"
 #include "remoting/host/security_key/gnubby_socket.h"
 
 namespace {
@@ -46,6 +48,67 @@
 
 namespace remoting {
 
+class GnubbyAuthHandlerLinux : public GnubbyAuthHandler {
+ public:
+  GnubbyAuthHandlerLinux();
+  ~GnubbyAuthHandlerLinux() override;
+
+ private:
+  typedef std::map<int, GnubbySocket*> ActiveSockets;
+
+  // GnubbyAuthHandler interface.
+  void CreateGnubbyConnection() override;
+  bool IsValidConnectionId(int gnubby_connection_id) const override;
+  void SendClientResponse(int gnubby_connection_id,
+                          const std::string& response) override;
+  void SendErrorAndCloseConnection(int gnubby_connection_id) override;
+  void SetSendMessageCallback(const SendMessageCallback& callback) override;
+  size_t GetActiveConnectionCountForTest() const override;
+  void SetRequestTimeoutForTest(const base::TimeDelta& timeout) override;
+
+  // Starts listening for connection.
+  void DoAccept();
+
+  // Called when a connection is accepted.
+  void OnAccepted(int result);
+
+  // Called when a GnubbySocket has done reading.
+  void OnReadComplete(int gnubby_connection_id);
+
+  // Gets an active socket iterator for |gnubby_connection_id|.
+  ActiveSockets::const_iterator GetSocketForConnectionId(
+      int gnubby_connection_id) const;
+
+  // Send an error and closes an active socket.
+  void SendErrorAndCloseActiveSocket(const ActiveSockets::const_iterator& iter);
+
+  // A request timed out.
+  void RequestTimedOut(int gnubby_connection_id);
+
+  // Ensures GnubbyAuthHandlerLinux methods are called on the same thread.
+  base::ThreadChecker thread_checker_;
+
+  // Socket used to listen for authorization requests.
+  scoped_ptr<net::UnixDomainServerSocket> auth_socket_;
+
+  // A temporary holder for an accepted connection.
+  scoped_ptr<net::StreamSocket> accept_socket_;
+
+  // Used to pass gnubby extension messages to the client.
+  SendMessageCallback send_message_callback_;
+
+  // The last assigned gnubby connection id.
+  int last_connection_id_;
+
+  // Sockets by connection id used to process gnubbyd requests.
+  ActiveSockets active_sockets_;
+
+  // Timeout used for a request.
+  base::TimeDelta request_timeout_;
+
+  DISALLOW_COPY_AND_ASSIGN(GnubbyAuthHandlerLinux);
+};
+
 scoped_ptr<GnubbyAuthHandler> GnubbyAuthHandler::Create(
     const SendMessageCallback& callback) {
   scoped_ptr<GnubbyAuthHandler> auth_handler(new GnubbyAuthHandlerLinux());
@@ -133,7 +196,7 @@
   send_message_callback_ = callback;
 }
 
-size_t GnubbyAuthHandlerLinux::GetActiveSocketsMapSizeForTest() const {
+size_t GnubbyAuthHandlerLinux::GetActiveConnectionCountForTest() const {
   return active_sockets_.size();
 }
 
diff --git a/remoting/host/security_key/gnubby_auth_handler_linux.h b/remoting/host/security_key/gnubby_auth_handler_linux.h
deleted file mode 100644
index ff27c203..0000000
--- a/remoting/host/security_key/gnubby_auth_handler_linux.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2016 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 REMOTING_HOST_SECURITY_KEY_GNUBBY_AUTH_HANDLER_LINUX_H_
-#define REMOTING_HOST_SECURITY_KEY_GNUBBY_AUTH_HANDLER_LINUX_H_
-
-#include <stddef.h>
-
-#include <map>
-#include <string>
-
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "net/base/completion_callback.h"
-#include "net/socket/stream_socket.h"
-#include "remoting/host/security_key/gnubby_auth_handler.h"
-
-namespace net {
-class UnixDomainServerSocket;
-}  // namespace net
-
-namespace remoting {
-
-class GnubbySocket;
-
-class GnubbyAuthHandlerLinux : public GnubbyAuthHandler {
- public:
-  GnubbyAuthHandlerLinux();
-  ~GnubbyAuthHandlerLinux() override;
-
-  size_t GetActiveSocketsMapSizeForTest() const;
-
-  void SetRequestTimeoutForTest(const base::TimeDelta& timeout);
-
- private:
-  typedef std::map<int, GnubbySocket*> ActiveSockets;
-
-  // GnubbyAuthHandler interface.
-  void CreateGnubbyConnection() override;
-  bool IsValidConnectionId(int gnubby_connection_id) const override;
-  void SendClientResponse(int gnubby_connection_id,
-                          const std::string& response) override;
-  void SendErrorAndCloseConnection(int gnubby_connection_id) override;
-  void SetSendMessageCallback(const SendMessageCallback& callback) override;
-
-  // Starts listening for connection.
-  void DoAccept();
-
-  // Called when a connection is accepted.
-  void OnAccepted(int result);
-
-  // Called when a GnubbySocket has done reading.
-  void OnReadComplete(int gnubby_connection_id);
-
-  // Gets an active socket iterator for |gnubby_connection_id|.
-  ActiveSockets::const_iterator GetSocketForConnectionId(
-      int gnubby_connection_id) const;
-
-  // Send an error and closes an active socket.
-  void SendErrorAndCloseActiveSocket(const ActiveSockets::const_iterator& iter);
-
-  // A request timed out.
-  void RequestTimedOut(int gnubby_connection_id);
-
-  // Ensures GnubbyAuthHandlerLinux methods are called on the same thread.
-  base::ThreadChecker thread_checker_;
-
-  // Socket used to listen for authorization requests.
-  scoped_ptr<net::UnixDomainServerSocket> auth_socket_;
-
-  // A temporary holder for an accepted connection.
-  scoped_ptr<net::StreamSocket> accept_socket_;
-
-  // Used to pass gnubby extension messages to the client.
-  SendMessageCallback send_message_callback_;
-
-  // The last assigned gnubby connection id.
-  int last_connection_id_;
-
-  // Sockets by connection id used to process gnubbyd requests.
-  ActiveSockets active_sockets_;
-
-  // Timeout used for a request.
-  base::TimeDelta request_timeout_;
-
-  DISALLOW_COPY_AND_ASSIGN(GnubbyAuthHandlerLinux);
-};
-
-}  // namespace remoting
-
-#endif  // REMOTING_HOST_SECURITY_KEY_GNUBBY_AUTH_HANDLER_LINUX_H_
diff --git a/remoting/host/security_key/gnubby_auth_handler_linux_unittest.cc b/remoting/host/security_key/gnubby_auth_handler_linux_unittest.cc
index 5fd43cc..354ecc4 100644
--- a/remoting/host/security_key/gnubby_auth_handler_linux_unittest.cc
+++ b/remoting/host/security_key/gnubby_auth_handler_linux_unittest.cc
@@ -16,7 +16,7 @@
 #include "net/base/net_errors.h"
 #include "net/base/test_completion_callback.h"
 #include "net/socket/unix_domain_client_socket_posix.h"
-#include "remoting/host/security_key/gnubby_auth_handler_linux.h"
+#include "remoting/host/security_key/gnubby_auth_handler.h"
 #include "remoting/host/security_key/gnubby_socket.h"
 #include "remoting/proto/internal.pb.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -57,9 +57,7 @@
     send_message_callback_ =
         base::Bind(&GnubbyAuthHandlerLinuxTest::SendMessageToClient,
                    base::Unretained(this));
-    auth_handler_linux_.reset(new GnubbyAuthHandlerLinux());
-    auth_handler_ = auth_handler_linux_.get();
-    auth_handler_->SetSendMessageCallback(send_message_callback_);
+    auth_handler_ = remoting::GnubbyAuthHandler::Create(send_message_callback_);
   }
 
   void WaitForSendMessageToClient() {
@@ -119,10 +117,7 @@
   scoped_ptr<base::RunLoop> run_loop_;
 
   // Object under test.
-  scoped_ptr<GnubbyAuthHandlerLinux> auth_handler_linux_;
-
-  // GnubbyAuthHandler interface for |auth_handler_linux_|.
-  GnubbyAuthHandler* auth_handler_;
+  scoped_ptr<GnubbyAuthHandler> auth_handler_;
 
   GnubbyAuthHandler::SendMessageCallback send_message_callback_;
 
@@ -138,7 +133,7 @@
 };
 
 TEST_F(GnubbyAuthHandlerLinuxTest, NotClosedAfterRequest) {
-  ASSERT_EQ(0u, auth_handler_linux_->GetActiveSocketsMapSizeForTest());
+  ASSERT_EQ(0u, auth_handler_->GetActiveConnectionCountForTest());
 
   auth_handler_->CreateGnubbyConnection();
 
@@ -156,11 +151,11 @@
   ASSERT_TRUE(auth_handler_->IsValidConnectionId(1));
 
   // Verify that completing a request/response cycle didn't close the socket.
-  ASSERT_EQ(1u, auth_handler_linux_->GetActiveSocketsMapSizeForTest());
+  ASSERT_EQ(1u, auth_handler_->GetActiveConnectionCountForTest());
 }
 
 TEST_F(GnubbyAuthHandlerLinuxTest, HandleTwoRequests) {
-  ASSERT_EQ(0u, auth_handler_linux_->GetActiveSocketsMapSizeForTest());
+  ASSERT_EQ(0u, auth_handler_->GetActiveConnectionCountForTest());
 
   auth_handler_->CreateGnubbyConnection();
 
@@ -186,11 +181,11 @@
 
   // Verify that completing two request/response cycles didn't close the
   // socket.
-  ASSERT_EQ(1u, auth_handler_linux_->GetActiveSocketsMapSizeForTest());
+  ASSERT_EQ(1u, auth_handler_->GetActiveConnectionCountForTest());
 }
 
 TEST_F(GnubbyAuthHandlerLinuxTest, HandleTwoIndependentRequests) {
-  ASSERT_EQ(0u, auth_handler_linux_->GetActiveSocketsMapSizeForTest());
+  ASSERT_EQ(0u, auth_handler_->GetActiveConnectionCountForTest());
 
   auth_handler_->CreateGnubbyConnection();
 
@@ -221,23 +216,23 @@
   ASSERT_FALSE(auth_handler_->IsValidConnectionId(1));
 
   // Verify that the initial socket was released properly.
-  ASSERT_EQ(1u, auth_handler_linux_->GetActiveSocketsMapSizeForTest());
+  ASSERT_EQ(1u, auth_handler_->GetActiveConnectionCountForTest());
 }
 
 TEST_F(GnubbyAuthHandlerLinuxTest, DidReadTimeout) {
-  ASSERT_EQ(0u, auth_handler_linux_->GetActiveSocketsMapSizeForTest());
+  ASSERT_EQ(0u, auth_handler_->GetActiveConnectionCountForTest());
   auth_handler_->CreateGnubbyConnection();
 
   net::UnixDomainClientSocket client_socket(socket_path_.value(), false);
   net::TestCompletionCallback connect_callback;
   int rv = client_socket.Connect(connect_callback.callback());
   ASSERT_EQ(net::OK, connect_callback.GetResult(rv));
-  auth_handler_linux_->SetRequestTimeoutForTest(base::TimeDelta());
-  ASSERT_EQ(0u, auth_handler_linux_->GetActiveSocketsMapSizeForTest());
+  auth_handler_->SetRequestTimeoutForTest(base::TimeDelta());
+  ASSERT_EQ(0u, auth_handler_->GetActiveConnectionCountForTest());
 }
 
 TEST_F(GnubbyAuthHandlerLinuxTest, ClientErrorMessageDelivered) {
-  ASSERT_EQ(0u, auth_handler_linux_->GetActiveSocketsMapSizeForTest());
+  ASSERT_EQ(0u, auth_handler_->GetActiveConnectionCountForTest());
   auth_handler_->CreateGnubbyConnection();
 
   net::UnixDomainClientSocket client_socket(socket_path_.value(), false);
@@ -246,7 +241,7 @@
   ASSERT_EQ(net::OK, connect_callback.GetResult(rv));
 
   auth_handler_->SendErrorAndCloseConnection(1);
-  ASSERT_EQ(0u, auth_handler_linux_->GetActiveSocketsMapSizeForTest());
+  ASSERT_EQ(0u, auth_handler_->GetActiveConnectionCountForTest());
 }
 
 }  // namespace remoting
diff --git a/remoting/host/setup/daemon_controller_delegate_win.cc b/remoting/host/setup/daemon_controller_delegate_win.cc
index baab288..91e72679 100644
--- a/remoting/host/setup/daemon_controller_delegate_win.cc
+++ b/remoting/host/setup/daemon_controller_delegate_win.cc
@@ -68,7 +68,8 @@
 bool ReadConfig(const base::FilePath& filename,
                 scoped_ptr<base::DictionaryValue>* config_out) {
   std::string file_content;
-  if (!base::ReadFileToString(filename, &file_content, kMaxConfigFileSize)) {
+  if (!base::ReadFileToStringWithMaxSize(filename, &file_content,
+                                         kMaxConfigFileSize)) {
     PLOG(ERROR) << "Failed to read '" << filename.value() << "'.";
     return false;
   }
diff --git a/remoting/host/win/host_service.cc b/remoting/host/win/host_service.cc
index 950219d..37fb9c6 100644
--- a/remoting/host/win/host_service.cc
+++ b/remoting/host/win/host_service.cc
@@ -434,7 +434,7 @@
 int DaemonProcessMain() {
   HostService* service = HostService::GetInstance();
   if (!service->InitWithCommandLine(base::CommandLine::ForCurrentProcess())) {
-    return kUsageExitCode;
+    return kInvalidCommandLineExitCode;
   }
 
   return service->Run();
diff --git a/remoting/protocol/fake_datagram_socket.cc b/remoting/protocol/fake_datagram_socket.cc
index 4d5280d..cb837466 100644
--- a/remoting/protocol/fake_datagram_socket.cc
+++ b/remoting/protocol/fake_datagram_socket.cc
@@ -14,7 +14,6 @@
 #include "net/base/address_list.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace remoting {
diff --git a/remoting/protocol/fake_stream_socket.cc b/remoting/protocol/fake_stream_socket.cc
index 545b46a..547e2bd6 100644
--- a/remoting/protocol/fake_stream_socket.cc
+++ b/remoting/protocol/fake_stream_socket.cc
@@ -14,7 +14,6 @@
 #include "net/base/address_list.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace remoting {
diff --git a/remoting/protocol/jingle_info_request.cc b/remoting/protocol/jingle_info_request.cc
index 9644a8f2..b8044995 100644
--- a/remoting/protocol/jingle_info_request.cc
+++ b/remoting/protocol/jingle_info_request.cc
@@ -11,7 +11,6 @@
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/time/time.h"
-#include "net/base/net_util.h"
 #include "remoting/protocol/ice_config.h"
 #include "remoting/signaling/iq_sender.h"
 #include "third_party/webrtc/base/socketaddress.h"
diff --git a/remoting/protocol/pseudotcp_adapter.cc b/remoting/protocol/pseudotcp_adapter.cc
index 464d359..9992ef2 100644
--- a/remoting/protocol/pseudotcp_adapter.cc
+++ b/remoting/protocol/pseudotcp_adapter.cc
@@ -17,7 +17,6 @@
 #include "net/base/completion_callback.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "remoting/protocol/p2p_datagram_socket.h"
 
 using cricket::PseudoTcp;
diff --git a/remoting/protocol/webrtc_data_stream_adapter.cc b/remoting/protocol/webrtc_data_stream_adapter.cc
index bd38ebf..c155087 100644
--- a/remoting/protocol/webrtc_data_stream_adapter.cc
+++ b/remoting/protocol/webrtc_data_stream_adapter.cc
@@ -6,6 +6,7 @@
 
 #include <stdint.h>
 
+#include "base/bind.h"
 #include "base/callback.h"
 #include "base/callback_helpers.h"
 #include "base/location.h"
@@ -134,8 +135,11 @@
     return;
 
   state_ = State::CLOSED;
-  if (adapter_)
-    adapter_->OnChannelError(this);
+
+  // Notify the adapter about the error asychronously.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(&WebrtcDataStreamAdapter::OnChannelError, adapter_));
 }
 
 void WebrtcDataStreamAdapter::Channel::OnMessage(
@@ -226,7 +230,7 @@
   pending_channel.connected_callback.Run(std::move(pending_channel.channel));
 }
 
-void WebrtcDataStreamAdapter::OnChannelError(Channel* channel) {
+void WebrtcDataStreamAdapter::OnChannelError() {
   error_callback_.Run(CHANNEL_CONNECTION_ERROR);
 }
 
diff --git a/remoting/protocol/webrtc_data_stream_adapter.h b/remoting/protocol/webrtc_data_stream_adapter.h
index 9d6262d5..90ad8f56 100644
--- a/remoting/protocol/webrtc_data_stream_adapter.h
+++ b/remoting/protocol/webrtc_data_stream_adapter.h
@@ -53,7 +53,7 @@
   struct PendingChannel;
 
   void OnChannelConnected(Channel* channel);
-  void OnChannelError(Channel* channel);
+  void OnChannelError();
 
   const bool outgoing_;
   ErrorCallback error_callback_;
diff --git a/remoting/protocol/webrtc_transport_unittest.cc b/remoting/protocol/webrtc_transport_unittest.cc
index 591e216..40f4613bf 100644
--- a/remoting/protocol/webrtc_transport_unittest.cc
+++ b/remoting/protocol/webrtc_transport_unittest.cc
@@ -119,10 +119,12 @@
     host_event_handler_.set_connected_callback(base::Bind(&base::DoNothing));
     client_event_handler_.set_connected_callback(base::Bind(&base::DoNothing));
 
-    host_event_handler_.set_error_callback(base::Bind(
-        &WebrtcTransportTest::OnSessionError, base::Unretained(this)));
-    client_event_handler_.set_error_callback(base::Bind(
-        &WebrtcTransportTest::OnSessionError, base::Unretained(this)));
+    host_event_handler_.set_error_callback(
+        base::Bind(&WebrtcTransportTest::OnSessionError, base::Unretained(this),
+                   TransportRole::SERVER));
+    client_event_handler_.set_error_callback(
+        base::Bind(&WebrtcTransportTest::OnSessionError, base::Unretained(this),
+                   TransportRole::CLIENT));
 
     // Start both transports.
     host_transport_->Start(
@@ -150,7 +152,8 @@
     host_event_handler_.set_connected_callback(base::Closure());
     client_event_handler_.set_connected_callback(base::Closure());
 
-    EXPECT_EQ(OK, error_);
+    EXPECT_EQ(OK, client_error_);
+    EXPECT_EQ(OK, host_error_);
   }
 
   void CreateClientDataStream() {
@@ -177,8 +180,21 @@
       run_loop_->Quit();
   }
 
-  void OnSessionError(ErrorCode error) {
-    error_ = error;
+  void OnSessionError(TransportRole role, ErrorCode error) {
+    if (role == TransportRole::SERVER) {
+      host_error_ = error;
+      if (destroy_on_error_) {
+        host_message_pipe_.reset();
+        host_transport_.reset();
+      }
+    } else {
+      CHECK(role == TransportRole::CLIENT);
+      client_error_ = error;
+      if (destroy_on_error_) {
+        client_message_pipe_.reset();
+        client_transport_.reset();
+      }
+    }
     run_loop_->Quit();
   }
 
@@ -205,7 +221,10 @@
   scoped_ptr<MessagePipe> client_message_pipe_;
   scoped_ptr<MessagePipe> host_message_pipe_;
 
-  ErrorCode error_ = OK;
+  ErrorCode client_error_ = OK;
+  ErrorCode host_error_ = OK;
+
+  bool destroy_on_error_ = false;
 };
 
 TEST_F(WebrtcTransportTest, Connects) {
@@ -253,5 +272,33 @@
   EXPECT_TRUE(host_message_pipe_);
 }
 
+TEST_F(WebrtcTransportTest, TerminateDataChannel) {
+  InitializeConnection();
+  StartConnection();
+  WaitUntilConnected();
+
+  CreateClientDataStream();
+  CreateHostDataStream();
+
+  run_loop_.reset(new base::RunLoop());
+  run_loop_->Run();
+
+  EXPECT_TRUE(client_message_pipe_);
+  EXPECT_TRUE(host_message_pipe_);
+
+  destroy_on_error_ = true;
+
+  // Destroy pipe on one side of the of the connection. It should get closed on
+  // the other side.
+  client_message_pipe_.reset();
+
+  run_loop_.reset(new base::RunLoop());
+  run_loop_->Run();
+
+  // Check that OnSessionError() has been called.
+  EXPECT_EQ(CHANNEL_CONNECTION_ERROR, host_error_);
+  EXPECT_FALSE(host_transport_);
+}
+
 }  // namespace protocol
 }  // namespace remoting
diff --git a/remoting/protocol/webrtc_video_capturer_adapter.cc b/remoting/protocol/webrtc_video_capturer_adapter.cc
index 96c2c3a..c0aeea1 100644
--- a/remoting/protocol/webrtc_video_capturer_adapter.cc
+++ b/remoting/protocol/webrtc_video_capturer_adapter.cc
@@ -161,11 +161,16 @@
   DCHECK(capture_pending_);
   capture_pending_ = false;
 
+  if (!frame)
+    return;
+
   scoped_ptr<webrtc::DesktopFrame> owned_frame(frame);
 
-  // Drop the frame if there were no changes.
-  if (!owned_frame || owned_frame->updated_region().is_empty())
-    return;
+  // TODO(sergeyu): Currently the adapter keeps generating frames even when
+  // nothing is changing on the screen. This is necessary because the video
+  // sender drops frames. Obviously this is a suboptimal. The sending code in
+  // WebRTC needs to have some mechanism to notify when the bandwidth is
+  // exceeded, so the capturer can adapt frame rate.
 
   size_t width = frame->size().width();
   size_t height = frame->size().height();
diff --git a/remoting/remoting_host_srcs.gypi b/remoting/remoting_host_srcs.gypi
index 7fa4018e..a9023ea 100644
--- a/remoting/remoting_host_srcs.gypi
+++ b/remoting/remoting_host_srcs.gypi
@@ -214,7 +214,6 @@
       'host/screen_resolution.h',
       'host/security_key/gnubby_auth_handler.h',
       'host/security_key/gnubby_auth_handler_linux.cc',
-      'host/security_key/gnubby_auth_handler_linux.h',
       'host/security_key/gnubby_auth_handler_mac.cc',
       'host/security_key/gnubby_auth_handler_win.cc',
       'host/security_key/gnubby_extension.cc',
diff --git a/storage/browser/fileapi/file_system_quota_client.cc b/storage/browser/fileapi/file_system_quota_client.cc
index b988a99..f6cab0d 100644
--- a/storage/browser/fileapi/file_system_quota_client.cc
+++ b/storage/browser/fileapi/file_system_quota_client.cc
@@ -14,7 +14,6 @@
 #include "base/sequenced_task_runner.h"
 #include "base/single_thread_task_runner.h"
 #include "base/task_runner_util.h"
-#include "net/base/net_util.h"
 #include "storage/browser/fileapi/file_system_context.h"
 #include "storage/browser/fileapi/file_system_usage_cache.h"
 #include "storage/browser/fileapi/sandbox_file_system_backend.h"
diff --git a/storage/browser/fileapi/file_system_url_request_job.cc b/storage/browser/fileapi/file_system_url_request_job.cc
index 48ce68e7..28b9ea6 100644
--- a/storage/browser/fileapi/file_system_url_request_job.cc
+++ b/storage/browser/fileapi/file_system_url_request_job.cc
@@ -21,7 +21,6 @@
 #include "net/base/io_buffer.h"
 #include "net/base/mime_util.h"
 #include "net/base/net_errors.h"
-#include "net/base/net_util.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_response_info.h"
 #include "net/http/http_util.h"
diff --git a/sync/BUILD.gn b/sync/BUILD.gn
index 9cd103d3..f28fee83 100644
--- a/sync/BUILD.gn
+++ b/sync/BUILD.gn
@@ -297,8 +297,6 @@
     "internal_api/read_node.cc",
     "internal_api/read_transaction.cc",
     "internal_api/shared_model_type_processor.cc",
-    "internal_api/sync_backup_manager.cc",
-    "internal_api/sync_backup_manager.h",
     "internal_api/sync_context.cc",
     "internal_api/sync_context_proxy.cc",
     "internal_api/sync_context_proxy_impl.cc",
@@ -309,10 +307,6 @@
     "internal_api/sync_manager_factory.cc",
     "internal_api/sync_manager_impl.cc",
     "internal_api/sync_manager_impl.h",
-    "internal_api/sync_rollback_manager.cc",
-    "internal_api/sync_rollback_manager.h",
-    "internal_api/sync_rollback_manager_base.cc",
-    "internal_api/sync_rollback_manager_base.h",
     "internal_api/syncapi_internal.cc",
     "internal_api/syncapi_internal.h",
     "internal_api/syncapi_server_connection_manager.cc",
@@ -348,8 +342,6 @@
     "sessions/sync_session.h",
     "sessions/sync_session_context.cc",
     "sessions/sync_session_context.h",
-    "syncable/deferred_on_disk_directory_backing_store.cc",
-    "syncable/deferred_on_disk_directory_backing_store.h",
     "syncable/dir_open_result.h",
     "syncable/directory.cc",
     "syncable/directory.h",
@@ -554,7 +546,6 @@
 static_library("test_support_sync_internal_api") {
   testonly = true
   sources = [
-    "internal_api/public/test/fake_metadata_change_list.h",
     "internal_api/public/test/fake_model_type_service.h",
     "internal_api/public/test/fake_sync_manager.h",
     "internal_api/public/test/model_type_store_test_util.h",
@@ -563,7 +554,6 @@
     "internal_api/public/test/test_entry_factory.h",
     "internal_api/public/test/test_internal_components_factory.h",
     "internal_api/public/test/test_user_share.h",
-    "internal_api/test/fake_metadata_change_list.cc",
     "internal_api/test/fake_model_type_service.cc",
     "internal_api/test/fake_sync_manager.cc",
     "internal_api/test/model_type_store_test_util.cc",
@@ -668,12 +658,9 @@
     "internal_api/public/util/proto_value_ptr_unittest.cc",
     "internal_api/public/util/weak_handle_unittest.cc",
     "internal_api/shared_model_type_processor_unittest.cc",
-    "internal_api/sync_backup_manager_unittest.cc",
     "internal_api/sync_context_proxy_impl_unittest.cc",
     "internal_api/sync_encryption_handler_impl_unittest.cc",
     "internal_api/sync_manager_impl_unittest.cc",
-    "internal_api/sync_rollback_manager_base_unittest.cc",
-    "internal_api/sync_rollback_manager_unittest.cc",
     "internal_api/syncapi_server_connection_manager_unittest.cc",
     "js/js_event_details_unittest.cc",
     "js/sync_js_controller_unittest.cc",
@@ -682,7 +669,6 @@
     "sessions/model_type_registry_unittest.cc",
     "sessions/nudge_tracker_unittest.cc",
     "sessions/status_controller_unittest.cc",
-    "syncable/deferred_on_disk_directory_backing_store_unittest.cc",
     "syncable/directory_backing_store_unittest.cc",
     "syncable/directory_unittest.cc",
     "syncable/directory_unittest.h",
diff --git a/sync/api/entity_data.h b/sync/api/entity_data.h
index c1bbba9..842c512 100644
--- a/sync/api/entity_data.h
+++ b/sync/api/entity_data.h
@@ -5,6 +5,7 @@
 #ifndef SYNC_API_ENTITY_DATA_H_
 #define SYNC_API_ENTITY_DATA_H_
 
+#include <map>
 #include <string>
 #include <vector>
 
@@ -26,6 +27,7 @@
 
 typedef syncer::ProtoValuePtr<EntityData, EntityDataTraits> EntityDataPtr;
 typedef std::vector<EntityDataPtr> EntityDataList;
+typedef std::map<std::string, EntityDataPtr> EntityDataMap;
 
 // A light-weight container for sync entity data which represents either
 // local data created on the ModelTypeService side or remote data created
diff --git a/sync/api/model_type_service.h b/sync/api/model_type_service.h
index 469ed4a..950060e 100644
--- a/sync/api/model_type_service.h
+++ b/sync/api/model_type_service.h
@@ -42,7 +42,7 @@
   // to be called when sync is first turned on, not on every restart.
   virtual syncer::SyncError MergeSyncData(
       scoped_ptr<MetadataChangeList> metadata_change_list,
-      EntityDataList entity_data_list) = 0;
+      EntityDataMap entity_data_map) = 0;
 
   // Apply changes from the sync server locally.
   // Please note that |entity_changes| might have fewer entries than
diff --git a/sync/engine/get_updates_processor.cc b/sync/engine/get_updates_processor.cc
index 8bc701f..82c590f 100644
--- a/sync/engine/get_updates_processor.cc
+++ b/sync/engine/get_updates_processor.cc
@@ -370,6 +370,7 @@
 void GetUpdatesProcessor::ApplyUpdates(
     ModelTypeSet gu_types,
     sessions::StatusController* status_controller) {
+  status_controller->set_get_updates_request_types(gu_types);
   delegate_.ApplyUpdates(gu_types, status_controller, update_handler_map_);
 }
 
diff --git a/sync/engine/get_updates_processor_unittest.cc b/sync/engine/get_updates_processor_unittest.cc
index d6456a5..db3ea8c 100644
--- a/sync/engine/get_updates_processor_unittest.cc
+++ b/sync/engine/get_updates_processor_unittest.cc
@@ -434,6 +434,8 @@
 
   EXPECT_EQ(0, GetNonAppliedHandler()->GetPassiveApplyUpdatesCount());
   EXPECT_EQ(0, GetAppliedHandler()->GetPassiveApplyUpdatesCount());
+
+  EXPECT_TRUE(status.get_updates_request_types().Equals(GetGuTypes()));
 }
 
 // Verify that a configure cycle applies updates passively to the specified
@@ -455,6 +457,8 @@
 
   EXPECT_EQ(0, GetNonAppliedHandler()->GetApplyUpdatesCount());
   EXPECT_EQ(0, GetAppliedHandler()->GetApplyUpdatesCount());
+
+  EXPECT_TRUE(status.get_updates_request_types().Equals(GetGuTypes()));
 }
 
 // Verify that a poll cycle applies updates non-passively to the specified
@@ -475,6 +479,8 @@
 
   EXPECT_EQ(0, GetNonAppliedHandler()->GetPassiveApplyUpdatesCount());
   EXPECT_EQ(0, GetAppliedHandler()->GetPassiveApplyUpdatesCount());
+
+  EXPECT_TRUE(status.get_updates_request_types().Equals(GetGuTypes()));
 }
 
 class DownloadUpdatesDebugInfoTest : public ::testing::Test {
diff --git a/sync/engine/sync_scheduler_impl.cc b/sync/engine/sync_scheduler_impl.cc
index f126473..cc5e4a7 100644
--- a/sync/engine/sync_scheduler_impl.cc
+++ b/sync/engine/sync_scheduler_impl.cc
@@ -58,7 +58,6 @@
     case CLIENT_DATA_OBSOLETE:
     case CLEAR_PENDING:
     case DISABLED_BY_ADMIN:
-    case USER_ROLLBACK:
       // If we send terminate sync early then |sync_cycle_ended| notification
       // would not be sent. If there were no actions then |ACTIONABLE_ERROR|
       // notification wouldnt be sent either. Then the UI layer would be left
diff --git a/sync/engine/syncer_proto_util.cc b/sync/engine/syncer_proto_util.cc
index 306137b..66c4013 100644
--- a/sync/engine/syncer_proto_util.cc
+++ b/sync/engine/syncer_proto_util.cc
@@ -124,8 +124,6 @@
       return MIGRATION_DONE;
     case sync_pb::SyncEnums::DISABLED_BY_ADMIN:
       return DISABLED_BY_ADMIN;
-    case sync_pb::SyncEnums::USER_ROLLBACK:
-      return USER_ROLLBACK;
     case sync_pb::SyncEnums::PARTIAL_FAILURE:
       return PARTIAL_FAILURE;
     case sync_pb::SyncEnums::CLIENT_DATA_OBSOLETE:
@@ -193,8 +191,6 @@
     error.action = RESET_LOCAL_SYNC_DATA;
   } else if (error_type == sync_pb::SyncEnums::DISABLED_BY_ADMIN) {
     error.action = STOP_SYNC_FOR_DISABLED_ACCOUNT;
-  } else if (error_type == sync_pb::SyncEnums::USER_ROLLBACK) {
-    error.action = DISABLE_SYNC_AND_ROLLBACK;
   }  // There is no other action we can compute for legacy server.
   return error;
 }
@@ -498,8 +494,6 @@
       return SERVER_RETURN_NOT_MY_BIRTHDAY;
     case DISABLED_BY_ADMIN:
       return SERVER_RETURN_DISABLED_BY_ADMIN;
-    case USER_ROLLBACK:
-      return SERVER_RETURN_USER_ROLLBACK;
     case PARTIAL_FAILURE:
       // This only happens when partial throttling during GetUpdates.
       if (!sync_protocol_error.error_data_types.Empty()) {
diff --git a/sync/internal_api/internal_components_factory_impl.cc b/sync/internal_api/internal_components_factory_impl.cc
index 4f2f32e..65fcfaf 100644
--- a/sync/internal_api/internal_components_factory_impl.cc
+++ b/sync/internal_api/internal_components_factory_impl.cc
@@ -11,7 +11,6 @@
 #include "sync/engine/syncer.h"
 #include "sync/engine/sync_scheduler_impl.h"
 #include "sync/sessions/sync_session_context.h"
-#include "sync/syncable/deferred_on_disk_directory_backing_store.h"
 #include "sync/syncable/on_disk_directory_backing_store.h"
 
 using base::TimeDelta;
@@ -68,10 +67,6 @@
   if (storage == STORAGE_ON_DISK) {
     return scoped_ptr<syncable::DirectoryBackingStore>(
         new syncable::OnDiskDirectoryBackingStore(dir_name, backing_filepath));
-  } else if (storage == STORAGE_ON_DISK_DEFERRED) {
-    return scoped_ptr<syncable::DirectoryBackingStore>(
-        new syncable::DeferredOnDiskDirectoryBackingStore(dir_name,
-                                                          backing_filepath));
   } else {
     NOTREACHED();
     return scoped_ptr<syncable::DirectoryBackingStore>();
diff --git a/sync/internal_api/model_type_entity.cc b/sync/internal_api/model_type_entity.cc
index 99e1062..19be3e6 100644
--- a/sync/internal_api/model_type_entity.cc
+++ b/sync/internal_api/model_type_entity.cc
@@ -51,7 +51,12 @@
 ModelTypeEntity::~ModelTypeEntity() {}
 
 void ModelTypeEntity::CacheCommitData(EntityData* data) {
+  DCHECK(RequiresCommitRequest());
+  if (data->client_tag_hash.empty()) {
+    data->client_tag_hash = metadata_.client_tag_hash();
+  }
   commit_data_ = data->PassToPtr();
+  DCHECK(HasCommitData());
 }
 
 bool ModelTypeEntity::HasCommitData() const {
@@ -66,6 +71,10 @@
   return metadata_.sequence_number() > commit_requested_sequence_number_;
 }
 
+bool ModelTypeEntity::RequiresCommitData() const {
+  return RequiresCommitRequest() && !HasCommitData() && !metadata_.is_deleted();
+}
+
 bool ModelTypeEntity::UpdateIsReflection(int64_t update_version) const {
   return metadata_.server_version() >= update_version;
 }
@@ -137,26 +146,27 @@
   IncrementSequenceNumber();
   metadata_.set_is_deleted(true);
   metadata_.clear_specifics_hash();
-
-  EntityData data;
-  data.client_tag_hash = metadata_.client_tag_hash();
-  data.id = metadata_.server_id();
-  data.creation_time = syncer::ProtoTimeToTime(metadata_.creation_time());
-
-  CacheCommitData(&data);
+  // Clear any cached pending commit data.
+  if (HasCommitData()) commit_data_.reset();
 }
 
-void ModelTypeEntity::InitializeCommitRequestData(
-    CommitRequestData* request) const {
-  DCHECK(HasCommitData());
-  DCHECK_EQ(commit_data_->client_tag_hash, metadata_.client_tag_hash());
+void ModelTypeEntity::InitializeCommitRequestData(CommitRequestData* request) {
+  if (!metadata_.is_deleted()) {
+    DCHECK(HasCommitData());
+    DCHECK_EQ(commit_data_->client_tag_hash, metadata_.client_tag_hash());
+    request->entity = commit_data_;
+  } else {
+    // Make an EntityData with empty specifics to indicate deletion. This is
+    // done lazily here to simplify loading a pending deletion on startup.
+    EntityData data;
+    data.client_tag_hash = metadata_.client_tag_hash();
+    data.id = metadata_.server_id();
+    data.creation_time = syncer::ProtoTimeToTime(metadata_.creation_time());
+    request->entity = data.PassToPtr();
+  }
 
   request->sequence_number = metadata_.sequence_number();
   request->base_version = metadata_.server_version();
-  request->entity = commit_data_;
-}
-
-void ModelTypeEntity::SetCommitRequestInProgress() {
   commit_requested_sequence_number_ = metadata_.sequence_number();
 }
 
@@ -178,19 +188,6 @@
   commit_requested_sequence_number_ = metadata_.acked_sequence_number();
 }
 
-void ModelTypeEntity::ClearSyncState() {
-  // TODO(stanisc): crbug/561830: Need to review this entire method. It looks
-  // like the tests expect this to reset some metadata state but not the data.
-  // We should be able to reimplement this once we have the code fore
-  // fetching the data from the service.
-  metadata_.set_server_version(kUncommittedVersion);
-  // TODO(stanisc): Why is this 1 and not 0? This leaves the item unsynced.
-  metadata_.set_sequence_number(1);
-  metadata_.set_acked_sequence_number(0);
-  metadata_.clear_server_id();
-  commit_requested_sequence_number_ = 0;
-}
-
 void ModelTypeEntity::IncrementSequenceNumber() {
   DCHECK(metadata_.has_sequence_number());
   metadata_.set_sequence_number(metadata_.sequence_number() + 1);
diff --git a/sync/internal_api/model_type_entity_unittest.cc b/sync/internal_api/model_type_entity_unittest.cc
index 0f539e55..c1d0035 100644
--- a/sync/internal_api/model_type_entity_unittest.cc
+++ b/sync/internal_api/model_type_entity_unittest.cc
@@ -228,7 +228,8 @@
   entity->Delete();
   EXPECT_FALSE(HasSpecificsHash(entity));
 
-  EXPECT_TRUE(entity->HasCommitData());
+  EXPECT_FALSE(entity->HasCommitData());
+  EXPECT_FALSE(entity->RequiresCommitData());
   EXPECT_TRUE(entity->IsUnsynced());
 
   EXPECT_TRUE(entity->UpdateIsReflection(10));
diff --git a/sync/internal_api/public/configure_reason.h b/sync/internal_api/public/configure_reason.h
index 8fbbc4e3..4d015b9 100644
--- a/sync/internal_api/public/configure_reason.h
+++ b/sync/internal_api/public/configure_reason.h
@@ -33,9 +33,6 @@
   // cryptographer errors/resolutions.
   CONFIGURE_REASON_CRYPTO,
 
-  // Configure data types for backup/rollback.
-  CONFIGURE_REASON_BACKUP_ROLLBACK,
-
   // The client is configuring because of a programmatic type enable/disable,
   // such as when an error is encountered/resolved.
   CONFIGURE_REASON_PROGRAMMATIC,
diff --git a/sync/internal_api/public/internal_components_factory.h b/sync/internal_api/public/internal_components_factory.h
index f077af0..fee9bec 100644
--- a/sync/internal_api/public/internal_components_factory.h
+++ b/sync/internal_api/public/internal_components_factory.h
@@ -80,9 +80,6 @@
     // Use this if you want BuildDirectoryBackingStore to create/use a real
     // on disk store.
     STORAGE_ON_DISK,
-    // Use this to defer creating on-disk database until
-    // DirectoryBackingStore::SaveChanges() is called.
-    STORAGE_ON_DISK_DEFERRED,
     // Use this to test the case where a directory fails to load.
     STORAGE_INVALID
   };
diff --git a/sync/internal_api/public/model_type_entity.h b/sync/internal_api/public/model_type_entity.h
index 23a32acd..f8204a2 100644
--- a/sync/internal_api/public/model_type_entity.h
+++ b/sync/internal_api/public/model_type_entity.h
@@ -60,6 +60,10 @@
   // this item.
   bool RequiresCommitRequest() const;
 
+  // Whether commit data is needed to be cached before a commit request can be
+  // created. Note that deletions do not require cached data.
+  bool RequiresCommitData() const;
+
   // Returns true if the specified update version does not contain new data.
   bool UpdateIsReflection(int64_t update_version) const;
 
@@ -85,11 +89,8 @@
   void Delete();
 
   // Initializes a message representing this item's uncommitted state
-  // to be forwarded to the sync server for committing.
-  void InitializeCommitRequestData(CommitRequestData* request) const;
-
-  // Notes that the current version of this item has been queued for commit.
-  void SetCommitRequestInProgress();
+  // and assumes that it is forwarded to the sync engine for commiting.
+  void InitializeCommitRequestData(CommitRequestData* request);
 
   // Receives a successful commit response.
   //
@@ -107,9 +108,6 @@
   // Clears any in-memory sync state associated with outstanding commits.
   void ClearTransientSyncState();
 
-  // Clears all sync state.  Invoked when a user signs out.
-  void ClearSyncState();
-
   // Takes the passed commit data and caches it in the instance.
   // The data is swapped from the input struct without copying.
   void CacheCommitData(EntityData* data);
diff --git a/sync/internal_api/public/model_type_processor.h b/sync/internal_api/public/model_type_processor.h
index 4ab4946..2f1c724 100644
--- a/sync/internal_api/public/model_type_processor.h
+++ b/sync/internal_api/public/model_type_processor.h
@@ -35,7 +35,7 @@
   // handle.
   virtual void OnUpdateReceived(
       const sync_pb::DataTypeState& type_state,
-      const UpdateResponseDataList& response_list,
+      const UpdateResponseDataList& updates,
       const UpdateResponseDataList& pending_updates) = 0;
 };
 
diff --git a/sync/internal_api/public/sessions/model_neutral_state.h b/sync/internal_api/public/sessions/model_neutral_state.h
index a80a10d..91bce882 100644
--- a/sync/internal_api/public/sessions/model_neutral_state.h
+++ b/sync/internal_api/public/sessions/model_neutral_state.h
@@ -21,6 +21,9 @@
   ModelNeutralState();
   ~ModelNeutralState();
 
+  // The set of types for which updates were requested from the server.
+  ModelTypeSet get_updates_request_types;
+
   // The set of types for which commits were sent to the server.
   ModelTypeSet commit_request_types;
 
@@ -54,7 +57,7 @@
   bool items_committed;
 };
 
-bool HasSyncerError(const ModelNeutralState& state);
+SYNC_EXPORT bool HasSyncerError(const ModelNeutralState& state);
 
 }  // namespace sessions
 }  // namespace syncer
diff --git a/sync/internal_api/public/shared_model_type_processor.h b/sync/internal_api/public/shared_model_type_processor.h
index 606a22bf..b9034fedc4 100644
--- a/sync/internal_api/public/shared_model_type_processor.h
+++ b/sync/internal_api/public/shared_model_type_processor.h
@@ -11,6 +11,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/non_thread_safe.h"
+#include "sync/api/data_batch.h"
 #include "sync/api/metadata_batch.h"
 #include "sync/api/metadata_change_list.h"
 #include "sync/api/model_type_change_processor.h"
@@ -89,7 +90,7 @@
   void OnCommitCompleted(const sync_pb::DataTypeState& type_state,
                          const CommitResponseDataList& response_list) override;
   void OnUpdateReceived(const sync_pb::DataTypeState& type_state,
-                        const UpdateResponseDataList& response_list,
+                        const UpdateResponseDataList& updates,
                         const UpdateResponseDataList& pending_updates) override;
 
  private:
@@ -98,21 +99,32 @@
   using EntityMap = std::map<std::string, scoped_ptr<ModelTypeEntity>>;
   using UpdateMap = std::map<std::string, scoped_ptr<UpdateResponseData>>;
 
-  // Complete the start process.
-  void ReadyToConnect();
+  // Callback for ModelTypeService::GetData(). Used when we need to load data
+  // for pending commits during the initialization process.
+  void OnDataLoaded(syncer::SyncError error, scoped_ptr<DataBatch> data_batch);
+
+  // Check conditions, and if met inform sync that we are ready to connect.
+  void ConnectIfReady();
 
   // Handle the first update received from the server after being enabled.
   void OnInitialUpdateReceived(const sync_pb::DataTypeState& type_state,
-                               const UpdateResponseDataList& response_list,
-                               const UpdateResponseDataList& pending_updates);
+                               const UpdateResponseDataList& updates);
 
   // Sends all commit requests that are due to be sent to the sync thread.
   void FlushPendingCommitRequests();
 
-  // Clears any state related to outstanding communications with the
-  // CommitQueue.  Used when we want to disconnect from
-  // the current worker.
-  void ClearTransientSyncState();
+  // Computes the client tag hash for the given client |tag|.
+  std::string GetHashForTag(const std::string& tag);
+
+  // Gets the entity for the given tag, or null if there isn't one.
+  ModelTypeEntity* GetEntityForTag(const std::string& tag);
+
+  // Gets the entity for the given tag hash, or null if there isn't one.
+  ModelTypeEntity* GetEntityForTagHash(const std::string& tag_hash);
+
+  // Create an entity in the entity map for |tag| and return a pointer to it.
+  // Requires that no entity for |tag| already exists in the map.
+  ModelTypeEntity* CreateEntity(const std::string& tag, const EntityData& data);
 
   syncer::ModelType type_;
   sync_pb::DataTypeState data_type_state_;
@@ -123,6 +135,9 @@
   // Indicates whether the metadata has finished loading.
   bool is_metadata_loaded_;
 
+  // Indicates whether data for pending commits has finished loading.
+  bool is_pending_commit_data_loaded_;
+
   // Reference to the CommitQueue.
   //
   // The interface hides the posting of tasks across threads as well as the
@@ -148,7 +163,7 @@
   // thread, we want to make sure that no tasks generated as part of the
   // now-obsolete connection to affect us.  But we also want the WeakPtr we
   // sent to the UI thread to remain valid.
-  base::WeakPtrFactory<SharedModelTypeProcessor> weak_ptr_factory_for_ui_;
+  base::WeakPtrFactory<SharedModelTypeProcessor> weak_ptr_factory_;
   base::WeakPtrFactory<SharedModelTypeProcessor> weak_ptr_factory_for_sync_;
 };
 
diff --git a/sync/internal_api/public/shutdown_reason.h b/sync/internal_api/public/shutdown_reason.h
index f913eec5..604dc0e 100644
--- a/sync/internal_api/public/shutdown_reason.h
+++ b/sync/internal_api/public/shutdown_reason.h
@@ -14,8 +14,6 @@
   STOP_SYNC,         // Sync is asked to stop, e.g. due to scarce resource.
   DISABLE_SYNC,      // Sync is disabled, e.g. user sign out, dashboard clear.
   BROWSER_SHUTDOWN,  // Browser is closed.
-  SWITCH_MODE_SYNC,  // Engine is shut down and a new engine will start in
-                     // sync mode.
 };
 
 }  // namespace syncer
diff --git a/sync/internal_api/public/sync_manager_factory.h b/sync/internal_api/public/sync_manager_factory.h
index ef6ee6bf..feb9e8bd 100644
--- a/sync/internal_api/public/sync_manager_factory.h
+++ b/sync/internal_api/public/sync_manager_factory.h
@@ -15,22 +15,15 @@
 
 class SyncManager;
 
-// Helper class to allow dependency injection of the SyncManager.
+// Helper class to allow dependency injection of the SyncManager in tests.
 class SYNC_EXPORT SyncManagerFactory {
  public:
-  enum MANAGER_TYPE {
-    NORMAL,     // Normal sync manager
-    BACKUP,     // Backup sync manager
-    ROLLBACK,   // Rollback sync manager
-  };
-
-  explicit SyncManagerFactory(MANAGER_TYPE type);
+  SyncManagerFactory();
   virtual ~SyncManagerFactory();
 
   virtual scoped_ptr<SyncManager> CreateSyncManager(const std::string& name);
 
  private:
-  MANAGER_TYPE type_;
   DISALLOW_COPY_AND_ASSIGN(SyncManagerFactory);
 };
 
diff --git a/sync/internal_api/public/test/fake_metadata_change_list.h b/sync/internal_api/public/test/fake_metadata_change_list.h
deleted file mode 100644
index 3941f0a..0000000
--- a/sync/internal_api/public/test/fake_metadata_change_list.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2016 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 SYNC_INTERNAL_API_PUBLIC_TEST_FAKE_METADATA_CHANGE_LIST_H_
-#define SYNC_INTERNAL_API_PUBLIC_TEST_FAKE_METADATA_CHANGE_LIST_H_
-
-#include <string>
-#include <vector>
-
-#include "sync/api/metadata_change_list.h"
-#include "sync/internal_api/public/non_blocking_sync_common.h"
-#include "sync/protocol/data_type_state.pb.h"
-#include "sync/protocol/entity_metadata.pb.h"
-
-namespace syncer_v2 {
-
-// A non-functional implementation of MetadataChangeList for
-// testing purposes.
-// This class simply records all calls with all arguments for further
-// analysis by the test code.
-class FakeMetadataChangeList : public MetadataChangeList {
- public:
-  FakeMetadataChangeList();
-  ~FakeMetadataChangeList() override;
-
-  void UpdateDataTypeState(
-      const sync_pb::DataTypeState& data_type_state) override;
-  void ClearDataTypeState() override;
-  void UpdateMetadata(const std::string& client_tag,
-                      const sync_pb::EntityMetadata& metadata) override;
-  void ClearMetadata(const std::string& client_tag) override;
-
-  enum Action {
-    UPDATE_DATA_TYPE_STATE,
-    CLEAR_DATA_TYPE_STATE,
-    UPDATE_METADATA,
-    CLEAR_METADATA
-  };
-
-  struct Record {
-    Record();
-    virtual ~Record();
-
-    Action action;
-    std::string tag;
-    sync_pb::DataTypeState data_type_state;
-    sync_pb::EntityMetadata metadata;
-  };
-
-  size_t GetNumRecords() const;
-  const Record& GetNthRecord(size_t n) const;
-
- private:
-  std::vector<Record> records_;
-};
-
-}  // namespace syncer_v2
-
-#endif  // SYNC_INTERNAL_API_PUBLIC_TEST_FAKE_METADATA_CHANGE_LIST_H_
diff --git a/sync/internal_api/public/test/fake_model_type_service.h b/sync/internal_api/public/test/fake_model_type_service.h
index 76d21412..966680a 100644
--- a/sync/internal_api/public/test/fake_model_type_service.h
+++ b/sync/internal_api/public/test/fake_model_type_service.h
@@ -29,7 +29,7 @@
 
   syncer::SyncError MergeSyncData(
       scoped_ptr<MetadataChangeList> metadata_change_list,
-      EntityDataList entity_data_list) override;
+      EntityDataMap entity_data_map) override;
 
   syncer::SyncError ApplySyncChanges(
       scoped_ptr<MetadataChangeList> metadata_change_list,
diff --git a/sync/internal_api/shared_model_type_processor.cc b/sync/internal_api/shared_model_type_processor.cc
index 83a6a51d..3db885f7 100644
--- a/sync/internal_api/shared_model_type_processor.cc
+++ b/sync/internal_api/shared_model_type_processor.cc
@@ -5,6 +5,7 @@
 #include "sync/internal_api/public/shared_model_type_processor.h"
 
 #include <utility>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/location.h"
@@ -29,7 +30,7 @@
   void OnCommitCompleted(const sync_pb::DataTypeState& type_state,
                          const CommitResponseDataList& response_list) override;
   void OnUpdateReceived(const sync_pb::DataTypeState& type_state,
-                        const UpdateResponseDataList& response_list,
+                        const UpdateResponseDataList& updates,
                         const UpdateResponseDataList& pending_updates) override;
 
  private:
@@ -60,11 +61,11 @@
 
 void ModelTypeProcessorProxy::OnUpdateReceived(
     const sync_pb::DataTypeState& type_state,
-    const UpdateResponseDataList& response_list,
+    const UpdateResponseDataList& updates,
     const UpdateResponseDataList& pending_updates) {
   processor_task_runner_->PostTask(
       FROM_HERE, base::Bind(&ModelTypeProcessor::OnUpdateReceived, processor_,
-                            type_state, response_list, pending_updates));
+                            type_state, updates, pending_updates));
 }
 
 }  // namespace
@@ -74,7 +75,7 @@
     : type_(type),
       is_metadata_loaded_(false),
       service_(service),
-      weak_ptr_factory_for_ui_(this),
+      weak_ptr_factory_(this),
       weak_ptr_factory_for_sync_(this) {
   DCHECK(service);
 }
@@ -88,30 +89,38 @@
   DVLOG(1) << "Sync is starting for " << ModelTypeToString(type_);
 
   start_callback_ = start_callback;
-
-  if (is_metadata_loaded_) {
-    // The metadata was already loaded, so we are ready to connect.
-    ReadyToConnect();
-  }
+  ConnectIfReady();
 }
 
 void SharedModelTypeProcessor::OnMetadataLoaded(
     scoped_ptr<MetadataBatch> batch) {
   DCHECK(CalledOnValidThread());
   DCHECK(entities_.empty());
+  DCHECK(!is_metadata_loaded_);
   DCHECK(!IsConnected());
 
+  // Flip this flag here to cover all cases where we don't need to load data.
+  is_pending_commit_data_loaded_ = true;
+
   if (batch->GetDataTypeState().initial_sync_done()) {
     EntityMetadataMap metadata_map(batch->TakeAllMetadata());
+    std::vector<std::string> entities_to_commit;
+
     for (auto it = metadata_map.begin(); it != metadata_map.end(); it++) {
-      entities_.insert(std::make_pair(
-          it->second.client_tag_hash(),
-          ModelTypeEntity::CreateFromMetadata(it->first, &it->second)));
+      scoped_ptr<ModelTypeEntity> entity =
+          ModelTypeEntity::CreateFromMetadata(it->first, &it->second);
+      if (entity->RequiresCommitData()) {
+        entities_to_commit.push_back(entity->client_tag());
+      }
+      entities_[entity->metadata().client_tag_hash()] = std::move(entity);
     }
     data_type_state_ = batch->GetDataTypeState();
-    // TODO(maxbogue): crbug.com/569642: Load data for pending commits.
-    // TODO(maxbogue): crbug.com/569642: Check for inconsistent state where
-    // we have data but no metadata?
+    if (!entities_to_commit.empty()) {
+      is_pending_commit_data_loaded_ = false;
+      service_->GetData(entities_to_commit,
+                        base::Bind(&SharedModelTypeProcessor::OnDataLoaded,
+                                   weak_ptr_factory_.GetWeakPtr()));
+    }
   } else {
     // First time syncing; initialize metadata.
     data_type_state_.mutable_progress_marker()->set_data_type_id(
@@ -119,17 +128,28 @@
   }
 
   is_metadata_loaded_ = true;
-
-  if (!start_callback_.is_null()) {
-    // If OnSyncStarting() was already called, we are now ready to connect.
-    ReadyToConnect();
-  }
+  ConnectIfReady();
 }
 
-void SharedModelTypeProcessor::ReadyToConnect() {
+void SharedModelTypeProcessor::OnDataLoaded(syncer::SyncError error,
+                                            scoped_ptr<DataBatch> data_batch) {
+  while (data_batch->HasNext()) {
+    TagAndData data = data_batch->Next();
+    ModelTypeEntity* entity = GetEntityForTag(data.first);
+    // If the entity wasn't deleted or updated with new commit.
+    if (entity != nullptr && entity->RequiresCommitData()) {
+      entity->CacheCommitData(data.second.get());
+    }
+  }
+  is_pending_commit_data_loaded_ = true;
+  FlushPendingCommitRequests();
+}
+
+void SharedModelTypeProcessor::ConnectIfReady() {
   DCHECK(CalledOnValidThread());
-  DCHECK(is_metadata_loaded_);
-  DCHECK(!start_callback_.is_null());
+  if (!is_metadata_loaded_ || start_callback_.is_null()) {
+    return;
+  }
 
   scoped_ptr<ActivationContext> activation_context =
       make_scoped_ptr(new ActivationContext);
@@ -176,13 +196,15 @@
   weak_ptr_factory_for_sync_.InvalidateWeakPtrs();
   worker_.reset();
 
-  ClearTransientSyncState();
+  for (auto it = entities_.begin(); it != entities_.end(); ++it) {
+    it->second->ClearTransientSyncState();
+  }
 }
 
 base::WeakPtr<SharedModelTypeProcessor>
 SharedModelTypeProcessor::AsWeakPtrForUI() {
   DCHECK(CalledOnValidThread());
-  return weak_ptr_factory_for_ui_.GetWeakPtr();
+  return weak_ptr_factory_.GetWeakPtr();
 }
 
 void SharedModelTypeProcessor::ConnectSync(scoped_ptr<CommitQueue> worker) {
@@ -203,6 +225,11 @@
   DCHECK(!entity_data->non_unique_name.empty());
   DCHECK_EQ(type_, syncer::GetModelTypeFromSpecifics(entity_data->specifics));
 
+  if (!data_type_state_.initial_sync_done()) {
+    // Ignore changes before the initial sync is done.
+    return;
+  }
+
   // If the service specified an overriding hash, use that, otherwise generate
   // one from the tag.
   // TODO(skym): This behavior should be delayed, once crbug.com/561818 is fixed
@@ -214,20 +241,17 @@
 
   base::Time now = base::Time::Now();
 
-  ModelTypeEntity* entity = nullptr;
   // TODO(stanisc): crbug.com/561818: Search by client_tag rather than
   // client_tag_hash.
-  auto it = entities_.find(client_tag_hash);
-  if (it == entities_.end()) {
+  ModelTypeEntity* entity = GetEntityForTagHash(client_tag_hash);
+  if (entity == nullptr) {
     // The service is creating a new entity.
     scoped_ptr<ModelTypeEntity> scoped_entity = ModelTypeEntity::CreateNew(
         client_tag, client_tag_hash, entity_data->id, now);
     entity = scoped_entity.get();
-    entities_.insert(
-        std::make_pair(client_tag_hash, std::move(scoped_entity)));
+    entities_[client_tag_hash] = std::move(scoped_entity);
   } else {
     // The service is updating an existing entity.
-    entity = it->second.get();
     DCHECK_EQ(client_tag, entity->client_tag());
   }
 
@@ -244,13 +268,18 @@
     MetadataChangeList* metadata_change_list) {
   DCHECK(IsAllowingChanges());
 
+  if (!data_type_state_.initial_sync_done()) {
+    // Ignore changes before the initial sync is done.
+    return;
+  }
+
   const std::string client_tag_hash(
       syncer::syncable::GenerateSyncableHash(type_, client_tag));
 
   // TODO(skym): crbug.com/561818: Search by client_tag rather than
   // client_tag_hash.
-  auto it = entities_.find(client_tag_hash);
-  if (it == entities_.end()) {
+  ModelTypeEntity* entity = GetEntityForTagHash(client_tag_hash);
+  if (entity == nullptr) {
     // That's unusual, but not necessarily a bad thing.
     // Missing is as good as deleted as far as the model is concerned.
     DLOG(WARNING) << "Attempted to delete missing item."
@@ -258,7 +287,6 @@
     return;
   }
 
-  ModelTypeEntity* entity = it->second.get();
   entity->Delete();
 
   metadata_change_list->UpdateMetadata(client_tag, entity->metadata());
@@ -277,13 +305,18 @@
   if (!data_type_state_.initial_sync_done())
     return;
 
+  // Dont send anything if the initial data load is incomplete.
+  if (!is_pending_commit_data_loaded_)
+    return;
+
   // TODO(rlarocque): Do something smarter than iterate here.
   for (auto it = entities_.begin(); it != entities_.end(); ++it) {
-    if (it->second->RequiresCommitRequest()) {
+    ModelTypeEntity* entity = it->second.get();
+    if (entity->RequiresCommitRequest()) {
+      DCHECK(!entity->RequiresCommitData());
       CommitRequestData request;
-      it->second->InitializeCommitRequestData(&request);
+      entity->InitializeCommitRequestData(&request);
       commit_requests.push_back(request);
-      it->second->SetCommitRequestInProgress();
     }
   }
 
@@ -300,41 +333,35 @@
   data_type_state_ = type_state;
   change_list->UpdateDataTypeState(data_type_state_);
 
-  for (auto list_it = response_list.begin(); list_it != response_list.end();
-       ++list_it) {
-    const CommitResponseData& response_data = *list_it;
-    const std::string& client_tag_hash = response_data.client_tag_hash;
-
-    auto it = entities_.find(client_tag_hash);
-    if (it == entities_.end()) {
+  for (const CommitResponseData& data : response_list) {
+    ModelTypeEntity* entity = GetEntityForTagHash(data.client_tag_hash);
+    if (entity == nullptr) {
       NOTREACHED() << "Received commit response for missing item."
-                   << " type: " << type_ << " client_tag: " << client_tag_hash;
-      return;
-    } else {
-      it->second->ReceiveCommitResponse(response_data.id,
-                                        response_data.sequence_number,
-                                        response_data.response_version,
-                                        data_type_state_.encryption_key_name());
-      // TODO(stanisc): crbug.com/573333: Delete case.
-      // This might be the right place to clear a metadata entry that has
-      // been deleted locally and confirmed deleted by the server.
-      change_list->UpdateMetadata(it->second->client_tag(),
-                                  it->second->metadata());
+                   << " type: " << type_
+                   << " client_tag_hash: " << data.client_tag_hash;
+      continue;
     }
+
+    entity->ReceiveCommitResponse(data.id, data.sequence_number,
+                                  data.response_version,
+                                  data_type_state_.encryption_key_name());
+    // TODO(stanisc): crbug.com/573333: Delete case.
+    // This might be the right place to clear a metadata entry that has
+    // been deleted locally and confirmed deleted by the server.
+    change_list->UpdateMetadata(entity->client_tag(), entity->metadata());
   }
 
-  // TODO(stanisc): What is the right method to submit metadata changes to the
-  // service? Is using empty EntityChangeList OK?
   // TODO(stanisc): crbug.com/570085: Error handling.
   service_->ApplySyncChanges(std::move(change_list), EntityChangeList());
 }
 
 void SharedModelTypeProcessor::OnUpdateReceived(
     const sync_pb::DataTypeState& data_type_state,
-    const UpdateResponseDataList& response_list,
+    const UpdateResponseDataList& updates,
     const UpdateResponseDataList& pending_updates) {
   if (!data_type_state_.initial_sync_done()) {
-    OnInitialUpdateReceived(data_type_state, response_list, pending_updates);
+    OnInitialUpdateReceived(data_type_state, updates);
+    return;
   }
 
   scoped_ptr<MetadataChangeList> metadata_changes =
@@ -347,19 +374,16 @@
       data_type_state.encryption_key_name();
   data_type_state_ = data_type_state;
 
-  for (auto list_it = response_list.begin(); list_it != response_list.end();
-       ++list_it) {
-    const UpdateResponseData& response_data = *list_it;
-    const EntityData& data = response_data.entity.value();
+  for (const UpdateResponseData& update : updates) {
+    const EntityData& data = update.entity.value();
     const std::string& client_tag_hash = data.client_tag_hash;
 
     // If we're being asked to apply an update to this entity, this overrides
     // the previous pending updates.
     pending_updates_map_.erase(client_tag_hash);
 
-    ModelTypeEntity* entity = nullptr;
-    auto it = entities_.find(client_tag_hash);
-    if (it == entities_.end()) {
+    ModelTypeEntity* entity = GetEntityForTagHash(client_tag_hash);
+    if (entity == nullptr) {
       if (data.is_deleted()) {
         DLOG(WARNING) << "Received remote delete for a non-existing item."
                       << " client_tag_hash: " << client_tag_hash;
@@ -367,31 +391,29 @@
       }
 
       // Let the service define |client_tag| based on the entity data.
-      std::string client_tag = service_->GetClientTag(data);
+      const std::string client_tag = service_->GetClientTag(data);
 
       scoped_ptr<ModelTypeEntity> scoped_entity = ModelTypeEntity::CreateNew(
           client_tag, client_tag_hash, data.id, data.creation_time);
       entity = scoped_entity.get();
-      entities_.insert(
-          std::make_pair(client_tag_hash, std::move(scoped_entity)));
+      entities_[client_tag_hash] = std::move(scoped_entity);
 
       entity_changes.push_back(
-          EntityChange::CreateAdd(client_tag, response_data.entity));
+          EntityChange::CreateAdd(client_tag, update.entity));
 
     } else {
-      entity = it->second.get();
       if (data.is_deleted()) {
         entity_changes.push_back(
             EntityChange::CreateDelete(entity->client_tag()));
       } else {
         // TODO(stanisc): crbug.com/561829: Avoid sending an update to the
         // service if there is no actual change.
-        entity_changes.push_back(EntityChange::CreateUpdate(
-            entity->client_tag(), response_data.entity));
+        entity_changes.push_back(
+            EntityChange::CreateUpdate(entity->client_tag(), update.entity));
       }
     }
 
-    entity->ApplyUpdateFromServer(response_data);
+    entity->ApplyUpdateFromServer(update);
     // TODO(stanisc): crbug.com/573333: Delete case.
     // This might be the right place to clear metadata entry instead of
     // updating it.
@@ -402,10 +424,9 @@
 
     // If the received entity has out of date encryption, we schedule another
     // commit to fix it.
-    if (data_type_state_.encryption_key_name() !=
-        response_data.encryption_key_name) {
+    if (data_type_state_.encryption_key_name() != update.encryption_key_name) {
       DVLOG(2) << ModelTypeToString(type_) << ": Requesting re-encrypt commit "
-               << response_data.encryption_key_name << " -> "
+               << update.encryption_key_name << " -> "
                << data_type_state_.encryption_key_name();
       auto it2 = entities_.find(client_tag_hash);
       it2->second->UpdateDesiredEncryptionKey(
@@ -415,9 +436,7 @@
 
   // TODO(stanisc): crbug.com/529498: stop saving pending updates.
   // Save pending updates in the appropriate data structure.
-  for (auto list_it = pending_updates.begin(); list_it != pending_updates.end();
-       ++list_it) {
-    const UpdateResponseData& update = *list_it;
+  for (const UpdateResponseData& update : pending_updates) {
     const std::string& client_tag_hash = update.entity->client_tag_hash;
 
     auto lookup_it = pending_updates_map_.find(client_tag_hash);
@@ -450,10 +469,38 @@
 
 void SharedModelTypeProcessor::OnInitialUpdateReceived(
     const sync_pb::DataTypeState& data_type_state,
-    const UpdateResponseDataList& response_list,
-    const UpdateResponseDataList& pending_updates) {
-  // TODO(maxbogue): crbug.com/569675: Generate metadata for all entities.
-  // TODO(maxbogue): crbug.com/569675: Call merge method on the service.
+    const UpdateResponseDataList& updates) {
+  DCHECK(entities_.empty());
+  // Ensure that initial sync was not already done and that the worker
+  // correctly marked initial sync as done for this update.
+  DCHECK(!data_type_state_.initial_sync_done());
+  DCHECK(data_type_state.initial_sync_done());
+
+  scoped_ptr<MetadataChangeList> metadata_changes =
+      service_->CreateMetadataChangeList();
+  EntityDataMap data_map;
+
+  data_type_state_ = data_type_state;
+  metadata_changes->UpdateDataTypeState(data_type_state_);
+
+  for (const UpdateResponseData& update : updates) {
+    const EntityData& data = update.entity.value();
+
+    // Let the service define a client |tag| based on the entity data.
+    std::string tag = service_->GetClientTag(data);
+
+    ModelTypeEntity* entity = CreateEntity(tag, data);
+    entity->ApplyUpdateFromServer(update);
+    metadata_changes->UpdateMetadata(tag, entity->metadata());
+    data_map[tag] = update.entity;
+  }
+
+  // Let the service handle associating and merging the data.
+  // TODO(stanisc): crbug.com/570085: Error handling.
+  service_->MergeSyncData(std::move(metadata_changes), data_map);
+
+  // We may have new reasons to commit by the time this function is done.
+  FlushPendingCommitRequests();
 }
 
 UpdateResponseDataList SharedModelTypeProcessor::GetPendingUpdates() {
@@ -465,10 +512,30 @@
   return pending_updates_list;
 }
 
-void SharedModelTypeProcessor::ClearTransientSyncState() {
-  for (auto it = entities_.begin(); it != entities_.end(); ++it) {
-    it->second->ClearTransientSyncState();
-  }
+std::string SharedModelTypeProcessor::GetHashForTag(const std::string& tag) {
+  return syncer::syncable::GenerateSyncableHash(type_, tag);
+}
+
+ModelTypeEntity* SharedModelTypeProcessor::GetEntityForTag(
+    const std::string& tag) {
+  return GetEntityForTagHash(GetHashForTag(tag));
+}
+
+ModelTypeEntity* SharedModelTypeProcessor::GetEntityForTagHash(
+    const std::string& tag_hash) {
+  auto it = entities_.find(tag_hash);
+  return it != entities_.end() ? it->second.get() : nullptr;
+}
+
+ModelTypeEntity* SharedModelTypeProcessor::CreateEntity(
+    const std::string& tag,
+    const EntityData& data) {
+  DCHECK(entities_.find(data.client_tag_hash) == entities_.end());
+  scoped_ptr<ModelTypeEntity> entity = ModelTypeEntity::CreateNew(
+      tag, data.client_tag_hash, data.id, data.creation_time);
+  ModelTypeEntity* entity_ptr = entity.get();
+  entities_[data.client_tag_hash] = std::move(entity);
+  return entity_ptr;
 }
 
 }  // namespace syncer_v2
diff --git a/sync/internal_api/shared_model_type_processor_unittest.cc b/sync/internal_api/shared_model_type_processor_unittest.cc
index 183ff65..5a8cd66 100644
--- a/sync/internal_api/shared_model_type_processor_unittest.cc
+++ b/sync/internal_api/shared_model_type_processor_unittest.cc
@@ -6,15 +6,18 @@
 
 #include <stddef.h>
 #include <stdint.h>
+#include <unordered_map>
 
 #include "base/bind.h"
+#include "base/callback.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "sync/engine/commit_queue.h"
 #include "sync/internal_api/public/activation_context.h"
 #include "sync/internal_api/public/base/model_type.h"
+#include "sync/internal_api/public/data_batch_impl.h"
 #include "sync/internal_api/public/non_blocking_sync_common.h"
-#include "sync/internal_api/public/test/fake_metadata_change_list.h"
+#include "sync/internal_api/public/simple_metadata_change_list.h"
 #include "sync/internal_api/public/test/fake_model_type_service.h"
 #include "sync/protocol/data_type_state.pb.h"
 #include "sync/protocol/sync.pb.h"
@@ -27,56 +30,147 @@
 
 static const syncer::ModelType kModelType = syncer::PREFERENCES;
 
-// Tests the sync engine parts of SharedModelTypeProcessor.
+namespace {
+
+// It is intentionally very difficult to copy an EntityData, as in normal code
+// we never want to. However, since we store the data as an EntityData for the
+// test code here, this function is needed to manually copy it.
+scoped_ptr<EntityData> CopyEntityData(const EntityData& old_data) {
+  scoped_ptr<EntityData> new_data(new EntityData());
+  new_data->id = old_data.id;
+  new_data->client_tag_hash = old_data.client_tag_hash;
+  new_data->non_unique_name = old_data.non_unique_name;
+  new_data->specifics = old_data.specifics;
+  new_data->creation_time = old_data.creation_time;
+  new_data->modification_time = old_data.modification_time;
+  return new_data;
+}
+
+// A basic in-memory storage mechanism for data and metadata. This makes it
+// easier to test more complex behaviors involving when entities are written,
+// committed, etc. Having a separate class helps keep the main one cleaner.
+class SimpleStore {
+ public:
+  void PutData(const std::string& tag, const EntityData& data) {
+    data_store_[tag] = CopyEntityData(data);
+  }
+
+  void PutMetadata(const std::string& tag,
+                   const sync_pb::EntityMetadata& metadata) {
+    metadata_store_[tag] = metadata;
+  }
+
+  void RemoveData(const std::string& tag) { data_store_.erase(tag); }
+  void RemoveMetadata(const std::string& tag) { metadata_store_.erase(tag); }
+
+  bool HasData(const std::string& tag) const {
+    return data_store_.find(tag) != data_store_.end();
+  }
+
+  bool HasMetadata(const std::string& tag) const {
+    return metadata_store_.find(tag) != metadata_store_.end();
+  }
+
+  const std::unordered_map<std::string, scoped_ptr<EntityData>>& GetAllData()
+      const {
+    return data_store_;
+  }
+
+  const EntityData& GetData(const std::string& tag) const {
+    return *data_store_.find(tag)->second;
+  }
+
+  const sync_pb::EntityMetadata& GetMetadata(const std::string& tag) const {
+    return metadata_store_.find(tag)->second;
+  }
+
+  size_t DataCount() const { return data_store_.size(); }
+  size_t MetadataCount() const { return metadata_store_.size(); }
+
+  const sync_pb::DataTypeState& data_type_state() const {
+    return data_type_state_;
+  }
+
+  void set_data_type_state(const sync_pb::DataTypeState& data_type_state) {
+    data_type_state_ = data_type_state;
+  }
+
+  scoped_ptr<MetadataBatch> CreateMetadataBatch() const {
+    scoped_ptr<MetadataBatch> metadata_batch(new MetadataBatch());
+    metadata_batch->SetDataTypeState(data_type_state_);
+    for (auto it = metadata_store_.begin(); it != metadata_store_.end(); it++) {
+      metadata_batch->AddMetadata(it->first, it->second);
+    }
+    return metadata_batch;
+  }
+
+  void Reset() {
+    data_store_.clear();
+    metadata_store_.clear();
+    data_type_state_.Clear();
+  }
+
+ private:
+  std::unordered_map<std::string, scoped_ptr<EntityData>> data_store_;
+  std::unordered_map<std::string, sync_pb::EntityMetadata> metadata_store_;
+  sync_pb::DataTypeState data_type_state_;
+};
+
+}  // namespace
+
+// Tests the various functionality of SharedModelTypeProcessor.
 //
-// The SharedModelTypeProcessor contains a non-trivial amount of code dedicated
-// to turning the sync engine on and off again.  That code is fairly well
-// tested in the NonBlockingDataTypeController unit tests and it doesn't need
-// to be re-tested here.
+// The processor sits between the service (implemented by this test class) and
+// the worker, which is represented as a commit queue (MockCommitQueue). This
+// test suite exercises the initialization flows (whether initial sync is done,
+// loading pending updates, performing the initial merge, etc) as well as normal
+// functionality:
 //
-// These tests skip past initialization and focus on steady state sync engine
-// behavior.  This is where we test how the processor responds to the
-// model's requests to make changes to its data, the messages incoming from the
-// sync server, and what happens when the two conflict.
-//
-// Inputs:
-// - Initial state from permanent storage. (TODO)
-// - Create, update or delete requests from the model.
-// - Update responses and commit responses from the server.
-//
-// Outputs:
-// - Writes to permanent storage. (TODO)
-// - Callbacks into the model. (TODO)
-// - Requests to the sync thread.  Tested with MockCommitQueue.
+// - Initialization before the initial sync and merge correctly performs a merge
+//   and initializes the metadata in storage. TODO(maxbogue): crbug.com/569675.
+// - Initialization after the initial sync correctly loads metadata and queues
+//   any pending commits.
+// - Put and Delete calls from the service result in the correct metadata in
+//   storage and the correct commit requests on the worker side.
+// - Updates and commit responses from the worker correctly affect data and
+//   metadata in storage on the service side.
 class SharedModelTypeProcessorTest : public ::testing::Test,
                                      public FakeModelTypeService {
  public:
-  SharedModelTypeProcessorTest()
-      : mock_queue_(new MockCommitQueue()),
-        mock_queue_ptr_(mock_queue_),
-        metadata_batch_(new MetadataBatch()) {
+  SharedModelTypeProcessorTest() {}
+
+  ~SharedModelTypeProcessorTest() override {}
+
+  void CreateProcessor() {
+    ASSERT_FALSE(type_processor());
     set_change_processor(
         make_scoped_ptr(new SharedModelTypeProcessor(kModelType, this)));
   }
 
-  ~SharedModelTypeProcessorTest() override {}
+  void InitializeToMetadataLoaded() {
+    CreateProcessor();
+    sync_pb::DataTypeState data_type_state(db_.data_type_state());
+    data_type_state.set_initial_sync_done(true);
+    db_.set_data_type_state(data_type_state);
+    OnMetadataLoaded();
+  }
 
   // Initialize to a "ready-to-commit" state.
   void InitializeToReadyState() {
-    data_type_state_.set_initial_sync_done(true);
-    OnMetadataLoaded();
+    InitializeToMetadataLoaded();
+    OnDataLoaded();
     OnSyncStarting();
-    // TODO(maxbogue): crbug.com/569642: Remove this once entity data is loaded
-    // for the normal startup flow.
-    UpdateResponseDataList empty_update_list;
-    type_processor()->OnUpdateReceived(data_type_state_, empty_update_list,
-                                       empty_update_list);
   }
 
   void OnMetadataLoaded() {
-    metadata_batch_->SetDataTypeState(data_type_state_);
-    type_processor()->OnMetadataLoaded(std::move(metadata_batch_));
-    metadata_batch_.reset(new MetadataBatch());
+    type_processor()->OnMetadataLoaded(db_.CreateMetadataBatch());
+  }
+
+  void OnDataLoaded() {
+    if (!data_callback_.is_null()) {
+      data_callback_.Run();
+      data_callback_.Reset();
+    }
   }
 
   void OnSyncStarting() {
@@ -87,56 +181,92 @@
 
   void DisconnectSync() {
     type_processor()->DisconnectSync();
-    mock_queue_ = NULL;
-    mock_queue_ptr_.reset();
+    mock_queue_ = nullptr;
   }
 
   // Disable sync for this SharedModelTypeProcessor.  Should cause sync state to
   // be discarded.
   void Disable() {
     type_processor()->Disable();
-    mock_queue_ = NULL;
-    mock_queue_ptr_.reset();
+    mock_queue_ = nullptr;
     EXPECT_FALSE(type_processor());
   }
 
-  // Restart sync after DisconnectSync() or Disable().
-  void Restart() {
-    if (!type_processor()) {
-      set_change_processor(
-          make_scoped_ptr(new SharedModelTypeProcessor(kModelType, this)));
-    }
-    // Prepare a new MockCommitQueue instance, just as we would
-    // if this happened in the real world.
-    mock_queue_ptr_.reset(new MockCommitQueue());
-    mock_queue_ = mock_queue_ptr_.get();
-    // Restart sync with the new CommitQueue.
-    OnSyncStarting();
-  }
-
   // Local data modification.  Emulates signals from the model thread.
-  void WriteItem(const std::string& tag,
-                 const std::string& value,
-                 MetadataChangeList* change_list) {
-    scoped_ptr<EntityData> entity_data = make_scoped_ptr(new EntityData());
-    entity_data->specifics = GenerateSpecifics(tag, value);
-    entity_data->non_unique_name = tag;
-    type_processor()->Put(tag, std::move(entity_data), change_list);
+  void WriteItem(const std::string& tag, const std::string& value) {
+    WriteItem(tag, GenerateEntityData(tag, value));
   }
 
-  void DeleteItem(const std::string& tag, MetadataChangeList* change_list) {
-    type_processor()->Delete(tag, change_list);
+  // Overloaded form to allow passing of custom entity data.
+  void WriteItem(const std::string& tag, scoped_ptr<EntityData> entity_data) {
+    db_.PutData(tag, *entity_data);
+    if (type_processor()) {
+      scoped_ptr<MetadataChangeList> change_list(
+          new SimpleMetadataChangeList());
+      type_processor()->Put(tag, std::move(entity_data), change_list.get());
+      ApplyMetadataChangeList(std::move(change_list));
+    }
   }
 
-  // Emulates an "initial sync done" message from the CommitQueue.
-  void OnInitialSyncDone() {
-    data_type_state_.set_initial_sync_done(true);
-    UpdateResponseDataList empty_update_list;
+  // Writes data for |tag| and simulates a commit response for it.
+  void WriteItemAndAck(const std::string& tag, const std::string& value) {
+    WriteItem(tag, value);
+    ASSERT_TRUE(HasCommitRequestForTag(tag));
+    SuccessfulCommitResponse(GetLatestCommitRequestForTag(tag));
+  }
 
-    // TODO(stanisc): crbug/569645: replace this with loading the initial state
-    // via LoadMetadata callback.
-    type_processor()->OnUpdateReceived(data_type_state_, empty_update_list,
-                                       empty_update_list);
+  void DeleteItem(const std::string& tag) {
+    db_.RemoveData(tag);
+    if (type_processor()) {
+      scoped_ptr<MetadataChangeList> change_list(
+          new SimpleMetadataChangeList());
+      type_processor()->Delete(tag, change_list.get());
+      ApplyMetadataChangeList(std::move(change_list));
+    }
+  }
+
+  // Wipes existing DB and simulates one uncommited item.
+  void ResetStateWriteItem(const std::string& tag, const std::string& value) {
+    clear_change_processor();
+    db_.Reset();
+    InitializeToReadyState();
+    EXPECT_EQ(0U, ProcessorEntityCount());
+    WriteItem(tag, value);
+    EXPECT_EQ(1U, ProcessorEntityCount());
+    clear_change_processor();
+  }
+
+  // Wipes existing DB and simulates one uncommited deletion.
+  void ResetStateDeleteItem(const std::string& tag, const std::string& value) {
+    clear_change_processor();
+    db_.Reset();
+    InitializeToReadyState();
+    EXPECT_EQ(0U, ProcessorEntityCount());
+    WriteItemAndAck(tag, value);
+    EXPECT_EQ(1U, ProcessorEntityCount());
+    DeleteItem(tag);
+    EXPECT_EQ(1U, ProcessorEntityCount());
+    clear_change_processor();
+  }
+
+  // Simulates an initial GetUpdates response from the worker with |updates|.
+  void OnInitialSyncDone(UpdateResponseDataList updates) {
+    sync_pb::DataTypeState data_type_state(db_.data_type_state());
+    data_type_state.set_initial_sync_done(true);
+    type_processor()->OnUpdateReceived(data_type_state, updates,
+                                       UpdateResponseDataList());
+  }
+
+  // Overloaded form with no updates.
+  void OnInitialSyncDone() { OnInitialSyncDone(UpdateResponseDataList()); }
+
+  // Overloaded form that constructs an update for a single entity.
+  void OnInitialSyncDone(const std::string& tag, const std::string& value) {
+    UpdateResponseDataList updates;
+    UpdateResponseData update;
+    update.entity = GenerateEntityData(tag, value)->PassToPtr();
+    updates.push_back(update);
+    OnInitialSyncDone(updates);
   }
 
   // Emulate updates from the server.
@@ -150,7 +280,7 @@
 
     UpdateResponseDataList list;
     list.push_back(data);
-    type_processor()->OnUpdateReceived(data_type_state_, list,
+    type_processor()->OnUpdateReceived(db_.data_type_state(), list,
                                        UpdateResponseDataList());
   }
 
@@ -163,7 +293,7 @@
 
     UpdateResponseDataList list;
     list.push_back(data);
-    type_processor()->OnUpdateReceived(data_type_state_, list,
+    type_processor()->OnUpdateReceived(db_.data_type_state(), list,
                                        UpdateResponseDataList());
   }
 
@@ -180,7 +310,7 @@
 
     UpdateResponseDataList list;
     list.push_back(data);
-    type_processor()->OnUpdateReceived(data_type_state_,
+    type_processor()->OnUpdateReceived(db_.data_type_state(),
                                        UpdateResponseDataList(), list);
   }
 
@@ -188,9 +318,8 @@
   bool HasPendingUpdate(const std::string& tag) const {
     const std::string client_tag_hash = GenerateTagHash(tag);
     const UpdateResponseDataList list = type_processor()->GetPendingUpdates();
-    for (UpdateResponseDataList::const_iterator it = list.begin();
-         it != list.end(); ++it) {
-      if (it->entity->client_tag_hash == client_tag_hash)
+    for (const UpdateResponseData& update : list) {
+      if (update.entity->client_tag_hash == client_tag_hash)
         return true;
     }
     return false;
@@ -201,10 +330,9 @@
     DCHECK(HasPendingUpdate(tag));
     const std::string client_tag_hash = GenerateTagHash(tag);
     const UpdateResponseDataList list = type_processor()->GetPendingUpdates();
-    for (UpdateResponseDataList::const_iterator it = list.begin();
-         it != list.end(); ++it) {
-      if (it->entity->client_tag_hash == client_tag_hash)
-        return *it;
+    for (const UpdateResponseData& update : list) {
+      if (update.entity->client_tag_hash == client_tag_hash)
+        return update;
     }
     NOTREACHED();
     return UpdateResponseData();
@@ -217,6 +345,7 @@
 
   // Read emitted commit requests as batches.
   size_t GetNumCommitRequestLists() {
+    DCHECK(mock_queue_);
     return mock_queue_->GetNumCommitRequestLists();
   }
 
@@ -239,15 +368,16 @@
   void SuccessfulCommitResponse(const CommitRequestData& request_data) {
     CommitResponseDataList list;
     list.push_back(mock_queue_->SuccessfulCommitResponse(request_data));
-    type_processor()->OnCommitCompleted(data_type_state_, list);
+    type_processor()->OnCommitCompleted(db_.data_type_state(), list);
   }
 
   // Sends the type sync proxy an updated DataTypeState to let it know that
   // the desired encryption key has changed.
   void UpdateDesiredEncryptionKey(const std::string& key_name) {
-    data_type_state_.set_encryption_key_name(key_name);
+    sync_pb::DataTypeState data_type_state(db_.data_type_state());
+    data_type_state.set_encryption_key_name(key_name);
     type_processor()->OnUpdateReceived(
-        data_type_state_, UpdateResponseDataList(), UpdateResponseDataList());
+        data_type_state, UpdateResponseDataList(), UpdateResponseDataList());
   }
 
   // Sets the key_name that the mock CommitQueue will claim is in use
@@ -256,38 +386,42 @@
     mock_queue_->SetServerEncryptionKey(key_name);
   }
 
-  void AddMetadataToBatch(const std::string& tag) {
-    const std::string tag_hash = GenerateTagHash(tag);
-    base::Time creation_time = base::Time::Now();
-
-    sync_pb::EntityMetadata metadata;
-    metadata.set_client_tag_hash(tag_hash);
-    metadata.set_creation_time(syncer::TimeToProtoTime(creation_time));
-
-    metadata_batch()->AddMetadata(tag, metadata);
-  }
-
   // Return the number of entities the processor has metadata for.
   size_t ProcessorEntityCount() const {
+    DCHECK(type_processor());
     return type_processor()->entities_.size();
   }
 
+  // Expect that the |n|th commit request list has one commit request for |tag|
+  // with |value| set.
+  void ExpectNthCommitRequestList(size_t n,
+                                  const std::string& tag,
+                                  const std::string& value) {
+    const CommitRequestDataList& list = GetNthCommitRequestList(n);
+    ASSERT_EQ(1U, list.size());
+    const EntityData& data = list[0].entity.value();
+    EXPECT_EQ(GenerateTagHash(tag), data.client_tag_hash);
+    EXPECT_EQ(value, data.specifics.preference().value());
+  }
+
+  // For each tag in |tags|, expect a corresponding request list of length one.
+  void ExpectCommitRequests(const std::vector<std::string>& tags) {
+    EXPECT_EQ(tags.size(), GetNumCommitRequestLists());
+    for (size_t i = 0; i < tags.size(); i++) {
+      const CommitRequestDataList& commits = GetNthCommitRequestList(i);
+      EXPECT_EQ(1U, commits.size());
+      EXPECT_EQ(GenerateTagHash(tags[i]), commits[0].entity->client_tag_hash);
+    }
+  }
+
+  const SimpleStore& db() const { return db_; }
+
   MockCommitQueue* mock_queue() { return mock_queue_; }
 
   SharedModelTypeProcessor* type_processor() const {
     return static_cast<SharedModelTypeProcessor*>(change_processor());
   }
 
-  const EntityChangeList* entity_change_list() const {
-    return entity_change_list_.get();
-  }
-
-  const FakeMetadataChangeList* metadata_change_list() const {
-    return metadata_change_list_.get();
-  }
-
-  MetadataBatch* metadata_batch() { return metadata_batch_.get(); }
-
  private:
   static std::string GenerateTagHash(const std::string& tag) {
     return syncer::syncable::GenerateSyncableHash(kModelType, tag);
@@ -314,12 +448,21 @@
     return specifics;
   }
 
+  static scoped_ptr<EntityData> GenerateEntityData(const std::string& tag,
+                                                   const std::string& value) {
+    scoped_ptr<EntityData> entity_data = make_scoped_ptr(new EntityData());
+    entity_data->client_tag_hash = GenerateTagHash(tag);
+    entity_data->specifics = GenerateSpecifics(tag, value);
+    entity_data->non_unique_name = tag;
+    return entity_data;
+  }
+
   void OnReadyToConnect(syncer::SyncError error,
                         scoped_ptr<ActivationContext> context) {
-    // Hand off ownership of |mock_queue_ptr_|, while keeping
-    // an unsafe pointer to it.  This is why we can only connect once.
-    DCHECK(mock_queue_ptr_);
-    context->type_processor->ConnectSync(std::move(mock_queue_ptr_));
+    scoped_ptr<MockCommitQueue> commit_queue(new MockCommitQueue());
+    // Keep an unsafe pointer to the commit queue the processor will use.
+    mock_queue_ = commit_queue.get();
+    context->type_processor->ConnectSync(std::move(commit_queue));
     // The context's type processor is a proxy; run the task it posted.
     sync_loop_.RunUntilIdle();
   }
@@ -332,50 +475,344 @@
   }
 
   scoped_ptr<MetadataChangeList> CreateMetadataChangeList() override {
-    // Reset the current first and return a new one.
-    metadata_change_list_.reset();
-    return scoped_ptr<MetadataChangeList>(new FakeMetadataChangeList());
+    return scoped_ptr<MetadataChangeList>(new SimpleMetadataChangeList());
+  }
+
+  syncer::SyncError MergeSyncData(
+      scoped_ptr<MetadataChangeList> metadata_changes,
+      EntityDataMap data_map) override {
+    // Commit any local entities that aren't being overwritten by the server.
+    const auto& local_data = db_.GetAllData();
+    for (auto it = local_data.begin(); it != local_data.end(); it++) {
+      if (data_map.find(it->first) == data_map.end()) {
+        type_processor()->Put(it->first, CopyEntityData(*it->second),
+                              metadata_changes.get());
+      }
+    }
+    // Store any new remote entities.
+    for (auto it = data_map.begin(); it != data_map.end(); it++) {
+      db_.PutData(it->first, it->second.value());
+    }
+    ApplyMetadataChangeList(std::move(metadata_changes));
+    return syncer::SyncError();
   }
 
   syncer::SyncError ApplySyncChanges(
-      scoped_ptr<MetadataChangeList> metadata_change_list,
+      scoped_ptr<MetadataChangeList> metadata_changes,
       EntityChangeList entity_changes) override {
-    EXPECT_FALSE(metadata_change_list_);
-    // |metadata_change_list| is expected to be an instance of
-    // FakeMetadataChangeList - see above.
-    metadata_change_list_.reset(
-        static_cast<FakeMetadataChangeList*>(metadata_change_list.release()));
-    EXPECT_TRUE(metadata_change_list_);
-    entity_change_list_.reset(new EntityChangeList(entity_changes));
+    for (const EntityChange& change : entity_changes) {
+      switch (change.type()) {
+        case EntityChange::ACTION_ADD:
+          EXPECT_FALSE(db_.HasData(change.client_tag()));
+          db_.PutData(change.client_tag(), change.data());
+          break;
+        case EntityChange::ACTION_UPDATE:
+          EXPECT_TRUE(db_.HasData(change.client_tag()));
+          db_.PutData(change.client_tag(), change.data());
+          break;
+        case EntityChange::ACTION_DELETE:
+          EXPECT_TRUE(db_.HasData(change.client_tag()));
+          db_.RemoveData(change.client_tag());
+          break;
+      }
+    }
+    ApplyMetadataChangeList(std::move(metadata_changes));
     return syncer::SyncError();
   }
 
+  void ApplyMetadataChangeList(scoped_ptr<MetadataChangeList> change_list) {
+    DCHECK(change_list);
+    SimpleMetadataChangeList* changes =
+        static_cast<SimpleMetadataChangeList*>(change_list.get());
+    const auto& metadata_changes = changes->GetMetadataChanges();
+    for (auto it = metadata_changes.begin(); it != metadata_changes.end();
+         it++) {
+      switch (it->second.type) {
+        case SimpleMetadataChangeList::UPDATE:
+          db_.PutMetadata(it->first, it->second.metadata);
+          break;
+        case SimpleMetadataChangeList::CLEAR:
+          db_.RemoveMetadata(it->first);
+          break;
+      }
+    }
+    if (changes->HasDataTypeStateChange()) {
+      const SimpleMetadataChangeList::DataTypeStateChange& state_change =
+          changes->GetDataTypeStateChange();
+      switch (state_change.type) {
+        case SimpleMetadataChangeList::UPDATE:
+          db_.set_data_type_state(state_change.state);
+          break;
+        case SimpleMetadataChangeList::CLEAR:
+          db_.set_data_type_state(sync_pb::DataTypeState());
+          break;
+      }
+    }
+  }
+
+  void GetData(ClientTagList tags, DataCallback callback) override {
+    scoped_ptr<DataBatchImpl> batch(new DataBatchImpl());
+    for (const std::string& tag : tags) {
+      batch->Put(tag, CopyEntityData(db_.GetData(tag)));
+    }
+    data_callback_ =
+        base::Bind(callback, syncer::SyncError(), base::Passed(&batch));
+  }
+
   // This sets ThreadTaskRunnerHandle on the current thread, which the type
   // processor will pick up as the sync task runner.
   base::MessageLoop sync_loop_;
 
-  // The current mock queue which might be owned by either |mock_queue_ptr_| or
-  // |type_processor()|.
+  // The current mock queue, which is owned by |type_processor()|.
   MockCommitQueue* mock_queue_;
-  scoped_ptr<MockCommitQueue> mock_queue_ptr_;
 
-  sync_pb::DataTypeState data_type_state_;
+  // Stores the data callback between GetData() and OnDataLoaded().
+  base::Closure data_callback_;
 
-  // The last received EntityChangeList.
-  scoped_ptr<EntityChangeList> entity_change_list_;
-  // The last received MetadataChangeList.
-  scoped_ptr<FakeMetadataChangeList> metadata_change_list_;
-  scoped_ptr<MetadataBatch> metadata_batch_;
+  // Contains all of the data and metadata state for these tests.
+  SimpleStore db_;
 };
 
-TEST_F(SharedModelTypeProcessorTest, Initialize) {
-  // TODO(maxbogue): crbug.com/569642: Add data for tag1.
-  AddMetadataToBatch("tag1");
-  ASSERT_EQ(0U, ProcessorEntityCount());
+// Test that an initial sync handles local and remote items properly.
+TEST_F(SharedModelTypeProcessorTest, InitialSync) {
+  CreateProcessor();
+  OnMetadataLoaded();
+  OnSyncStarting();
+
+  // Local write before initial sync.
+  WriteItem("tag1", "value1");
+
+  // Has data, but no metadata, entity in the processor, or commit request.
+  EXPECT_EQ(1U, db().DataCount());
+  EXPECT_EQ(0U, db().MetadataCount());
+  EXPECT_EQ(0U, ProcessorEntityCount());
+  EXPECT_EQ(0U, GetNumCommitRequestLists());
+
+  // Initial sync with one server item.
+  OnInitialSyncDone("tag2", "value2");
+
+  // Now have data and metadata for both items, as well as a commit request for
+  // the local item.
+  EXPECT_EQ(2U, db().DataCount());
+  EXPECT_EQ(2U, db().MetadataCount());
+  EXPECT_EQ(2U, ProcessorEntityCount());
+  EXPECT_EQ(1, db().GetMetadata("tag1").sequence_number());
+  EXPECT_EQ(0, db().GetMetadata("tag2").sequence_number());
+  ExpectCommitRequests({"tag1"});
+}
+
+// This test covers race conditions during loading pending data. All cases
+// start with no processor and one item with a pending commit. There are three
+// different events that can occur in any order once metadata is loaded:
+//
+// - Pending commit data is loaded.
+// - Sync gets connected.
+// - Optionally, a put or delete happens to the item.
+//
+// This results in 2 + 12 = 14 orderings of the events.
+TEST_F(SharedModelTypeProcessorTest, LoadPendingCommit) {
+  // Data, connect.
+  ResetStateWriteItem("tag1", "value1");
+  InitializeToMetadataLoaded();
+  OnDataLoaded();
+  OnSyncStarting();
+  EXPECT_EQ(1U, GetNumCommitRequestLists());
+  ExpectNthCommitRequestList(0, "tag1", "value1");
+
+  // Connect, data.
+  ResetStateWriteItem("tag1", "value1");
+  InitializeToMetadataLoaded();
+  OnSyncStarting();
+  EXPECT_EQ(0U, GetNumCommitRequestLists());
+  OnDataLoaded();
+  EXPECT_EQ(1U, GetNumCommitRequestLists());
+  ExpectNthCommitRequestList(0, "tag1", "value1");
+
+  // Data, connect, put.
+  ResetStateWriteItem("tag1", "value1");
+  InitializeToMetadataLoaded();
+  OnDataLoaded();
+  OnSyncStarting();
+  WriteItem("tag1", "value2");
+  EXPECT_EQ(2U, GetNumCommitRequestLists());
+  ExpectNthCommitRequestList(0, "tag1", "value1");
+  ExpectNthCommitRequestList(1, "tag1", "value2");
+
+  // Data, put, connect.
+  ResetStateWriteItem("tag1", "value1");
+  InitializeToMetadataLoaded();
+  OnDataLoaded();
+  WriteItem("tag1", "value2");
+  OnSyncStarting();
+  EXPECT_EQ(1U, GetNumCommitRequestLists());
+  ExpectNthCommitRequestList(0, "tag1", "value2");
+
+  // Connect, data, put.
+  ResetStateWriteItem("tag1", "value1");
+  InitializeToMetadataLoaded();
+  OnSyncStarting();
+  OnDataLoaded();
+  WriteItem("tag1", "value2");
+  EXPECT_EQ(2U, GetNumCommitRequestLists());
+  ExpectNthCommitRequestList(0, "tag1", "value1");
+  ExpectNthCommitRequestList(1, "tag1", "value2");
+
+  // Connect, put, data.
+  ResetStateWriteItem("tag1", "value1");
+  InitializeToMetadataLoaded();
+  OnSyncStarting();
+  WriteItem("tag1", "value2");
+  EXPECT_EQ(0U, GetNumCommitRequestLists());
+  OnDataLoaded();
+  EXPECT_EQ(1U, GetNumCommitRequestLists());
+  ExpectNthCommitRequestList(0, "tag1", "value2");
+
+  // Put, data, connect.
+  ResetStateWriteItem("tag1", "value1");
+  InitializeToMetadataLoaded();
+  WriteItem("tag1", "value2");
+  OnDataLoaded();
+  OnSyncStarting();
+  EXPECT_EQ(1U, GetNumCommitRequestLists());
+  ExpectNthCommitRequestList(0, "tag1", "value2");
+
+  // Put, connect, data.
+  ResetStateWriteItem("tag1", "value1");
+  InitializeToMetadataLoaded();
+  WriteItem("tag1", "value2");
+  OnSyncStarting();
+  EXPECT_EQ(0U, GetNumCommitRequestLists());
+  OnDataLoaded();
+  EXPECT_EQ(1U, GetNumCommitRequestLists());
+  ExpectNthCommitRequestList(0, "tag1", "value2");
+
+  // Data, connect, delete.
+  ResetStateWriteItem("tag1", "value1");
+  InitializeToMetadataLoaded();
+  OnDataLoaded();
+  OnSyncStarting();
+  DeleteItem("tag1");
+  EXPECT_EQ(2U, GetNumCommitRequestLists());
+  ExpectNthCommitRequestList(0, "tag1", "value1");
+  ExpectNthCommitRequestList(1, "tag1", "");
+
+  // Data, delete, connect.
+  ResetStateWriteItem("tag1", "value1");
+  InitializeToMetadataLoaded();
+  OnDataLoaded();
+  DeleteItem("tag1");
+  OnSyncStarting();
+  EXPECT_EQ(1U, GetNumCommitRequestLists());
+  ExpectNthCommitRequestList(0, "tag1", "");
+
+  // Connect, data, delete.
+  ResetStateWriteItem("tag1", "value1");
+  InitializeToMetadataLoaded();
+  OnSyncStarting();
+  OnDataLoaded();
+  DeleteItem("tag1");
+  EXPECT_EQ(2U, GetNumCommitRequestLists());
+  ExpectNthCommitRequestList(0, "tag1", "value1");
+  ExpectNthCommitRequestList(1, "tag1", "");
+
+  // Connect, delete, data.
+  ResetStateWriteItem("tag1", "value1");
+  InitializeToMetadataLoaded();
+  OnSyncStarting();
+  DeleteItem("tag1");
+  EXPECT_EQ(0U, GetNumCommitRequestLists());
+  OnDataLoaded();
+  EXPECT_EQ(1U, GetNumCommitRequestLists());
+  ExpectNthCommitRequestList(0, "tag1", "");
+
+  // Delete, data, connect.
+  ResetStateWriteItem("tag1", "value1");
+  InitializeToMetadataLoaded();
+  DeleteItem("tag1");
+  OnDataLoaded();
+  OnSyncStarting();
+  EXPECT_EQ(1U, GetNumCommitRequestLists());
+  ExpectNthCommitRequestList(0, "tag1", "");
+
+  // Delete, connect, data.
+  ResetStateWriteItem("tag1", "value1");
+  InitializeToMetadataLoaded();
+  DeleteItem("tag1");
+  OnSyncStarting();
+  EXPECT_EQ(0U, GetNumCommitRequestLists());
+  OnDataLoaded();
+  EXPECT_EQ(1U, GetNumCommitRequestLists());
+  ExpectNthCommitRequestList(0, "tag1", "");
+}
+
+// This test covers race conditions during loading a pending delete. All cases
+// start with no processor and one item with a pending delete. There are two
+// different events that can occur in any order once metadata is loaded, since
+// for a deletion there is no data to load:
+//
+// - Sync gets connected.
+// - Optionally, a put or delete happens to the item (repeated deletes should be
+//   handled properly).
+//
+// This results in 1 + 4 = 5 orderings of the events.
+TEST_F(SharedModelTypeProcessorTest, LoadPendingDelete) {
+  // Connect.
+  ResetStateDeleteItem("tag1", "value1");
+  InitializeToMetadataLoaded();
+  OnSyncStarting();
+  EXPECT_EQ(1U, GetNumCommitRequestLists());
+  ExpectNthCommitRequestList(0, "tag1", "");
+
+  // Connect, put.
+  ResetStateDeleteItem("tag1", "value1");
+  InitializeToMetadataLoaded();
+  OnSyncStarting();
+  EXPECT_EQ(1U, GetNumCommitRequestLists());
+  WriteItem("tag1", "value2");
+  EXPECT_EQ(2U, GetNumCommitRequestLists());
+  ExpectNthCommitRequestList(0, "tag1", "");
+  ExpectNthCommitRequestList(1, "tag1", "value2");
+
+  // Put, connect.
+  ResetStateDeleteItem("tag1", "value1");
+  InitializeToMetadataLoaded();
+  WriteItem("tag1", "value2");
+  OnSyncStarting();
+  EXPECT_EQ(1U, GetNumCommitRequestLists());
+  ExpectNthCommitRequestList(0, "tag1", "value2");
+
+  // Connect, delete.
+  ResetStateDeleteItem("tag1", "value1");
+  InitializeToMetadataLoaded();
+  OnSyncStarting();
+  EXPECT_EQ(1U, GetNumCommitRequestLists());
+  DeleteItem("tag1");
+  EXPECT_EQ(2U, GetNumCommitRequestLists());
+  ExpectNthCommitRequestList(0, "tag1", "");
+  ExpectNthCommitRequestList(1, "tag1", "");
+
+  // Delete, connect.
+  ResetStateDeleteItem("tag1", "value1");
+  InitializeToMetadataLoaded();
+  DeleteItem("tag1");
+  OnSyncStarting();
+  EXPECT_EQ(1U, GetNumCommitRequestLists());
+  ExpectNthCommitRequestList(0, "tag1", "");
+}
+
+// Test that loading a committed item does not queue another commit.
+TEST_F(SharedModelTypeProcessorTest, LoadCommited) {
   InitializeToReadyState();
-  ASSERT_EQ(1U, ProcessorEntityCount());
-  // TODO(maxbogue): crbug.com/569642: Verify that a commit is added to the
-  // queue.
+  WriteItem("tag1", "value1");
+  // Complete the commit.
+  EXPECT_TRUE(HasCommitRequestForTag("tag1"));
+  SuccessfulCommitResponse(GetLatestCommitRequestForTag("tag1"));
+  clear_change_processor();
+
+  // Test that a new processor loads the metadata without committing.
+  InitializeToReadyState();
+  EXPECT_EQ(1U, ProcessorEntityCount());
+  EXPECT_EQ(0U, GetNumCommitRequestLists());
 }
 
 // Creates a new item locally.
@@ -384,12 +821,10 @@
   InitializeToReadyState();
   EXPECT_EQ(0U, GetNumCommitRequestLists());
 
-  FakeMetadataChangeList change_list;
-  WriteItem("tag1", "value1", &change_list);
+  WriteItem("tag1", "value1");
 
   // Verify the commit request this operation has triggered.
-  EXPECT_EQ(1U, GetNumCommitRequestLists());
-  ASSERT_TRUE(HasCommitRequestForTag("tag1"));
+  ExpectCommitRequests({"tag1"});
   const CommitRequestData& tag1_request_data =
       GetLatestCommitRequestForTag("tag1");
   const EntityData& tag1_data = tag1_request_data.entity.value();
@@ -403,20 +838,17 @@
   EXPECT_EQ("tag1", tag1_data.specifics.preference().name());
   EXPECT_EQ("value1", tag1_data.specifics.preference().value());
 
-  EXPECT_EQ(1U, change_list.GetNumRecords());
-
-  const FakeMetadataChangeList::Record& record = change_list.GetNthRecord(0);
-  EXPECT_EQ(FakeMetadataChangeList::UPDATE_METADATA, record.action);
-  EXPECT_EQ("tag1", record.tag);
-  EXPECT_TRUE(record.metadata.has_client_tag_hash());
-  EXPECT_FALSE(record.metadata.has_server_id());
-  EXPECT_FALSE(record.metadata.is_deleted());
-  EXPECT_EQ(1, record.metadata.sequence_number());
-  EXPECT_EQ(0, record.metadata.acked_sequence_number());
-  EXPECT_EQ(kUncommittedVersion, record.metadata.server_version());
-  EXPECT_TRUE(record.metadata.has_creation_time());
-  EXPECT_TRUE(record.metadata.has_modification_time());
-  EXPECT_TRUE(record.metadata.has_specifics_hash());
+  EXPECT_EQ(1U, db().MetadataCount());
+  const sync_pb::EntityMetadata metadata = db().GetMetadata("tag1");
+  EXPECT_TRUE(metadata.has_client_tag_hash());
+  EXPECT_FALSE(metadata.has_server_id());
+  EXPECT_FALSE(metadata.is_deleted());
+  EXPECT_EQ(1, metadata.sequence_number());
+  EXPECT_EQ(0, metadata.acked_sequence_number());
+  EXPECT_EQ(kUncommittedVersion, metadata.server_version());
+  EXPECT_TRUE(metadata.has_creation_time());
+  EXPECT_TRUE(metadata.has_modification_time());
+  EXPECT_TRUE(metadata.has_specifics_hash());
 }
 
 // The purpose of this test case is to test setting |client_tag_hash| and |id|
@@ -427,8 +859,6 @@
   InitializeToReadyState();
   EXPECT_EQ(0U, GetNumCommitRequestLists());
 
-  FakeMetadataChangeList change_list;
-
   scoped_ptr<EntityData> entity_data = make_scoped_ptr(new EntityData());
   entity_data->specifics.mutable_preference()->set_name("name1");
   entity_data->specifics.mutable_preference()->set_value("value1");
@@ -436,7 +866,7 @@
   entity_data->non_unique_name = "name1";
   entity_data->client_tag_hash = "hash";
   entity_data->id = "cid1";
-  type_processor()->Put("tag1", std::move(entity_data), &change_list);
+  WriteItem("tag1", std::move(entity_data));
 
   // Don't access through tag because we forced a specific hash.
   EXPECT_EQ(1U, GetNumCommitRequestLists());
@@ -448,7 +878,10 @@
   EXPECT_EQ("cid1", out_entity1.id);
   EXPECT_EQ("value1", out_entity1.specifics.preference().value());
 
-  EXPECT_EQ(1U, change_list.GetNumRecords());
+  EXPECT_EQ(1U, db().MetadataCount());
+  const sync_pb::EntityMetadata metadata_v1 = db().GetMetadata("tag1");
+  EXPECT_EQ("cid1", metadata_v1.server_id());
+  EXPECT_EQ("hash", metadata_v1.client_tag_hash());
 
   entity_data.reset(new EntityData());
   entity_data->specifics.mutable_preference()->set_name("name2");
@@ -459,7 +892,7 @@
   // client once established.
   entity_data->id = "cid2";
 
-  type_processor()->Put("tag1", std::move(entity_data), &change_list);
+  WriteItem("tag1", std::move(entity_data));
 
   EXPECT_EQ(2U, GetNumCommitRequestLists());
   ASSERT_TRUE(mock_queue()->HasCommitRequestForTagHash("hash"));
@@ -471,100 +904,75 @@
   EXPECT_EQ("cid1", out_entity2.id);
   EXPECT_EQ("value2", out_entity2.specifics.preference().value());
 
-  EXPECT_EQ(2U, change_list.GetNumRecords());
-
-  const FakeMetadataChangeList::Record& record1 = change_list.GetNthRecord(0);
-  EXPECT_EQ(FakeMetadataChangeList::UPDATE_METADATA, record1.action);
-  EXPECT_EQ("tag1", record1.tag);
-  EXPECT_EQ("cid1", record1.metadata.server_id());
-  EXPECT_EQ("hash", record1.metadata.client_tag_hash());
-
-  const FakeMetadataChangeList::Record& record2 = change_list.GetNthRecord(1);
-  EXPECT_EQ(FakeMetadataChangeList::UPDATE_METADATA, record2.action);
-  EXPECT_EQ("tag1", record2.tag);
+  EXPECT_EQ(1U, db().MetadataCount());
+  const sync_pb::EntityMetadata metadata_v2 = db().GetMetadata("tag1");
   // TODO(skym): Is this correct?
-  EXPECT_EQ("cid1", record2.metadata.server_id());
-  EXPECT_EQ("hash", record2.metadata.client_tag_hash());
+  EXPECT_EQ("cid1", metadata_v2.server_id());
+  EXPECT_EQ("hash", metadata_v2.client_tag_hash());
 
-  EXPECT_NE(record1.metadata.specifics_hash(),
-            record2.metadata.specifics_hash());
+  EXPECT_NE(metadata_v1.specifics_hash(), metadata_v2.specifics_hash());
 }
 
 // Creates a new local item then modifies it.
 // Thoroughly tests data generated by modification of server-unknown item.
 TEST_F(SharedModelTypeProcessorTest, CreateAndModifyLocalItem) {
   InitializeToReadyState();
-  EXPECT_EQ(0U, GetNumCommitRequestLists());
 
-  FakeMetadataChangeList change_list;
+  WriteItem("tag1", "value1");
+  EXPECT_EQ(1U, db().MetadataCount());
+  ExpectCommitRequests({"tag1"});
 
-  WriteItem("tag1", "value1", &change_list);
-  EXPECT_EQ(1U, GetNumCommitRequestLists());
-  ASSERT_TRUE(HasCommitRequestForTag("tag1"));
-  const CommitRequestData& tag1_v1_request_data =
+  const CommitRequestData& request_data_v1 =
       GetLatestCommitRequestForTag("tag1");
-  const EntityData& tag1_v1_data = tag1_v1_request_data.entity.value();
+  const EntityData& data_v1 = request_data_v1.entity.value();
+  const sync_pb::EntityMetadata metadata_v1 = db().GetMetadata("tag1");
 
-  WriteItem("tag1", "value2", &change_list);
-  EXPECT_EQ(2U, GetNumCommitRequestLists());
+  WriteItem("tag1", "value2");
+  EXPECT_EQ(1U, db().MetadataCount());
+  ExpectCommitRequests({"tag1", "tag1"});
 
-  ASSERT_TRUE(HasCommitRequestForTag("tag1"));
-  const CommitRequestData& tag1_v2_request_data =
+  const CommitRequestData& request_data_v2 =
       GetLatestCommitRequestForTag("tag1");
-  const EntityData& tag1_v2_data = tag1_v2_request_data.entity.value();
+  const EntityData& data_v2 = request_data_v2.entity.value();
+  const sync_pb::EntityMetadata metadata_v2 = db().GetMetadata("tag1");
 
   // Test some of the relations between old and new commit requests.
-  EXPECT_GT(tag1_v2_request_data.sequence_number,
-            tag1_v1_request_data.sequence_number);
-  EXPECT_EQ(tag1_v1_data.specifics.preference().value(), "value1");
+  EXPECT_GT(request_data_v2.sequence_number, request_data_v1.sequence_number);
+  EXPECT_EQ(data_v1.specifics.preference().value(), "value1");
 
   // Perform a thorough examination of the update-generated request.
-  EXPECT_EQ(kUncommittedVersion, tag1_v2_request_data.base_version);
-  EXPECT_TRUE(tag1_v2_data.id.empty());
-  EXPECT_FALSE(tag1_v2_data.creation_time.is_null());
-  EXPECT_FALSE(tag1_v2_data.modification_time.is_null());
-  EXPECT_EQ("tag1", tag1_v2_data.non_unique_name);
-  EXPECT_FALSE(tag1_v2_data.is_deleted());
-  EXPECT_EQ("tag1", tag1_v2_data.specifics.preference().name());
-  EXPECT_EQ("value2", tag1_v2_data.specifics.preference().value());
+  EXPECT_EQ(kUncommittedVersion, request_data_v2.base_version);
+  EXPECT_TRUE(data_v2.id.empty());
+  EXPECT_FALSE(data_v2.creation_time.is_null());
+  EXPECT_FALSE(data_v2.modification_time.is_null());
+  EXPECT_EQ("tag1", data_v2.non_unique_name);
+  EXPECT_FALSE(data_v2.is_deleted());
+  EXPECT_EQ("tag1", data_v2.specifics.preference().name());
+  EXPECT_EQ("value2", data_v2.specifics.preference().value());
 
-  EXPECT_EQ(2U, change_list.GetNumRecords());
+  EXPECT_FALSE(metadata_v1.has_server_id());
+  EXPECT_FALSE(metadata_v1.is_deleted());
+  EXPECT_EQ(1, metadata_v1.sequence_number());
+  EXPECT_EQ(0, metadata_v1.acked_sequence_number());
+  EXPECT_EQ(kUncommittedVersion, metadata_v1.server_version());
 
-  const FakeMetadataChangeList::Record& record1 = change_list.GetNthRecord(0);
-  EXPECT_EQ(FakeMetadataChangeList::UPDATE_METADATA, record1.action);
-  EXPECT_EQ("tag1", record1.tag);
-  EXPECT_FALSE(record1.metadata.has_server_id());
-  EXPECT_FALSE(record1.metadata.is_deleted());
-  EXPECT_EQ(1, record1.metadata.sequence_number());
-  EXPECT_EQ(0, record1.metadata.acked_sequence_number());
-  EXPECT_EQ(kUncommittedVersion, record1.metadata.server_version());
+  EXPECT_FALSE(metadata_v2.has_server_id());
+  EXPECT_FALSE(metadata_v2.is_deleted());
+  EXPECT_EQ(2, metadata_v2.sequence_number());
+  EXPECT_EQ(0, metadata_v2.acked_sequence_number());
+  EXPECT_EQ(kUncommittedVersion, metadata_v2.server_version());
 
-  const FakeMetadataChangeList::Record& record2 = change_list.GetNthRecord(1);
-  EXPECT_EQ(FakeMetadataChangeList::UPDATE_METADATA, record1.action);
-  EXPECT_EQ("tag1", record2.tag);
-  EXPECT_FALSE(record2.metadata.has_server_id());
-  EXPECT_FALSE(record2.metadata.is_deleted());
-  EXPECT_EQ(2, record2.metadata.sequence_number());
-  EXPECT_EQ(0, record2.metadata.acked_sequence_number());
-  EXPECT_EQ(kUncommittedVersion, record2.metadata.server_version());
-
-  EXPECT_EQ(record1.metadata.client_tag_hash(),
-            record2.metadata.client_tag_hash());
-  EXPECT_NE(record1.metadata.specifics_hash(),
-            record2.metadata.specifics_hash());
+  EXPECT_EQ(metadata_v1.client_tag_hash(), metadata_v2.client_tag_hash());
+  EXPECT_NE(metadata_v1.specifics_hash(), metadata_v2.specifics_hash());
 }
 
 // Deletes an item we've never seen before.
 // Should have no effect and not crash.
 TEST_F(SharedModelTypeProcessorTest, DeleteUnknown) {
   InitializeToReadyState();
-
-  FakeMetadataChangeList change_list;
-
-  DeleteItem("tag1", &change_list);
+  DeleteItem("tag1");
   EXPECT_EQ(0U, GetNumCommitRequestLists());
-
-  EXPECT_EQ(0U, change_list.GetNumRecords());
+  EXPECT_EQ(0U, db().MetadataCount());
 }
 
 // Creates an item locally then deletes it.
@@ -575,38 +983,33 @@
 TEST_F(SharedModelTypeProcessorTest, DeleteServerUnknown) {
   InitializeToReadyState();
 
-  FakeMetadataChangeList change_list;
-
   // TODO(stanisc): crbug.com/573333: Review this case. If the flush of
   // all locally modified items was scheduled to run on a separate task, than
   // the correct behavior would be to commit just the detele, or perhaps no
   // commit at all.
 
-  WriteItem("tag1", "value1", &change_list);
-  EXPECT_EQ(1U, GetNumCommitRequestLists());
-  ASSERT_TRUE(HasCommitRequestForTag("tag1"));
-  const CommitRequestData& tag1_v1_data = GetLatestCommitRequestForTag("tag1");
+  WriteItem("tag1", "value1");
+  EXPECT_EQ(1U, db().MetadataCount());
+  ExpectCommitRequests({"tag1"});
+  const CommitRequestData& data_v1 = GetLatestCommitRequestForTag("tag1");
+  const sync_pb::EntityMetadata metadata_v1 = db().GetMetadata("tag1");
 
-  DeleteItem("tag1", &change_list);
-  EXPECT_EQ(2U, GetNumCommitRequestLists());
-  ASSERT_TRUE(HasCommitRequestForTag("tag1"));
-  const CommitRequestData& tag1_v2_data = GetLatestCommitRequestForTag("tag1");
+  DeleteItem("tag1");
+  EXPECT_EQ(1U, db().MetadataCount());
+  ExpectCommitRequests({"tag1", "tag1"});
+  const CommitRequestData& data_v2 = GetLatestCommitRequestForTag("tag1");
+  const sync_pb::EntityMetadata metadata_v2 = db().GetMetadata("tag1");
 
-  EXPECT_GT(tag1_v2_data.sequence_number, tag1_v1_data.sequence_number);
+  EXPECT_GT(data_v2.sequence_number, data_v1.sequence_number);
 
-  EXPECT_TRUE(tag1_v2_data.entity->id.empty());
-  EXPECT_EQ(kUncommittedVersion, tag1_v2_data.base_version);
-  EXPECT_TRUE(tag1_v2_data.entity->is_deleted());
+  EXPECT_TRUE(data_v2.entity->id.empty());
+  EXPECT_EQ(kUncommittedVersion, data_v2.base_version);
+  EXPECT_TRUE(data_v2.entity->is_deleted());
 
-  EXPECT_EQ(2U, change_list.GetNumRecords());
-
-  const FakeMetadataChangeList::Record& record1 = change_list.GetNthRecord(0);
-  EXPECT_EQ(FakeMetadataChangeList::UPDATE_METADATA, record1.action);
-  EXPECT_EQ("tag1", record1.tag);
-  EXPECT_FALSE(record1.metadata.is_deleted());
-  EXPECT_EQ(1, record1.metadata.sequence_number());
-  EXPECT_EQ(0, record1.metadata.acked_sequence_number());
-  EXPECT_EQ(kUncommittedVersion, record1.metadata.server_version());
+  EXPECT_FALSE(metadata_v1.is_deleted());
+  EXPECT_EQ(1, metadata_v1.sequence_number());
+  EXPECT_EQ(0, metadata_v1.acked_sequence_number());
+  EXPECT_EQ(kUncommittedVersion, metadata_v1.server_version());
 
   // TODO(stanisc): crbug.com/573333: Review this case. Depending on the
   // implementation the second action performed on metadata change list might
@@ -615,13 +1018,10 @@
   // records at all - the first call would create an entry and the second would
   // remove it.
 
-  const FakeMetadataChangeList::Record& record2 = change_list.GetNthRecord(1);
-  EXPECT_EQ(FakeMetadataChangeList::UPDATE_METADATA, record1.action);
-  EXPECT_EQ("tag1", record2.tag);
-  EXPECT_TRUE(record2.metadata.is_deleted());
-  EXPECT_EQ(2, record2.metadata.sequence_number());
-  EXPECT_EQ(0, record2.metadata.acked_sequence_number());
-  EXPECT_EQ(kUncommittedVersion, record2.metadata.server_version());
+  EXPECT_TRUE(metadata_v2.is_deleted());
+  EXPECT_EQ(2, metadata_v2.sequence_number());
+  EXPECT_EQ(0, metadata_v2.acked_sequence_number());
+  EXPECT_EQ(kUncommittedVersion, metadata_v2.server_version());
 }
 
 // Creates an item locally then deletes it.
@@ -632,48 +1032,38 @@
 TEST_F(SharedModelTypeProcessorTest, DeleteServerUnknown_RacyCommitResponse) {
   InitializeToReadyState();
 
-  FakeMetadataChangeList change_list;
+  WriteItem("tag1", "value1");
+  EXPECT_EQ(1U, db().DataCount());
+  EXPECT_EQ(1U, db().MetadataCount());
+  ExpectCommitRequests({"tag1"});
+  const CommitRequestData& data_v1 = GetLatestCommitRequestForTag("tag1");
+  EXPECT_FALSE(db().GetMetadata("tag1").is_deleted());
 
-  WriteItem("tag1", "value1", &change_list);
-  EXPECT_EQ(1U, GetNumCommitRequestLists());
-  ASSERT_TRUE(HasCommitRequestForTag("tag1"));
-  const CommitRequestData& tag1_v1_data = GetLatestCommitRequestForTag("tag1");
-
-  DeleteItem("tag1", &change_list);
-  EXPECT_EQ(2U, GetNumCommitRequestLists());
-  ASSERT_TRUE(HasCommitRequestForTag("tag1"));
+  DeleteItem("tag1");
+  EXPECT_EQ(0U, db().DataCount());
+  EXPECT_EQ(1U, db().MetadataCount());
+  ExpectCommitRequests({"tag1", "tag1"});
+  EXPECT_TRUE(db().GetMetadata("tag1").is_deleted());
 
   // This commit happened while the deletion was in progress, but the commit
   // response didn't arrive on our thread until after the delete was issued to
   // the sync thread.  It will update some metadata, but won't do much else.
-  SuccessfulCommitResponse(tag1_v1_data);
+  SuccessfulCommitResponse(data_v1);
+  EXPECT_EQ(0U, db().DataCount());
+  EXPECT_EQ(1U, db().MetadataCount());
 
   // In reality the change list used to commit local changes should never
   // overlap with the changelist used to deliver commit confirmation. In this
   // test setup the two change lists are isolated - one is on the stack and
   // another is the class member.
 
-  // Local metadata changes.
-  EXPECT_EQ(2U, change_list.GetNumRecords());
-
-  // Metadata changes from commit response.
-  EXPECT_TRUE(metadata_change_list());
-  EXPECT_EQ(2U, metadata_change_list()->GetNumRecords());
-
-  const FakeMetadataChangeList::Record& record1 =
-      metadata_change_list()->GetNthRecord(0);
-  EXPECT_EQ(FakeMetadataChangeList::UPDATE_DATA_TYPE_STATE, record1.action);
-
-  const FakeMetadataChangeList::Record& record2 =
-      metadata_change_list()->GetNthRecord(1);
-  EXPECT_EQ(FakeMetadataChangeList::UPDATE_METADATA, record2.action);
-  EXPECT_EQ("tag1", record2.tag);
+  const sync_pb::EntityMetadata metadata_v2 = db().GetMetadata("tag1");
   // Deleted from the second local modification.
-  EXPECT_TRUE(record2.metadata.is_deleted());
+  EXPECT_TRUE(metadata_v2.is_deleted());
   // sequence_number = 2 from the second local modification.
-  EXPECT_EQ(2, record2.metadata.sequence_number());
+  EXPECT_EQ(2, metadata_v2.sequence_number());
   // acked_sequence_number = 1 from the first commit response.
-  EXPECT_EQ(1, record2.metadata.acked_sequence_number());
+  EXPECT_EQ(1, metadata_v2.acked_sequence_number());
 
   // TODO(rlarocque): Verify the state of the item is correct once we get
   // storage hooked up in these tests.  For example, verify the item is still
@@ -686,64 +1076,31 @@
   InitializeToReadyState();
   EXPECT_EQ(0U, GetNumCommitRequestLists());
 
-  FakeMetadataChangeList change_list;
-
-  WriteItem("tag1", "value1", &change_list);
+  WriteItem("tag1", "value1");
+  EXPECT_EQ(1U, db().DataCount());
+  EXPECT_EQ(1U, db().MetadataCount());
+  const sync_pb::EntityMetadata metadata1 = db().GetMetadata("tag1");
 
   // There should be one commit request for this item only.
-  ASSERT_EQ(1U, GetNumCommitRequestLists());
-  EXPECT_EQ(1U, GetNthCommitRequestList(0).size());
-  ASSERT_TRUE(HasCommitRequestForTag("tag1"));
+  ExpectCommitRequests({"tag1"});
 
-  WriteItem("tag2", "value2", &change_list);
+  WriteItem("tag2", "value2");
+  EXPECT_EQ(2U, db().DataCount());
+  EXPECT_EQ(2U, db().MetadataCount());
+  const sync_pb::EntityMetadata metadata2 = db().GetMetadata("tag2");
 
   // The second write should trigger another single-item commit request.
-  ASSERT_EQ(2U, GetNumCommitRequestLists());
-  EXPECT_EQ(1U, GetNthCommitRequestList(1).size());
-  ASSERT_TRUE(HasCommitRequestForTag("tag2"));
+  ExpectCommitRequests({"tag1", "tag2"});
 
-  EXPECT_EQ(2U, change_list.GetNumRecords());
+  EXPECT_FALSE(metadata1.is_deleted());
+  EXPECT_EQ(1, metadata1.sequence_number());
+  EXPECT_EQ(0, metadata1.acked_sequence_number());
+  EXPECT_EQ(kUncommittedVersion, metadata1.server_version());
 
-  const FakeMetadataChangeList::Record& record1 = change_list.GetNthRecord(0);
-  EXPECT_EQ(FakeMetadataChangeList::UPDATE_METADATA, record1.action);
-  EXPECT_EQ("tag1", record1.tag);
-  EXPECT_FALSE(record1.metadata.is_deleted());
-  EXPECT_EQ(1, record1.metadata.sequence_number());
-  EXPECT_EQ(0, record1.metadata.acked_sequence_number());
-  EXPECT_EQ(kUncommittedVersion, record1.metadata.server_version());
-
-  const FakeMetadataChangeList::Record& record2 = change_list.GetNthRecord(1);
-  EXPECT_EQ(FakeMetadataChangeList::UPDATE_METADATA, record2.action);
-  EXPECT_EQ("tag2", record2.tag);
-  EXPECT_FALSE(record2.metadata.is_deleted());
-  EXPECT_EQ(1, record2.metadata.sequence_number());
-  EXPECT_EQ(0, record2.metadata.acked_sequence_number());
-  EXPECT_EQ(kUncommittedVersion, record2.metadata.server_version());
-}
-
-// Starts the type sync proxy with no local state.
-// Verify that it waits until initial sync is complete before requesting
-// commits.
-TEST_F(SharedModelTypeProcessorTest, NoCommitsUntilInitialSyncDone) {
-  OnSyncStarting();
-  OnMetadataLoaded();
-
-  FakeMetadataChangeList change_list;
-
-  WriteItem("tag1", "value1", &change_list);
-  EXPECT_EQ(0U, GetNumCommitRequestLists());
-
-  // Even though there the item hasn't been committed its metadata should have
-  // already been updated and the sequence number changed.
-  EXPECT_EQ(1U, change_list.GetNumRecords());
-  const FakeMetadataChangeList::Record& record1 = change_list.GetNthRecord(0);
-  EXPECT_EQ(FakeMetadataChangeList::UPDATE_METADATA, record1.action);
-  EXPECT_EQ("tag1", record1.tag);
-  EXPECT_EQ(1, record1.metadata.sequence_number());
-
-  OnInitialSyncDone();
-  EXPECT_EQ(1U, GetNumCommitRequestLists());
-  EXPECT_TRUE(HasCommitRequestForTag("tag1"));
+  EXPECT_FALSE(metadata2.is_deleted());
+  EXPECT_EQ(1, metadata2.sequence_number());
+  EXPECT_EQ(0, metadata2.acked_sequence_number());
+  EXPECT_EQ(kUncommittedVersion, metadata2.server_version());
 }
 
 // Test proper handling of disconnect and reconnect.
@@ -753,23 +1110,20 @@
 TEST_F(SharedModelTypeProcessorTest, Disconnect) {
   InitializeToReadyState();
 
-  FakeMetadataChangeList change_list;
-
   // The first item is fully committed.
-  WriteItem("tag1", "value1", &change_list);
-  ASSERT_TRUE(HasCommitRequestForTag("tag1"));
-  SuccessfulCommitResponse(GetLatestCommitRequestForTag("tag1"));
+  WriteItemAndAck("tag1", "value1");
 
   // The second item has a commit request in progress.
-  WriteItem("tag2", "value2", &change_list);
+  WriteItem("tag2", "value2");
   EXPECT_TRUE(HasCommitRequestForTag("tag2"));
 
   DisconnectSync();
 
   // The third item is added after stopping.
-  WriteItem("tag3", "value3", &change_list);
+  WriteItem("tag3", "value3");
 
-  Restart();
+  // Reconnect.
+  OnSyncStarting();
 
   EXPECT_EQ(1U, GetNumCommitRequestLists());
   EXPECT_EQ(2U, GetNthCommitRequestList(0).size());
@@ -791,24 +1145,20 @@
 TEST_F(SharedModelTypeProcessorTest, DISABLED_Disable) {
   InitializeToReadyState();
 
-  FakeMetadataChangeList change_list;
-
   // The first item is fully committed.
-  WriteItem("tag1", "value1", &change_list);
-  ASSERT_TRUE(HasCommitRequestForTag("tag1"));
-  SuccessfulCommitResponse(GetLatestCommitRequestForTag("tag1"));
+  WriteItemAndAck("tag1", "value1");
 
   // The second item has a commit request in progress.
-  WriteItem("tag2", "value2", &change_list);
+  WriteItem("tag2", "value2");
   EXPECT_TRUE(HasCommitRequestForTag("tag2"));
 
   Disable();
 
   // The third item is added after disable.
-  WriteItem("tag3", "value3", &change_list);
+  WriteItem("tag3", "value3");
 
   // Now we re-enable.
-  Restart();
+  InitializeToReadyState();
 
   // Once we're ready to commit, all three local items should consider
   // themselves uncommitted and pending for commit.
@@ -860,7 +1210,7 @@
   ASSERT_TRUE(HasPendingUpdate("tag1"));
 
   Disable();
-  Restart();
+  InitializeToReadyState();
 
   EXPECT_EQ(0U, GetNumPendingUpdates());
   EXPECT_FALSE(HasPendingUpdate("tag1"));
@@ -875,7 +1225,7 @@
   ASSERT_TRUE(HasPendingUpdate("tag1"));
 
   DisconnectSync();
-  Restart();
+  OnSyncStarting();
 
   EXPECT_EQ(1U, GetNumPendingUpdates());
   EXPECT_TRUE(HasPendingUpdate("tag1"));
@@ -887,16 +1237,11 @@
 TEST_F(SharedModelTypeProcessorTest, DISABLED_ReEncryptCommitsWithNewKey) {
   InitializeToReadyState();
 
-  FakeMetadataChangeList change_list;
-
   // Commit an item.
-  WriteItem("tag1", "value1", &change_list);
-  ASSERT_TRUE(HasCommitRequestForTag("tag1"));
-  const CommitRequestData& tag1_v1_data = GetLatestCommitRequestForTag("tag1");
-  SuccessfulCommitResponse(tag1_v1_data);
+  WriteItemAndAck("tag1", "value1");
 
   // Create another item and don't wait for its commit response.
-  WriteItem("tag2", "value2", &change_list);
+  WriteItem("tag2", "value2");
 
   ASSERT_EQ(2U, GetNumCommitRequestLists());
 
diff --git a/sync/internal_api/sync_backup_manager.cc b/sync/internal_api/sync_backup_manager.cc
deleted file mode 100644
index 9151e52..0000000
--- a/sync/internal_api/sync_backup_manager.cc
+++ /dev/null
@@ -1,151 +0,0 @@
-// 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 "sync/internal_api/sync_backup_manager.h"
-
-#include <stdint.h>
-
-#include <vector>
-
-#include "sync/internal_api/public/read_node.h"
-#include "sync/internal_api/public/write_transaction.h"
-#include "sync/syncable/directory.h"
-#include "sync/syncable/mutable_entry.h"
-#include "url/gurl.h"
-
-namespace syncer {
-
-SyncBackupManager::SyncBackupManager()
-    : in_normalization_(false) {
-}
-
-SyncBackupManager::~SyncBackupManager() {
-}
-
-void SyncBackupManager::Init(InitArgs* args) {
-  if (SyncRollbackManagerBase::InitInternal(
-          args->database_location,
-          args->internal_components_factory.get(),
-          InternalComponentsFactory::STORAGE_ON_DISK_DEFERRED,
-          args->unrecoverable_error_handler,
-          args->report_unrecoverable_error_function)) {
-    GetUserShare()->directory->CollectMetaHandleCounts(
-        &status_.num_entries_by_type, &status_.num_to_delete_entries_by_type);
-
-    HideSyncPreference(PRIORITY_PREFERENCES);
-    HideSyncPreference(PREFERENCES);
-  }
-}
-
-void SyncBackupManager::SaveChanges() {
-  if (initialized())
-    NormalizeEntries();
-}
-
-SyncStatus SyncBackupManager::GetDetailedStatus() const {
-  return status_;
-}
-
-ModelTypeSet SyncBackupManager::HandleTransactionEndingChangeEvent(
-    const syncable::ImmutableWriteTransactionInfo& write_transaction_info,
-    syncable::BaseTransaction* trans) {
-  ModelTypeSet types;
-  if (in_normalization_) {
-    // Skip if in our own WriteTransaction from NormalizeEntries().
-    in_normalization_ = false;
-    return types;
-  }
-
-  for (syncable::EntryKernelMutationMap::const_iterator it =
-      write_transaction_info.Get().mutations.Get().begin();
-      it != write_transaction_info.Get().mutations.Get().end(); ++it) {
-    int64_t id = it->first;
-    if (unsynced_.find(id) == unsynced_.end()) {
-      unsynced_.insert(id);
-
-      const syncable::EntryKernel& e = it->second.mutated;
-      ModelType type = e.GetModelType();
-      types.Put(type);
-      if (!e.ref(syncable::ID).ServerKnows())
-        status_.num_entries_by_type[type]++;
-      if (e.ref(syncable::IS_DEL))
-        status_.num_to_delete_entries_by_type[type]++;
-    }
-  }
-  return types;
-}
-
-void SyncBackupManager::NormalizeEntries() {
-  WriteTransaction trans(FROM_HERE, GetUserShare());
-  in_normalization_ = true;
-  for (std::set<int64_t>::const_iterator it = unsynced_.begin();
-       it != unsynced_.end(); ++it) {
-    syncable::MutableEntry entry(trans.GetWrappedWriteTrans(),
-                                 syncable::GET_BY_HANDLE, *it);
-    CHECK(entry.good());
-
-    if (!entry.GetId().ServerKnows())
-      entry.PutId(syncable::Id::CreateFromServerId(entry.GetId().value()));
-    if (!entry.GetParentId().IsNull() && !entry.GetParentId().ServerKnows()) {
-      entry.PutParentIdPropertyOnly(syncable::Id::CreateFromServerId(
-          entry.GetParentId().value()));
-    }
-    entry.PutBaseVersion(1);
-    entry.PutIsUnsynced(false);
-  }
-  unsynced_.clear();
-}
-
-void SyncBackupManager::HideSyncPreference(ModelType type) {
-  WriteTransaction trans(FROM_HERE, GetUserShare());
-  ReadNode pref_root(&trans);
-  if (BaseNode::INIT_OK != pref_root.InitTypeRoot(type))
-    return;
-
-  std::vector<int64_t> pref_ids;
-  pref_root.GetChildIds(&pref_ids);
-  for (uint32_t i = 0; i < pref_ids.size(); ++i) {
-    syncable::MutableEntry entry(trans.GetWrappedWriteTrans(),
-                                 syncable::GET_BY_HANDLE, pref_ids[i]);
-    if (entry.good()) {
-      // HACKY: Set IS_DEL to true to remove entry from parent-children
-      // index so that it's not returned when syncable service asks
-      // for sync data. Syncable service then creates entry for local
-      // model. Then the existing entry is undeleted and set to local value
-      // because it has the same unique client tag.
-      entry.PutIsDel(true);
-      entry.PutIsUnsynced(false);
-
-      // Don't persist on disk so that if backup is aborted before receiving
-      // local preference values, values in sync DB are saved.
-      GetUserShare()->directory->UnmarkDirtyEntry(
-          trans.GetWrappedWriteTrans(), &entry);
-    }
-  }
-}
-
-void SyncBackupManager::ShutdownOnSyncThread(ShutdownReason reason) {
-  if (reason == SWITCH_MODE_SYNC) {
-    NormalizeEntries();
-    GetUserShare()->directory->SaveChanges();
-  }
-
-  SyncRollbackManagerBase::ShutdownOnSyncThread(reason);
-}
-
-void SyncBackupManager::RegisterDirectoryTypeDebugInfoObserver(
-    syncer::TypeDebugInfoObserver* observer) {}
-
-void SyncBackupManager::UnregisterDirectoryTypeDebugInfoObserver(
-    syncer::TypeDebugInfoObserver* observer) {}
-
-bool SyncBackupManager::HasDirectoryTypeDebugInfoObserver(
-    syncer::TypeDebugInfoObserver* observer) { return false; }
-
-void SyncBackupManager::RequestEmitDebugInfo() {}
-
-void SyncBackupManager::ClearServerData(
-    const ClearServerDataCallback& callback) {}
-
-}  // namespace syncer
diff --git a/sync/internal_api/sync_backup_manager.h b/sync/internal_api/sync_backup_manager.h
deleted file mode 100644
index e7e50fa..0000000
--- a/sync/internal_api/sync_backup_manager.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// 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 SYNC_INTERNAL_API_SYNC_BACKUP_MANAGER_H_
-#define SYNC_INTERNAL_API_SYNC_BACKUP_MANAGER_H_
-
-#include <stdint.h>
-
-#include <set>
-
-#include "base/macros.h"
-#include "sync/internal_api/sync_rollback_manager_base.h"
-#include "url/gurl.h"
-
-namespace syncer {
-
-// SyncBackupManager runs before user signs in to sync to back up user's data
-// before sync starts. The data that's backed up can be used to restore user's
-// settings to pre-sync state.
-class SYNC_EXPORT SyncBackupManager : public SyncRollbackManagerBase {
- public:
-  SyncBackupManager();
-  ~SyncBackupManager() override;
-
-  // SyncManager implementation.
-  void Init(InitArgs* args) override;
-  void SaveChanges() override;
-  SyncStatus GetDetailedStatus() const override;
-  void ShutdownOnSyncThread(ShutdownReason reason) override;
-
-  // DirectoryChangeDelegate implementation.
-  ModelTypeSet HandleTransactionEndingChangeEvent(
-      const syncable::ImmutableWriteTransactionInfo& write_transaction_info,
-      syncable::BaseTransaction* trans) override;
-
-  void RegisterDirectoryTypeDebugInfoObserver(
-      syncer::TypeDebugInfoObserver* observer) override;
-  void UnregisterDirectoryTypeDebugInfoObserver(
-      syncer::TypeDebugInfoObserver* observer) override;
-  bool HasDirectoryTypeDebugInfoObserver(
-      syncer::TypeDebugInfoObserver* observer) override;
-  void RequestEmitDebugInfo() override;
-  void ClearServerData(const ClearServerDataCallback& callback) override;
-
- private:
-  // Replaces local IDs with server IDs and clear unsynced bit of modified
-  // entries.
-  void NormalizeEntries();
-
-  // Manipulate preference nodes so that they'll be overwritten by local
-  // preference values during model association, i.e. local wins instead of
-  // server wins. This is for preventing backup from changing preferences in
-  // case backup DB has hijacked preferences.
-  void HideSyncPreference(ModelType pref_type);
-
-  // Handles of unsynced entries caused by local model changes.
-  std::set<int64_t> unsynced_;
-
-  // True if NormalizeEntries() is being called.
-  bool in_normalization_;
-
-  SyncStatus status_;
-
-  DISALLOW_COPY_AND_ASSIGN(SyncBackupManager);
-};
-
-}  // namespace syncer
-
-#endif  // SYNC_INTERNAL_API_SYNC_BACKUP_MANAGER_H_
diff --git a/sync/internal_api/sync_backup_manager_unittest.cc b/sync/internal_api/sync_backup_manager_unittest.cc
deleted file mode 100644
index 919356d..0000000
--- a/sync/internal_api/sync_backup_manager_unittest.cc
+++ /dev/null
@@ -1,185 +0,0 @@
-// 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 "sync/internal_api/sync_backup_manager.h"
-
-#include <string>
-
-#include "base/files/scoped_temp_dir.h"
-#include "base/run_loop.h"
-#include "sync/internal_api/public/read_node.h"
-#include "sync/internal_api/public/read_transaction.h"
-#include "sync/internal_api/public/sessions/sync_session_snapshot.h"
-#include "sync/internal_api/public/test/test_internal_components_factory.h"
-#include "sync/internal_api/public/write_node.h"
-#include "sync/internal_api/public/write_transaction.h"
-#include "sync/syncable/entry.h"
-#include "sync/test/test_directory_backing_store.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-using ::testing::_;
-using ::testing::Invoke;
-using ::testing::WithArgs;
-
-namespace syncer {
-
-namespace {
-
-void OnConfigDone(bool success) {
-  EXPECT_TRUE(success);
-}
-
-class SyncBackupManagerTest : public syncer::SyncManager::Observer,
-                              public testing::Test {
- public:
-  MOCK_METHOD1(OnSyncCycleCompleted,
-               void(const sessions::SyncSessionSnapshot&));
-  MOCK_METHOD1(OnConnectionStatusChange, void(ConnectionStatus));
-  MOCK_METHOD1(OnActionableError, void(const SyncProtocolError&));
-  MOCK_METHOD1(OnMigrationRequested, void(ModelTypeSet));
-  MOCK_METHOD1(OnProtocolEvent, void(const ProtocolEvent&));
-  MOCK_METHOD4(OnInitializationComplete,
-               void(const WeakHandle<JsBackend>&,
-                    const WeakHandle<DataTypeDebugInfoListener>&,
-                    bool, ModelTypeSet));
-
- protected:
-  void SetUp() override {
-    CHECK(temp_dir_.CreateUniqueTempDir());
-  }
-
-  void InitManager(SyncManager* manager,
-                   InternalComponentsFactory::StorageOption storage_option) {
-    manager_ = manager;
-    EXPECT_CALL(*this, OnInitializationComplete(_, _, _, _))
-        .WillOnce(WithArgs<2>(Invoke(this,
-                                     &SyncBackupManagerTest::HandleInit)));
-
-    manager->AddObserver(this);
-
-    base::RunLoop run_loop;
-
-    SyncManager::InitArgs args;
-    args.database_location = temp_dir_.path();
-    args.event_handler = MakeWeakHandle(base::WeakPtr<JsEventHandler>());
-    args.service_url = GURL("https://example.com/");
-    args.post_factory = scoped_ptr<HttpPostProviderFactory>();
-    args.internal_components_factory.reset(new TestInternalComponentsFactory(
-        InternalComponentsFactory::Switches(), storage_option,
-        &storage_used_));
-    manager->Init(&args);
-    EXPECT_EQ(InternalComponentsFactory::STORAGE_ON_DISK_DEFERRED,
-              storage_used_);
-    loop_.PostTask(FROM_HERE, run_loop.QuitClosure());
-    run_loop.Run();
-  }
-
-  void CreateEntry(UserShare* user_share, ModelType type,
-                   const std::string& client_tag) {
-    WriteTransaction trans(FROM_HERE, user_share);
-
-    WriteNode node(&trans);
-    EXPECT_EQ(WriteNode::INIT_SUCCESS,
-              node.InitUniqueByCreation(type, client_tag));
-  }
-
-  void ConfigureSyncer() {
-    manager_->ConfigureSyncer(CONFIGURE_REASON_NEW_CLIENT,
-                              ModelTypeSet(SEARCH_ENGINES),
-                              ModelTypeSet(), ModelTypeSet(), ModelTypeSet(),
-                              ModelSafeRoutingInfo(),
-                              base::Bind(&OnConfigDone, true),
-                              base::Bind(&OnConfigDone, false));
-  }
-
-  void HandleInit(bool success) {
-    if (success) {
-      loop_.PostTask(FROM_HERE,
-                     base::Bind(&SyncBackupManagerTest::ConfigureSyncer,
-                                base::Unretained(this)));
-    } else {
-      manager_->ShutdownOnSyncThread(STOP_SYNC);
-    }
-  }
-
-  base::ScopedTempDir temp_dir_;
-  base::MessageLoop loop_;    // Needed for WeakHandle
-  SyncManager* manager_;
-  InternalComponentsFactory::StorageOption storage_used_;
-};
-
-TEST_F(SyncBackupManagerTest, NormalizeEntry) {
-  scoped_ptr<SyncBackupManager> manager(new SyncBackupManager);
-  InitManager(manager.get(), InternalComponentsFactory::STORAGE_IN_MEMORY);
-
-  CreateEntry(manager->GetUserShare(), SEARCH_ENGINES, "test");
-
-  {
-    // New entry is local and unsynced at first.
-    ReadTransaction trans(FROM_HERE, manager->GetUserShare());
-    ReadNode pref(&trans);
-    EXPECT_EQ(BaseNode::INIT_OK,
-              pref.InitByClientTagLookup(SEARCH_ENGINES, "test"));
-    EXPECT_FALSE(pref.GetEntry()->GetId().ServerKnows());
-    EXPECT_TRUE(pref.GetEntry()->GetIsUnsynced());
-  }
-
-  manager->SaveChanges();
-
-  {
-    // New entry has server ID and unsynced bit is cleared after saving.
-    ReadTransaction trans(FROM_HERE, manager->GetUserShare());
-    ReadNode pref(&trans);
-    EXPECT_EQ(BaseNode::INIT_OK,
-              pref.InitByClientTagLookup(SEARCH_ENGINES, "test"));
-    EXPECT_TRUE(pref.GetEntry()->GetId().ServerKnows());
-    EXPECT_FALSE(pref.GetEntry()->GetIsUnsynced());
-  }
-}
-
-TEST_F(SyncBackupManagerTest, PersistWithSwitchToSyncShutdown) {
-  scoped_ptr<SyncBackupManager> manager(new SyncBackupManager);
-  InitManager(manager.get(),
-              InternalComponentsFactory::STORAGE_ON_DISK_DEFERRED);
-
-  CreateEntry(manager->GetUserShare(), SEARCH_ENGINES, "test");
-  manager->SaveChanges();
-  manager->ShutdownOnSyncThread(SWITCH_MODE_SYNC);
-
-  // Reopen db to verify entry is persisted.
-  manager.reset(new SyncBackupManager);
-  InitManager(manager.get(), InternalComponentsFactory::STORAGE_ON_DISK);
-  {
-    ReadTransaction trans(FROM_HERE, manager->GetUserShare());
-    ReadNode pref(&trans);
-    EXPECT_EQ(BaseNode::INIT_OK,
-              pref.InitByClientTagLookup(SEARCH_ENGINES, "test"));
-    EXPECT_TRUE(pref.GetEntry()->GetId().ServerKnows());
-    EXPECT_FALSE(pref.GetEntry()->GetIsUnsynced());
-  }
-}
-
-TEST_F(SyncBackupManagerTest, DontPersistWithOtherShutdown) {
-  scoped_ptr<SyncBackupManager> manager(new SyncBackupManager);
-  InitManager(manager.get(),
-              InternalComponentsFactory::STORAGE_ON_DISK_DEFERRED);
-
-  CreateEntry(manager->GetUserShare(), SEARCH_ENGINES, "test");
-  manager->SaveChanges();
-  manager->ShutdownOnSyncThread(STOP_SYNC);
-  EXPECT_FALSE(base::PathExists(
-      temp_dir_.path().Append(syncable::Directory::kSyncDatabaseFilename)));
-}
-
-TEST_F(SyncBackupManagerTest, FailToInitialize) {
-  // Test graceful shutdown on initialization failure.
-  scoped_ptr<SyncBackupManager> manager(new SyncBackupManager);
-  InitManager(manager.get(), InternalComponentsFactory::STORAGE_INVALID);
-}
-
-}  // anonymous namespace
-
-}  // namespace syncer
diff --git a/sync/internal_api/sync_manager_factory.cc b/sync/internal_api/sync_manager_factory.cc
index 288b5dad..48ff69d 100644
--- a/sync/internal_api/sync_manager_factory.cc
+++ b/sync/internal_api/sync_manager_factory.cc
@@ -4,32 +4,18 @@
 
 #include "sync/internal_api/public/sync_manager_factory.h"
 
-#include "sync/internal_api/sync_backup_manager.h"
 #include "sync/internal_api/sync_manager_impl.h"
-#include "sync/internal_api/sync_rollback_manager.h"
 
 namespace syncer {
 
-SyncManagerFactory::SyncManagerFactory(SyncManagerFactory::MANAGER_TYPE type)
-    : type_(type) {
-}
+SyncManagerFactory::SyncManagerFactory() {}
 
 SyncManagerFactory::~SyncManagerFactory() {
 }
 
 scoped_ptr<SyncManager> SyncManagerFactory::CreateSyncManager(
     const std::string& name) {
-  switch (type_) {
-    case NORMAL:
-      return scoped_ptr<SyncManager>(new SyncManagerImpl(name));
-    case BACKUP:
-      return scoped_ptr<SyncManager>(new SyncBackupManager());
-    case ROLLBACK:
-      return scoped_ptr<SyncManager>(new SyncRollbackManager());
-    default:
-      NOTREACHED();
-      return scoped_ptr<SyncManager>(new SyncManagerImpl(name));
-  }
+  return scoped_ptr<SyncManager>(new SyncManagerImpl(name));
 }
 
 }  // namespace syncer
diff --git a/sync/internal_api/sync_rollback_manager.cc b/sync/internal_api/sync_rollback_manager.cc
deleted file mode 100644
index e2a5c84..0000000
--- a/sync/internal_api/sync_rollback_manager.cc
+++ /dev/null
@@ -1,128 +0,0 @@
-// 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 "sync/internal_api/sync_rollback_manager.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "sync/internal_api/public/base/model_type.h"
-#include "sync/internal_api/public/read_node.h"
-#include "sync/internal_api/public/read_transaction.h"
-#include "sync/internal_api/public/util/syncer_error.h"
-#include "sync/internal_api/public/write_transaction.h"
-#include "sync/syncable/directory.h"
-#include "sync/syncable/mutable_entry.h"
-#include "url/gurl.h"
-
-namespace syncer {
-
-SyncRollbackManager::SyncRollbackManager()
-    : change_delegate_(NULL) {
-}
-
-SyncRollbackManager::~SyncRollbackManager() {
-}
-
-void SyncRollbackManager::Init(InitArgs* args) {
-  if (SyncRollbackManagerBase::InitInternal(
-          args->database_location,
-          args->internal_components_factory.get(),
-          InternalComponentsFactory::STORAGE_ON_DISK,
-          args->unrecoverable_error_handler,
-          args->report_unrecoverable_error_function)) {
-    change_delegate_ = args->change_delegate;
-
-    for (size_t i = 0; i < args->workers.size(); ++i) {
-      ModelSafeGroup group = args->workers[i]->GetModelSafeGroup();
-      CHECK(workers_.find(group) == workers_.end());
-      workers_[group] = args->workers[i];
-    }
-
-    rollback_ready_types_ = GetUserShare()->directory->InitialSyncEndedTypes();
-    rollback_ready_types_.RetainAll(BackupTypes());
-  }
-}
-
-void SyncRollbackManager::StartSyncingNormally(
-    const ModelSafeRoutingInfo& routing_info,
-    base::Time last_poll_time) {
-  if (rollback_ready_types_.Empty()) {
-    NotifyRollbackDone();
-    return;
-  }
-
-  std::map<ModelType, syncable::Directory::Metahandles> to_delete;
-  {
-    WriteTransaction trans(FROM_HERE, GetUserShare());
-    syncable::Directory::Metahandles unsynced;
-    GetUserShare()->directory->GetUnsyncedMetaHandles(trans.GetWrappedTrans(),
-                                                      &unsynced);
-    for (size_t i = 0; i < unsynced.size(); ++i) {
-      syncable::MutableEntry e(trans.GetWrappedWriteTrans(),
-                               syncable::GET_BY_HANDLE, unsynced[i]);
-      if (!e.good() || e.GetIsDel() || e.GetId().ServerKnows())
-        continue;
-
-      // TODO(haitaol): roll back entries that are backed up but whose content
-      //                is merged with local model during association.
-
-      ModelType type = GetModelTypeFromSpecifics(e.GetSpecifics());
-      if (!rollback_ready_types_.Has(type))
-        continue;
-
-      to_delete[type].push_back(unsynced[i]);
-    }
-  }
-
-  for (std::map<ModelType, syncable::Directory::Metahandles>::iterator it =
-      to_delete.begin(); it != to_delete.end(); ++it) {
-    ModelSafeGroup group = routing_info.find(it->first)->second;
-    CHECK(workers_.find(group) != workers_.end());
-    workers_[group]->DoWorkAndWaitUntilDone(
-        base::Bind(&SyncRollbackManager::DeleteOnWorkerThread,
-                   base::Unretained(this),
-                   it->first, it->second));
-  }
-
-  NotifyRollbackDone();
-}
-
-SyncerError SyncRollbackManager::DeleteOnWorkerThread(
-    ModelType type,
-    std::vector<int64_t> handles) {
-  CHECK(change_delegate_);
-
-  {
-    ChangeRecordList deletes;
-    WriteTransaction trans(FROM_HERE, GetUserShare());
-    for (size_t i = 0; i < handles.size(); ++i) {
-      syncable::MutableEntry e(trans.GetWrappedWriteTrans(),
-                               syncable::GET_BY_HANDLE, handles[i]);
-      if (!e.good() || e.GetIsDel())
-        continue;
-
-      ChangeRecord del;
-      del.action = ChangeRecord::ACTION_DELETE;
-      del.id = handles[i];
-      del.specifics = e.GetSpecifics();
-      deletes.push_back(del);
-    }
-
-    change_delegate_->OnChangesApplied(type, 1, &trans,
-                                       MakeImmutable(&deletes));
-  }
-
-  change_delegate_->OnChangesComplete(type);
-  return SYNCER_OK;
-}
-
-void SyncRollbackManager::NotifyRollbackDone() {
-  SyncProtocolError error;
-  error.action = ROLLBACK_DONE;
-  FOR_EACH_OBSERVER(SyncManager::Observer, *GetObservers(),
-                    OnActionableError(error));
-}
-
-}  // namespace syncer
diff --git a/sync/internal_api/sync_rollback_manager.h b/sync/internal_api/sync_rollback_manager.h
deleted file mode 100644
index d41086a..0000000
--- a/sync/internal_api/sync_rollback_manager.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// 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 SYNC_INTERNAL_API_SYNC_ROLLBACK_MANAGER_H_
-#define SYNC_INTERNAL_API_SYNC_ROLLBACK_MANAGER_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "sync/internal_api/sync_rollback_manager_base.h"
-
-class GURL;
-
-namespace syncer {
-
-// SyncRollbackManager restores user's data to pre-sync state using backup
-// DB created by SyncBackupManager.
-class SYNC_EXPORT SyncRollbackManager : public SyncRollbackManagerBase {
- public:
-  SyncRollbackManager();
-  ~SyncRollbackManager() override;
-
-  // SyncManager implementation.
-  void Init(InitArgs* args) override;
-  void StartSyncingNormally(const ModelSafeRoutingInfo& routing_info,
-                            base::Time last_poll_time) override;
-
- private:
-  // Deletes specified entries in local model.
-  SyncerError DeleteOnWorkerThread(ModelType type,
-                                   std::vector<int64_t> handles);
-
-  void NotifyRollbackDone();
-
-  std::map<ModelSafeGroup, scoped_refptr<ModelSafeWorker> > workers_;
-
-  SyncManager::ChangeDelegate* change_delegate_;
-
-  // Types that can be rolled back.
-  ModelTypeSet rollback_ready_types_;
-
-  DISALLOW_COPY_AND_ASSIGN(SyncRollbackManager);
-};
-
-}  // namespace syncer
-
-#endif  // SYNC_INTERNAL_API_SYNC_ROLLBACK_MANAGER_H_
diff --git a/sync/internal_api/sync_rollback_manager_base.cc b/sync/internal_api/sync_rollback_manager_base.cc
deleted file mode 100644
index d62f354eb..0000000
--- a/sync/internal_api/sync_rollback_manager_base.cc
+++ /dev/null
@@ -1,329 +0,0 @@
-// 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 "sync/internal_api/sync_rollback_manager_base.h"
-
-#include <stdint.h>
-
-#include "sync/internal_api/public/base/model_type.h"
-#include "sync/internal_api/public/read_node.h"
-#include "sync/internal_api/public/read_transaction.h"
-#include "sync/internal_api/public/write_transaction.h"
-#include "sync/syncable/directory_backing_store.h"
-#include "sync/syncable/mutable_entry.h"
-
-namespace {
-
-// Permanent bookmark folders as defined in bookmark_model_associator.cc.
-// No mobile bookmarks because they only exists with sync enabled.
-const char kBookmarkBarTag[] = "bookmark_bar";
-const char kOtherBookmarksTag[] = "other_bookmarks";
-
-class DummyEntryptionHandler : public syncer::SyncEncryptionHandler {
-  void AddObserver(Observer* observer) override {}
-  void RemoveObserver(Observer* observer) override {}
-  void Init() override {}
-  void SetEncryptionPassphrase(const std::string& passphrase,
-                               bool is_explicit) override {}
-  void SetDecryptionPassphrase(const std::string& passphrase) override {}
-  void EnableEncryptEverything() override {}
-  bool IsEncryptEverythingEnabled() const override { return false; }
-  syncer::PassphraseType GetPassphraseType() const override {
-    return syncer::KEYSTORE_PASSPHRASE;
-  }
-};
-
-}  // anonymous namespace
-
-namespace syncer {
-
-SyncRollbackManagerBase::SyncRollbackManagerBase()
-    : dummy_handler_(new DummyEntryptionHandler),
-      initialized_(false),
-      weak_ptr_factory_(this) {
-}
-
-SyncRollbackManagerBase::~SyncRollbackManagerBase() {
-}
-
-bool SyncRollbackManagerBase::InitInternal(
-    const base::FilePath& database_location,
-    InternalComponentsFactory* internal_components_factory,
-    InternalComponentsFactory::StorageOption storage,
-    const WeakHandle<UnrecoverableErrorHandler>& unrecoverable_error_handler,
-    const base::Closure& report_unrecoverable_error_function) {
-  unrecoverable_error_handler_ = unrecoverable_error_handler;
-  report_unrecoverable_error_function_ = report_unrecoverable_error_function;
-
-  if (!InitBackupDB(database_location, internal_components_factory, storage)) {
-    NotifyInitializationFailure();
-    return false;
-  }
-
-  initialized_ = true;
-  NotifyInitializationSuccess();
-  return true;
-}
-
-ModelTypeSet SyncRollbackManagerBase::InitialSyncEndedTypes() {
-  return share_.directory->InitialSyncEndedTypes();
-}
-
-ModelTypeSet SyncRollbackManagerBase::GetTypesWithEmptyProgressMarkerToken(
-      ModelTypeSet types) {
-  ModelTypeSet inited_types = share_.directory->InitialSyncEndedTypes();
-  types.RemoveAll(inited_types);
-  return types;
-}
-
-bool SyncRollbackManagerBase::PurgePartiallySyncedTypes() {
-  NOTREACHED();
-  return true;
-}
-
-void SyncRollbackManagerBase::UpdateCredentials(
-    const SyncCredentials& credentials) {
-}
-
-void SyncRollbackManagerBase::StartSyncingNormally(
-    const ModelSafeRoutingInfo& routing_info,
-    base::Time last_poll_time) {}
-
-void SyncRollbackManagerBase::ConfigureSyncer(
-      ConfigureReason reason,
-      ModelTypeSet to_download,
-      ModelTypeSet to_purge,
-      ModelTypeSet to_journal,
-      ModelTypeSet to_unapply,
-      const ModelSafeRoutingInfo& new_routing_info,
-      const base::Closure& ready_task,
-      const base::Closure& retry_task) {
-  for (ModelTypeSet::Iterator type = to_download.First();
-      type.Good(); type.Inc()) {
-    if (InitTypeRootNode(type.Get())) {
-      if (type.Get() == BOOKMARKS) {
-        InitBookmarkFolder(kBookmarkBarTag);
-        InitBookmarkFolder(kOtherBookmarksTag);
-      }
-    }
-  }
-
-  ready_task.Run();
-}
-
-void SyncRollbackManagerBase::SetInvalidatorEnabled(bool invalidator_enabled) {
-}
-
-void SyncRollbackManagerBase::OnIncomingInvalidation(
-    syncer::ModelType type,
-    scoped_ptr<InvalidationInterface> invalidation) {
-  NOTREACHED();
-}
-
-void SyncRollbackManagerBase::AddObserver(SyncManager::Observer* observer) {
-  observers_.AddObserver(observer);
-}
-
-void SyncRollbackManagerBase::RemoveObserver(SyncManager::Observer* observer) {
-  observers_.RemoveObserver(observer);
-}
-
-SyncStatus SyncRollbackManagerBase::GetDetailedStatus() const {
-  return SyncStatus();
-}
-
-void SyncRollbackManagerBase::SaveChanges() {
-}
-
-void SyncRollbackManagerBase::ShutdownOnSyncThread(ShutdownReason reason) {
-  if (initialized_) {
-    share_.directory.reset();
-    initialized_ = false;
-  }
-}
-
-UserShare* SyncRollbackManagerBase::GetUserShare() {
-  return &share_;
-}
-
-const std::string SyncRollbackManagerBase::cache_guid() {
-  return share_.directory->cache_guid();
-}
-
-bool SyncRollbackManagerBase::ReceivedExperiment(Experiments* experiments) {
-  return false;
-}
-
-bool SyncRollbackManagerBase::HasUnsyncedItems() {
-  ReadTransaction trans(FROM_HERE, &share_);
-  syncable::Directory::Metahandles unsynced;
-  share_.directory->GetUnsyncedMetaHandles(trans.GetWrappedTrans(), &unsynced);
-  return !unsynced.empty();
-}
-
-SyncEncryptionHandler* SyncRollbackManagerBase::GetEncryptionHandler() {
-  return dummy_handler_.get();
-}
-
-void SyncRollbackManagerBase::RefreshTypes(ModelTypeSet types) {
-}
-
-void SyncRollbackManagerBase::HandleTransactionCompleteChangeEvent(
-    ModelTypeSet models_with_changes) {
-}
-
-ModelTypeSet SyncRollbackManagerBase::HandleTransactionEndingChangeEvent(
-      const syncable::ImmutableWriteTransactionInfo& write_transaction_info,
-      syncable::BaseTransaction* trans) {
-  return ModelTypeSet();
-}
-
-void SyncRollbackManagerBase::HandleCalculateChangesChangeEventFromSyncApi(
-    const syncable::ImmutableWriteTransactionInfo& write_transaction_info,
-    syncable::BaseTransaction* trans,
-    std::vector<int64_t>* entries_changed) {}
-
-void SyncRollbackManagerBase::HandleCalculateChangesChangeEventFromSyncer(
-    const syncable::ImmutableWriteTransactionInfo& write_transaction_info,
-    syncable::BaseTransaction* trans,
-    std::vector<int64_t>* entries_changed) {}
-
-void SyncRollbackManagerBase::OnTransactionWrite(
-    const syncable::ImmutableWriteTransactionInfo& write_transaction_info,
-    ModelTypeSet models_with_changes) {
-}
-
-void SyncRollbackManagerBase::NotifyInitializationSuccess() {
-  FOR_EACH_OBSERVER(
-      SyncManager::Observer, observers_,
-      OnInitializationComplete(
-          MakeWeakHandle(base::WeakPtr<JsBackend>()),
-          MakeWeakHandle(base::WeakPtr<DataTypeDebugInfoListener>()),
-          true, InitialSyncEndedTypes()));
-}
-
-void SyncRollbackManagerBase::NotifyInitializationFailure() {
-  FOR_EACH_OBSERVER(
-      SyncManager::Observer, observers_,
-      OnInitializationComplete(
-          MakeWeakHandle(base::WeakPtr<JsBackend>()),
-          MakeWeakHandle(base::WeakPtr<DataTypeDebugInfoListener>()),
-          false, ModelTypeSet()));
-}
-
-syncer_v2::SyncContextProxy* SyncRollbackManagerBase::GetSyncContextProxy() {
-  return NULL;
-}
-
-ScopedVector<syncer::ProtocolEvent>
-SyncRollbackManagerBase::GetBufferedProtocolEvents() {
-  return ScopedVector<syncer::ProtocolEvent>();
-}
-
-scoped_ptr<base::ListValue> SyncRollbackManagerBase::GetAllNodesForType(
-    syncer::ModelType type) {
-  ReadTransaction trans(FROM_HERE, GetUserShare());
-  scoped_ptr<base::ListValue> nodes(
-      trans.GetDirectory()->GetNodeDetailsForType(trans.GetWrappedTrans(),
-                                                  type));
-  return nodes;
-}
-
-bool SyncRollbackManagerBase::InitBackupDB(
-    const base::FilePath& sync_folder,
-    InternalComponentsFactory* internal_components_factory,
-    InternalComponentsFactory::StorageOption storage) {
-  base::FilePath backup_db_path = sync_folder.Append(
-      syncable::Directory::kSyncDatabaseFilename);
-  scoped_ptr<syncable::DirectoryBackingStore> backing_store =
-      internal_components_factory->BuildDirectoryBackingStore(storage, "backup",
-                                                              backup_db_path);
-
-  DCHECK(backing_store.get());
-  share_.directory.reset(
-      new syncable::Directory(
-          backing_store.release(),
-          unrecoverable_error_handler_,
-          report_unrecoverable_error_function_,
-          NULL,
-          NULL));
-  return syncable::OPENED ==
-      share_.directory->Open(
-          "backup", this,
-          MakeWeakHandle(weak_ptr_factory_.GetWeakPtr()));
-}
-
-bool SyncRollbackManagerBase::InitTypeRootNode(ModelType type) {
-  WriteTransaction trans(FROM_HERE, &share_);
-  ReadNode root(&trans);
-  if (BaseNode::INIT_OK == root.InitTypeRoot(type))
-    return true;
-
-  syncable::MutableEntry entry(trans.GetWrappedWriteTrans(),
-                               syncable::CREATE_NEW_UPDATE_ITEM,
-                               syncable::Id::CreateFromServerId(
-                                   ModelTypeToString(type)));
-  if (!entry.good())
-    return false;
-
-  entry.PutParentId(syncable::Id::GetRoot());
-  entry.PutBaseVersion(1);
-  entry.PutUniqueServerTag(ModelTypeToRootTag(type));
-  entry.PutNonUniqueName(ModelTypeToString(type));
-  entry.PutIsDel(false);
-  entry.PutIsDir(true);
-
-  sync_pb::EntitySpecifics specifics;
-  AddDefaultFieldValue(type, &specifics);
-  entry.PutSpecifics(specifics);
-
-  return true;
-}
-
-void SyncRollbackManagerBase::InitBookmarkFolder(const std::string& folder) {
-  WriteTransaction trans(FROM_HERE, &share_);
-  syncable::Entry bookmark_root(trans.GetWrappedTrans(),
-                                syncable::GET_TYPE_ROOT,
-                                BOOKMARKS);
-  if (!bookmark_root.good())
-    return;
-
-  syncable::MutableEntry entry(trans.GetWrappedWriteTrans(),
-                               syncable::CREATE_NEW_UPDATE_ITEM,
-                               syncable::Id::CreateFromServerId(folder));
-  if (!entry.good())
-    return;
-
-  entry.PutParentId(bookmark_root.GetId());
-  entry.PutBaseVersion(1);
-  entry.PutUniqueServerTag(folder);
-  entry.PutNonUniqueName(folder);
-  entry.PutIsDel(false);
-  entry.PutIsDir(true);
-
-  sync_pb::EntitySpecifics specifics;
-  AddDefaultFieldValue(BOOKMARKS, &specifics);
-  entry.PutSpecifics(specifics);
-}
-
-base::ObserverList<SyncManager::Observer>*
-SyncRollbackManagerBase::GetObservers() {
-  return &observers_;
-}
-
-void SyncRollbackManagerBase::RegisterDirectoryTypeDebugInfoObserver(
-    syncer::TypeDebugInfoObserver* observer) {}
-
-void SyncRollbackManagerBase::UnregisterDirectoryTypeDebugInfoObserver(
-    syncer::TypeDebugInfoObserver* observer) {}
-
-bool SyncRollbackManagerBase::HasDirectoryTypeDebugInfoObserver(
-    syncer::TypeDebugInfoObserver* observer) { return false; }
-
-void SyncRollbackManagerBase::RequestEmitDebugInfo() {}
-
-void SyncRollbackManagerBase::ClearServerData(
-    const ClearServerDataCallback& callback) {}
-
-}  // namespace syncer
diff --git a/sync/internal_api/sync_rollback_manager_base.h b/sync/internal_api/sync_rollback_manager_base.h
deleted file mode 100644
index ad3ad62..0000000
--- a/sync/internal_api/sync_rollback_manager_base.h
+++ /dev/null
@@ -1,149 +0,0 @@
-// 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 SYNC_INTERNAL_API_SYNC_ROLLBACK_MANAGER_BASE_H_
-#define SYNC_INTERNAL_API_SYNC_ROLLBACK_MANAGER_BASE_H_
-
-#include <stdint.h>
-
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "sync/base/sync_export.h"
-#include "sync/internal_api/public/http_post_provider_factory.h"
-#include "sync/internal_api/public/internal_components_factory.h"
-#include "sync/internal_api/public/sync_manager.h"
-#include "sync/internal_api/public/user_share.h"
-#include "sync/syncable/directory_change_delegate.h"
-#include "sync/syncable/transaction_observer.h"
-
-namespace syncer {
-
-class WriteTransaction;
-
-// Base class of sync managers used for backup and rollback. Two major
-// functions are:
-//   * Init(): load backup DB into sync directory.
-//   * ConfigureSyncer(): initialize permanent sync nodes (root, bookmark
-//                        permanent folders) for configured type as needed.
-//
-// Most of other functions are no ops.
-class SYNC_EXPORT SyncRollbackManagerBase
-    : public SyncManager,
-      public syncable::DirectoryChangeDelegate,
-      public syncable::TransactionObserver {
- public:
-  SyncRollbackManagerBase();
-  ~SyncRollbackManagerBase() override;
-
-  // SyncManager implementation.
-  ModelTypeSet InitialSyncEndedTypes() override;
-  ModelTypeSet GetTypesWithEmptyProgressMarkerToken(
-      ModelTypeSet types) override;
-  bool PurgePartiallySyncedTypes() override;
-  void UpdateCredentials(const SyncCredentials& credentials) override;
-  void StartSyncingNormally(const ModelSafeRoutingInfo& routing_info,
-                            base::Time last_poll_time) override;
-  void ConfigureSyncer(ConfigureReason reason,
-                       ModelTypeSet to_download,
-                       ModelTypeSet to_purge,
-                       ModelTypeSet to_journal,
-                       ModelTypeSet to_unapply,
-                       const ModelSafeRoutingInfo& new_routing_info,
-                       const base::Closure& ready_task,
-                       const base::Closure& retry_task) override;
-  void SetInvalidatorEnabled(bool invalidator_enabled) override;
-  void OnIncomingInvalidation(
-      syncer::ModelType type,
-      scoped_ptr<InvalidationInterface> invalidation) override;
-  void AddObserver(SyncManager::Observer* observer) override;
-  void RemoveObserver(SyncManager::Observer* observer) override;
-  SyncStatus GetDetailedStatus() const override;
-  void SaveChanges() override;
-  void ShutdownOnSyncThread(ShutdownReason reason) override;
-  UserShare* GetUserShare() override;
-  const std::string cache_guid() override;
-  bool ReceivedExperiment(Experiments* experiments) override;
-  bool HasUnsyncedItems() override;
-  SyncEncryptionHandler* GetEncryptionHandler() override;
-  void RefreshTypes(ModelTypeSet types) override;
-  syncer_v2::SyncContextProxy* GetSyncContextProxy() override;
-  ScopedVector<ProtocolEvent> GetBufferedProtocolEvents() override;
-  scoped_ptr<base::ListValue> GetAllNodesForType(
-      syncer::ModelType type) override;
-  void ClearServerData(const ClearServerDataCallback& callback) override;
-
-  // DirectoryChangeDelegate implementation.
-  void HandleTransactionCompleteChangeEvent(
-      ModelTypeSet models_with_changes) override;
-  ModelTypeSet HandleTransactionEndingChangeEvent(
-      const syncable::ImmutableWriteTransactionInfo& write_transaction_info,
-      syncable::BaseTransaction* trans) override;
-  void HandleCalculateChangesChangeEventFromSyncApi(
-      const syncable::ImmutableWriteTransactionInfo& write_transaction_info,
-      syncable::BaseTransaction* trans,
-      std::vector<int64_t>* entries_changed) override;
-  void HandleCalculateChangesChangeEventFromSyncer(
-      const syncable::ImmutableWriteTransactionInfo& write_transaction_info,
-      syncable::BaseTransaction* trans,
-      std::vector<int64_t>* entries_changed) override;
-
-  // syncable::TransactionObserver implementation.
-  void OnTransactionWrite(
-      const syncable::ImmutableWriteTransactionInfo& write_transaction_info,
-      ModelTypeSet models_with_changes) override;
-
- protected:
-  base::ObserverList<SyncManager::Observer>* GetObservers();
-
-  // Initialize sync backup DB.
-  bool InitInternal(
-      const base::FilePath& database_location,
-      InternalComponentsFactory* internal_components_factory,
-      InternalComponentsFactory::StorageOption storage,
-      const WeakHandle<UnrecoverableErrorHandler>& unrecoverable_error_handler,
-      const base::Closure& report_unrecoverable_error_function);
-
-  void RegisterDirectoryTypeDebugInfoObserver(
-      syncer::TypeDebugInfoObserver* observer) override;
-  void UnregisterDirectoryTypeDebugInfoObserver(
-      syncer::TypeDebugInfoObserver* observer) override;
-  bool HasDirectoryTypeDebugInfoObserver(
-      syncer::TypeDebugInfoObserver* observer) override;
-  void RequestEmitDebugInfo() override;
-
-  bool initialized() const {
-    return initialized_;
-  }
-
- private:
-  void NotifyInitializationSuccess();
-  void NotifyInitializationFailure();
-
-  bool InitBackupDB(const base::FilePath& sync_folder,
-                    InternalComponentsFactory* internal_components_factory,
-                    InternalComponentsFactory::StorageOption storage);
-
-  bool InitTypeRootNode(ModelType type);
-  void InitBookmarkFolder(const std::string& folder);
-
-  UserShare share_;
-  base::ObserverList<SyncManager::Observer> observers_;
-
-  WeakHandle<UnrecoverableErrorHandler> unrecoverable_error_handler_;
-  base::Closure report_unrecoverable_error_function_;
-
-  scoped_ptr<SyncEncryptionHandler> dummy_handler_;
-
-  bool initialized_;
-
-  base::WeakPtrFactory<SyncRollbackManagerBase> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(SyncRollbackManagerBase);
-};
-
-}  // namespace syncer
-
-#endif  // SYNC_INTERNAL_API_SYNC_ROLLBACK_MANAGER_BASE_H_
diff --git a/sync/internal_api/sync_rollback_manager_base_unittest.cc b/sync/internal_api/sync_rollback_manager_base_unittest.cc
deleted file mode 100644
index bb5ec93f..0000000
--- a/sync/internal_api/sync_rollback_manager_base_unittest.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-// 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 "sync/internal_api/sync_rollback_manager_base.h"
-
-#include "base/bind.h"
-#include "sync/internal_api/public/read_node.h"
-#include "sync/internal_api/public/read_transaction.h"
-#include "sync/internal_api/public/test/test_internal_components_factory.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-namespace syncer {
-
-namespace {
-
-void OnConfigDone(bool success) {
-  EXPECT_TRUE(success);
-}
-
-class SyncTestRollbackManager : public SyncRollbackManagerBase {
- public:
-  void Init(InitArgs* args) override {
-    SyncRollbackManagerBase::InitInternal(
-        args->database_location,
-        args->internal_components_factory.get(),
-        InternalComponentsFactory::STORAGE_IN_MEMORY,
-        args->unrecoverable_error_handler,
-        args->report_unrecoverable_error_function);
-  }
-};
-
-class SyncRollbackManagerBaseTest : public testing::Test {
- protected:
-  void SetUp() override {
-    SyncManager::InitArgs args;
-    args.database_location = base::FilePath(base::FilePath::kCurrentDirectory);
-    args.service_url = GURL("https://example.com/");
-    args.internal_components_factory.reset(new TestInternalComponentsFactory(
-        InternalComponentsFactory::Switches(),
-        InternalComponentsFactory::STORAGE_IN_MEMORY,
-        &storage_used_));
-    manager_.Init(&args);
-    EXPECT_EQ(InternalComponentsFactory::STORAGE_IN_MEMORY, storage_used_);
-  }
-
-  SyncTestRollbackManager manager_;
-  base::MessageLoop loop_;    // Needed for WeakHandle
-  InternalComponentsFactory::StorageOption storage_used_;
-};
-
-TEST_F(SyncRollbackManagerBaseTest, InitTypeOnConfiguration) {
-  EXPECT_TRUE(manager_.InitialSyncEndedTypes().Empty());
-
-  manager_.ConfigureSyncer(
-      CONFIGURE_REASON_NEW_CLIENT,
-      ModelTypeSet(PREFERENCES, BOOKMARKS),
-      ModelTypeSet(), ModelTypeSet(), ModelTypeSet(), ModelSafeRoutingInfo(),
-      base::Bind(&OnConfigDone, true),
-      base::Bind(&OnConfigDone, false));
-
-  ReadTransaction trans(FROM_HERE, manager_.GetUserShare());
-  ReadNode pref_root(&trans);
-  EXPECT_EQ(BaseNode::INIT_OK,
-            pref_root.InitTypeRoot(PREFERENCES));
-
-  ReadNode bookmark_root(&trans);
-  EXPECT_EQ(BaseNode::INIT_OK,
-            bookmark_root.InitTypeRoot(BOOKMARKS));
-  ReadNode bookmark_bar(&trans);
-  EXPECT_EQ(BaseNode::INIT_OK,
-            bookmark_bar.InitByTagLookupForBookmarks("bookmark_bar"));
-  ReadNode bookmark_mobile(&trans);
-  EXPECT_EQ(BaseNode::INIT_FAILED_ENTRY_NOT_GOOD,
-            bookmark_mobile.InitByTagLookupForBookmarks("synced_bookmarks"));
-  ReadNode bookmark_other(&trans);
-  EXPECT_EQ(BaseNode::INIT_OK,
-            bookmark_other.InitByTagLookupForBookmarks("other_bookmarks"));
-}
-
-}  // anonymous namespace
-
-}  // namespace syncer
diff --git a/sync/internal_api/sync_rollback_manager_unittest.cc b/sync/internal_api/sync_rollback_manager_unittest.cc
deleted file mode 100644
index 400cebc..0000000
--- a/sync/internal_api/sync_rollback_manager_unittest.cc
+++ /dev/null
@@ -1,269 +0,0 @@
-// 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 "sync/internal_api/sync_rollback_manager.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <set>
-
-#include "base/files/scoped_temp_dir.h"
-#include "base/run_loop.h"
-#include "sync/internal_api/public/read_node.h"
-#include "sync/internal_api/public/read_transaction.h"
-#include "sync/internal_api/public/sessions/sync_session_snapshot.h"
-#include "sync/internal_api/public/test/test_internal_components_factory.h"
-#include "sync/internal_api/public/write_node.h"
-#include "sync/internal_api/public/write_transaction.h"
-#include "sync/internal_api/sync_backup_manager.h"
-#include "sync/syncable/entry.h"
-#include "sync/test/engine/fake_model_worker.h"
-#include "sync/test/test_directory_backing_store.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-using ::testing::_;
-using ::testing::DoDefault;
-using ::testing::Invoke;
-using ::testing::Truly;
-using ::testing::WithArgs;
-
-namespace syncer {
-
-namespace {
-
-class TestChangeDelegate : public SyncManager::ChangeDelegate {
- public:
-  TestChangeDelegate() {
-    ON_CALL(*this, OnChangesApplied(_, _, _, _))
-        .WillByDefault(
-            WithArgs<3>(Invoke(this,
-                               &TestChangeDelegate::VerifyDeletes)));
-  }
-
-  void add_expected_delete(int64_t v) { expected_deletes_.insert(v); }
-
-  MOCK_METHOD4(OnChangesApplied,
-               void(ModelType model_type,
-                    int64_t model_version,
-                    const BaseTransaction* trans,
-                    const ImmutableChangeRecordList& changes));
-  MOCK_METHOD1(OnChangesComplete, void(ModelType model_type));
-
- private:
-  void VerifyDeletes(const ImmutableChangeRecordList& changes) {
-    std::set<int64_t> deleted;
-    for (size_t i = 0; i < changes.Get().size(); ++i) {
-      const ChangeRecord& change = (changes.Get())[i];
-      EXPECT_EQ(ChangeRecord::ACTION_DELETE, change.action);
-      EXPECT_TRUE(deleted.find(change.id) == deleted.end());
-      deleted.insert(change.id);
-    }
-    EXPECT_TRUE(expected_deletes_ == deleted);
-  }
-
-  std::set<int64_t> expected_deletes_;
-};
-
-class SyncRollbackManagerTest : public testing::Test,
-                                public SyncManager::Observer {
- protected:
-  void SetUp() override {
-    CHECK(temp_dir_.CreateUniqueTempDir());
-
-    worker_ = new FakeModelWorker(GROUP_UI);
-  }
-
-  MOCK_METHOD1(OnSyncCycleCompleted,
-               void(const sessions::SyncSessionSnapshot&));
-  MOCK_METHOD1(OnConnectionStatusChange, void(ConnectionStatus));
-  MOCK_METHOD4(OnInitializationComplete,
-               void(const WeakHandle<JsBackend>&,
-                    const WeakHandle<DataTypeDebugInfoListener>&,
-                    bool, ModelTypeSet));
-  MOCK_METHOD1(OnActionableError, void(const SyncProtocolError&));
-  MOCK_METHOD1(OnMigrationRequested, void(ModelTypeSet));
-  MOCK_METHOD1(OnProtocolEvent, void(const ProtocolEvent&));
-
-  void OnConfigDone(bool success) {
-    EXPECT_TRUE(success);
-  }
-
-  int64_t CreateEntry(UserShare* user_share,
-                      ModelType type,
-                      const std::string& client_tag) {
-    WriteTransaction trans(FROM_HERE, user_share);
-    WriteNode node(&trans);
-    EXPECT_EQ(WriteNode::INIT_SUCCESS,
-              node.InitUniqueByCreation(type, client_tag));
-    return node.GetId();
-  }
-
-  void InitManager(SyncManager* manager, ModelTypeSet types,
-                   TestChangeDelegate* delegate,
-                   InternalComponentsFactory::StorageOption storage_option) {
-    manager_ = manager;
-    types_ = types;
-
-    EXPECT_CALL(*this, OnInitializationComplete(_, _, _, _))
-        .WillOnce(WithArgs<2>(Invoke(this,
-                                     &SyncRollbackManagerTest::HandleInit)));
-
-    manager->AddObserver(this);
-
-    base::RunLoop run_loop;
-    SyncManager::InitArgs args;
-    args.database_location = temp_dir_.path();
-    args.service_url = GURL("https://example.com/");
-    args.workers.push_back(worker_);
-    args.change_delegate = delegate;
-
-    InternalComponentsFactory::StorageOption storage_used;
-    args.internal_components_factory.reset(new TestInternalComponentsFactory(
-        InternalComponentsFactory::Switches(), storage_option, &storage_used));
-    manager->Init(&args);
-    EXPECT_EQ(storage_option, storage_used);
-    loop_.PostTask(FROM_HERE, run_loop.QuitClosure());
-    run_loop.Run();
-  }
-
-  // Create and persist an entry by unique tag in DB.
-  void PrepopulateDb(ModelType type, const std::string& client_tag) {
-    SyncBackupManager backup_manager;
-    TestChangeDelegate delegate;
-    InitManager(&backup_manager, ModelTypeSet(type), &delegate,
-                InternalComponentsFactory::STORAGE_ON_DISK_DEFERRED);
-    CreateEntry(backup_manager.GetUserShare(), type, client_tag);
-    backup_manager.ShutdownOnSyncThread(SWITCH_MODE_SYNC);
-  }
-
-  // Verify entry with |client_tag| exists in sync directory.
-  bool VerifyEntry(UserShare* user_share, ModelType type,
-                   const std::string& client_tag) {
-    ReadTransaction trans(FROM_HERE, user_share);
-    ReadNode node(&trans);
-    return BaseNode::INIT_OK == node.InitByClientTagLookup(type, client_tag);
-  }
-
- private:
-  void ConfigureSyncer() {
-    manager_->ConfigureSyncer(
-          CONFIGURE_REASON_NEW_CLIENT,
-          types_,
-          ModelTypeSet(), ModelTypeSet(), ModelTypeSet(),
-          ModelSafeRoutingInfo(),
-          base::Bind(&SyncRollbackManagerTest::OnConfigDone,
-                     base::Unretained(this), true),
-          base::Bind(&SyncRollbackManagerTest::OnConfigDone,
-                     base::Unretained(this), false));
-  }
-
-  void HandleInit(bool success) {
-    if (success) {
-      loop_.PostTask(FROM_HERE,
-                     base::Bind(&SyncRollbackManagerTest::ConfigureSyncer,
-                                base::Unretained(this)));
-    } else {
-      manager_->ShutdownOnSyncThread(STOP_SYNC);
-    }
-  }
-
-  base::ScopedTempDir temp_dir_;
-  scoped_refptr<ModelSafeWorker> worker_;
-  base::MessageLoop loop_;    // Needed for WeakHandle
-  SyncManager* manager_;
-  ModelTypeSet types_;
-};
-
-bool IsRollbackDoneAction(SyncProtocolError e) {
-  return e.action == syncer::ROLLBACK_DONE;
-}
-
-TEST_F(SyncRollbackManagerTest, RollbackBasic) {
-  PrepopulateDb(PREFERENCES, "pref1");
-
-  TestChangeDelegate delegate;
-  SyncRollbackManager rollback_manager;
-  InitManager(&rollback_manager, ModelTypeSet(PREFERENCES), &delegate,
-              InternalComponentsFactory::STORAGE_ON_DISK);
-
-  // Simulate a new entry added during type initialization.
-  int64_t new_pref_id =
-      CreateEntry(rollback_manager.GetUserShare(), PREFERENCES, "pref2");
-
-  delegate.add_expected_delete(new_pref_id);
-  EXPECT_CALL(delegate, OnChangesApplied(_, _, _, _))
-      .Times(1)
-      .WillOnce(DoDefault());
-  EXPECT_CALL(delegate, OnChangesComplete(_)).Times(1);
-  EXPECT_CALL(*this, OnActionableError(Truly(IsRollbackDoneAction))).Times(1);
-
-  ModelSafeRoutingInfo routing_info;
-  routing_info[PREFERENCES] = GROUP_UI;
-  rollback_manager.StartSyncingNormally(routing_info, base::Time());
-}
-
-TEST_F(SyncRollbackManagerTest, NoRollbackOfTypesNotBackedUp) {
-  PrepopulateDb(PREFERENCES, "pref1");
-
-  TestChangeDelegate delegate;
-  SyncRollbackManager rollback_manager;
-  InitManager(&rollback_manager, ModelTypeSet(PREFERENCES, APPS), &delegate,
-              InternalComponentsFactory::STORAGE_ON_DISK);
-
-  // Simulate new entry added during type initialization.
-  int64_t new_pref_id =
-      CreateEntry(rollback_manager.GetUserShare(), PREFERENCES, "pref2");
-  CreateEntry(rollback_manager.GetUserShare(), APPS, "app1");
-
-  delegate.add_expected_delete(new_pref_id);
-  EXPECT_CALL(delegate, OnChangesApplied(_, _, _, _))
-      .Times(1)
-      .WillOnce(DoDefault());
-  EXPECT_CALL(delegate, OnChangesComplete(_)).Times(1);
-
-  ModelSafeRoutingInfo routing_info;
-  routing_info[PREFERENCES] = GROUP_UI;
-  rollback_manager.StartSyncingNormally(routing_info, base::Time());
-
-  // APP entry is still valid.
-  EXPECT_TRUE(VerifyEntry(rollback_manager.GetUserShare(), APPS, "app1"));
-}
-
-TEST_F(SyncRollbackManagerTest, BackupDbNotChangedOnAbort) {
-  PrepopulateDb(PREFERENCES, "pref1");
-
-  TestChangeDelegate delegate;
-  scoped_ptr<SyncRollbackManager> rollback_manager(
-      new SyncRollbackManager);
-  InitManager(rollback_manager.get(), ModelTypeSet(PREFERENCES), &delegate,
-              InternalComponentsFactory::STORAGE_ON_DISK);
-
-  // Simulate a new entry added during type initialization.
-  CreateEntry(rollback_manager->GetUserShare(), PREFERENCES, "pref2");
-
-  // Manager was shut down before sync starts.
-  rollback_manager->ShutdownOnSyncThread(STOP_SYNC);
-
-  // Verify new entry was not persisted.
-  rollback_manager.reset(new SyncRollbackManager);
-  InitManager(rollback_manager.get(), ModelTypeSet(PREFERENCES), &delegate,
-              InternalComponentsFactory::STORAGE_ON_DISK);
-  EXPECT_FALSE(VerifyEntry(rollback_manager->GetUserShare(), PREFERENCES,
-                           "pref2"));
-}
-
-TEST_F(SyncRollbackManagerTest, OnInitializationFailure) {
-  // Test graceful shutdown on initialization failure.
-  scoped_ptr<SyncRollbackManager> rollback_manager(
-      new SyncRollbackManager);
-  InitManager(rollback_manager.get(), ModelTypeSet(PREFERENCES), NULL,
-              InternalComponentsFactory::STORAGE_ON_DISK);
-}
-
-}  // anonymous namespace
-
-}  // namespace syncer
diff --git a/sync/internal_api/test/fake_metadata_change_list.cc b/sync/internal_api/test/fake_metadata_change_list.cc
deleted file mode 100644
index ceba2cb..0000000
--- a/sync/internal_api/test/fake_metadata_change_list.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2016 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 <string>
-
-#include "sync/internal_api/public/test/fake_metadata_change_list.h"
-
-namespace syncer_v2 {
-
-FakeMetadataChangeList::FakeMetadataChangeList() {}
-
-FakeMetadataChangeList::~FakeMetadataChangeList() {}
-
-FakeMetadataChangeList::Record::Record() {}
-
-FakeMetadataChangeList::Record::~Record() {}
-
-void FakeMetadataChangeList::UpdateDataTypeState(
-    const sync_pb::DataTypeState& data_type_state) {
-  Record record;
-  record.action = UPDATE_DATA_TYPE_STATE;
-  record.data_type_state = data_type_state;
-  records_.push_back(record);
-}
-
-void FakeMetadataChangeList::ClearDataTypeState() {
-  Record record;
-  record.action = CLEAR_DATA_TYPE_STATE;
-  records_.push_back(record);
-}
-
-void FakeMetadataChangeList::UpdateMetadata(
-    const std::string& client_tag,
-    const sync_pb::EntityMetadata& metadata) {
-  Record record;
-  record.action = UPDATE_METADATA;
-  record.tag = client_tag;
-  record.metadata.CopyFrom(metadata);
-  records_.push_back(record);
-}
-
-void FakeMetadataChangeList::ClearMetadata(const std::string& client_tag) {
-  Record record;
-  record.action = CLEAR_METADATA;
-  record.tag = client_tag;
-  records_.push_back(record);
-}
-
-size_t FakeMetadataChangeList::GetNumRecords() const {
-  return records_.size();
-}
-
-const FakeMetadataChangeList::Record& FakeMetadataChangeList::GetNthRecord(
-    size_t n) const {
-  return records_[n];
-}
-
-}  // namespace syncer_v2
diff --git a/sync/internal_api/test/fake_model_type_service.cc b/sync/internal_api/test/fake_model_type_service.cc
index 999d501a..8f1e14c 100644
--- a/sync/internal_api/test/fake_model_type_service.cc
+++ b/sync/internal_api/test/fake_model_type_service.cc
@@ -17,7 +17,7 @@
 
 syncer::SyncError FakeModelTypeService::MergeSyncData(
     scoped_ptr<MetadataChangeList> metadata_change_list,
-    EntityDataList entity_data_list) {
+    EntityDataMap entity_data_map) {
   return syncer::SyncError();
 }
 
diff --git a/sync/internal_api/test/sync_manager_factory_for_profile_sync_test.cc b/sync/internal_api/test/sync_manager_factory_for_profile_sync_test.cc
index ff72bcd3..4c0689d0 100644
--- a/sync/internal_api/test/sync_manager_factory_for_profile_sync_test.cc
+++ b/sync/internal_api/test/sync_manager_factory_for_profile_sync_test.cc
@@ -10,7 +10,7 @@
 
 SyncManagerFactoryForProfileSyncTest::SyncManagerFactoryForProfileSyncTest(
     base::Closure init_callback)
-  : SyncManagerFactory(SyncManagerFactory::NORMAL),
+  : SyncManagerFactory(),
     init_callback_(init_callback) {
 }
 
@@ -20,9 +20,7 @@
 SyncManagerFactoryForProfileSyncTest::CreateSyncManager(
     const std::string& name) {
   return scoped_ptr<syncer::SyncManager>(
-      new SyncManagerForProfileSyncTest(
-          name,
-          init_callback_));
+      new SyncManagerForProfileSyncTest(name, init_callback_));
 }
 
 }  // namespace syncer
diff --git a/sync/internal_api/test/test_internal_components_factory.cc b/sync/internal_api/test/test_internal_components_factory.cc
index 1e26b4e..d6a72fa 100644
--- a/sync/internal_api/test/test_internal_components_factory.cc
+++ b/sync/internal_api/test/test_internal_components_factory.cc
@@ -5,7 +5,6 @@
 #include "sync/internal_api/public/test/test_internal_components_factory.h"
 
 #include "sync/sessions/sync_session_context.h"
-#include "sync/syncable/deferred_on_disk_directory_backing_store.h"
 #include "sync/syncable/in_memory_directory_backing_store.h"
 #include "sync/syncable/on_disk_directory_backing_store.h"
 #include "sync/syncable/invalid_directory_backing_store.h"
@@ -69,10 +68,6 @@
       return scoped_ptr<syncable::DirectoryBackingStore>(
           new syncable::OnDiskDirectoryBackingStore(dir_name,
                                                     backing_filepath));
-    case STORAGE_ON_DISK_DEFERRED:
-      return scoped_ptr<syncable::DirectoryBackingStore>(
-          new syncable::DeferredOnDiskDirectoryBackingStore(dir_name,
-                                                            backing_filepath));
     case STORAGE_INVALID:
       return scoped_ptr<syncable::DirectoryBackingStore>(
           new syncable::InvalidDirectoryBackingStore());
diff --git a/sync/protocol/device_info_specifics.proto b/sync/protocol/device_info_specifics.proto
index 99af88b..0103aa6 100644
--- a/sync/protocol/device_info_specifics.proto
+++ b/sync/protocol/device_info_specifics.proto
@@ -37,7 +37,8 @@
 
   // Last time when pre-sync data on the device was saved. The device can be
   // restored to state back to this time. In millisecond since UNIX epoch.
-  optional int64 backup_timestamp = 6;
+  // DEPRECATED in M50.
+  optional int64 deprecated_backup_timestamp = 6 [deprecated=true];
 
   // Device_id that is stable until user signs out. This device_id is used for
   // annotating login scoped refresh token.
diff --git a/sync/protocol/proto_enum_conversions.cc b/sync/protocol/proto_enum_conversions.cc
index 0c6cf73..84a5b03 100644
--- a/sync/protocol/proto_enum_conversions.cc
+++ b/sync/protocol/proto_enum_conversions.cc
@@ -164,7 +164,7 @@
     ENUM_CASE(sync_pb::SyncEnums, TRANSIENT_ERROR);
     ENUM_CASE(sync_pb::SyncEnums, MIGRATION_DONE);
     ENUM_CASE(sync_pb::SyncEnums, DISABLED_BY_ADMIN);
-    ENUM_CASE(sync_pb::SyncEnums, USER_ROLLBACK);
+    ENUM_CASE(sync_pb::SyncEnums, DEPRECATED_USER_ROLLBACK);
     ENUM_CASE(sync_pb::SyncEnums, PARTIAL_FAILURE);
     ENUM_CASE(sync_pb::SyncEnums, CLIENT_DATA_OBSOLETE);
     ENUM_CASE(sync_pb::SyncEnums, UNKNOWN);
diff --git a/sync/protocol/proto_value_conversions.cc b/sync/protocol/proto_value_conversions.cc
index 4fee4ee..327723c 100644
--- a/sync/protocol/proto_value_conversions.cc
+++ b/sync/protocol/proto_value_conversions.cc
@@ -80,10 +80,6 @@
   return list;
 }
 
-base::string16 TimestampToString(int64_t tm) {
-  return base::TimeFormatShortDateAndTime(syncer::ProtoTimeToTime(tm));
-}
-
 }  // namespace
 
 // Helper macros to reduce the amount of boilerplate.
@@ -412,7 +408,6 @@
   SET_ENUM(device_type, GetDeviceTypeString);
   SET_STR(sync_user_agent);
   SET_STR(chrome_version);
-  SET_TIME_STR(backup_timestamp);
   SET_STR(signin_scoped_device_id);
   return value;
 }
diff --git a/sync/protocol/sync_enums.proto b/sync/protocol/sync_enums.proto
index bdfb45e..0e1857554 100644
--- a/sync/protocol/sync_enums.proto
+++ b/sync/protocol/sync_enums.proto
@@ -96,7 +96,7 @@
                                 // a server.
     DISABLED_BY_ADMIN    = 10;  // An administrator disabled sync for this
                                 // domain.
-    USER_ROLLBACK        = 11;  // Client told to stop syncing and roll back.
+    DEPRECATED_USER_ROLLBACK        = 11;  // Deprecated in M50.
     PARTIAL_FAILURE      = 12;  // Return when client want to update several
                                 // data types, but some of them failed(e.g.
                                 // throttled).
diff --git a/sync/protocol/sync_protocol_error.cc b/sync/protocol/sync_protocol_error.cc
index 992f6ac..c82d32e 100644
--- a/sync/protocol/sync_protocol_error.cc
+++ b/sync/protocol/sync_protocol_error.cc
@@ -22,7 +22,6 @@
     ENUM_CASE(MIGRATION_DONE);
     ENUM_CASE(INVALID_CREDENTIAL);
     ENUM_CASE(DISABLED_BY_ADMIN);
-    ENUM_CASE(USER_ROLLBACK);
     ENUM_CASE(PARTIAL_FAILURE);
     ENUM_CASE(CLIENT_DATA_OBSOLETE);
     ENUM_CASE(UNKNOWN_ERROR);
@@ -39,8 +38,6 @@
     ENUM_CASE(STOP_AND_RESTART_SYNC);
     ENUM_CASE(DISABLE_SYNC_ON_CLIENT);
     ENUM_CASE(STOP_SYNC_FOR_DISABLED_ACCOUNT);
-    ENUM_CASE(DISABLE_SYNC_AND_ROLLBACK);
-    ENUM_CASE(ROLLBACK_DONE);
     ENUM_CASE(RESET_LOCAL_SYNC_DATA);
     ENUM_CASE(UNKNOWN_ACTION);
   }
diff --git a/sync/protocol/sync_protocol_error.h b/sync/protocol/sync_protocol_error.h
index 38c5f189..7ba8d6c 100644
--- a/sync/protocol/sync_protocol_error.h
+++ b/sync/protocol/sync_protocol_error.h
@@ -38,9 +38,6 @@
   // An administrator disabled sync for this domain.
   DISABLED_BY_ADMIN,
 
-  // Client told to stop syncing this device and roll back local data.
-  USER_ROLLBACK,
-
   // Some of servers are busy. Try later with busy servers.
   PARTIAL_FAILURE,
 
@@ -72,13 +69,6 @@
   // settings page that account is disabled.
   STOP_SYNC_FOR_DISABLED_ACCOUNT,
 
-  // Disable sync and roll back local model to pre-sync state.
-  DISABLE_SYNC_AND_ROLLBACK,
-
-  // Generated by SyncRollbackManager to notify ProfileSyncService that
-  // rollback is finished.
-  ROLLBACK_DONE,
-
   // Generated in response to CLIENT_DATA_OBSOLETE error. ProfileSyncService
   // should stop sync engine, delete directory and restart sync engine.
   RESET_LOCAL_SYNC_DATA,
diff --git a/sync/sessions/status_controller.cc b/sync/sessions/status_controller.cc
index 01b9781..4f9e1411 100644
--- a/sync/sessions/status_controller.cc
+++ b/sync/sessions/status_controller.cc
@@ -17,6 +17,22 @@
 
 StatusController::~StatusController() {}
 
+const ModelTypeSet StatusController::get_updates_request_types() const {
+  return model_neutral_.get_updates_request_types;
+}
+
+void StatusController::set_get_updates_request_types(ModelTypeSet value) {
+  model_neutral_.get_updates_request_types = value;
+}
+
+const ModelTypeSet StatusController::commit_request_types() const {
+  return model_neutral_.commit_request_types;
+}
+
+void StatusController::set_commit_request_types(ModelTypeSet value) {
+  model_neutral_.commit_request_types = value;
+}
+
 void StatusController::increment_num_updates_downloaded_by(int value) {
   model_neutral_.num_updates_downloaded_total += value;
 }
diff --git a/sync/sessions/status_controller.h b/sync/sessions/status_controller.h
index 9cf63d8..4551dfd 100644
--- a/sync/sessions/status_controller.h
+++ b/sync/sessions/status_controller.h
@@ -36,13 +36,11 @@
   StatusController();
   ~StatusController();
 
-  // ClientToServer messages.
-  const ModelTypeSet commit_request_types() const {
-    return model_neutral_.commit_request_types;
-  }
-  void set_commit_request_types(ModelTypeSet value) {
-    model_neutral_.commit_request_types = value;
-  }
+  // The types included in the get updates and commit client to server requests.
+  const ModelTypeSet get_updates_request_types() const;
+  void set_get_updates_request_types(ModelTypeSet value);
+  const ModelTypeSet commit_request_types() const;
+  void set_commit_request_types(ModelTypeSet value);
 
   // Various conflict counters.
   int num_encryption_conflicts() const;
diff --git a/sync/sync.gyp b/sync/sync.gyp
index 9981376c..f5303cb 100644
--- a/sync/sync.gyp
+++ b/sync/sync.gyp
@@ -350,8 +350,6 @@
         'internal_api/read_node.cc',
         'internal_api/read_transaction.cc',
         'internal_api/shared_model_type_processor.cc',
-        'internal_api/sync_backup_manager.cc',
-        'internal_api/sync_backup_manager.h',
         'internal_api/sync_context.cc',
         'internal_api/sync_context_proxy.cc',
         'internal_api/sync_context_proxy_impl.cc',
@@ -362,10 +360,6 @@
         'internal_api/sync_manager_factory.cc',
         'internal_api/sync_manager_impl.cc',
         'internal_api/sync_manager_impl.h',
-        'internal_api/sync_rollback_manager.cc',
-        'internal_api/sync_rollback_manager.h',
-        'internal_api/sync_rollback_manager_base.cc',
-        'internal_api/sync_rollback_manager_base.h',
         'internal_api/syncapi_internal.cc',
         'internal_api/syncapi_internal.h',
         'internal_api/syncapi_server_connection_manager.cc',
@@ -401,8 +395,6 @@
         'sessions/sync_session.h',
         'sessions/sync_session_context.cc',
         'sessions/sync_session_context.h',
-        'syncable/deferred_on_disk_directory_backing_store.cc',
-        'syncable/deferred_on_disk_directory_backing_store.h',
         'syncable/dir_open_result.h',
         'syncable/directory.cc',
         'syncable/directory.h',
diff --git a/sync/sync_tests.gypi b/sync/sync_tests.gypi
index 6f3231a..bacf8374 100644
--- a/sync/sync_tests.gypi
+++ b/sync/sync_tests.gypi
@@ -183,7 +183,6 @@
         'test_support_sync_core',
       ],
       'sources': [
-        'internal_api/public/test/fake_metadata_change_list.h',
         'internal_api/public/test/fake_model_type_service.h',
         'internal_api/public/test/fake_sync_manager.h',
         'internal_api/public/test/model_type_store_test_util.h',
@@ -192,7 +191,6 @@
         'internal_api/public/test/test_entry_factory.h',
         'internal_api/public/test/test_internal_components_factory.h',
         'internal_api/public/test/test_user_share.h',
-        'internal_api/test/fake_metadata_change_list.cc',
         'internal_api/test/fake_model_type_service.cc',
         'internal_api/test/fake_sync_manager.cc',
         'internal_api/test/model_type_store_test_util.cc',
@@ -323,12 +321,9 @@
         'internal_api/public/util/proto_value_ptr_unittest.cc',
         'internal_api/public/util/weak_handle_unittest.cc',
         'internal_api/shared_model_type_processor_unittest.cc',
-        'internal_api/sync_backup_manager_unittest.cc',
         'internal_api/sync_context_proxy_impl_unittest.cc',
         'internal_api/sync_encryption_handler_impl_unittest.cc',
         'internal_api/sync_manager_impl_unittest.cc',
-        'internal_api/sync_rollback_manager_base_unittest.cc',
-        'internal_api/sync_rollback_manager_unittest.cc',
         'internal_api/syncapi_server_connection_manager_unittest.cc',
         'js/js_event_details_unittest.cc',
         'js/sync_js_controller_unittest.cc',
@@ -337,7 +332,6 @@
         'sessions/model_type_registry_unittest.cc',
         'sessions/nudge_tracker_unittest.cc',
         'sessions/status_controller_unittest.cc',
-        'syncable/deferred_on_disk_directory_backing_store_unittest.cc',
         'syncable/directory_backing_store_unittest.cc',
         'syncable/directory_unittest.cc',
         'syncable/directory_unittest.h',
diff --git a/sync/syncable/deferred_on_disk_directory_backing_store.cc b/sync/syncable/deferred_on_disk_directory_backing_store.cc
deleted file mode 100644
index 5e960d2..0000000
--- a/sync/syncable/deferred_on_disk_directory_backing_store.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-// 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 "sync/syncable/deferred_on_disk_directory_backing_store.h"
-
-#include "base/logging.h"
-#include "base/metrics/histogram.h"
-#include "base/stl_util.h"
-#include "sync/syncable/syncable-inl.h"
-
-namespace syncer {
-namespace syncable {
-
-DeferredOnDiskDirectoryBackingStore::DeferredOnDiskDirectoryBackingStore(
-    const std::string& dir_name,
-    const base::FilePath& backing_file_path)
-    : OnDiskDirectoryBackingStore(dir_name, backing_file_path),
-      created_on_disk_(false) {
-}
-
-DeferredOnDiskDirectoryBackingStore::~DeferredOnDiskDirectoryBackingStore() {}
-
-bool DeferredOnDiskDirectoryBackingStore::SaveChanges(
-    const Directory::SaveChangesSnapshot& snapshot) {
-  DCHECK(CalledOnValidThread());
-
-  // Back out early if there is nothing to save.
-  if (!snapshot.HasUnsavedMetahandleChanges()) {
-    return true;
-  }
-  if (!created_on_disk_ && !CreateOnDisk())
-    return false;
-  return OnDiskDirectoryBackingStore::SaveChanges(snapshot);
-}
-
-bool DeferredOnDiskDirectoryBackingStore::CreateOnDisk() {
-  DCHECK(CalledOnValidThread());
-  DCHECK(!created_on_disk_);
-  ResetAndCreateConnection();
-  if (!base::DeleteFile(backing_file_path(), false))
-    return false;
-  if (!Open(backing_file_path()) || !InitializeTables())
-    return false;
-  created_on_disk_ = true;
-  return true;
-}
-
-DirOpenResult DeferredOnDiskDirectoryBackingStore::Load(
-    Directory::MetahandlesMap* handles_map,
-    JournalIndex* delete_journals,
-    MetahandleSet* metahandles_to_purge,
-    Directory::KernelLoadInfo* kernel_load_info) {
-  DCHECK(CalledOnValidThread());
-  // Open an in-memory database at first to create initial sync data needed by
-  // Directory.
-  CHECK(!IsOpen());
-  if (!OpenInMemory())
-    return FAILED_OPEN_DATABASE;
-
-  if (!InitializeTables())
-    return FAILED_OPEN_DATABASE;
-  if (!LoadEntries(handles_map, metahandles_to_purge))
-    return FAILED_DATABASE_CORRUPT;
-  if (!LoadInfo(kernel_load_info))
-    return FAILED_DATABASE_CORRUPT;
-
-  return OPENED;
-}
-
-}  // namespace syncable
-}  // namespace syncer
diff --git a/sync/syncable/deferred_on_disk_directory_backing_store.h b/sync/syncable/deferred_on_disk_directory_backing_store.h
deleted file mode 100644
index 0531737..0000000
--- a/sync/syncable/deferred_on_disk_directory_backing_store.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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 SYNC_SYNCABLE_DEFERRED_ON_DISK_DIRECTORY_BACKING_STORE_H_
-#define SYNC_SYNCABLE_DEFERRED_ON_DISK_DIRECTORY_BACKING_STORE_H_
-
-#include <string>
-
-#include "base/files/file_path.h"
-#include "base/macros.h"
-#include "sync/base/sync_export.h"
-#include "sync/syncable/on_disk_directory_backing_store.h"
-
-namespace syncer {
-namespace syncable {
-
-// Store used for backing up user's data before first sync. It creates an
-// in-memory store first and switch to on-disk store if SaveChanges() is
-// called, which only happens when SyncBackupManager is shut down and a
-// syncing backend is to be created. Thus we guarantee that user data is not
-// persisted until user is actually going to sync.
-class SYNC_EXPORT DeferredOnDiskDirectoryBackingStore
-    : public OnDiskDirectoryBackingStore {
- public:
-  DeferredOnDiskDirectoryBackingStore(const std::string& dir_name,
-                                      const base::FilePath& backing_file_path);
-  ~DeferredOnDiskDirectoryBackingStore() override;
-  DirOpenResult Load(Directory::MetahandlesMap* handles_map,
-                     JournalIndex* delete_journals,
-                     MetahandleSet* metahandles_to_purge,
-                     Directory::KernelLoadInfo* kernel_load_info) override;
-  bool SaveChanges(const Directory::SaveChangesSnapshot& snapshot) override;
-
- private:
-  // Create an on-disk directory backing store. Returns true on success, false
-  // on error.
-  bool CreateOnDisk();
-
-  // Whether an on-disk directory backing store has been created.
-  bool created_on_disk_;
-
-  DISALLOW_COPY_AND_ASSIGN(DeferredOnDiskDirectoryBackingStore);
-};
-
-}  // namespace syncable
-}  // namespace syncer
-
-#endif  // SYNC_SYNCABLE_DEFERRED_ON_DISK_DIRECTORY_BACKING_STORE_H_
diff --git a/sync/syncable/deferred_on_disk_directory_backing_store_unittest.cc b/sync/syncable/deferred_on_disk_directory_backing_store_unittest.cc
deleted file mode 100644
index a62060a..0000000
--- a/sync/syncable/deferred_on_disk_directory_backing_store_unittest.cc
+++ /dev/null
@@ -1,117 +0,0 @@
-// 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 "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop.h"
-#include "base/stl_util.h"
-#include "sync/syncable/deferred_on_disk_directory_backing_store.h"
-#include "sync/syncable/directory.h"
-#include "sync/syncable/entry_kernel.h"
-#include "sync/syncable/on_disk_directory_backing_store.h"
-#include "sync/syncable/syncable_delete_journal.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace syncer {
-namespace syncable {
-namespace {
-
-static const base::FilePath::CharType kSyncDataFolderName[] =
-    FILE_PATH_LITERAL("Sync Data");
-
-class DeferredOnDiskDirectoryBackingStoreTest : public testing::Test {
- protected:
-  void SetUp() override {
-    CHECK(temp_dir_.CreateUniqueTempDir());
-    db_path_ = temp_dir_.path().Append(kSyncDataFolderName);
-  }
-
-  void TearDown() override { STLDeleteValues(&handles_map_); }
-
-  base::MessageLoop message_loop_;
-  base::ScopedTempDir temp_dir_;
-  base::FilePath db_path_;
-  Directory::MetahandlesMap handles_map_;
-  JournalIndex delete_journals_;
-  MetahandleSet metahandles_to_purge_;
-  Directory::KernelLoadInfo kernel_load_info_;
-};
-
-// Test initialization of root entry when calling Load().
-TEST_F(DeferredOnDiskDirectoryBackingStoreTest, Load) {
-  DeferredOnDiskDirectoryBackingStore store("test", db_path_);
-  EXPECT_EQ(OPENED, store.Load(&handles_map_, &delete_journals_,
-                               &metahandles_to_purge_, &kernel_load_info_));
-  EXPECT_TRUE(delete_journals_.empty());
-  EXPECT_TRUE(metahandles_to_purge_.empty());
-  ASSERT_EQ(1u, handles_map_.size());   // root node
-  ASSERT_TRUE(handles_map_.count(1));
-  EntryKernel* root = handles_map_[1];
-  EXPECT_TRUE(root->ref(ID).IsRoot());
-  EXPECT_EQ(1, root->ref(META_HANDLE));
-  EXPECT_TRUE(root->ref(IS_DIR));
-}
-
-// Test on-disk DB is not created if SaveChanges() is not called.
-TEST_F(DeferredOnDiskDirectoryBackingStoreTest,
-       DontPersistIfSavingChangesNotCalled) {
-  {
-    // Open and close.
-    DeferredOnDiskDirectoryBackingStore store("test", db_path_);
-    EXPECT_EQ(OPENED, store.Load(&handles_map_, &delete_journals_,
-                                 &metahandles_to_purge_, &kernel_load_info_));
-  }
-
-  EXPECT_FALSE(base::PathExists(db_path_));
-}
-
-// Test on-disk DB is not created when there are no changes.
-TEST_F(DeferredOnDiskDirectoryBackingStoreTest,
-       DontPersistWhenSavingNoChanges) {
-  {
-    // Open and close.
-    DeferredOnDiskDirectoryBackingStore store("test", db_path_);
-    EXPECT_EQ(OPENED, store.Load(&handles_map_, &delete_journals_,
-                                 &metahandles_to_purge_, &kernel_load_info_));
-
-    Directory::SaveChangesSnapshot snapshot;
-    store.SaveChanges(snapshot);
-  }
-
-  EXPECT_FALSE(base::PathExists(db_path_));
-}
-
-// Test changes are persisted to disk when SaveChanges() is called.
-TEST_F(DeferredOnDiskDirectoryBackingStoreTest, PersistWhenSavingValidChanges) {
-  {
-    // Open and close.
-    DeferredOnDiskDirectoryBackingStore store("test", db_path_);
-    EXPECT_EQ(OPENED, store.Load(&handles_map_, &delete_journals_,
-                                 &metahandles_to_purge_, &kernel_load_info_));
-
-    Directory::SaveChangesSnapshot snapshot;
-    EntryKernel* entry = new EntryKernel();
-    entry->put(ID, Id::CreateFromClientString("test_entry"));
-    entry->put(META_HANDLE, 2);
-    entry->mark_dirty(NULL);
-    snapshot.dirty_metas.insert(entry);
-    store.SaveChanges(snapshot);
-  }
-
-  STLDeleteValues(&handles_map_);
-
-  ASSERT_TRUE(base::PathExists(db_path_));
-  OnDiskDirectoryBackingStore read_store("test", db_path_);
-  EXPECT_EQ(OPENED,
-            read_store.Load(&handles_map_, &delete_journals_,
-                            &metahandles_to_purge_, &kernel_load_info_));
-  ASSERT_EQ(2u, handles_map_.size());
-  ASSERT_TRUE(handles_map_.count(1));     // root node
-  ASSERT_TRUE(handles_map_.count(2));
-  EntryKernel* entry = handles_map_[2];
-  EXPECT_EQ(Id::CreateFromClientString("test_entry"), entry->ref(ID));
-}
-
-}  // namespace
-}  // namespace syncable
-}  // namespace syncer
diff --git a/sync/tools/sync_client.cc b/sync/tools/sync_client.cc
index deba666c..36c7561a 100644
--- a/sync/tools/sync_client.cc
+++ b/sync/tools/sync_client.cc
@@ -396,7 +396,7 @@
   workers.push_back(passive_model_safe_worker);
 
   // Set up sync manager.
-  SyncManagerFactory sync_manager_factory(SyncManagerFactory::NORMAL);
+  SyncManagerFactory sync_manager_factory;
   scoped_ptr<SyncManager> sync_manager =
       sync_manager_factory.CreateSyncManager("sync_client manager");
   LoggingJsEventHandler js_event_handler;
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index 5f3718a..10e2356 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -1252,6 +1252,19 @@
         "test": "angle_deqp_gles2_tests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:104a",
+              "os": "Linux"
+            }
+          ],
+          "shards": 12
+        },
+        "test": "angle_deqp_gles3_tests"
+      },
+      {
         "args": [
           "--use-gpu-in-tests"
         ],
@@ -1667,23 +1680,6 @@
       }
     ]
   },
-  "Linux Release dEQP (NVIDIA)": {
-    "gtest_tests": [
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "10de:104a",
-              "os": "Linux"
-            }
-          ],
-          "shards": 12
-        },
-        "test": "angle_deqp_gles3_tests"
-      }
-    ]
-  },
   "Mac 10.10 Debug (ATI)": {
     "gtest_tests": [
       {
@@ -6595,6 +6591,19 @@
         "test": "angle_deqp_gles2_tests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:104a",
+              "os": "Windows-2008ServerR2-SP1"
+            }
+          ],
+          "shards": 12
+        },
+        "test": "angle_deqp_gles3_tests"
+      },
+      {
         "args": [
           "--use-gpu-in-tests"
         ],
@@ -7068,23 +7077,6 @@
       }
     ]
   },
-  "Win7 Release dEQP (NVIDIA)": {
-    "gtest_tests": [
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "10de:104a",
-              "os": "Windows-2008ServerR2-SP1"
-            }
-          ],
-          "shards": 12
-        },
-        "test": "angle_deqp_gles3_tests"
-      }
-    ]
-  },
   "Win7 x64 Debug (NVIDIA)": {
     "gtest_tests": [
       {
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index 9bfcdb29..a2a33a0 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -430,13 +430,368 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "accessibility_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "app_list_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "app_shell_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "ash_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "aura_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "base_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "battor_agent_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "cacheinvalidation_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "cast_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "cc_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "chrome_app_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "chrome_elf_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "chromedriver_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "components_browsertests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "components_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "compositor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "content_browsertests"
       },
       {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "content_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "courgette_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "crypto_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "device_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "events_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "extensions_browsertests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "extensions_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "gcm_unit_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "gfx_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "gn_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "google_apis_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "gpu_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "installer_util_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 2
+        },
+        "test": "interactive_ui_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "ipc_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "jingle_unittests"
+      },
+      {
+        "test": "keyboard_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "media_blink_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "media_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "midi_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "mojo_common_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "mojo_public_bindings_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "mojo_public_environment_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "mojo_public_system_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "mojo_public_utility_unittests"
+      },
+      {
+        "test": "mojo_system_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "nacl_loader_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "net_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "ppapi_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "printing_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "remoting_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "sbox_integration_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "sbox_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "sbox_validation_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "setup_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "skia_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "sql_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "sync_integration_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "sync_unit_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "ui_base_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "ui_touch_selection_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "unit_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "url_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "views_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "wm_unittests"
       }
     ]
   },
diff --git a/testing/buildbot/filters/browser-side-navigation.linux.content_browsertests.filter b/testing/buildbot/filters/browser-side-navigation.linux.content_browsertests.filter
index 03035cb..9ab32c4 100644
--- a/testing/buildbot/filters/browser-side-navigation.linux.content_browsertests.filter
+++ b/testing/buildbot/filters/browser-side-navigation.linux.content_browsertests.filter
@@ -4,11 +4,8 @@
 -CrossSiteTransferTest.NoLeakOnCrossSiteCancel
 -DevToolsProtocolTest.CrossSitePauseInBeforeUnload
 -LoFiResourceDispatcherHostBrowserTest.ShouldEnableLoFiModeNavigateBackThenForward
--NavigationControllerBrowserTest.CorrectLengthWithCurrentItemReplacement
 -NavigationControllerBrowserTest.FrameNavigationEntry_SubframeHistoryFallback
--NavigationControllerBrowserTest.PreventSpoofFromSubframeAndReplace
 -NavigationControllerBrowserTest.StopCausesFailureDespiteJavaScriptURL
--NavigationControllerBrowserTest.SubframeBackFromReplaceState
 -RenderFrameHostManagerTest.RestoreSubframeFileAccessForHistoryNavigation
 -RenderViewImplTest.BrowserNavigationStartNotUsedForHistoryNavigation
 -RenderViewImplTest.GetCompositionCharacterBoundsTest
diff --git a/testing/buildbot/filters/isolate-extensions.browser_tests.filter b/testing/buildbot/filters/isolate-extensions.browser_tests.filter
index a81bc837..d17f1d7 100644
--- a/testing/buildbot/filters/isolate-extensions.browser_tests.filter
+++ b/testing/buildbot/filters/isolate-extensions.browser_tests.filter
@@ -1 +1,4 @@
 # List below tests to be excluded from running.
+
+# crbug.com/589177: ProcessManagerBrowserTest.FrameClassification is flaky with --site-per-process
+-ProcessManagerBrowserTest.FrameClassification
diff --git a/testing/buildbot/filters/site-per-process.browser_tests.filter b/testing/buildbot/filters/site-per-process.browser_tests.filter
index 943ff33d..86dac224 100644
--- a/testing/buildbot/filters/site-per-process.browser_tests.filter
+++ b/testing/buildbot/filters/site-per-process.browser_tests.filter
@@ -25,3 +25,6 @@
 -ExtensionApiTest.TabsOnUpdated
 -ExtensionURLRewriteBrowserTest.NewTabPageURL
 -IsolatedAppTest.*
+
+# crbug.com/589177: ProcessManagerBrowserTest.FrameClassification is flaky with --site-per-process
+-ProcessManagerBrowserTest.FrameClassification
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index e0515aba..48d3218 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -386,7 +386,7 @@
   },
   "message_center_unittests": {
     "label": "//ui/message_center:message_center_unittests",
-    "type": "unknown",
+    "type": "console_test_launcher",
   },
   "mash_unittests": {
     "label": "//mash:mash_unittests",
diff --git a/testing/legion/tools/legion.py b/testing/legion/tools/legion.py
index 7170f2c..85073a9 100755
--- a/testing/legion/tools/legion.py
+++ b/testing/legion/tools/legion.py
@@ -52,7 +52,7 @@
   pass
 
 
-def GetArgs():
+def GetArgs(cmd_args):
   parser = argparse.ArgumentParser(description=__doc__)
   parser.add_argument('action', choices=['run', 'trigger'],
                       help='The swarming action to perform.')
@@ -82,7 +82,7 @@
                       'are in the form of --controller-var name value and are '
                       'passed to the controller as --name value.')
   parser.add_argument('-v', '--verbosity', default=0, action='count')
-  return parser.parse_args()
+  return parser.parse_args(cmd_args)
 
 
 def RunCommand(cmd, stream_stdout=False):
@@ -116,7 +116,7 @@
   return RunCommand(cmd).split()[0] # The isolated hash
 
 
-def GetSwarmingCommandLine(args):
+def GetSwarmingCommandLine(args, extra_args):
   """Builds and returns the command line for swarming.py run|trigger."""
   cmd = [
       sys.executable,
@@ -133,14 +133,17 @@
     cmd.extend(['--dimension', name, value])
 
   cmd.append('--')
-
+  cmd.extend(extra_args)
   cmd.extend(['--swarming-server', args.swarming_server])
   cmd.extend(['--isolate-server', args.isolate_server])
   # Specify the output dir
   cmd.extend(['--output-dir', '${ISOLATED_OUTDIR}'])
   # Task name/hash values
   for name, isolated in args.tasks:
-    cmd.extend(['--' + name, Archive(isolated, args.isolate_server)])
+    if args.format_only:
+      cmd.extend(['--' + name, isolated + '_test_only'])
+    else:
+      cmd.extend(['--' + name, Archive(isolated, args.isolate_server)])
   # Test controller args
   for name, value in args.controller_vars:
     cmd.extend(['--' + name, value])
@@ -149,7 +152,14 @@
 
 
 def main():
-  args = GetArgs()
+  if '--' not in sys.argv:
+    cmd_args = sys.argv[1:]
+    extra_args = []
+  else:
+    index = sys.argv.index('--')
+    cmd_args = sys.argv[1:index]
+    extra_args = sys.argv[index+1:]
+  args = GetArgs(cmd_args)
   if not args.swarming_server:
     raise ArgumentError('Missing required argument: --swarming-server')
   if not args.isolate_server:
@@ -158,7 +168,7 @@
       format='%(asctime)s %(filename)s:%(lineno)s %(levelname)s] %(message)s',
       datefmt='%H:%M:%S',
       level=LOGGING_LEVELS[len(LOGGING_LEVELS)-args.verbosity-1])
-  cmd = GetSwarmingCommandLine(args)
+  cmd = GetSwarmingCommandLine(args, extra_args)
   if not args.format_only:
     RunCommand(cmd, True)
   return 0
diff --git a/testing/variations/fieldtrial_testing_config_android.json b/testing/variations/fieldtrial_testing_config_android.json
index 5fc4381..1e6f1a5 100644
--- a/testing/variations/fieldtrial_testing_config_android.json
+++ b/testing/variations/fieldtrial_testing_config_android.json
@@ -242,6 +242,11 @@
             "group_name": "DoNotShow"
         }
     ],
+    "RenderingPipelineThrottling": [
+        {
+            "group_name": "Enabled"
+        }
+    ],
     "ReportCertificateErrors": [
         {
             "group_name": "ShowAndPossiblySend",
diff --git a/testing/variations/fieldtrial_testing_config_chromeos.json b/testing/variations/fieldtrial_testing_config_chromeos.json
index ec142ee9..8f8a29a 100644
--- a/testing/variations/fieldtrial_testing_config_chromeos.json
+++ b/testing/variations/fieldtrial_testing_config_chromeos.json
@@ -89,6 +89,11 @@
             }
         }
     ],
+    "RenderingPipelineThrottling": [
+        {
+            "group_name": "Enabled"
+        }
+    ],
     "ReportCertificateErrors": [
         {
             "group_name": "ShowAndPossiblySend",
diff --git a/testing/variations/fieldtrial_testing_config_linux.json b/testing/variations/fieldtrial_testing_config_linux.json
index 4fd387e..7d03bf12 100644
--- a/testing/variations/fieldtrial_testing_config_linux.json
+++ b/testing/variations/fieldtrial_testing_config_linux.json
@@ -109,6 +109,11 @@
             "group_name": "Enabled"
         }
     ],
+    "RenderingPipelineThrottling": [
+        {
+            "group_name": "Enabled"
+        }
+    ],
     "ReportCertificateErrors": [
         {
             "group_name": "ShowAndPossiblySend",
diff --git a/testing/variations/fieldtrial_testing_config_mac.json b/testing/variations/fieldtrial_testing_config_mac.json
index d94267c..004c5a8 100644
--- a/testing/variations/fieldtrial_testing_config_mac.json
+++ b/testing/variations/fieldtrial_testing_config_mac.json
@@ -125,6 +125,11 @@
             "group_name": "Enabled"
         }
     ],
+    "RenderingPipelineThrottling": [
+        {
+            "group_name": "Enabled"
+        }
+    ],
     "ReportCertificateErrors": [
         {
             "group_name": "ShowAndPossiblySend",
diff --git a/testing/variations/fieldtrial_testing_config_win.json b/testing/variations/fieldtrial_testing_config_win.json
index beb2a69..19910bc00 100644
--- a/testing/variations/fieldtrial_testing_config_win.json
+++ b/testing/variations/fieldtrial_testing_config_win.json
@@ -184,6 +184,11 @@
             "group_name": "Enabled"
         }
     ],
+    "RenderingPipelineThrottling": [
+        {
+            "group_name": "Enabled"
+        }
+    ],
     "ReportCertificateErrors": [
         {
             "group_name": "ShowAndPossiblySend",
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
index 83d2fd8..3a4582c 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
@@ -1,12 +1,6 @@
 # These tests currently fail when they run with --site-per-process.
 # See https://crbug.com/477150.
 
-# https://crbug.com/587909 - Regression caused by recent render pipeline throttling changes.
-http/tests/misc/dns-prefetch-control.html [ Timeout ]
-http/tests/navigatorconnect/connect-cross-origin.html [ Timeout ]
-http/tests/security/document-origin.html [ Timeout ]
-http/tests/serviceworker/navigation-redirect.html [ Timeout ]
-
 # https://crbug.com/584984 - Recent, uninvestigated yet regression.
 http/tests/security/opened-document-security-origin-resets-on-navigation.html [ Crash ]
 
@@ -62,13 +56,13 @@
 http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-setAttribute.html [ Failure ]
 http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-setAttributeNode.html [ Failure ]
 http/tests/security/javascriptURL/javascriptURL-execution-context-iframe-src-setAttributeNS.html [ Failure ]
-http/tests/security/xss-DENIED-iframe-src-alias.html [ Crash Failure Timeout ]
+http/tests/security/xss-DENIED-iframe-src-alias.html [ Crash Failure ]
 http/tests/security/xss-DENIED-javascript-with-spaces.html [ Failure ]
 
 # https://crbug.com/582245 - no exception, b/c BindingSecurity::shouldAllowAccessTo exits early when |!target|.
 http/tests/security/xss-DENIED-getSVGDocument-iframe.html [ Failure ]
 http/tests/security/xss-DENIED-getSVGDocument-object.html [ Failure ]
-http/tests/security/xssAuditor/block-does-not-leak-location.html [ Failure Timeout ]
+http/tests/security/xssAuditor/block-does-not-leak-location.html [ Failure ]
 http/tests/security/xssAuditor/block-does-not-leak-referrer.html [ Failure ]
 http/tests/security/xssAuditor/full-block-script-tag-cross-domain.html [ Failure ]
 
@@ -81,7 +75,7 @@
 
 # https://crbug.com/582551 - testRunner.overridePreference doesn't impact all renderers.
 http/tests/security/powerfulFeatureRestrictions/geolocation-on-sandboxed-insecure-origin.html [ Failure ]
-http/tests/security/powerfulFeatureRestrictions/geolocation-on-secure-origin-in-insecure-origin.html [ Failure Timeout ]
+http/tests/security/powerfulFeatureRestrictions/geolocation-on-secure-origin-in-insecure-origin.html [ Failure ]
 
 # https://crbug.com/584845 - bad message - RFH_NO_PROXY_TO_PARENT from OnDispatchLoad.
 http/tests/security/contentSecurityPolicy/1.1/frame-ancestors/frame-ancestors-nested-cross-in-same-none-block.html [ Timeout ]
@@ -127,7 +121,6 @@
 http/tests/security/mixedContent/insecure-eventsource-in-main-frame.html [ Failure ]
 
 # Uninvestigated failures under http/tests/security:
-http/tests/security/contentTypeOptions/nosniff-script-without-content-type-blocked.html [ Failure ]
 http/tests/security/cookies/third-party-cookie-blocking.html [ Timeout ]
 http/tests/security/cookies/third-party-cookie-blocking-user-action.html [ Timeout ]
 http/tests/security/cookies/third-party-cookie-blocking-xslt.xml [ Timeout ]
@@ -148,15 +141,13 @@
 http/tests/security/frameNavigation/not-opener.html [ Timeout ]
 http/tests/security/frameNavigation/xss-DENIED-targeted-link-navigation.html [ Timeout ]
 http/tests/security/host-compare-case-insensitive.html [ Timeout ]
-http/tests/security/isolatedWorld/media-query-wrapper-leaks.html [ Pass Failure ]
 http/tests/security/javascriptURL/xss-DENIED-from-javascript-url-in-foreign-domain-subframe.html [ Timeout ]
-http/tests/security/javascriptURL/xss-DENIED-from-javascript-url-in-foreign-domain-window-open.html [ Pass Crash ]
-http/tests/security/local-image-from-remote-whitelisted.html [ Failure ]
+http/tests/security/javascriptURL/xss-DENIED-from-javascript-url-in-foreign-domain-window-open.html [ Crash ]
 http/tests/security/mixedContent/insecure-css-image-with-reload.html [ Timeout ]
 http/tests/security/mixedContent/insecure-xhr-in-main-frame.html [ Timeout ]
-http/tests/security/mixedContent/strict-mode-image-blocked.https.html [ Pass Timeout ]
+http/tests/security/mixedContent/strict-mode-image-blocked.https.html [ Timeout ]
 http/tests/security/referrer-policy-redirect-link.html [ Timeout ]
-http/tests/security/upgrade-insecure-requests/basic-upgrade.https.html [ Pass Timeout ]
+http/tests/security/upgrade-insecure-requests/basic-upgrade.https.html [ Timeout ]
 http/tests/security/window-events-clear-domain.html [ Timeout ]
 http/tests/security/window-properties-clear-domain.html [ Timeout ]
 http/tests/security/xssAuditor/anchor-url-dom-write-location-javascript-URL.html [ Timeout ]
@@ -193,7 +184,6 @@
 http/tests/security/xssAuditor/xss-filter-bypass-big5.html [ Timeout ]
 http/tests/security/xssAuditor/xss-filter-bypass-long-string.html [ Timeout ]
 http/tests/security/xssAuditor/xss-filter-bypass-sjis.html [ Timeout ]
-http/tests/security/xss-DENIED-xml-external-entity.xhtml [ Failure ]
 
 # Uninvestigated failures under http/tests (but outside of http/tests/security):
 http/tests/appcache/remove-cache.html [ Failure ]
@@ -232,7 +222,7 @@
 http/tests/misc/selectionAsMarkup.html [ Missing ]
 http/tests/navigation/pushstate-whitelisted-at-blob-denied.html [ Missing ]
 http/tests/security/cookies/third-party-cookie-blocking-main-frame.html [ Missing ]
-http/tests/security/frameNavigation/xss-ALLOWED-parent-navigation-change.html [ Missing Timeout ]
+http/tests/security/frameNavigation/xss-ALLOWED-parent-navigation-change.html [ Missing ]
 http/tests/security/originHeader/origin-header-for-https.html [ Missing ]
 http/tests/security/powerfulFeatureRestrictions/durable-storage-on-insecure-origin.html [ Missing ]
 http/tests/security/referrer-on-client-redirect.html [ Missing ]
diff --git a/third_party/WebKit/LayoutTests/LeakExpectations b/third_party/WebKit/LayoutTests/LeakExpectations
index 76be4cb..27144f9 100644
--- a/third_party/WebKit/LayoutTests/LeakExpectations
+++ b/third_party/WebKit/LayoutTests/LeakExpectations
@@ -153,9 +153,3 @@
 crbug.com/578297 [ Linux ] media/video-autoplay-experiment-modes.html [ Slow ]
 crbug.com/578297 [ Linux ] virtual/threaded/printing/webgl-oversized-printing.html [ Slow ]
 crbug.com/578297 [ Linux ] http/tests/media/media-source/mediasource-appendstream-quota-exceeded.html [ Slow ]
-
-# -----------------------------------------------------------------
-# Temmporary leaks that must be fixed in a reasonable timeline.
-# -----------------------------------------------------------------
-crbug.com/582376 cssom/cssvalue-comparison.html [ Leak ]
-crbug.com/582376 fast/css/getComputedStyle/computed-style-with-zoom.html [ Leak ]
diff --git a/third_party/WebKit/LayoutTests/NeverFixTests b/third_party/WebKit/LayoutTests/NeverFixTests
index 42b7b516..dba1aaa 100644
--- a/third_party/WebKit/LayoutTests/NeverFixTests
+++ b/third_party/WebKit/LayoutTests/NeverFixTests
@@ -41,9 +41,6 @@
 # These tests are only valid on platforms with overlay scrollbars support.
 [ SnowLeopard ] inspector-protocol/emulation [ WontFix ]
 
-# <progress> on Mac is always animated. So it's hard to get a reliable pixel result.
-[ Mac ] fast/dom/HTMLProgressElement/progress-element.html [ WontFix ]
-
 # Mac's popup behavior is different.
 [ Mac ] fast/forms/select/menulist-onchange-fired-with-key-up-down.html [ WontFix ]
 [ Mac ] fast/forms/select/popup-with-display-none-optgroup.html [ WontFix ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 02de3cc..0129779 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -498,6 +498,9 @@
 crbug.com/552532 [ Win10 ] plugins/plugin-initiate-popup-window.html [ Pass Crash ]
 crbug.com/552532 [ Win10 ] plugins/tabindex.html [ Pass Crash ]
 
+# Skia roll
+crbug.com/589617 virtual/gpu/fast/canvas/canvas-imageSmoothingQuality-pixel.html [ NeedsRebaseline ]
+
 crbug.com/505364 imported/web-platform-tests/shadow-dom/untriaged/shadow-trees/lower-boundary-encapsulation/test-004.html [ Failure ]
 crbug.com/505364 imported/web-platform-tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/dom-tree-accessors-001.html [ Failure ]
 crbug.com/505364 imported/web-platform-tests/shadow-dom/untriaged/shadow-trees/upper-boundary-encapsulation/dom-tree-accessors-002.html [ Failure ]
@@ -919,6 +922,8 @@
 crbug.com/364614 [ Mac ] virtual/scroll_customization/fast/scroll-behavior/overflow-scroll-root-frame-animates.html [ Skip ]
 
 crbug.com/574283 [ Mac ] virtual/threaded/fast/scroll-behavior/smooth-scroll/fixed-background-in-iframe.html [ Skip ]
+crbug.com/574283 [ Mac ] virtual/threaded/fast/scroll-behavior/smooth-scroll/main-thread-scrolling-reason-added.html [ Skip ]
+crbug.com/574283 [ Mac ] virtual/threaded/fast/scroll-behavior/smooth-scroll/main-thread-scrolling-reason-correctness.html [ Skip ]
 
 crbug.com/552556 [ Win Linux ] virtual/threaded/fast/scroll-behavior/overflow-scroll-root-frame-animates.html [ Pass Timeout ]
 crbug.com/552556 [ Win Linux ] virtual/threaded/fast/scroll-behavior/overflow-scroll-animates.html [ Pass Timeout ]
@@ -1097,6 +1102,8 @@
 crbug.com/445194 [ Debug ] fast/dom/shadow/focus-controller-recursion-crash.html [ Skip ]
 crbug.com/505387 [ Win ] virtual/prefer_compositing_to_lcd_text/scrollbars/rtl/overflow-scroll-rtl.html [ Failure ]
 
+crbug.com/584170 fast/repaint/invalidation-after-opacity-change-subtree.html [ NeedsRebaseline ]
+
 # Mac10.10-specific failures that still need triaging.
 # Form controls need rebaseline because of the default font change.
 # If you see wider INPUT elements or narrower TEXTAREA elements, you may do just
@@ -1153,6 +1160,15 @@
 
 crbug.com/521730 [ Win10 ] plugins/windowless_plugin_paint_test.html [ Crash ]
 
+crbug.com/569928 [ Win ] fast/forms/month/month-appearance-l10n.html [ NeedsRebaseline ]
+crbug.com/569928 [ Win ] fast/text/international/khmer-selection.html [ NeedsRebaseline ]
+crbug.com/569928 [ Win ] fast/forms/datetimelocal/datetimelocal-appearance-l10n.html [ NeedsRebaseline ]
+crbug.com/569928 [ Win ] fast/text/international/lang-glyph-cache-separation.html [ NeedsRebaseline ]
+crbug.com/569928 [ Win ] fast/text/emphasis-complex.html [ NeedsRebaseline ]
+crbug.com/569928 [ Win ] inspector-protocol/layout-fonts/cjk-ideograph-fallback-by-lang.html [ NeedsRebaseline ]
+crbug.com/569928 [ Win ] inspector-protocol/layout-fonts/languages-emoji-rare-glyphs.html [ NeedsRebaseline ]
+crbug.com/569928 fast/text/font-fallback.html [ NeedsRebaseline ]
+
 crbug.com/521730 [ Win10 ] fast/forms/month-multiple-fields/month-multiple-fields-preserve-value-after-history-back.html [ Failure ]
 crbug.com/521730 [ Win10 ] fast/forms/month-multiple-fields/month-multiple-fields-value-set-empty.html [ Failure ]
 crbug.com/521730 [ Win10 ] fast/forms/suggested-value.html [ Failure ]
@@ -1160,7 +1176,6 @@
 crbug.com/521730 [ Win10 ] fast/forms/time-multiple-fields/time-multiple-fields-localization.html [ Failure ]
 crbug.com/521730 [ Win10 ] fast/text/international/vertical-text-metrics-test.html [ Failure ]
 crbug.com/521730 [ Win10 ] svg/custom/svg-fonts-in-text-controls.html [ Failure ]
-crbug.com/521730 [ Win10 ] fast/forms/datetimelocal/datetimelocal-appearance-l10n.html [ Failure ]
 crbug.com/521730 [ Win10 ] fast/forms/month/month-appearance-basic.html [ Failure ]
 crbug.com/521730 [ Win10 ] fast/text-autosizing/hackernews-comments.html [ Failure ]
 crbug.com/521730 [ Win10 ] fast/text-autosizing/list-item-above-dbcat.html [ Failure ]
@@ -1217,7 +1232,6 @@
 crbug.com/521730 [ Win10 ] fast/dynamic/text-combine.html [ Failure ]
 crbug.com/521730 [ Win10 ] fast/ruby/base-shorter-than-text.html [ Failure ]
 crbug.com/521730 [ Win10 ] fast/text/emphasis-combined-text.html [ Failure ]
-crbug.com/521730 [ Win10 ] fast/text/emphasis-complex.html [ Failure ]
 crbug.com/521730 [ Win10 ] fast/text/font-weight-variant.html [ Failure ]
 crbug.com/521730 [ Win10 ] fast/text/international/003.html [ Failure ]
 crbug.com/521730 [ Win10 ] fast/text/international/bold-bengali.html [ Failure ]
@@ -1229,7 +1243,6 @@
 crbug.com/521730 [ Win10 ] fast/writing-mode/japanese-ruby-vertical-lr.html [ Failure ]
 crbug.com/521730 [ Win10 ] media/track/track-cue-rendering-vertical.html [ Failure ]
 crbug.com/521730 [ Win10 ] fast/css/line-height-determined-by-primary-font.html [ Failure ]
-crbug.com/521730 [ Win10 ] fast/forms/month/month-appearance-l10n.html [ Failure ]
 crbug.com/521730 [ Win10 ] fast/forms/month/month-appearance-pseudo-elements.html [ Failure ]
 crbug.com/521730 [ Win10 ] fast/inline/justify-emphasis-inline-box.html [ Failure ]
 crbug.com/521730 [ Win10 ] fast/ruby/nested-ruby.html [ Failure ]
@@ -1252,8 +1265,6 @@
 crbug.com/521730 [ Win10 ] fast/text/international/bidi-linebreak-002.html [ Failure ]
 crbug.com/521730 [ Win10 ] fast/text/international/danda-space.html [ Failure ]
 crbug.com/521730 [ Win10 ] fast/text/international/hebrew-vowels.html [ Failure ]
-crbug.com/521730 [ Win10 ] fast/text/international/khmer-selection.html [ Failure ]
-crbug.com/521730 [ Win10 ] fast/text/international/lang-glyph-cache-separation.html [ Failure ]
 crbug.com/521730 [ Win10 ] fast/text/international/rtl-white-space-pre-wrap.html [ Failure ]
 crbug.com/521730 [ Win10 ] fast/text/international/text-spliced-font.html [ Failure ]
 crbug.com/521730 [ Win10 ] fast/text/international/wrap-CJK-001.html [ Failure ]
@@ -1286,7 +1297,6 @@
 crbug.com/571233 compositing/background-color/background-color-outside-document.html [ Skip ]
 
 crbug.com/474759 fast/writing-mode/vertical-rl-replaced-selection.html [ Failure ]
-crbug.com/474759 fast/block/line-layout/selection-highlight-overlap.html [ Failure ]
 
 crbug.com/353746 virtual/android/fullscreen/video-specified-size.html [ Failure Pass ]
 
@@ -1401,6 +1411,8 @@
 
 crbug.com/585724 fast/js/JSON-parse.html [ NeedsManualRebaseline ]
 
+crbug.com/570756 [ Mac ] fast/dom/HTMLProgressElement/progress-element.html [ NeedsRebaseline ]
+
 crbug.com/587136 [ Linux Debug ] http/tests/security/xss-DENIED-cross-origin-stack-overflow.html [ Timeout Pass ]
 
 crbug.com/587593 [ Android ] fast/js/pic/cached-single-entry-transition.html [ Pass Failure ]
@@ -1409,8 +1421,6 @@
 
 crbug.com/587950 [ Mac Win ] virtual/threaded/animations/background-shorthand-crash.html [ Failure ]
 
-crbug.com/588056 [ Linux Debug ] webaudio/periodicwave-normalization.html [ Timeout Pass ]
-
 crbug.com/588061 [ Debug ] inspector/sources/debugger-breakpoints/debugger-reload-breakpoints-with-source-maps.html [ Pass Failure ]
 
 crbug.com/248063 [ Win ] plugins/plugin-clip-subframe.html [ Pass Failure ]
diff --git a/third_party/WebKit/LayoutTests/animations/multiple-same-name-css-animations.html b/third_party/WebKit/LayoutTests/animations/multiple-same-name-css-animations.html
index fe1c3f2..3474d84 100644
--- a/third_party/WebKit/LayoutTests/animations/multiple-same-name-css-animations.html
+++ b/third_party/WebKit/LayoutTests/animations/multiple-same-name-css-animations.html
@@ -110,7 +110,7 @@
   assert_equals(animations[1].currentTime, 2000);
   assert_equals(animations[1].effect.timing.duration, 3500);
 
-  assert_equals(animations[2].currentTime, null);
+  assert_equals(animations[2].currentTime, 0);
   assert_equals(animations[2].effect.timing.duration, 2500);
 }, 'Removing same animation names should cancel animations from the end of the name list.');
 
@@ -133,7 +133,7 @@
   assert_equals(animations[1].currentTime, 2000);
   assert_equals(animations[1].effect.timing.duration, 2500);
 
-  assert_equals(animations[2].currentTime, null);
+  assert_equals(animations[2].currentTime, 0);
   assert_equals(animations[2].effect.timing.duration, 1500);
 }, 'Adding same animation names should start additional animations from the end of the name list.');
 </script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/getCharacteristic-blacklist.html b/third_party/WebKit/LayoutTests/bluetooth/getCharacteristic-blacklist.html
new file mode 100644
index 0000000..c950fe5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/bluetooth/getCharacteristic-blacklist.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="resources/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+
+test(t => { assert_true(window.testRunner instanceof Object); t.done(); },
+     'window.testRunner is required for the following tests.');
+
+promise_test(() => {
+  testRunner.setBluetoothMockDataSet('HeartRateAndHIDAdapter');
+  return requestDeviceWithKeyDown(
+    {
+      filters: [{services: ['device_information']}]
+    })
+    .then(device => device.gatt.connect())
+    .then(gattServer => gattServer.getPrimaryService('device_information'))
+    .then(service => {
+      return assert_promise_rejects_with_message(
+        service.getCharacteristic('serial_number_string'),
+        new DOMException('getCharacteristic(s) called with blacklisted UUID. ' +
+                         'https://goo.gl/4NeimX',
+                         'SecurityError'),
+        'Serial Number String characteristic is blacklisted.');
+    });
+}, 'Serial Number String characteristic is blacklisted.');
+</script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice-matches-a-filter.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice-matches-a-filter.html
index ad4ae7a..4a07dc15 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice-matches-a-filter.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice-matches-a-filter.html
@@ -120,16 +120,19 @@
 }, {
   filters: [{
     name: matching_name,
-  }]
+  }],
+  optionalServices: matching_services
 }, {
   filters: [{
     name: matching_name,
     namePrefix: matching_namePrefix
-  }]
+  }],
+  optionalServices: matching_services
 }, {
   filters: [{
     namePrefix: matching_namePrefix
-  }]
+  }],
+  optionalServices: matching_services
 }, {
   filters: [{
     services: matching_services,
@@ -140,6 +143,8 @@
   promise_test(() => {
     testRunner.setBluetoothMockDataSet('GlucoseHeartRateAdapter');
     return requestDeviceWithKeyDown(args).then(device => {
+      // We always have access to the services in matching_services
+      // because we include them in a filter or in optionalServices.
       assert_in_array(matching_services[0], device.uuids);
       assert_equals(device.name, matching_name);
       assert_true(device.name.startsWith(matching_namePrefix));
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice.html
index c65b3fd3..243d422b 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice.html
@@ -177,6 +177,18 @@
 
 promise_test(() => {
   testRunner.setBluetoothMockDataSet('GlucoseHeartRateAdapter');
+  return requestDeviceWithKeyDown({filters: [{services: ['glucose']}],
+                                   optionalServices: ['tx_power']})
+    .then(device => {
+      assert_equals(device.uuids.length, 2);
+      assert_in_array(BluetoothUUID.getService('glucose'), device.uuids);
+      assert_in_array(BluetoothUUID.getService('tx_power'), device.uuids);
+    });
+}, 'We should only see UUID\'s that we\'ve been given permission for.')
+
+
+promise_test(() => {
+  testRunner.setBluetoothMockDataSet('GlucoseHeartRateAdapter');
   // Both devices support the Generic Access service, but things need to
   // support both services to pass the filter, and neither has a Battery
   // service.
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/dont-squash-into-animated-layers.html b/third_party/WebKit/LayoutTests/compositing/squashing/dont-squash-into-animated-layers.html
index 7b2c5d5..006e4ed63 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/dont-squash-into-animated-layers.html
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/dont-squash-into-animated-layers.html
@@ -1,21 +1,31 @@
 <!doctype HTML>
 Any errors will show below this line.
-<div id="target" style="position: absolute; width: 200px; height: 200px; will-change: transform; transition: transform 0.1s cubic-bezier(0.23, 1, 0.32, 1); background: lightblue"></div>
+<style>
+@keyframes twiddle {
+  0% { transform: rotate(0deg); }
+  100% { transform: rotate(180deg); }
+}
+
+.animated {
+  animation: twiddle 3s alternate infinite linear;
+  width: 100px;
+  height: 100px;
+  background: orange;
+}
+</style>
+<div id="target" class="animated" style="position: absolute; width: 200px; height: 200px; background: lightblue"></div>
 <div style="position: absolute; width: 200px; height: 200px; top: 100px; left: 100px; background: lightgray"></div>
 <script src="../../resources/testharness.js"></script>
 <script>
 if (window.testRunner) {
     testRunner.dumpAsText();
-    testRunner.waitUntilDone();
 }
 onload = function() {
     target.style.transform = "translateX(10px)";
-    requestAnimationFrame(function() {
-        if (window.internals) {
-            var layers = JSON.parse(internals.layerTreeAsText(document, 1));
-            assert_true(layers.children[0].children[1].compositingReasons[1] == "Cannot squash into a layer that is animating.");
-        }
-        testRunner.notifyDone();
-    });
+    if (window.internals) {
+        var layers = JSON.parse(internals.layerTreeAsText(document, 1));
+        assert_true(layers.children[0].children[1].compositingReasons[1] == "Layer was separately composited because it could not be squashed.");
+        assert_true(layers.children[0].children[1].squashingDisallowedReasons[0] == "Cannot squash into a layer that is animating.");
+    }
 };
-</script>
\ No newline at end of file
+</script>
diff --git a/third_party/WebKit/LayoutTests/compositing/squashing/dont-squash-into-blend-mode.html b/third_party/WebKit/LayoutTests/compositing/squashing/dont-squash-into-blend-mode.html
index 1365ce3a..27bfd32 100644
--- a/third_party/WebKit/LayoutTests/compositing/squashing/dont-squash-into-blend-mode.html
+++ b/third_party/WebKit/LayoutTests/compositing/squashing/dont-squash-into-blend-mode.html
@@ -8,8 +8,9 @@
     testRunner.dumpAsText();
 onload = function() {
     if (window.internals) {
-        var layers = JSON.parse(internals.layerTreeAsText(document, 1));
-        assert_true(layers.children[0].children[0].children[1].compositingReasons[1] == "Squashing a layer with blending is not supported.");
+        var layers = JSON.parse(internals.layerTreeAsText(document, internals.LAYER_TREE_INCLUDES_DEBUG_INFO));
+        assert_true(layers.children[0].children[0].children[1].compositingReasons[1] == "Layer was separately composited because it could not be squashed.");
+        assert_true(layers.children[0].children[0].children[1].squashingDisallowedReasons[0] == "Squashing a layer with blending is not supported.");
     }
 };
-</script>
\ No newline at end of file
+</script>
diff --git a/third_party/WebKit/LayoutTests/css3/flexbox/flexitem-expected.txt b/third_party/WebKit/LayoutTests/css3/flexbox/flexitem-expected.txt
index f69dd3d..3d3db47 100644
--- a/third_party/WebKit/LayoutTests/css3/flexbox/flexitem-expected.txt
+++ b/third_party/WebKit/LayoutTests/css3/flexbox/flexitem-expected.txt
@@ -1,4 +1,3 @@
-CONSOLE WARNING: 'SVGElement.offsetWidth' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
 This is a testharness.js-based test.
 PASS .flexbox 1 
 PASS .flexbox 2 
diff --git a/third_party/WebKit/LayoutTests/css3/flexbox/flexitem.html b/third_party/WebKit/LayoutTests/css3/flexbox/flexitem.html
index 17b46e22..33b96ef2 100644
--- a/third_party/WebKit/LayoutTests/css3/flexbox/flexitem.html
+++ b/third_party/WebKit/LayoutTests/css3/flexbox/flexitem.html
@@ -52,11 +52,11 @@
 </div>
 
 <div class="flexbox">
-  <svg data-expected-display="block" data-expected-width="100" style="flex: 1 0 auto; width: 100px; height: 100px">
+  <svg data-expected-display="block" data-expected-bounding-client-rect-width="100" style="flex: 1 0 auto; width: 100px; height: 100px">
     <circle cx="50" cy="50" r="50" fill="blue">
     </circle>
   </svg>
-  <svg data-expected-display="block" data-expected-width="500" style="flex: 1 1 auto; height: 100px; width: 100%">
+  <svg data-expected-display="block" data-expected-bounding-client-rect-width="500" style="flex: 1 1 auto; height: 100px; width: 100%">
     <circle cx="50" cy="50" r="50" fill="green">
     </circle>
   </svg>
diff --git a/third_party/WebKit/LayoutTests/editing/execCommand/dispatch-text-event-crash.html b/third_party/WebKit/LayoutTests/editing/execCommand/dispatch-text-event-crash.html
new file mode 100644
index 0000000..dbc6ed5a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/editing/execCommand/dispatch-text-event-crash.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<hr id="el0" contenteditable="true" />
+<output id="el10"></output>
+<form id="form"/>
+<div id="log"></div>
+<script>
+test(function(){
+  el0.appendChild(document.createComment("text"));
+
+  document.designMode = 'on';
+  document.execCommand('selectall');
+  document.execCommand('bold');
+  document.designMode = 'off';
+  enterEvent = document.createEvent('TextEvent');
+  enterEvent.initTextEvent('textInput', true, true, document.defaultView, '\\n');
+  form.dispatchEvent(enterEvent);
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/block/line-layout/selection-highlight-overlap-expected.html b/third_party/WebKit/LayoutTests/fast/block/line-layout/selection-highlight-overlap-expected.html
deleted file mode 100644
index 803c33f..0000000
--- a/third_party/WebKit/LayoutTests/fast/block/line-layout/selection-highlight-overlap-expected.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<style>
-    body { font-size: 64px; font-family: Ahem; color: transparent; margin-top: 0px; }
-    div { outline: 1px dashed green; }
-    div > div { outline: initial; background-color: rgba(0, 0, 255, .4); }
-</style>
-<div style="outline: none;">
-    <div style="height: 8px; margin-left: 128px;"></div>
-</div>
-<div style="outline: none;">
-    <div style="height: 30px; margin-left: 128px;"></div>
-</div>
-<div>
-    <div style="height: 17px; margin-left: 128px;"></div>
-    <div style="height: 47px;"></div>
-</div>
-<div style="margin-top: -10px; height: 64px;">
-    <div style="height: 10px; background-color: transparent;"></div>
-    <div style="height: 54px; width: 256px;"></div>
-</div>
diff --git a/third_party/WebKit/LayoutTests/fast/block/line-layout/selection-highlight-overlap.html b/third_party/WebKit/LayoutTests/fast/block/line-layout/selection-highlight-overlap.html
deleted file mode 100644
index e55a61e..0000000
--- a/third_party/WebKit/LayoutTests/fast/block/line-layout/selection-highlight-overlap.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<style>
-    body { font-size: 64px; font-family: Ahem; color: transparent; }
-    div { outline: 1px dashed green; }
-    div::selection { background-color: rgba(0, 0, 255, .4); }
-</style>
-<div id="start" style="line-height: 30px; outline: none">queue theory</div>
-<div>problem</div>
-<div id="end" style="margin-top: -10px;">information</div>
-<script>
-	getSelection().setBaseAndExtent(document.getElementById("start").firstChild, 2, document.getElementById("end").firstChild, 4);
-</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffScreenCanvas-invalid-args-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/OffScreenCanvas-invalid-args-expected.txt
deleted file mode 100644
index 9b251fc..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/OffScreenCanvas-invalid-args-expected.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-Tests that the OffScreenCanvas can handle invalid arguments
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS canvas1.width is setWidth-1
-PASS canvas1.height is setHeight-1
-PASS canvas1.width is 0
-PASS canvas1.height is 0
-PASS new OffScreenCanvas(-1, -1) threw exception TypeError: Failed to construct 'OffScreenCanvas': Value is outside the 'unsigned long' value range..
-PASS canvas2.width is 0
-PASS canvas2.height is 0
-PASS canvas2.width is setWidth-1
-PASS canvas2.height is setHeight-1
-PASS canvas2.width = -1 threw exception TypeError: Failed to set the 'width' property on 'OffScreenCanvas': Value is outside the 'unsigned long' value range..
-PASS canvas2.height = -1 threw exception TypeError: Failed to set the 'height' property on 'OffScreenCanvas': Value is outside the 'unsigned long' value range..
-PASS canvas2.width = obj threw exception TypeError: Failed to set the 'width' property on 'OffScreenCanvas': Value is not of type 'unsigned long'..
-PASS canvas2.height = obj threw exception TypeError: Failed to set the 'height' property on 'OffScreenCanvas': Value is not of type 'unsigned long'..
-PASS new OffScreenCanvas(obj, obj) threw exception TypeError: Failed to construct 'OffScreenCanvas': Value is not of type 'unsigned long'..
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffScreenCanvas-constructor-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvasTemp-constructor-expected.txt
similarity index 73%
rename from third_party/WebKit/LayoutTests/fast/canvas/OffScreenCanvas-constructor-expected.txt
rename to third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvasTemp-constructor-expected.txt
index aaea896..63e32b44 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/OffScreenCanvas-constructor-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvasTemp-constructor-expected.txt
@@ -1,4 +1,4 @@
-Tests that the constructor of the OffScreenCanvas can be called on the main thread
+Tests that the constructor of the OffscreenCanvasTemp can be called on the main thread
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffScreenCanvas-constructor-in-worker-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvasTemp-constructor-in-worker-expected.txt
similarity index 73%
rename from third_party/WebKit/LayoutTests/fast/canvas/OffScreenCanvas-constructor-in-worker-expected.txt
rename to third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvasTemp-constructor-in-worker-expected.txt
index fe62ed5..d2b8ec5 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/OffScreenCanvas-constructor-in-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvasTemp-constructor-in-worker-expected.txt
@@ -1,4 +1,4 @@
-Tests that the OffScreenCanvas can be constructed on a worker thread.
+Tests that the OffscreenCanvasTemp can be constructed on a worker thread.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffScreenCanvas-constructor-in-worker.html b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvasTemp-constructor-in-worker.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/fast/canvas/OffScreenCanvas-constructor-in-worker.html
rename to third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvasTemp-constructor-in-worker.html
index 01df0f46..8ad2a50 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/OffScreenCanvas-constructor-in-worker.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvasTemp-constructor-in-worker.html
@@ -4,7 +4,7 @@
 <body>
 <script id="myWorker" type="text/worker">
 self.onmessage = function(e) {
-  var aCanvas = new OffScreenCanvas(50, 50);
+  var aCanvas = new OffscreenCanvasTemp(50, 50);
   self.postMessage({version:'first', width:aCanvas.width, height:aCanvas.height});
 
   aCanvas.width = 100;
@@ -15,7 +15,7 @@
 
 <script>
 jsTestIsAsync = true;
-description("Tests that the OffScreenCanvas can be constructed on a worker thread.");
+description("Tests that the OffscreenCanvasTemp can be constructed on a worker thread.");
 
 var width;
 var height;
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffScreenCanvas-constructor.html b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvasTemp-constructor.html
similarity index 64%
rename from third_party/WebKit/LayoutTests/fast/canvas/OffScreenCanvas-constructor.html
rename to third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvasTemp-constructor.html
index 119a9f5..7f978c2 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/OffScreenCanvas-constructor.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvasTemp-constructor.html
@@ -1,9 +1,9 @@
 <!DOCTYPE html>
 <script src="../../resources/js-test.js"></script>
 <script>
-description("Tests that the constructor of the OffScreenCanvas can be called on the main thread");
+description("Tests that the constructor of the OffscreenCanvasTemp can be called on the main thread");
 
-var aCanvas = new OffScreenCanvas(50, 50);
+var aCanvas = new OffscreenCanvasTemp(50, 50);
 shouldBe("aCanvas.width", "50");
 shouldBe("aCanvas.height", "50");
 
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvasTemp-invalid-args-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvasTemp-invalid-args-expected.txt
new file mode 100644
index 0000000..f667ba7a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvasTemp-invalid-args-expected.txt
@@ -0,0 +1,23 @@
+Tests that the OffscreenCanvasTemp can handle invalid arguments
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS canvas1.width is setWidth-1
+PASS canvas1.height is setHeight-1
+PASS canvas1.width is 0
+PASS canvas1.height is 0
+PASS new OffscreenCanvasTemp(-1, -1) threw exception TypeError: Failed to construct 'OffscreenCanvasTemp': Value is outside the 'unsigned long' value range..
+PASS canvas2.width is 0
+PASS canvas2.height is 0
+PASS canvas2.width is setWidth-1
+PASS canvas2.height is setHeight-1
+PASS canvas2.width = -1 threw exception TypeError: Failed to set the 'width' property on 'OffscreenCanvasTemp': Value is outside the 'unsigned long' value range..
+PASS canvas2.height = -1 threw exception TypeError: Failed to set the 'height' property on 'OffscreenCanvasTemp': Value is outside the 'unsigned long' value range..
+PASS canvas2.width = obj threw exception TypeError: Failed to set the 'width' property on 'OffscreenCanvasTemp': Value is not of type 'unsigned long'..
+PASS canvas2.height = obj threw exception TypeError: Failed to set the 'height' property on 'OffscreenCanvasTemp': Value is not of type 'unsigned long'..
+PASS new OffscreenCanvasTemp(obj, obj) threw exception TypeError: Failed to construct 'OffscreenCanvasTemp': Value is not of type 'unsigned long'..
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffScreenCanvas-invalid-args-in-worker-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvasTemp-invalid-args-in-worker-expected.txt
similarity index 74%
rename from third_party/WebKit/LayoutTests/fast/canvas/OffScreenCanvas-invalid-args-in-worker-expected.txt
rename to third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvasTemp-invalid-args-in-worker-expected.txt
index b6f502f..eab15bf 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/OffScreenCanvas-invalid-args-in-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvasTemp-invalid-args-in-worker-expected.txt
@@ -1,4 +1,4 @@
-Tests that the OffScreenCanvas can handle invalid arguments on a worker
+Tests that the OffscreenCanvasTemp can handle invalid arguments on a worker
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffScreenCanvas-invalid-args-in-worker.html b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvasTemp-invalid-args-in-worker.html
similarity index 85%
rename from third_party/WebKit/LayoutTests/fast/canvas/OffScreenCanvas-invalid-args-in-worker.html
rename to third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvasTemp-invalid-args-in-worker.html
index ed550638..88d923e 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/OffScreenCanvas-invalid-args-in-worker.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvasTemp-invalid-args-in-worker.html
@@ -7,17 +7,17 @@
 var setHeight = Math.pow(2, 31);
 
 self.onmessage = function(e) {
-  var canvas1 = new OffScreenCanvas(setWidth, setHeight);
+  var canvas1 = new OffscreenCanvasTemp(setWidth, setHeight);
   self.postMessage({version:'canvas1', width:canvas1.width, height:canvas1.height});
 
-  var canvas2 = new OffScreenCanvas(null, null);
+  var canvas2 = new OffscreenCanvasTemp(null, null);
   self.postMessage({version:'canvas2', width:canvas2.width, height:canvas2.height});
 };
 </script>
 
 <script>
 jsTestIsAsync = true;
-description("Tests that the OffScreenCanvas can handle invalid arguments on a worker");
+description("Tests that the OffscreenCanvasTemp can handle invalid arguments on a worker");
 
 var width;
 var height;
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffScreenCanvas-invalid-args.html b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvasTemp-invalid-args.html
similarity index 76%
rename from third_party/WebKit/LayoutTests/fast/canvas/OffScreenCanvas-invalid-args.html
rename to third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvasTemp-invalid-args.html
index 9ce02a7c..8ebb85d 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/OffScreenCanvas-invalid-args.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvasTemp-invalid-args.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <script src="../../resources/js-test.js"></script>
 <script>
-description("Tests that the OffScreenCanvas can handle invalid arguments");
+description("Tests that the OffscreenCanvasTemp can handle invalid arguments");
 
 // Since blink uses signed int internally, this case tests how the constructor
 // responds to the arguments that are larger than INT_MAX which would cause
@@ -10,7 +10,7 @@
 var setHeight = Math.pow(2, 31);
 var obj = {Name: "John Doe", Age: 30};
 
-var canvas1 = new OffScreenCanvas(setWidth, setHeight);
+var canvas1 = new OffscreenCanvasTemp(setWidth, setHeight);
 shouldBe("canvas1.width", "setWidth-1");
 shouldBe("canvas1.height", "setHeight-1");
 
@@ -19,9 +19,9 @@
 shouldBe("canvas1.width", "0");
 shouldBe("canvas1.height", "0");
 
-shouldThrow("new OffScreenCanvas(-1, -1)");
+shouldThrow("new OffscreenCanvasTemp(-1, -1)");
 
-var canvas2 = new OffScreenCanvas(null, null);
+var canvas2 = new OffscreenCanvasTemp(null, null);
 shouldBe("canvas2.width", "0");
 shouldBe("canvas2.height", "0");
 
@@ -36,5 +36,5 @@
 shouldThrow("canvas2.width = obj");
 shouldThrow("canvas2.height = obj");
 
-shouldThrow("new OffScreenCanvas(obj, obj)");
+shouldThrow("new OffscreenCanvasTemp(obj, obj)");
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-gutters-get-set-expected.txt b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-gutters-get-set-expected.txt
index ff25689..473ba8f 100644
--- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-gutters-get-set-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-gutters-get-set-expected.txt
@@ -6,8 +6,10 @@
 Test getting grid-column-gap and grid-row-gap set through CSS
 PASS window.getComputedStyle(defaultGrid, '').getPropertyValue('grid-row-gap') is "0px"
 PASS window.getComputedStyle(defaultGrid, '').getPropertyValue('grid-column-gap') is "0px"
-PASS window.getComputedStyle(gridGap, '').getPropertyValue('grid-row-gap') is "25px"
-PASS window.getComputedStyle(gridGap, '').getPropertyValue('grid-column-gap') is "25px"
+PASS window.getComputedStyle(gridGap, '').getPropertyValue('grid-row-gap') is "20px"
+PASS window.getComputedStyle(gridGap, '').getPropertyValue('grid-column-gap') is "15px"
+PASS window.getComputedStyle(gridSimpleGap, '').getPropertyValue('grid-row-gap') is "25px"
+PASS window.getComputedStyle(gridSimpleGap, '').getPropertyValue('grid-column-gap') is "25px"
 PASS window.getComputedStyle(gridColumnGap, '').getPropertyValue('grid-row-gap') is "0px"
 PASS window.getComputedStyle(gridColumnGap, '').getPropertyValue('grid-column-gap') is "16px"
 PASS window.getComputedStyle(gridRowGap, '').getPropertyValue('grid-row-gap') is "32px"
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-gutters-get-set.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-gutters-get-set.html
index bce6b48..7af88fa 100644
--- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-gutters-get-set.html
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-gutters-get-set.html
@@ -3,7 +3,8 @@
 <head>
 <link href="resources/grid.css" rel="stylesheet">
 <style>
-.gridGap { grid-gap: 25px; }
+.gridGap { grid-gap: 20px 15px; }
+.gridSimpleGap { grid-gap: 25px; }
 .gridColumnGap { grid-column-gap: 2vw; }
 .gridRowGap { grid-row-gap: 2em; }
 .gridRowColumnGaps {
@@ -43,14 +44,15 @@
 
 <div class="grid" id="defaultGrid"></div>
 <div class="grid gridGap" id="gridGap"></div>
+<div class="grid gridSimpleGap" id="gridSimpleGap"></div>
 <div class="grid gridColumnGap" id="gridColumnGap"></div>
 <div class="grid gridRowGap" id="gridRowGap"></div>
 <div class="grid gridCalcGaps" id="gridCalcGaps"></div>
 <div class="grid gridRowColumnGaps" id="gridRowColumnGaps"></div>
-<div class="grid gridGap">
+<div class="grid gridSimpleGap">
     <div class="grid gridRowColumnInheritGaps" id="gridRowColumnInheritGaps"></div>
 </div>
-<div class="grid gridGap">
+<div class="grid gridSimpleGap">
     <div class="grid gridRowColumnInitialGaps" id="gridRowColumnInitialGaps"></div>
 </div>
 <div class="grid gridInvalidRowGap" id="gridInvalidRowGap"></div>
@@ -69,7 +71,8 @@
 debug("Test getting grid-column-gap and grid-row-gap set through CSS");
 
 testGridGapDefinitionsValues("defaultGrid", "0px", "0px");
-testGridGapDefinitionsValues("gridGap", "25px", "25px");
+testGridGapDefinitionsValues("gridGap", "20px", "15px");
+testGridGapDefinitionsValues("gridSimpleGap", "25px", "25px");
 testGridGapDefinitionsValues("gridColumnGap", "0px", "16px");
 testGridGapDefinitionsValues("gridRowGap", "32px", "0px");
 testGridGapDefinitionsValues("gridCalcGaps", "13px", "10px");
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-display-expected.txt b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-display-expected.txt
index 7c3656e..c9c1bc2 100644
--- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-display-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-display-expected.txt
@@ -1,5 +1,3 @@
-CONSOLE WARNING: 'SVGElement.offsetLeft' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
-CONSOLE WARNING: 'SVGElement.offsetTop' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
 This test checks that the grid items' 'display' computed value matches the specification. It also checks that the grid items are placed in the right grid area.
 
 PASS
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-display.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-display.html
index c178a9b3..076626e6 100644
--- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-display.html
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-item-display.html
@@ -59,7 +59,7 @@
         <img data-expected-display="block" data-offset-x="50" data-offset-y="150" src="../images/resources/green-256x256.png"></img>
         <img data-expected-display="block" data-offset-x="50" data-offset-y="150" src="nonexistent.png"></img>
 
-        <svg data-expected-display="block" data-offset-x="50" data-offset-y="150">
+        <svg data-expected-display="block" data-positioned-offset-x="50" data-positioned-offset-y="150">
             <circle cx="50" cy="50" r="50" fill="blue">
             </circle>
         </svg>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt
index af312af..ef3f742 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt
@@ -94,7 +94,7 @@
 PASS window.cached_screen.width is 0
 PASS window.cached_screen_orientation.angle is 0
 PASS window.cached_screen_orientation.onchange is null
-FAIL window.cached_screen_orientation.type should be . Was portrait-primary.
+FAIL window.cached_screen_orientation.type should be . Was landscape-primary.
 PASS window.cached_scrollbars.visible is false
 PASS window.cached_speechSynthesis.onvoiceschanged is null
 PASS window.cached_speechSynthesis.paused is false
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt
index bec90ae..ecddff7 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt
@@ -94,7 +94,7 @@
 PASS window.cached_screen.width is 0
 PASS window.cached_screen_orientation.angle is 0
 PASS window.cached_screen_orientation.onchange is null
-FAIL window.cached_screen_orientation.type should be . Was portrait-primary.
+FAIL window.cached_screen_orientation.type should be . Was landscape-primary.
 PASS window.cached_scrollbars.visible is false
 PASS window.cached_speechSynthesis.onvoiceschanged is null
 PASS window.cached_speechSynthesis.paused is false
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt
index 5962ffc..c4ad6b4 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt
@@ -94,7 +94,7 @@
 PASS window.cached_screen.width is 0
 PASS window.cached_screen_orientation.angle is 0
 PASS window.cached_screen_orientation.onchange is null
-FAIL window.cached_screen_orientation.type should be . Was portrait-primary.
+FAIL window.cached_screen_orientation.type should be . Was landscape-primary.
 PASS window.cached_scrollbars.visible is false
 PASS window.cached_speechSynthesis.onvoiceschanged is null
 PASS window.cached_speechSynthesis.paused is false
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/resources/event-dispatching.js b/third_party/WebKit/LayoutTests/fast/dom/shadow/resources/event-dispatching.js
index d06e5a9..9f4b9e4 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/shadow/resources/event-dispatching.js
+++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/resources/event-dispatching.js
@@ -5,19 +5,21 @@
     if (!window.eventSender || !window.internals)
         return;
 
-    var x = element.offsetLeft + element.offsetWidth / 2;
+    var rect = element.getBoundingClientRect();
+    var x = rect.left + rect.width / 2;
     var y;
     if (element.hasChildNodes() || window.internals.shadowRoot(element))
-        y = element.offsetTop + defaultPaddingSize / 2;
+        y = rect.top + defaultPaddingSize / 2;
     else
-        y = element.offsetTop + element.offsetHeight / 2;
+        y = rect.top + rect.height / 2;
     eventSender.mouseMoveTo(x, y);
 }
 
 function touchLocation(node)
 {
-    var x = node.offsetLeft + 5;
-    var y = node.offsetTop + defaultPaddingSize + 5;
+    var rect = node.getBoundingClientRect();
+    var x = rect.left + 5;
+    var y = rect.top + defaultPaddingSize + 5;
     eventSender.addTouchPoint(x, y);
     eventSender.touchStart();
     eventSender.leapForward(100);
@@ -30,9 +32,11 @@
     getSelection().setBaseAndExtent(node, 0, node, node.length);
 }
 
-function dragMouse(node) {
-    var x = node.offsetLeft + 5;
-    var y = node.offsetTop + defaultPaddingSize + 5;
+function dragMouse(node)
+{
+    var rect = node.getBoundingClientRect();
+    var x = rect.left + 5;
+    var y = rect.top + defaultPaddingSize + 5;
 
     eventSender.mouseMoveTo(x, y);
     eventSender.mouseDown();
@@ -42,9 +46,11 @@
     eventSender.mouseMoveTo(x, y);
 }
 
-function scrollMouseWheel(node) {
-    var x = node.offsetLeft + 5;
-    var y = node.offsetTop + defaultPaddingSize + 5;
+function scrollMouseWheel(node)
+{
+    var rect = node.getBoundingClientRect();
+    var x = rect.left + 5;
+    var y = rect.top + defaultPaddingSize + 5;
     eventSender.mouseMoveTo(x, y);
     eventSender.mouseScrollBy(0, 120);
 }
@@ -176,6 +182,6 @@
 function showSandboxTree()
 {
     var sandbox = document.getElementById('sandbox');
-    sandbox.offsetLeft;
+    sandbox.clientLeft;
     debug('\n\nFlat Tree will be:\n' + dumpFlatTree(sandbox));
 }
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/shadow-dom-event-dispatching-svg-in-shadow-subtree-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/shadow/shadow-dom-event-dispatching-svg-in-shadow-subtree-expected.txt
index b074c78..7f7ba51 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/shadow/shadow-dom-event-dispatching-svg-in-shadow-subtree-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/shadow-dom-event-dispatching-svg-in-shadow-subtree-expected.txt
@@ -1,7 +1,3 @@
-CONSOLE WARNING: 'SVGElement.offsetLeft' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
-CONSOLE WARNING: 'SVGElement.offsetWidth' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
-CONSOLE WARNING: 'SVGElement.offsetTop' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
-CONSOLE WARNING: 'SVGElement.offsetHeight' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
 
 
 Flat Tree will be:
diff --git a/third_party/WebKit/LayoutTests/fast/events/drag-nested-eventSender-on-dragover-expected.txt b/third_party/WebKit/LayoutTests/fast/events/drag-nested-eventSender-on-dragover-expected.txt
new file mode 100644
index 0000000..a4f7be6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/events/drag-nested-eventSender-on-dragover-expected.txt
@@ -0,0 +1,9 @@
+Test that nested use of eventSender.beginDragWithFiles() from within |dragover| is handled without crashing.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/fast/events/drag-nested-eventSender-on-dragover.html b/third_party/WebKit/LayoutTests/fast/events/drag-nested-eventSender-on-dragover.html
new file mode 100644
index 0000000..1eb5c9f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/events/drag-nested-eventSender-on-dragover.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<body>
+<script>
+if (window.testRunner)
+    testRunner.dumpAsText();
+
+document.addEventListener("dragover", function () {
+    try {
+        eventSender.beginDragWithFiles(["resources/empty.html"]);
+        console.log("FAIL - nested beginDragWithFiles() expected to throw.");
+    } catch (e) {;}
+});
+
+eventSender.beginDragWithFiles(["resources/empty.html"]);
+eventSender.mouseMoveTo(10, 10);
+eventSender.mouseUp();
+</script>
+<script src="../../resources/js-test.js"></script>
+<script>
+description('Test that nested use of eventSender.beginDragWithFiles() from within |dragover| is handled without crashing.');
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/fast/events/resources/focus-anchor-by-mouse.js b/third_party/WebKit/LayoutTests/fast/events/resources/focus-anchor-by-mouse.js
index f6dc80f2..4144296 100644
--- a/third_party/WebKit/LayoutTests/fast/events/resources/focus-anchor-by-mouse.js
+++ b/third_party/WebKit/LayoutTests/fast/events/resources/focus-anchor-by-mouse.js
@@ -1,7 +1,8 @@
 window.onload = function() {
     if (window.eventSender) {
         var aElement = document.getElementById('anchor');
-        eventSender.mouseMoveTo(aElement.offsetLeft + 2, aElement.offsetTop + 2);
+        var aRect = aElement.getBoundingClientRect();
+        eventSender.mouseMoveTo(aRect.left + 2, aRect.top + 2);
         eventSender.mouseDown();
     }
 };
diff --git a/third_party/WebKit/LayoutTests/fast/forms/radio/radio-crash-by-keyboard-event.html b/third_party/WebKit/LayoutTests/fast/forms/radio/radio-crash-by-keyboard-event.html
new file mode 100644
index 0000000..9be32722
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/radio/radio-crash-by-keyboard-event.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<body>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script>
+test(function() {
+    var radio = document.createElement('input');
+    radio.type = 'radio';
+    radio.dispatchEvent(new KeyboardEvent('keydown', { keyIdentifier: 'Down' } ));
+}, 'Sending a keydown event to detached radio button should not crash.');
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/select/listbox-selection-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/select/listbox-selection-expected.txt
index 9acff3c0..d877cdc 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/select/listbox-selection-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/forms/select/listbox-selection-expected.txt
@@ -35,6 +35,7 @@
 PASS selectionPattern("sl15") is "01000"
 PASS mouseMoveToOption("sl15", 3); selectionPattern("sl15") is "01110"
 PASS mouseMoveToOption("sl15", 2); selectionPattern("sl15") is "01100"
+PASS sl15.add(new Option("a")); eventSender.keyDown("upArrow"); selectionPattern("sl15") is "010000"
 16) Active-selection after type-ahead
 PASS mouseClickOnSelect('sl16', 1); selectionPattern('sl16') is "01000"
 PASS keyDownOnSelect('sl16', 'e'); selectionPattern('sl16') is "00001"
diff --git a/third_party/WebKit/LayoutTests/fast/forms/select/listbox-selection.html b/third_party/WebKit/LayoutTests/fast/forms/select/listbox-selection.html
index bf3680cc..1faa74b 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/select/listbox-selection.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/select/listbox-selection.html
@@ -154,6 +154,10 @@
 shouldBeEqualToString('mouseMoveToOption("sl15", 3); selectionPattern("sl15")', "01110");
 shouldBeEqualToString('mouseMoveToOption("sl15", 2); selectionPattern("sl15")', "01100");
 eventSender.mouseUp(0);
+// activeSelectionEnd is the third OPTION.  upArrow should select the previous
+// one of the third OPTION.  Adding new OPTION shouldn't clear
+// activeSelectionEnd.
+shouldBeEqualToString('sl15.add(new Option("a")); eventSender.keyDown("upArrow"); selectionPattern("sl15")', "010000");
 
 debug("16) Active-selection after type-ahead");
 shouldBeEqualToString("mouseClickOnSelect('sl16', 1); selectionPattern('sl16')", "01000");
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/nested-with-line-taller-than-outer-expected.txt b/third_party/WebKit/LayoutTests/fast/multicol/nested-with-line-taller-than-outer-expected.txt
new file mode 100644
index 0000000..7bf8ef7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/nested-with-line-taller-than-outer-expected.txt
@@ -0,0 +1,4 @@
+PASS if no crash or assertion failure.
+
+
+
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/nested-with-line-taller-than-outer.html b/third_party/WebKit/LayoutTests/fast/multicol/nested-with-line-taller-than-outer.html
new file mode 100644
index 0000000..062336c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/nested-with-line-taller-than-outer.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<script>
+    if (window.testRunner)
+        testRunner.dumpAsText();
+</script>
+<p>PASS if no crash or assertion failure.</p>
+<div style="-webkit-columns:2; column-fill:auto; height:15px; line-height:20px;">
+    <div style="-webkit-columns:2;">
+        <br>
+    </div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/rule-in-nested-with-too-tall-line-expected.html b/third_party/WebKit/LayoutTests/fast/multicol/rule-in-nested-with-too-tall-line-expected.html
new file mode 100644
index 0000000..0f4437d9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/rule-in-nested-with-too-tall-line-expected.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<p>There should only be <em>one</em> vertical line below.</p>
+<div style="margin-left:23px; border-left:4px solid; width:0; height:100px;"></div>
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/rule-in-nested-with-too-tall-line.html b/third_party/WebKit/LayoutTests/fast/multicol/rule-in-nested-with-too-tall-line.html
new file mode 100644
index 0000000..480c235
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/rule-in-nested-with-too-tall-line.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<style>
+    .multicol { columns:2; column-gap:0; column-fill:auto; }
+</style>
+<p>There should only be <em>one</em> vertical line below.</p>
+<div class="multicol" style="width:100px; height:100px; line-height:200px;">
+    <div class="multicol" style="column-rule:4px solid; height:200px;">
+        <br>
+    </div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/fast/table/section-with-opaque-background-expected.html b/third_party/WebKit/LayoutTests/fast/table/section-with-opaque-background-expected.html
new file mode 100644
index 0000000..35027382
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/table/section-with-opaque-background-expected.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<style>
+td { background-color: green; width: 100px; height: 100px; }
+</style>
+A table section with opaque background should not be treated as opaque because
+it may have transparent areas due to table border-spacing, empty cells, etc.
+Passes if the table borders, empty cells are yellow (transparent to show the
+background of the underlying div).
+<div style="position: absolute; background: yellow">
+  <table style="margin: 0px; border-spacing: 10px">
+    <tr><td></td></tr>
+    <tr><td></td><td></td></tr>
+  </table>
+</div>
diff --git a/third_party/WebKit/LayoutTests/fast/table/section-with-opaque-background.html b/third_party/WebKit/LayoutTests/fast/table/section-with-opaque-background.html
new file mode 100644
index 0000000..80cd891
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/table/section-with-opaque-background.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<style>
+td { background-color: green; width: 100px; height: 100px; }
+</style>
+A table section with opaque background should not be treated as opaque because
+it may have transparent areas due to table border-spacing, empty cells, etc.
+Passes if the table borders, empty cells are yellow (transparent to show the
+background of the underlying div).
+<div style="position: absolute; will-change: transform; background: yellow">
+  <table style="margin: 0px; border-spacing: 10px">
+    <thead style="background: red">
+      <tr><td></td></tr>
+      <tr><td></td><td></td></tr>
+    </thead>
+  </table>
+</div>
diff --git a/third_party/WebKit/LayoutTests/fast/text/font-fallback.html b/third_party/WebKit/LayoutTests/fast/text/font-fallback.html
new file mode 100644
index 0000000..b86777e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/text/font-fallback.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta charset="utf-8">
+        <title>Tests Font Fallback</title>
+        <style>
+            span { display: inline-block; width: 10em; }
+        </style>
+    </head>
+    <body>
+        <div><span>Arabic:</span> الأَبْجَدِيَّة العَرَبِيَّة ‎</div>
+        <div><span>Armenian:</span> Հայոց գրեր Hayots grer</div>
+        <div><span>Cherokee:</span> ᎢᏣᎵᏍᎠᏁᏗ</div>
+        <div><span>Devanagari:</span> देवनागरी</div>
+        <div><span>Gurmukhi:</span> ਦਿਲ</div>
+        <div><span>Khmer:</span> អក្សរខ្មែរ;</div>
+        <div><span>Hangul:</span> ㄱ ㄴ ㄷ ㄹ ㅁ ㅂ ㅅ ㆁ ㅋ ㅌ ㅍ ㅈ ㅊ ㅿ ㅇ ㅎ</div>
+        <div><span>Mongolian:</span> ᠮᠣᠩᠭᠣᠯᠪᠢᠴᠢᠭ</div>
+        <div><span>Glagolitic:</span> ⰉⰊⰟⰉ</div>
+    </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fullscreen/orthogonal-writing-mode-full-screen-crash-expected.txt b/third_party/WebKit/LayoutTests/fullscreen/orthogonal-writing-mode-full-screen-crash-expected.txt
new file mode 100644
index 0000000..c7d0804
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fullscreen/orthogonal-writing-mode-full-screen-crash-expected.txt
@@ -0,0 +1,7 @@
+entering fullscreen OK
+EVENT(webkitfullscreenchange)
+entered fullscreen OK
+EVENT(webkitfullscreenchange)
+exited fullscreen OK
+END OF TEST
+
diff --git a/third_party/WebKit/LayoutTests/fullscreen/orthogonal-writing-mode-full-screen-crash.html b/third_party/WebKit/LayoutTests/fullscreen/orthogonal-writing-mode-full-screen-crash.html
new file mode 100644
index 0000000..5db949b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fullscreen/orthogonal-writing-mode-full-screen-crash.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<script src="full-screen-test.js"></script>
+<style type="text/css">
+#v {
+  -webkit-writing-mode: vertical-rl;
+}
+</style>
+
+<div id="v"><span id="fullscreen"></span></div>
+
+<script>
+(function () {
+  if (!window.eventSender) {
+    logResult(false, "This test requires eventSender");
+    return;
+  }
+
+  function fullscreenChanged()
+  {
+    if (document.webkitIsFullScreen) {
+      logResult(true, "entered fullscreen");
+      document.exitFullscreen();
+      return;
+    }
+    logResult(true, "exited fullscreen");
+    endTest();
+  }
+
+  waitForEvent(document, "fullscreenchange", fullscreenChanged);
+  waitForEvent(document, "webkitfullscreenchange", fullscreenChanged);
+
+  runWithKeyDown(function () {
+    logResult(true, "entering fullscreen");
+    fullscreen.webkitRequestFullscreen();
+  });
+})();
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/cachestorage/script-tests/cache-delete.js b/third_party/WebKit/LayoutTests/http/tests/cachestorage/script-tests/cache-delete.js
index 5bdc782..0a44029 100644
--- a/third_party/WebKit/LayoutTests/http/tests/cachestorage/script-tests/cache-delete.js
+++ b/third_party/WebKit/LayoutTests/http/tests/cachestorage/script-tests/cache-delete.js
@@ -64,33 +64,52 @@
         });
   }, 'Cache.delete with a non-existent entry');
 
-var cache_entries = {
-  a: {
-    request: new Request('http://example.com/abc'),
-    response: new Response('')
+prepopulated_cache_test(simple_entries, function(cache, entries) {
+    return cache.matchAll(entries.a_with_query.request,
+                          { ignoreSearch: true })
+      .then(function(result) {
+          assert_response_array_equivalent(
+            result,
+            [
+              entries.a.response,
+              entries.a_with_query.response
+            ]);
+          return cache.delete(entries.a_with_query.request,
+                              { ignoreSearch: true });
+        })
+      .then(function(result) {
+          return cache.matchAll(entries.a_with_query.request,
+                                { ignoreSearch: true });
+        })
+      .then(function(result) {
+          assert_response_array_equivalent(result, []);
+        });
   },
+  'Cache.delete with ignoreSearch option (request with search parameters)');
 
-  b: {
-    request: new Request('http://example.com/b'),
-    response: new Response('')
+prepopulated_cache_test(simple_entries, function(cache, entries) {
+    return cache.matchAll(entries.a_with_query.request,
+                          { ignoreSearch: true })
+      .then(function(result) {
+          assert_response_array_equivalent(
+            result,
+            [
+              entries.a.response,
+              entries.a_with_query.response
+            ]);
+          // cache.delete()'s behavior should be the same if ignoreSearch is
+          // not provided or if ignoreSearch is false.
+          return cache.delete(entries.a_with_query.request,
+                              { ignoreSearch: false });
+        })
+      .then(function(result) {
+          return cache.matchAll(entries.a_with_query.request,
+                                { ignoreSearch: true });
+        })
+      .then(function(result) {
+          assert_response_array_equivalent(result, [ entries.a.response ]);
+        });
   },
-
-  a_with_query: {
-    request: new Request('http://example.com/abc?q=r'),
-    response: new Response('')
-  }
-};
-
-function prepopulated_cache_test(test_function, description) {
-  cache_test(function(cache) {
-      return Promise.all(Object.keys(cache_entries).map(function(k) {
-          return cache.put(cache_entries[k].request.clone(),
-                           cache_entries[k].response.clone());
-        }))
-        .then(function() {
-            return test_function(cache);
-          });
-    }, description);
-}
+  'Cache.delete with ignoreSearch option (when it is specified as false)');
 
 done();
diff --git a/third_party/WebKit/LayoutTests/http/tests/cachestorage/serviceworker/ignore-search-with-credentials.html b/third_party/WebKit/LayoutTests/http/tests/cachestorage/serviceworker/ignore-search-with-credentials.html
index cc59e92..82231d3 100644
--- a/third_party/WebKit/LayoutTests/http/tests/cachestorage/serviceworker/ignore-search-with-credentials.html
+++ b/third_party/WebKit/LayoutTests/http/tests/cachestorage/serviceworker/ignore-search-with-credentials.html
@@ -73,7 +73,15 @@
           var expected = remove_query(request.url);
           assert_equals(remove_query(results[0].url), expected);
           assert_equals(remove_query(results[1].url), expected);
+          return cache.delete(request, { ignoreSearch : true });
         })
+      .then(function(result) {
+          assert_true(result);
+          return cache.matchAll(request, { ignoreSearch : true });
+        })
+      .then(function(results) {
+          assert_equals(results.length, 0);
+        });
   });
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/indexeddb/database-structure-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/indexeddb/database-structure-expected.txt
index 1906ece4..3266884 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/indexeddb/database-structure-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/indexeddb/database-structure-expected.txt
@@ -13,12 +13,12 @@
 Dumping database:
 Dumping database:
 testDatabase1
-    intVersion: 1
+    version: 1
     objectStores:
 
 Dumping database:
 testDatabase1
-    intVersion: 2
+    version: 2
     objectStores:
     testObjectStore1
         keyPath: "test.key.path"
@@ -27,7 +27,7 @@
 
 Dumping database:
 testDatabase1
-    intVersion: 3
+    version: 3
     objectStores:
     testObjectStore1
         keyPath: "test.key.path"
@@ -40,7 +40,7 @@
 
 Dumping database:
 testDatabase1
-    intVersion: 4
+    version: 4
     objectStores:
     testObjectStore1
         keyPath: "test.key.path"
@@ -57,7 +57,7 @@
 
 Dumping database:
 testDatabase1
-    intVersion: 5
+    version: 5
     objectStores:
     testObjectStore1
         keyPath: "test.key.path"
@@ -78,7 +78,7 @@
 
 Dumping database:
 testDatabase1
-    intVersion: 6
+    version: 6
     objectStores:
     testObjectStore1
         keyPath: "test.key.path"
@@ -95,7 +95,7 @@
 
 Dumping database:
 testDatabase1
-    intVersion: 7
+    version: 7
     objectStores:
     testObjectStore1
         keyPath: "test.key.path"
@@ -108,7 +108,7 @@
 
 Dumping database:
 testDatabase1
-    intVersion: 8
+    version: 8
     objectStores:
     testObjectStore1
         keyPath: "test.key.path"
@@ -117,7 +117,7 @@
 
 Dumping database:
 testDatabase1
-    intVersion: 9
+    version: 9
     objectStores:
 
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/indexeddb/database-structure.html b/third_party/WebKit/LayoutTests/http/tests/inspector/indexeddb/database-structure.html
index af650afa..200887b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/indexeddb/database-structure.html
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/indexeddb/database-structure.html
@@ -19,7 +19,7 @@
         if (!database)
             return;
         InspectorTest.addResult(database.databaseId.name);
-        InspectorTest.addResult("    intVersion: " + database.intVersion);
+        InspectorTest.addResult("    version: " + database.version);
         InspectorTest.addResult("    objectStores:");
         var objectStoreNames = [];
         for (var objectStoreName in database.objectStores)
diff --git a/third_party/WebKit/LayoutTests/http/tests/preload/onload_event.html b/third_party/WebKit/LayoutTests/http/tests/preload/onload_event.html
index a0bd13d..f16e90b0 100644
--- a/third_party/WebKit/LayoutTests/http/tests/preload/onload_event.html
+++ b/third_party/WebKit/LayoutTests/http/tests/preload/onload_event.html
@@ -10,7 +10,8 @@
     var videoLoaded = false;
     var audioLoaded = false;
     var trackLoaded = false;
-    var gibrishLoaded = false;
+    var gibberishLoaded = false;
+    var gibberishErrored = false;
     var noTypeLoaded = false;
 </script>
 <link rel=preload href="../resources/dummy.js" as=script onload="scriptLoaded = true;">
@@ -20,7 +21,7 @@
 <link rel=preload href="../resources/test.mp4" as=video onload="videoLoaded = true;">
 <link rel=preload href="../resources/test.oga" as=audio onload="audioLoaded = true;">
 <link rel=preload href="../security/resources/captions.vtt" as=track onload="trackLoaded = true;">
-<link rel=preload href="../resources/dummy.xml" as=foobarxmlthing onload="gibrishLoaded = true;">
+<link rel=preload href="../resources/dummy.xml" as=foobarxmlthing onload="gibberishLoaded = true;" onerror="gibberishErrored = true;">
 <link rel=preload href="../resources/dummy.xml" onload="noTypeLoaded = true;">
 <script src="../resources/slow-script.pl?delay=500"></script>
 <script>
@@ -32,7 +33,8 @@
         assert_true(videoLoaded, "video triggered load event");
         assert_true(audioLoaded, "audio triggered load event");
         assert_true(trackLoaded, "track triggered load event");
-        assert_true(gibrishLoaded, "gibrish as value triggered load event");
+        assert_false(gibberishLoaded, "gibberish as value triggered load event");
+        assert_true(gibberishErrored, "gibberish as value triggered error event");
         assert_true(noTypeLoaded, "empty as triggered load event");
         t.done();
     });
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/script-src-unsafe-dynamic-whitelist.html b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/script-src-unsafe-dynamic-whitelist.html
new file mode 100644
index 0000000..0e1176f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/script-src-unsafe-dynamic-whitelist.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta http-equiv="Content-Security-Policy" content="script-src 'nonce-abcdefg' 'unsafe-dynamic' http://localhost:8000">
+    <script src="/resources/testharness.js" nonce="abcdefg"></script>
+    <script src="/resources/testharnessreport.js" nonce="abcdefg"></script>
+</head>
+<body>
+    <script nonce="abcdefg">
+        function generateURL(type) {
+          return 'http://localhost:8000/security/contentSecurityPolicy/resources/loaded.js?' + type;
+        }
+
+        var loaded = {};
+        var blocked = {};
+        window.addEventListener("message", function (e) {
+          loaded[e.data] = true;
+        });
+        document.addEventListener("securitypolicyviolation", function (e) {
+          blocked[e.lineNumber] = true;
+        });
+
+        async_test(function (t) {
+          document.write("<scr" + "ipt src='" + generateURL("write") + "'></scr" + "ipt>");
+          setTimeout(t.step_func_done(function () {
+            assert_equals(loaded[generateURL("write")], undefined);
+            assert_true(blocked[24]);
+          }, 1));
+        }, "Script injected via 'document.write' is not allowed with 'unsafe-dynamic', even if whitelisted.");
+
+        async_test(function (t) {
+          document.write("<scr" + "ipt defer src='" + generateURL("write-defer") + "'></scr" + "ipt>");
+          setTimeout(t.step_func_done(function () {
+            assert_equals(loaded[generateURL("write-defer")], undefined);
+            assert_true(blocked[32]);
+          }, 1));
+        }, "Deferred script injected via 'document.write' is not allowed with 'unsafe-dynamic', even if whitelisted.");
+
+        async_test(function (t) {
+          document.write("<scr" + "ipt async src='" + generateURL("write-async") + "'></scr" + "ipt>");
+          setTimeout(t.step_func_done(function () {
+            assert_equals(loaded[generateURL("write-async")], undefined);
+            assert_true(blocked[40]);
+          }, 1));
+        }, "Async script injected via 'document.write' is not allowed with 'unsafe-dynamic', even if whitelisted.");
+    </script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/cross-frame-access-put-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/cross-frame-access-put-expected.txt
index b1f0e1e6..84d28d9 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/cross-frame-access-put-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/cross-frame-access-put-expected.txt
@@ -92,7 +92,6 @@
 ALERT: PASS: window.devicePixelRatio should be '1' and is.
 ALERT: PASS: window.document should be '[object HTMLDocument]' and is.
 ALERT: PASS: window.embeds should be 'undefined' and is.
-ALERT: PASS: window.event should be 'undefined' and is.
 ALERT: PASS: window.frameElement should be 'null' and is.
 ALERT: PASS: window.frames should be '[object Window]' and is.
 ALERT: PASS: window.history should be '[object History]' and is.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/cross-frame-access-put.html b/third_party/WebKit/LayoutTests/http/tests/security/cross-frame-access-put.html
index 835baa87..90080f8f 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/cross-frame-access-put.html
+++ b/third_party/WebKit/LayoutTests/http/tests/security/cross-frame-access-put.html
@@ -221,7 +221,17 @@
     setForbiddenProperty(targetWindow, "setTimeout");
     setForbiddenProperty(targetWindow, "stop");
 
-    setTimeout(function() {
+    // Ask the child frame to verify that our xss attempt above
+    // didn't modify any actual values.  The child frame will
+    // post "TEST-COMPLETED" when the verification is done.
+    window.addEventListener("message", receiveMessage, false);
+    targetWindow.postMessage("READY-FOR-OLD-VALUES-VERIFICATION", "*");
+    function receiveMessage(event) {
+        if (event.data != "TEST-COMPLETED") {
+            log("UNEXPECTED MESSAGE: " + event.data);
+            return;
+        }
+
         // log(targetWindow.focus.__proto__);
         log("MAIN WINDOW: !!-- Test ended--!!");
 
@@ -229,6 +239,6 @@
 
         if (window.testRunner)
             testRunner.notifyDone();
-    }, 1);
+    }
 }
 </script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/powerfulFeatureRestrictions/old-powerful-features-on-insecure-origin-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/powerfulFeatureRestrictions/old-powerful-features-on-insecure-origin-expected.txt
index 856190a..714d8781 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/powerfulFeatureRestrictions/old-powerful-features-on-insecure-origin-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/powerfulFeatureRestrictions/old-powerful-features-on-insecure-origin-expected.txt
@@ -1,3 +1,4 @@
+CONSOLE WARNING: Use of the Application Cache is deprecated on insecure origins. Support will be removed in the future. You should consider switching your application to a secure origin, such as HTTPS. See https://goo.gl/rStTGz for more details.
 CONSOLE WARNING: The devicemotion event is deprecated on insecure origins, and support will be removed in the future. You should consider switching your application to a secure origin, such as HTTPS. See https://goo.gl/rStTGz for more details.
 CONSOLE WARNING: The deviceorientation event is deprecated on insecure origins, and support will be removed in the future. You should consider switching your application to a secure origin, such as HTTPS. See https://goo.gl/rStTGz for more details.
 CONSOLE WARNING: getCurrentPosition() and watchPosition() are deprecated on insecure origins. To use this feature, you should consider switching your application to a secure origin, such as HTTPS. See https://goo.gl/rStTGz for more details.
@@ -11,5 +12,6 @@
 PASS watchPosition 
 PASS navigator.webkitGetUserMedia 
 PASS navigator.mediaDevices.getUserMedia 
+PASS appcache 
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/powerfulFeatureRestrictions/old-powerful-features-on-insecure-origin.html b/third_party/WebKit/LayoutTests/http/tests/security/powerfulFeatureRestrictions/old-powerful-features-on-insecure-origin.html
index 31cd796..fc366bd 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/powerfulFeatureRestrictions/old-powerful-features-on-insecure-origin.html
+++ b/third_party/WebKit/LayoutTests/http/tests/security/powerfulFeatureRestrictions/old-powerful-features-on-insecure-origin.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html>
+<html manifest="/security/powerfulFeatureRestrictions/resources/simple.manifest">
 <head>
 <title>Old Powerful Features on an Insecure Origin</title>
 </head>
@@ -80,6 +80,22 @@
                 assert_equals(error.message, "Only secure origins are allowed (see: https://goo.gl/Y0ZkNV).");
             });
     }, 'navigator.mediaDevices.getUserMedia');
+
+    async_test(function() {
+        var cached = this.step_func(function() {
+            var test = this;
+            fetch("/security/powerfulFeatureRestrictions/resources/simple.txt")
+                .then(this.step_func(function(response) {
+                    assert_equals(response.status, 200);
+                    response.text().then(this.step_func_done(function(data) {
+                        assert_equals(data, "Hello, World!");
+                    }));
+                }))
+                .catch(this.unreached_func("fetch() for cachable resource unexpectedly failed"));
+        });
+
+        applicationCache.addEventListener('cached', cached, false);
+    }, 'appcache');
 }
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/powerfulFeatureRestrictions/resources/simple.manifest b/third_party/WebKit/LayoutTests/http/tests/security/powerfulFeatureRestrictions/resources/simple.manifest
new file mode 100644
index 0000000..4f36a67
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/powerfulFeatureRestrictions/resources/simple.manifest
@@ -0,0 +1,5 @@
+CACHE MANIFEST
+/security/powerfulFeatureRestrictions/resources/simple.txt
+
+NETWORK:
+*
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/powerfulFeatureRestrictions/resources/simple.txt b/third_party/WebKit/LayoutTests/http/tests/security/powerfulFeatureRestrictions/resources/simple.txt
new file mode 100644
index 0000000..b45ef6fe
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/powerfulFeatureRestrictions/resources/simple.txt
@@ -0,0 +1 @@
+Hello, World!
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/resources/cross-frame-iframe-for-put-test.html b/third_party/WebKit/LayoutTests/http/tests/security/resources/cross-frame-iframe-for-put-test.html
index b8fb1b3..667d544 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/resources/cross-frame-iframe-for-put-test.html
+++ b/third_party/WebKit/LayoutTests/http/tests/security/resources/cross-frame-iframe-for-put-test.html
@@ -128,13 +128,13 @@
         var XMLSerializerOld = window.XMLSerializer;
         var XPathEvaluatorOld = window.XPathEvaluator;
         var XPathResultOld = window.XPathResult;
-    
+
         // FIXME: find a way to test these Constructors
         // var ImageOld = window.Image;
         // var OptionOld = window.Option;
         // var XMLHttpRequestOld = window.XMLHttpRequest;
         // var XSLTProcessorOld = window.XSLTProcessor;
-    
+
         // Attributes
         var clientInformationOld = window.clientInformation;
         var closedOld = window.closed;
@@ -145,7 +145,6 @@
         var devicePixelRatioOld = window.devicePixelRatio;
         var documentOld = window.document;
         var embedsOld = window.embeds;
-        var eventOld = window.event;
         var framesOld = window.frames;
         var historyOld = window.history;
         var imagesOld = window.images;
@@ -238,7 +237,16 @@
         var setTimeoutOld = window.setTimeout;
         var stopOld = window.stop;
 
-        setTimeout(function() {
+        // Postpone verifying that old values haven't changed until
+        // the main frame notifies us that it has already attempted
+        // xss to set the property values.
+        window.addEventListener("message", receiveMessage, false);
+        function receiveMessage(event) {
+            if (event.data != "READY-FOR-OLD-VALUES-VERIFICATION") {
+                log("UNEXPECTED MESSAGE: " + event.data);
+                return;
+            }
+
             // Constructors
             shouldBe("window.Attr", "AttrOld");
             shouldBe("window.CDATASection", "CDATASectionOld");
@@ -342,7 +350,6 @@
             shouldBe("window.devicePixelRatio", "devicePixelRatioOld");
             shouldBe("window.document", "documentOld");
             shouldBe("window.embeds", "embedsOld");
-            shouldBe("window.event", "eventOld");
             shouldBe("window.frameElement", "null");
             shouldBe("window.frames", "framesOld");
             shouldBe("window.history", "historyOld");
@@ -447,7 +454,9 @@
             shouldBe("window.setTimeout", "setTimeoutOld");
 
             shouldBe("window.stop", "stopOld");
-        }, 0);
+
+            window.parent.postMessage("TEST-COMPLETED", "*");
+        }
     </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/clients-get-client-types.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/clients-get-client-types.html
new file mode 100644
index 0000000..75f54ebe
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/clients-get-client-types.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<title>Service Worker: Clients.get with window and worker clients</title>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.js"></script>
+<script>
+var scope = 'resources/clients-get-client-types';
+var frame_url = scope + '-frame.html';
+var shared_worker_url = scope + '-shared-worker.js';
+var client_ids = [];
+var frame;
+promise_test(function(t) {
+    return service_worker_unregister_and_register(
+        t, 'resources/clients-get-worker.js', scope)
+      .then(function(registration) {
+          add_completion_callback(function() { registration.unregister(); });
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() {
+          return with_iframe(frame_url);
+        })
+      .then(function(f) {
+          frame = f;
+          add_completion_callback(function() { frame.remove(); });
+          frame.focus();
+          return wait_for_clientId();
+        })
+      .then(function(client_id) {
+          client_ids.push(client_id);
+          return new Promise(function(resolve) {
+              var w = new SharedWorker(shared_worker_url);
+              w.port.onmessage = function(e) {
+                resolve(e.data.clientId);
+              };
+            });
+        })
+      .then(function(client_id) {
+          client_ids.push(client_id);
+          var channel = new MessageChannel();
+          var saw_message = new Promise(function(resolve) {
+              channel.port1.onmessage = resolve;
+            });
+          frame.contentWindow.navigator.serviceWorker.controller.postMessage(
+              {port: channel.port2, clientIds: client_ids}, [channel.port2]);
+          return saw_message;
+        })
+      .then(function(e) {
+          assert_equals(e.data.length, 2);
+          assert_array_equals(e.data[0], expected[0]);
+          assert_array_equals(e.data[1], expected[1]);
+        });
+  }, 'Test Clients.get() with window and worker clients');
+
+function wait_for_clientId() {
+  return new Promise(function(resolve) {
+      function get_client_id(e) {
+        window.removeEventListener('message', get_client_id);
+        resolve(e.data.clientId);
+      }
+      window.addEventListener('message', get_client_id, false);
+    });
+}
+
+var expected = [
+    /* visibilityState, focused, url, frameType */
+    ['visible', true, normalizeURL(scope) + '-frame.html', 'nested'],
+    [,,normalizeURL(scope) + '-shared-worker.js', 'none']
+];
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/clients-get-client-types-frame.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/clients-get-client-types-frame.html
new file mode 100644
index 0000000..7c94911
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/clients-get-client-types-frame.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<script>
+fetch('clientId')
+  .then(function(response) {
+      return response.text();
+    })
+  .then(function(text) {
+      parent.postMessage({clientId: text}, '*');
+    });
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/clients-get-client-types-shared-worker.js b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/clients-get-client-types-shared-worker.js
new file mode 100644
index 0000000..fadef97
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/clients-get-client-types-shared-worker.js
@@ -0,0 +1,10 @@
+onconnect = function(e) {
+  var port = e.ports[0];
+  fetch('clientId')
+    .then(function(response) {
+        return response.text();
+      })
+    .then(function(text) {
+        port.postMessage({clientId: text});
+      });
+};
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/clients-get-worker.js b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/clients-get-worker.js
index 0b99798..4705e35 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/clients-get-worker.js
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/clients-get-worker.js
@@ -1,5 +1,6 @@
 self.onfetch = function(e) {
-  if (e.request.url.indexOf('clients-get-frame.html') >= 0) {
+  if (e.request.url.indexOf('clients-get-frame.html') >= 0 ||
+      e.request.url.indexOf('clients-get-client-types') >= 0) {
     // On navigation, the client id should be null.
     if (e.clientId === null) {
       e.respondWith(fetch(e.request));
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index c3b6026..4ff27470d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -471,7 +471,7 @@
     getter action
     getter notification
     method constructor
-interface OffScreenCanvas
+interface OffscreenCanvasTemp
     getter height
     getter width
     method constructor
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodes-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodes-expected.txt
index 00ae81b..cba0b83 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodes-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodes-expected.txt
@@ -225,43 +225,20 @@
   "result": {
     "accessibilityNode": {
       "nodeId": "<string>",
-      "ignored": false,
+      "ignored": true,
       "role": {
         "type": "role",
         "value": "img"
       },
-      "properties": [],
-      "name": {
-        "type": "computedString",
-        "value": "",
-        "sources": [
-          {
-            "type": "relatedElement",
-            "attribute": "aria-labelledby"
-          },
-          {
-            "type": "attribute",
-            "attribute": "aria-label"
-          },
-          {
-            "type": "attribute",
-            "attributeValue": {
-              "type": "string",
-              "value": ""
-            },
-            "value": {
-              "type": "computedString",
-              "value": ""
-            },
-            "attribute": "alt"
-          },
-          {
-            "type": "attribute",
-            "attribute": "title",
-            "superseded": true
+      "ignoredReasons": [
+        {
+          "name": "emptyAlt",
+          "value": {
+            "type": "boolean",
+            "value": true
           }
-        ]
-      }
+        }
+      ]
     }
   }
 }
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodes.html b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodes.html
index 6eefb66..3b72df7 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodes.html
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/accessibility/accessibility-ignoredNodes.html
@@ -33,10 +33,6 @@
     <div id="_6" aria-hidden="true">
         <div id="_7">Descendant of aria-hidden node</div>
     </div>
-<!-- Known failure: image isn't ignored due to:
-    if (m_layoutObject->isLayoutBlockFlow() && m_layoutObject->childrenInline() && !canSetFocusAttribute()) {
-        if (toLayoutBlockFlow(m_layoutObject)->firstLineBox() || mouseButtonListener()) {
--->
     <img id="_8" alt="" src="foo.png">
     <ol role="none" id="_9"><!-- list is presentational -->
       <li id="_10">List item also presentational</li>
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/segmented-range-expected.txt b/third_party/WebKit/LayoutTests/inspector/components/segmented-range-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/inspector/tracing/segmented-range-expected.txt
rename to third_party/WebKit/LayoutTests/inspector/components/segmented-range-expected.txt
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/segmented-range.html b/third_party/WebKit/LayoutTests/inspector/components/segmented-range.html
similarity index 86%
rename from third_party/WebKit/LayoutTests/inspector/tracing/segmented-range.html
rename to third_party/WebKit/LayoutTests/inspector/components/segmented-range.html
index 383d299e..a60cd86 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/segmented-range.html
+++ b/third_party/WebKit/LayoutTests/inspector/components/segmented-range.html
@@ -9,14 +9,14 @@
     {
         InspectorTest.addResult("Test case: " + testName);
         InspectorTest.addResult("Input Segments: " + JSON.stringify(data));
-        var range = WebInspector.SegmentedRange(merge);
+        var range = SegmentedRange(merge);
 
-        var forwardRange = new WebInspector.SegmentedRange(merge);
-        data.map(entry => new WebInspector.Segment(entry[0], entry[1], entry[2])).forEach(forwardRange.append, forwardRange);
+        var forwardRange = new SegmentedRange(merge);
+        data.map(entry => new Segment(entry[0], entry[1], entry[2])).forEach(forwardRange.append, forwardRange);
         var forward = forwardRange.segments();
 
-        var backwardRange = new WebInspector.SegmentedRange(merge);
-        data.reverse().map(entry => new WebInspector.Segment(entry[0], entry[1], entry[2])).forEach(backwardRange.append, backwardRange);
+        var backwardRange = new SegmentedRange(merge);
+        data.reverse().map(entry => new Segment(entry[0], entry[1], entry[2])).forEach(backwardRange.append, backwardRange);
         var backward = backwardRange.segments();
 
         // Only do reverse if we merge, otherwise result is order-dependent.
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-formatting-expected.txt b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-formatting-expected.txt
index 70fa64a8..50bea70 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-formatting-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-formatting-expected.txt
@@ -11,7 +11,7 @@
     /* leading comment */
     firstProperty: rgba(1, 2, 3, 0);
     color: red;   /* comment1 */
-    margin: 0;/* comment2 */ /* like: property */
+    zoom: 1;/* comment2 */ /* like: property */
     padding: 0;
 }
 
@@ -20,7 +20,7 @@
 {
     /* leading comment */
     color: red;   /* comment1 */
-    margin: 0;/* comment2 */ /* like: property */
+    zoom: 1;/* comment2 */ /* like: property */
     padding: 0;
 }
 
@@ -30,7 +30,7 @@
     /* leading comment */
     color: red;   /* comment1 */
     middleProperty: middleValue /* comment */;
-    margin: 0;/* comment2 */ /* like: property */
+    zoom: 1;/* comment2 */ /* like: property */
     padding: 0;
 }
 
@@ -39,7 +39,7 @@
 {
     /* leading comment */
     color: red;   /* comment1 */
-    margin: 0;/* comment2 */ /* like: property */
+    zoom: 1;/* comment2 */ /* like: property */
     padding: 0;
 }
 
@@ -48,7 +48,7 @@
 {
     /* leading comment */
     color: red;   /* comment1 */
-    margin: 0;/* comment2 */ /* like: property */
+    zoom: 1;/* comment2 */ /* like: property */
     padding: 0;
     endProperty: endValue;
 }
@@ -58,7 +58,7 @@
 {
     /* leading comment */
     color: red;   /* comment1 */
-    margin: 0;/* comment2 */ /* like: property */
+    zoom: 1;/* comment2 */ /* like: property */
     padding: 0;
 }
 
@@ -67,7 +67,7 @@
 {
     /* leading comment */
     /* color: red; */   /* comment1 */
-    margin: 0;/* comment2 */ /* like: property */
+    zoom: 1;/* comment2 */ /* like: property */
     padding: 0;
 }
 
@@ -76,7 +76,7 @@
 {
     /* leading comment */
     /* color: red; */   /* comment1 */
-    margin: 0;/* comment2 */ /* like: property */
+    zoom: 1;/* comment2 */ /* like: property */
     /* padding: 0; */
 }
 
@@ -85,7 +85,7 @@
 {
     /* leading comment */
     /* color: red; */   /* comment1 */
-    /* margin: 0; *//* comment2 */ /* like: property */
+    /* zoom: 1; *//* comment2 */ /* like: property */
     /* padding: 0; */
 }
 
@@ -95,7 +95,7 @@
     /* leading comment */
     propA: valA;
     /* color: red; */   /* comment1 */
-    /* margin: 0; *//* comment2 */ /* like: property */
+    /* zoom: 1; *//* comment2 */ /* like: property */
     /* padding: 0; */
 }
 
@@ -106,7 +106,7 @@
     propA: valA;
     /* color: red; */   /* comment1 */
     propB: valB;
-    /* margin: 0; *//* comment2 */ /* like: property */
+    /* zoom: 1; *//* comment2 */ /* like: property */
     /* padding: 0; */
 }
 
@@ -117,7 +117,7 @@
     propA: valA;
     /* color: red; */   /* comment1 */
     propB: valB;
-    /* margin: 0; *//* comment2 */ /* like: property */
+    /* zoom: 1; *//* comment2 */ /* like: property */
     /* padding: 0; */
     propC: valC;
 }
@@ -129,7 +129,7 @@
     propA: valA;
     color: red;   /* comment1 */
     propB: valB;
-    /* margin: 0; *//* comment2 */ /* like: property */
+    /* zoom: 1; *//* comment2 */ /* like: property */
     /* padding: 0; */
     propC: valC;
 }
@@ -141,7 +141,7 @@
     propA: valA;
     color: red;   /* comment1 */
     propB: valB;
-    /* margin: 0; *//* comment2 */ /* like: property */
+    /* zoom: 1; *//* comment2 */ /* like: property */
     padding: 0;
     propC: valC;
 }
@@ -153,7 +153,7 @@
     propA: valA;
     color: red;   /* comment1 */
     propB: valB;
-    margin: 0;/* comment2 */ /* like: property */
+    zoom: 1;/* comment2 */ /* like: property */
     padding: 0;
     propC: valC;
 }
@@ -166,7 +166,7 @@
     propA: valA;
     color: red;   /* comment1 */
     propB: valB;
-    margin: 0;/* comment2 */ /* like: property */
+    zoom: 1;/* comment2 */ /* like: property */
     padding: 0;
     propC: valC;
 }
@@ -180,7 +180,7 @@
     propA: valA;
     color: red;   /* comment1 */
     propB: valB;
-    margin: 0;/* comment2 */ /* like: property */
+    zoom: 1;/* comment2 */ /* like: property */
     padding: 0;
     propC: valC;
 }
@@ -195,7 +195,7 @@
     propA: valA;
     color: red;   /* comment1 */
     propB: valB;
-    margin: 0;/* comment2 */ /* like: property */
+    zoom: 1;/* comment2 */ /* like: property */
     padding: 0;
     propC: valC;
 }
@@ -204,49 +204,49 @@
 
 Running: testUnformattedInsertStart
 raw cssText:
-{/*leading comment*/firstProperty: firstValue;color:red;margin:0;padding:0;}
+{/*leading comment*/firstProperty: firstValue;color:red;zoom:1;padding:0;}
 
 Running: testUnformattedRemoveStart
 raw cssText:
-{/*leading comment*/color:red;margin:0;padding:0;}
+{/*leading comment*/color:red;zoom:1;padding:0;}
 
 Running: testUnformattedInsertMiddle
 raw cssText:
-{/*leading comment*/color:red;middleProperty: middleValue;margin:0;padding:0;}
+{/*leading comment*/color:red;middleProperty: middleValue;zoom:1;padding:0;}
 
 Running: testUnformattedRemoveMiddle
 raw cssText:
-{/*leading comment*/color:red;margin:0;padding:0;}
+{/*leading comment*/color:red;zoom:1;padding:0;}
 
 Running: testUnformattedInsertEnd
 raw cssText:
-{/*leading comment*/color:red;margin:0;padding:0;endProperty: endValue;}
+{/*leading comment*/color:red;zoom:1;padding:0;endProperty: endValue;}
 
 Running: testUnformattedRemoveEnd
 raw cssText:
-{/*leading comment*/color:red;margin:0;padding:0;}
+{/*leading comment*/color:red;zoom:1;padding:0;}
 
 Running: testUnformattedDisableStart
 raw cssText:
-{/*leading comment*//* color:red; */margin:0;padding:0;}
+{/*leading comment*//* color:red; */zoom:1;padding:0;}
 
 Running: testUnformattedDisableEnd
 raw cssText:
-{/*leading comment*//* color:red; */margin:0;/* padding:0; */}
+{/*leading comment*//* color:red; */zoom:1;/* padding:0; */}
 
 Running: testUnformattedDisableMiddle
 raw cssText:
-{/*leading comment*//* color:red; *//* margin:0; *//* padding:0; */}
+{/*leading comment*//* color:red; *//* zoom:1; *//* padding:0; */}
 
 Running: testUnformattedEnableStart
 raw cssText:
-{/*leading comment*/color:red;/* margin:0; *//* padding:0; */}
+{/*leading comment*/color:red;/* zoom:1; *//* padding:0; */}
 
 Running: testUnformattedEnableEnd
 raw cssText:
-{/*leading comment*/color:red;/* margin:0; */padding:0;}
+{/*leading comment*/color:red;/* zoom:1; */padding:0;}
 
 Running: testUnformattedEnableMiddle
 raw cssText:
-{/*leading comment*/color:red;margin:0;padding:0;}
+{/*leading comment*/color:red;zoom:1;padding:0;}
 
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-formatting.html b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-formatting.html
index 3e0e4bc..0ac8156 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-formatting.html
+++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-formatting.html
@@ -265,11 +265,11 @@
 #formatted {
     /* leading comment */
     color: red;   /* comment1 */
-    margin: 0;/* comment2 */ /* like: property */
+    zoom: 1;/* comment2 */ /* like: property */
     padding: 0
 }
 
-#unformatted {/*leading comment*/color:red;margin:0;padding:0;}
+#unformatted {/*leading comment*/color:red;zoom:1;padding:0;}
 
 </style>
 </head>
diff --git a/third_party/WebKit/LayoutTests/inspector/sass/resources/test-edit-set-text.css b/third_party/WebKit/LayoutTests/inspector/sass/resources/test-edit-set-text.css
new file mode 100644
index 0000000..c6d1259
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/sass/resources/test-edit-set-text.css
@@ -0,0 +1,16 @@
+.box1 {
+  color: red;
+  margin: 10px; }
+
+.box2 {
+  color: red;
+  margin: 10px; }
+
+.box3 {
+  color: red;
+  margin: 10px; }
+
+body {
+  font-family: "arial"; }
+
+/*# sourceMappingURL=test-edit-set-text.css.map */
diff --git a/third_party/WebKit/LayoutTests/inspector/sass/resources/test-edit-set-text.css.map b/third_party/WebKit/LayoutTests/inspector/sass/resources/test-edit-set-text.css.map
new file mode 100644
index 0000000..b201c98
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/sass/resources/test-edit-set-text.css.map
@@ -0,0 +1,7 @@
+{
+"version": 3,
+"mappings": "AAGI,KAAU;EACN,KAAK,EAJL,GAAG;EAKH,MAAM,EAAE,IAAI;;AAFhB,KAAU;EACN,KAAK,EAJL,GAAG;EAKH,MAAM,EAAE,IAAI;;AAFhB,KAAU;EACN,KAAK,EAJL,GAAG;EAKH,MAAM,EAAE,IAAI;;AAIpB,IAAK;EACD,WAAW,EAAE,OAAO",
+"sources": ["test-edit-set-text.scss"],
+"names": [],
+"file": "test-edit-set-text.css"
+}
diff --git a/third_party/WebKit/LayoutTests/inspector/sass/resources/test-edit-set-text.scss b/third_party/WebKit/LayoutTests/inspector/sass/resources/test-edit-set-text.scss
new file mode 100644
index 0000000..1ee139ed
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/sass/resources/test-edit-set-text.scss
@@ -0,0 +1,12 @@
+$color: red;
+
+@for $i from 1 through 3 {
+    .box#{$i} {
+        color: $color;
+        margin: 10px;
+    }
+}
+
+body {
+    font-family: "arial";
+}
diff --git a/third_party/WebKit/LayoutTests/inspector/sass/sass-test.js b/third_party/WebKit/LayoutTests/inspector/sass/sass-test.js
index a98f1ec4..a9d502c 100644
--- a/third_party/WebKit/LayoutTests/inspector/sass/sass-test.js
+++ b/third_party/WebKit/LayoutTests/inspector/sass/sass-test.js
@@ -29,7 +29,6 @@
 
 InspectorTest.loadASTMapping = function(header, callback)
 {
-
     var completeSourceMapURL = WebInspector.ParsedURL.completeURL(header.sourceURL, header.sourceMapURL);
     WebInspector.SourceMap.load(completeSourceMapURL, header.sourceURL, onSourceMapLoaded);
 
@@ -210,5 +209,107 @@
     uiSourceCode.addRevision(newText);
 }
 
+InspectorTest.runCSSEditTests = function(header, tests)
+{
+    var astSourceMap;
+    var astService = new WebInspector.ASTService();
+    InspectorTest.loadASTMapping(header, onMapping);
+
+    function onMapping(map)
+    {
+        astSourceMap = map;
+        InspectorTest.addResult("INITIAL MODELS");
+        logASTText(map.cssAST(), true);
+        for (var ast of map.sassModels().values())
+            logASTText(ast, true);
+        runTests();
+    }
+
+    function runTests()
+    {
+        if (!tests.length) {
+            InspectorTest.completeTest();
+            astService.dispose();
+            return;
+        }
+        var test = tests.shift();
+        logTestName(test.name);
+        var text = astSourceMap.cssAST().document.text;
+        var edits = test(text);
+        logSourceEdits(text, edits);
+        var ranges = edits.map(edit => edit.oldRange);
+        var texts = edits.map(edit => edit.newText);
+        WebInspector.SASSProcessor.processCSSEdits(astService, astSourceMap, ranges, texts)
+            .then(onEditsDone);
+    }
+
+    function onEditsDone(result)
+    {
+        if (!result.map) {
+            InspectorTest.addResult("SASSProcessor failed to process edits.");
+            runTests();
+            return;
+        }
+        logASTText(result.map.cssAST());
+        for (var sassURL of result.newSASSSources.keys()) {
+            var ast = result.map.sassModels().get(sassURL);
+            logASTText(ast);
+        }
+        runTests();
+    }
+
+    function logASTText(ast, avoidIndent, customTitle)
+    {
+        customTitle = customTitle || ast.document.url.split("/").pop();
+        InspectorTest.addResult("===== " + customTitle + " =====");
+        var text = ast.document.text.replace(/ /g, ".");
+        var lines = text.split("\n");
+        if (!avoidIndent)
+            lines = indent(lines);
+        InspectorTest.addResult(lines.join("\n"));
+    }
+
+    function logTestName(testName)
+    {
+        var titleText = " TEST: " + testName + " ";
+        var totalLength = 80;
+        var prefixLength = ((totalLength - titleText.length) / 2)|0;
+        var suffixLength = totalLength - titleText.length - prefixLength;
+        var prefix = new Array(prefixLength).join("-");
+        var suffix = new Array(suffixLength).join("-");
+        InspectorTest.addResult("\n" + prefix + titleText + suffix + "\n");
+    }
+
+    function logSourceEdits(text, edits)
+    {
+        var lines = [];
+        for (var i = 0; i < edits.length; ++i) {
+            var edit = edits[i];
+            var range = edit.oldRange;
+            var line = String.sprintf("{%d, %d, %d, %d}", range.startLine, range.startColumn, range.endLine, range.endColumn);
+            line += String.sprintf(" '%s' => '%s'", range.extract(text), edit.newText);
+            lines.push(line);
+        }
+        lines = indent(lines);
+        lines.unshift("Edits:");
+        InspectorTest.addResult(lines.join("\n"));
+    }
+}
+
+InspectorTest.createEdit = function(source, pattern, newText, matchNumber)
+{
+    matchNumber = matchNumber || 0;
+    var re = new RegExp(pattern.escapeForRegExp(), "g");
+    var match;
+    while ((match = re.exec(source)) !== null && matchNumber) {
+        --matchNumber;
+    }
+    if (!match)
+        return null;
+    var sourceRange = new WebInspector.SourceRange(match.index, match[0].length);
+    var textRange = sourceRange.toTextRange(source);
+    return new WebInspector.SourceEdit("", textRange, newText);
+}
+
 }
 
diff --git a/third_party/WebKit/LayoutTests/inspector/sass/test-edit-set-property-text-expected.txt b/third_party/WebKit/LayoutTests/inspector/sass/test-edit-set-property-text-expected.txt
new file mode 100644
index 0000000..5b74cf9b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/sass/test-edit-set-property-text-expected.txt
@@ -0,0 +1,227 @@
+Verify that mapping is not valid for misaligned sources.
+
+INITIAL MODELS
+===== test-edit-set-text.css =====
+.box1.{
+..color:.red;
+..margin:.10px;.}
+
+.box2.{
+..color:.red;
+..margin:.10px;.}
+
+.box3.{
+..color:.red;
+..margin:.10px;.}
+
+body.{
+..font-family:."arial";.}
+
+/*#.sourceMappingURL=test-edit-set-text.css.map.*/
+
+===== test-edit-set-text.scss =====
+$color:.red;
+
+@for.$i.from.1.through.3.{
+.....box#{$i}.{
+........color:.$color;
+........margin:.10px;
+....}
+}
+
+body.{
+....font-family:."arial";
+}
+
+
+------------------------- TEST: testEditPropertyName -------------------------
+
+Edits:
+    {1, 2, 1, 7} 'color' => 'border'
+===== test-edit-set-text.css =====
+    .box1.{
+    ..border:.red;
+    ..margin:.10px;.}
+    
+    .box2.{
+    ..border:.red;
+    ..margin:.10px;.}
+    
+    .box3.{
+    ..border:.red;
+    ..margin:.10px;.}
+    
+    body.{
+    ..font-family:."arial";.}
+    
+    /*#.sourceMappingURL=test-edit-set-text.css.map.*/
+    
+===== test-edit-set-text.scss =====
+    $color:.red;
+    
+    @for.$i.from.1.through.3.{
+    .....box#{$i}.{
+    ........border:.$color;
+    ........margin:.10px;
+    ....}
+    }
+    
+    body.{
+    ....font-family:."arial";
+    }
+    
+
+------------------------ TEST: testEditPropertyValue -------------------------
+
+Edits:
+    {1, 9, 1, 12} 'red' => 'blue'
+===== test-edit-set-text.css =====
+    .box1.{
+    ..color:.blue;
+    ..margin:.10px;.}
+    
+    .box2.{
+    ..color:.blue;
+    ..margin:.10px;.}
+    
+    .box3.{
+    ..color:.blue;
+    ..margin:.10px;.}
+    
+    body.{
+    ..font-family:."arial";.}
+    
+    /*#.sourceMappingURL=test-edit-set-text.css.map.*/
+    
+===== test-edit-set-text.scss =====
+    $color:.blue;
+    
+    @for.$i.from.1.through.3.{
+    .....box#{$i}.{
+    ........color:.$color;
+    ........margin:.10px;
+    ....}
+    }
+    
+    body.{
+    ....font-family:."arial";
+    }
+    
+
+------------------------ TEST: testEditPropertyNames -------------------------
+
+Edits:
+    {1, 2, 1, 7} 'color' => 'border'
+    {5, 2, 5, 7} 'color' => 'border'
+    {9, 2, 9, 7} 'color' => 'border'
+===== test-edit-set-text.css =====
+    .box1.{
+    ..border:.red;
+    ..margin:.10px;.}
+    
+    .box2.{
+    ..border:.red;
+    ..margin:.10px;.}
+    
+    .box3.{
+    ..border:.red;
+    ..margin:.10px;.}
+    
+    body.{
+    ..font-family:."arial";.}
+    
+    /*#.sourceMappingURL=test-edit-set-text.css.map.*/
+    
+===== test-edit-set-text.scss =====
+    $color:.red;
+    
+    @for.$i.from.1.through.3.{
+    .....box#{$i}.{
+    ........border:.$color;
+    ........margin:.10px;
+    ....}
+    }
+    
+    body.{
+    ....font-family:."arial";
+    }
+    
+
+------------------------ TEST: testEditPropertyValues ------------------------
+
+Edits:
+    {1, 9, 1, 12} 'red' => 'blue'
+    {5, 9, 5, 12} 'red' => 'blue'
+    {9, 9, 9, 12} 'red' => 'blue'
+===== test-edit-set-text.css =====
+    .box1.{
+    ..color:.blue;
+    ..margin:.10px;.}
+    
+    .box2.{
+    ..color:.blue;
+    ..margin:.10px;.}
+    
+    .box3.{
+    ..color:.blue;
+    ..margin:.10px;.}
+    
+    body.{
+    ..font-family:."arial";.}
+    
+    /*#.sourceMappingURL=test-edit-set-text.css.map.*/
+    
+===== test-edit-set-text.scss =====
+    $color:.blue;
+    
+    @for.$i.from.1.through.3.{
+    .....box#{$i}.{
+    ........color:.$color;
+    ........margin:.10px;
+    ....}
+    }
+    
+    body.{
+    ....font-family:."arial";
+    }
+    
+
+------------------------- TEST: testConflictingEdits -------------------------
+
+Edits:
+    {1, 9, 1, 12} 'red' => 'green'
+    {5, 9, 5, 12} 'red' => 'magenta'
+    {9, 9, 9, 12} 'red' => 'yellow'
+===== test-edit-set-text.css =====
+    .box1.{
+    ..color:.green;
+    ..margin:.10px;.}
+    
+    .box2.{
+    ..color:.green;
+    ..margin:.10px;.}
+    
+    .box3.{
+    ..color:.green;
+    ..margin:.10px;.}
+    
+    body.{
+    ..font-family:."arial";.}
+    
+    /*#.sourceMappingURL=test-edit-set-text.css.map.*/
+    
+===== test-edit-set-text.scss =====
+    $color:.green;
+    
+    @for.$i.from.1.through.3.{
+    .....box#{$i}.{
+    ........color:.$color;
+    ........margin:.10px;
+    ....}
+    }
+    
+    body.{
+    ....font-family:."arial";
+    }
+    
+
diff --git a/third_party/WebKit/LayoutTests/inspector/sass/test-edit-set-property-text.html b/third_party/WebKit/LayoutTests/inspector/sass/test-edit-set-property-text.html
new file mode 100644
index 0000000..0f0cc785
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/sass/test-edit-set-property-text.html
@@ -0,0 +1,66 @@
+<html>
+<head>
+
+<link rel="stylesheet" href="resources/test-edit-set-text.css">
+
+<script src="../../http/tests/inspector/inspector-test.js"></script>
+<script src="../../http/tests/inspector/debugger-test.js"></script>
+<script src="./sass-test.js"></script>
+<script>
+
+function test()
+{
+    var header = InspectorTest.cssModel.styleSheetHeaders().find(header => !!header.sourceMapURL)
+
+    InspectorTest.runCSSEditTests(header, [
+        function testEditPropertyName(text)
+        {
+            return [
+                InspectorTest.createEdit(text, "color", "border")
+            ];
+        },
+
+        function testEditPropertyValue(text)
+        {
+            return [
+                InspectorTest.createEdit(text, "red", "blue")
+            ];
+        },
+
+        function testEditPropertyNames(text)
+        {
+            return [
+                InspectorTest.createEdit(text, "color", "border", 0),
+                InspectorTest.createEdit(text, "color", "border", 1),
+                InspectorTest.createEdit(text, "color", "border", 2),
+            ];
+        },
+
+        function testEditPropertyValues(text)
+        {
+            return [
+                InspectorTest.createEdit(text, "red", "blue", 0),
+                InspectorTest.createEdit(text, "red", "blue", 1),
+                InspectorTest.createEdit(text, "red", "blue", 2)
+            ];
+        },
+
+        function testConflictingEdits(text)
+        {
+            return [
+                InspectorTest.createEdit(text, "red", "green", 0),
+                InspectorTest.createEdit(text, "red", "magenta", 1),
+                InspectorTest.createEdit(text, "red", "yellow", 2)
+            ];
+        },
+    ]);
+}
+
+</script>
+
+</head>
+
+<body onload="runTest()">
+<p>Verify that mapping is not valid for misaligned sources.</p>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/inspector/sass/test-mapping-good-expected.txt b/third_party/WebKit/LayoutTests/inspector/sass/test-mapping-good-expected.txt
index 0015063d2..fb8076e 100644
--- a/third_party/WebKit/LayoutTests/inspector/sass/test-mapping-good-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sass/test-mapping-good-expected.txt
@@ -4,13 +4,8 @@
 Mapped SCSS: 12
 No stale entries found.
 
-Running: testCSSRebase
-Mapped CSS: 10
-Mapped SCSS: 10
-No stale entries found.
-
-Running: testSCSSRebase
-Mapped CSS: 8
-Mapped SCSS: 8
+Running: testRebase
+Mapped CSS: 12
+Mapped SCSS: 12
 No stale entries found.
 
diff --git a/third_party/WebKit/LayoutTests/inspector/sass/test-mapping-good.html b/third_party/WebKit/LayoutTests/inspector/sass/test-mapping-good.html
index 44b6401..2726cdab 100644
--- a/third_party/WebKit/LayoutTests/inspector/sass/test-mapping-good.html
+++ b/third_party/WebKit/LayoutTests/inspector/sass/test-mapping-good.html
@@ -28,29 +28,12 @@
     }
 
     var testSuite = [
-        function testCSSRebase(next)
+        function testRebase(next)
         {
             var cssClone = mapping.cssAST().clone();
-            cssClone.rules[0].properties[1].remove();
-            var cssDiff = WebInspector.SASSSupport.diffModels(mapping.cssAST(), cssClone);
-            var newMapping = mapping.rebaseForCSSDiff(cssDiff);
-            if (!newMapping.isValid()) {
-                InspectorTest.addResult("ERROR: mapping is not valid.");
-                InspectorTest.completeTest();
-                return;
-            }
-            InspectorTest.validateMapping(newMapping);
-            next();
-        },
-
-        function testSCSSRebase(next)
-        {
             var sassAST = mapping.sassModels().valuesArray()[0];
             var sassClone = sassAST.clone();
-            sassClone.rules[1].properties[2].remove();
-            sassClone.rules[1].properties[1].remove();
-            var sassDiff = WebInspector.SASSSupport.diffModels(sassAST, sassClone);
-            var newMapping = mapping.rebaseForSASSDiff(sassDiff);
+            var newMapping = mapping.rebase([cssClone, sassClone]);
             if (!newMapping.isValid()) {
                 InspectorTest.addResult("ERROR: mapping is not valid.");
                 InspectorTest.completeTest();
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/invalidation-after-opacity-change-subtree-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/invalidation-after-opacity-change-subtree-expected.txt
index a979ce1..b60ebcd 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/invalidation-after-opacity-change-subtree-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/repaint/invalidation-after-opacity-change-subtree-expected.txt
@@ -7,8 +7,12 @@
       "drawsContent": true,
       "repaintRects": [
         [8, 2196, 777, 107],
+        [8, 2196, 777, 107],
+        [8, 2196, 639, 107],
         [8, 2196, 639, 107],
         [8, 2046, 777, 107],
+        [8, 2046, 777, 107],
+        [8, 2046, 768, 107],
         [8, 2046, 768, 107],
         [8, 2000, 777, 350],
         [8, 2000, 777, 350]
@@ -25,7 +29,17 @@
         "InlineTextBox 'This text should be visible in the'",
         "InlineTextBox 'output.'",
         "LayoutBlockFlow DIV id='container'",
-        "LayoutBlockFlow (positioned) DIV id='absolute'"
+        "LayoutBlockFlow (positioned) DIV id='absolute'",
+        "LayoutBlockFlow P",
+        "RootInlineBox",
+        "LayoutText #text",
+        "InlineTextBox 'This test checks that switching opacity'",
+        "InlineTextBox 'invalidates the full subtree.'",
+        "LayoutBlockFlow P",
+        "RootInlineBox",
+        "LayoutText #text",
+        "InlineTextBox 'This text should be visible in the'",
+        "InlineTextBox 'output.'"
       ]
     }
   ]
diff --git a/third_party/WebKit/LayoutTests/platform/win/inspector-protocol/layout-fonts/ogham-expected.txt b/third_party/WebKit/LayoutTests/platform/win/inspector-protocol/layout-fonts/ogham-expected.txt
index a371847..b82ad05 100644
--- a/third_party/WebKit/LayoutTests/platform/win/inspector-protocol/layout-fonts/ogham-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/inspector-protocol/layout-fonts/ogham-expected.txt
@@ -1,9 +1,9 @@
  ᚁᚂᚃᚄᚅᚆᚇᚈᚉᚊᚋᚌᚍᚎᚏᚐᚑᚒᚓᚔᚕᚖᚗᚘᚙᚚ᚛᚜
 #oghammonofont:
-"Arial" : 29
+"Segoe UI Historic" : 29
 
  ᚁᚂᚃᚄᚅᚆᚇᚈᚉᚊᚋᚌᚍᚎᚏᚐᚑᚒᚓᚔᚕᚖᚗᚘᚙᚚ᚛᚜
 #oghamdefaultfont:
-"Arial" : 29
+"Segoe UI Historic" : 29
 
 There should be two lines of Ogham above.
diff --git a/third_party/WebKit/LayoutTests/resources/check-layout-th.js b/third_party/WebKit/LayoutTests/resources/check-layout-th.js
index 07f7d5d..3f257d4a 100644
--- a/third_party/WebKit/LayoutTests/resources/check-layout-th.js
+++ b/third_party/WebKit/LayoutTests/resources/check-layout-th.js
@@ -69,6 +69,11 @@
         assert_tolerance(node.scrollHeight, expectedHeight, prefix + "scrollHeight");
     }
 
+    var expectedWidth = checkAttribute(output, node, "data-expected-bounding-client-rect-width");
+    if (expectedWidth) {
+        assert_tolerance(node.getBoundingClientRect().width, expectedWidth, prefix + "getBoundingClientRect().width");
+    }
+
     var expectedOffset = checkAttribute(output, node, "data-total-x");
     if (expectedOffset) {
         var totalLeft = node.clientLeft + node.offsetLeft;
diff --git a/third_party/WebKit/LayoutTests/resources/check-layout.js b/third_party/WebKit/LayoutTests/resources/check-layout.js
index 0d617bea..3c701c92 100644
--- a/third_party/WebKit/LayoutTests/resources/check-layout.js
+++ b/third_party/WebKit/LayoutTests/resources/check-layout.js
@@ -16,6 +16,14 @@
         referenceNode.parentNode.appendChild(nodeToAdd);
 }
 
+function positionedAncestor(node)
+{
+    var ancestor = node.parentNode;
+    while (getComputedStyle(ancestor).position == 'static')
+        ancestor = ancestor.parentNode;
+    return ancestor;
+}
+
 function checkSubtreeExpectedValues(parent, failures)
 {
     var checkedLayout = checkExpectedValues(parent, failures);
@@ -59,6 +67,20 @@
             failures.push("Expected " + expectedOffset + " for offsetTop, but got " + node.offsetTop + ". ");
     }
 
+    var expectedOffset = checkAttribute(output, node, "data-positioned-offset-x");
+    if (expectedOffset) {
+        var actualOffset = node.getBoundingClientRect().left - positionedAncestor(node).getBoundingClientRect().left;
+        if (isNaN(expectedOffset) || Math.abs(actualOffset - expectedOffset) >= 1)
+            failures.push("Expected " + expectedOffset + " for getBoundingClientRect().left offset, but got " + actualOffset + ". ");
+    }
+
+    var expectedOffset = checkAttribute(output, node, "data-positioned-offset-y");
+    if (expectedOffset) {
+        var actualOffset = node.getBoundingClientRect().top - positionedAncestor(node).getBoundingClientRect().top;
+        if (isNaN(expectedOffset) || Math.abs(actualOffset - expectedOffset) >= 1)
+            failures.push("Expected " + expectedOffset + " for getBoundingClientRect().top offset, but got " + actualOffset + ". ");
+    }
+
     var expectedWidth = checkAttribute(output, node, "data-expected-client-width");
     if (expectedWidth) {
         if (isNaN(expectedWidth) || Math.abs(node.clientWidth - expectedWidth) >= 1)
diff --git a/third_party/WebKit/LayoutTests/resources/mojo-helpers.js b/third_party/WebKit/LayoutTests/resources/mojo-helpers.js
index 10350f7f..aca02bc 100644
--- a/third_party/WebKit/LayoutTests/resources/mojo-helpers.js
+++ b/third_party/WebKit/LayoutTests/resources/mojo-helpers.js
@@ -6,15 +6,26 @@
 
 // Fix up the global window.define, since all baked-in Mojo modules expect to
 // find it there. This define() also returns a promise to the module.
-function define(name, deps, factory) {
-  return new Promise(resolve => {
-    mojo.define(name, deps, (...modules) => {
-      let result = factory(...modules);
-      resolve(result);
-      return result;
-    });
-  });
-}
+let define = (function(){
+  let moduleCache = new Map();
+
+  return function(name, deps, factory) {
+    let promise = moduleCache.get(name);
+    if (promise === undefined) {
+      // This promise must be cached as mojo.define will only call the factory
+      // function the first time the module is defined.
+      promise = new Promise(resolve => {
+        mojo.define(name, deps, (...modules) => {
+          let result = factory(...modules);
+          resolve(result);
+          return result;
+        });
+      });
+      moduleCache.set(name, promise);
+    }
+    return promise;
+  }
+})();
 
 // Returns a promise to an object that exposes common Mojo module interfaces.
 // Additional modules to load can be specified in the |modules| parameter. The
diff --git a/third_party/WebKit/LayoutTests/svg/animations/smil-scheduled-in-inactive-document-crash.html b/third_party/WebKit/LayoutTests/svg/animations/smil-scheduled-in-inactive-document-crash.html
index c603a2d1..ed875bf 100644
--- a/third_party/WebKit/LayoutTests/svg/animations/smil-scheduled-in-inactive-document-crash.html
+++ b/third_party/WebKit/LayoutTests/svg/animations/smil-scheduled-in-inactive-document-crash.html
@@ -18,9 +18,10 @@
 svg.pauseAnimations();
 
 setTimeout(function() {
-  eventSender.mouseMoveTo(svg.offsetLeft + 20, svg.offsetTop + 20);
+  var rect = svg.getBoundingClientRect();
+  eventSender.mouseMoveTo(rect.left + 20, rect.top + 20);
   eventSender.mouseDown();
   eventSender.mouseUp();
+  finishJSTest();
 }, 0);
-finishJSTest();
 </script>
diff --git a/third_party/WebKit/LayoutTests/svg/as-iframe/svg-in-iframe.html b/third_party/WebKit/LayoutTests/svg/as-iframe/svg-in-iframe.html
index 5434e579..13da0738 100644
--- a/third_party/WebKit/LayoutTests/svg/as-iframe/svg-in-iframe.html
+++ b/third_party/WebKit/LayoutTests/svg/as-iframe/svg-in-iframe.html
@@ -8,12 +8,14 @@
     t = async_test("Test <iframe> and <svg> size");
     function check() {
         var iframe = document.querySelector('iframe');
+        var iframeRect = iframe.getBoundingClientRect();
         var svg = iframe.contentDocument.documentElement;
+        var svgRect = svg.getBoundingClientRect();
 
-        assert_equals(iframe.offsetWidth, 300, "width should be fallback width.");
-        assert_equals(iframe.offsetHeight, 150, "height should be the fallback height 150.");
-        assert_equals(svg.offsetWidth, svg.width.baseVal.value, "width should be what the <svg> requests.");
-        assert_equals(svg.offsetHeight, svg.height.baseVal.value, "height should be what the <svg> requests.");
+        assert_equals(iframeRect.width, 300, "width should be fallback width.");
+        assert_equals(iframeRect.height, 150, "height should be the fallback height 150.");
+        assert_equals(svgRect.width, svg.width.baseVal.value, "width should be what the <svg> requests.");
+        assert_equals(svgRect.height, svg.height.baseVal.value, "height should be what the <svg> requests.");
 
         t.done();
     }
diff --git a/third_party/WebKit/LayoutTests/svg/custom/animate-reference-crash-expected.txt b/third_party/WebKit/LayoutTests/svg/custom/animate-reference-crash-expected.txt
index bf7f6f5..db9481e 100644
--- a/third_party/WebKit/LayoutTests/svg/custom/animate-reference-crash-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/custom/animate-reference-crash-expected.txt
@@ -1,7 +1,2 @@
-CONSOLE WARNING: 'SVGElement.offsetParent' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
-CONSOLE WARNING: 'SVGElement.offsetTop' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
-CONSOLE WARNING: 'SVGElement.offsetLeft' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
-CONSOLE WARNING: 'SVGElement.offsetWidth' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
-CONSOLE WARNING: 'SVGElement.offsetHeight' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
 CONSOLE WARNING: SVG's SMIL animations (<animate>, <set>, etc.) are deprecated and will be removed. Please use CSS animations or Web animations instead.
 PASS
diff --git a/third_party/WebKit/LayoutTests/svg/custom/animate-svgsvgelement.html b/third_party/WebKit/LayoutTests/svg/custom/animate-svgsvgelement.html
index 6c22767..20d6fd9e 100644
--- a/third_party/WebKit/LayoutTests/svg/custom/animate-svgsvgelement.html
+++ b/third_party/WebKit/LayoutTests/svg/custom/animate-svgsvgelement.html
@@ -7,13 +7,13 @@
     var height_test = async_test("Test height");
     function do_width_test() {
         width_test.step(function() {
-            assert_equals(document.querySelector('svg').offsetWidth, 0, "width should be zero when the animation has ended.");
+            assert_equals(document.querySelector('svg').getBoundingClientRect().width, 0, "width should be zero when the animation has ended.");
         });
         width_test.done();
     }
     function do_height_test() {
         height_test.step(function() {
-            assert_equals(document.querySelector('svg').offsetHeight, 0, "height should be zero when the animation has ended.");
+            assert_equals(document.querySelector('svg').getBoundingClientRect().height, 0, "height should be zero when the animation has ended.");
         });
         height_test.done();
     }
diff --git a/third_party/WebKit/LayoutTests/svg/custom/detached-outermost-svg-crash-expected.txt b/third_party/WebKit/LayoutTests/svg/custom/detached-outermost-svg-crash-expected.txt
index 9204887..4ad3823 100644
--- a/third_party/WebKit/LayoutTests/svg/custom/detached-outermost-svg-crash-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/custom/detached-outermost-svg-crash-expected.txt
@@ -1,6 +1 @@
-CONSOLE WARNING: 'SVGElement.offsetParent' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
-CONSOLE WARNING: 'SVGElement.offsetTop' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
-CONSOLE WARNING: 'SVGElement.offsetLeft' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
-CONSOLE WARNING: 'SVGElement.offsetWidth' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
-CONSOLE WARNING: 'SVGElement.offsetHeight' is deprecated and will be removed in M50, around April 2016. See https://www.chromestatus.com/features/5724912467574784 for more details.
 PASSED -- webkit did not crash in SVGSVGElement::isOutermostSVG(). See https://bugs.webkit.org/show_bug.cgi?id=25105
diff --git a/third_party/WebKit/LayoutTests/svg/custom/size-follows-container-size.html b/third_party/WebKit/LayoutTests/svg/custom/size-follows-container-size.html
index eaa8c0d..3ae86c39 100644
--- a/third_party/WebKit/LayoutTests/svg/custom/size-follows-container-size.html
+++ b/third_party/WebKit/LayoutTests/svg/custom/size-follows-container-size.html
@@ -15,14 +15,16 @@
         requestAnimationFrame(function() {
             document.querySelector('div').style.width = "1000px";
             inc_test.step(function() {
-                assert_equals(document.querySelector('svg').offsetWidth, 1000);
-                assert_equals(document.querySelector('svg').offsetHeight, 1000);
+                var rect = document.querySelector('svg').getBoundingClientRect();
+                assert_equals(rect.width, 1000);
+                assert_equals(rect.height, 1000);
             });
             inc_test.done();
             document.querySelector('div').style.width = "100px";
             dec_test.step(function() {
-                assert_equals(document.querySelector('svg').offsetWidth, 100);
-                assert_equals(document.querySelector('svg').offsetHeight, 100);
+                var rect = document.querySelector('svg').getBoundingClientRect();
+                assert_equals(rect.width, 100);
+                assert_equals(rect.height, 100);
             });
             dec_test.done();
         });
diff --git a/third_party/WebKit/LayoutTests/usb/mock-services.html b/third_party/WebKit/LayoutTests/usb/mock-services.html
new file mode 100644
index 0000000..99a0d87b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/usb/mock-services.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="../resources/mojo-helpers.js"></script>
+<script src="resources/device.mojom.js"></script>
+<script src="resources/device_manager.mojom.js"></script>
+<script src="resources/permission_provider.mojom.js"></script>
+<script src="resources/fake-devices.js"></script>
+<script src="resources/usb-helpers.js"></script>
+<script>
+'use strict';
+
+usb_test(usb => {
+  assert_true(usb instanceof Object);
+  assert_true(usb.DeviceManager instanceof Object);
+  assert_true(usb.Device instanceof Object);
+  assert_true(usb.PermissionProvider instanceof Object);
+  assert_true(usb.mockDeviceManager instanceof Object);
+}, 'USB Mojo bindings and mock interfaces are available to tests.')
+</script>
diff --git a/third_party/WebKit/LayoutTests/usb/resources/fake-devices.js b/third_party/WebKit/LayoutTests/usb/resources/fake-devices.js
new file mode 100644
index 0000000..14d669a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/usb/resources/fake-devices.js
@@ -0,0 +1,107 @@
+'use strict';
+
+function fakeUsbDevices() {
+  return define('Fake USB Devices', [
+    'device/usb/public/interfaces/device.mojom',
+  ], device => Promise.resolve([
+    {
+      guid: 'CD9FA048-FC9B-7A71-DBFC-FD44B78D6397',
+      usb_version_major: 2,
+      usb_version_minor: 0,
+      usb_version_subminor: 0,
+      class_code: 7,
+      subclass_code: 1,
+      protocol_code: 2,
+      vendor_id: 0x18d1,
+      product_id: 0xf00d,
+      device_version_major: 1,
+      device_version_minor: 2,
+      device_version_subminor: 3,
+      manufacturer_name: 'Google, Inc.',
+      product_name: 'The amazing imaginary printer',
+      serial_number: '4',
+      configurations: [
+        {
+          configuration_value: 1,
+          configuration_name: 'Printer Mode',
+          interfaces: [
+            {
+              interface_number: 0,
+              alternates: [
+                {
+                  alternate_setting: 0,
+                  class_code: 0xff,
+                  subclass_code: 0x01,
+                  protocol_code: 0x01,
+                  interface_name: 'Control',
+                  endpoints: []
+                }
+              ]
+            },
+            {
+              interface_number: 1,
+              alternates: [
+                {
+                  alternate_setting: 0,
+                  class_code: 0xff,
+                  subclass_code: 0x02,
+                  protocol_code: 0x01,
+                  interface_name: 'Data',
+                  endpoints: [
+                    {
+                      endpoint_number: 1,
+                      direction: device.TransferDirection.OUTBOUND,
+                      type: device.EndpointType.BULK,
+                      packet_size: 1024
+                    }
+                  ]
+                }
+              ]
+            }
+          ]
+        },
+        {
+          configuration_value: 2,
+          configuration_name: 'Fighting Robot Mode',
+          interfaces: [
+            {
+              interface_number: 0,
+              alternates: [
+                {
+                  alternate_setting: 0,
+                  class_code: 0xff,
+                  subclass_code: 0x42,
+                  protocol_code: 0x01,
+                  interface_name: 'Disabled',
+                  endpoints: []
+                },
+                {
+                  alternate_setting: 1,
+                  class_code: 0xff,
+                  subclass_code: 0x42,
+                  protocol_code: 0x01,
+                  interface_name: 'Activate!',
+                  endpoints: [
+                    {
+                      endpoint_number: 2,
+                      direction: device.TransferDirection.INBOUND,
+                      type: device.EndpointType.ISOCHRONOUS,
+                      packet_size: 1024
+                    },
+                    {
+                      endpoint_number: 2,
+                      direction: device.TransferDirection.OUTBOUND,
+                      type: device.EndpointType.ISOCHRONOUS,
+                      packet_size: 1024
+                    }
+                  ]
+                }
+              ]
+            },
+          ]
+        }
+      ],
+      webusb_allowed_origins: { origins: [], configurations: [] },
+    }
+  ]));
+}
diff --git a/third_party/WebKit/LayoutTests/usb/resources/usb-helpers.js b/third_party/WebKit/LayoutTests/usb/resources/usb-helpers.js
new file mode 100644
index 0000000..bb13aeaf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/usb/resources/usb-helpers.js
@@ -0,0 +1,354 @@
+'use strict';
+
+function usbMocks(mojo) {
+  return define('USB Mocks', [
+    'device/usb/public/interfaces/device_manager.mojom',
+    'device/usb/public/interfaces/device.mojom',
+    'device/usb/public/interfaces/permission_provider.mojom',
+    'content/public/renderer/service_provider',
+  ], (deviceManager, device, permissionProvider) => {
+    function assertDeviceInfoEquals(device, info) {
+      assert_equals(device.guid, info.guid);
+      assert_equals(device.usbVersionMajor, info.usb_version_major);
+      assert_equals(device.usbVersionMinor, info.usb_version_minor);
+      assert_equals(device.usbVersionSubminor, info.usb_version_subminor);
+      assert_equals(device.deviceClass, info.class_code);
+      assert_equals(device.deviceSubclass, info.subclass_code);
+      assert_equals(device.deviceProtocol, info.protocol_code);
+      assert_equals(device.vendorId, info.vendor_id);
+      assert_equals(device.productId, info.product_id);
+      assert_equals(device.deviceVersionMajor, info.device_version_major);
+      assert_equals(device.deviceVersionMinor, info.device_version_minor);
+      assert_equals(device.deviceVersionSubminor,
+                    info.device_version_subminor);
+      assert_equals(device.manufacturerName, info.manufacturer_name);
+      assert_equals(device.productName, info.product_name);
+      assert_equals(device.serialNumber, info.serial_number);
+      assert_equals(device.configurations.length,
+                    info.configurations.length);
+      for (var i = 0; i < device.configurations.length; ++i) {
+        assertConfigurationInfoEquals(device.configurations[i],
+                                      info.configurations[i]);
+      }
+    };
+
+    function assertConfigurationInfoEquals(configuration, info) {
+      assert_equals(configuration.configurationValue,
+                    info.configuration_value);
+      assert_equals(configuration.configurationName,
+                    info.configuration_name);
+      assert_equals(configuration.interfaces.length,
+                    info.interfaces.length);
+      for (var i = 0; i < configuration.interfaces.length; ++i) {
+        assertInterfaceInfoEquals(configuration.interfaces[i],
+                                  info.interfaces[i]);
+      }
+    };
+
+    function assertInterfaceInfoEquals(iface, info) {
+      assert_equals(iface.interfaceNumber, info.interface_number);
+      assert_equals(iface.alternates.length, info.alternates.length);
+      for (var i = 0; i < iface.alternates.length; ++i) {
+        assertAlternateInfoEquals(iface.alternates[i], info.alternates[i]);
+      }
+    };
+
+    function assertAlternateInfoEquals(alternate, info) {
+      assert_equals(alternate.alternateSetting, info.alternate_setting);
+      assert_equals(alternate.interfaceClass, info.class_code);
+      assert_equals(alternate.interfaceSubclass, info.subclass_code);
+      assert_equals(alternate.interfaceProtocol, info.protocol_code);
+      assert_equals(alternate.interfaceName, info.interface_name);
+      assert_equals(alternate.endpoints.length, info.endpoints.length);
+      for (var i = 0; i < alternate.endpoints.length; ++i) {
+        assertEndpointInfoEquals(alternate.endpoints[i], info.endpoints[i]);
+      }
+    }
+
+    function assertEndpointInfoEquals(endpoint, info) {
+      var direction;
+      switch (info.direction) {
+        case device.TransferDirection.INBOUND:
+          direction = "in";
+          break;
+        case device.TransferDirection.OUTBOUND:
+          direction = "out";
+          break;
+      }
+
+      var type;
+      switch (info.type) {
+        case device.EndpointType.BULK:
+          type = "bulk";
+          break;
+        case device.EndpointType.INTERRUPT:
+          type = "interrupt";
+          break;
+        case device.EndpointType.ISOCHRONOUS:
+          type = "isochronous";
+          break;
+      }
+
+      assert_equals(endpoint.endpointNumber, info.endpoint_number);
+      assert_equals(endpoint.direction, direction);
+      assert_equals(endpoint.type, type);
+      assert_equals(endpoint.packetSize, info.packet_size);
+    }
+
+    class MockDevice extends device.Device.stubClass {
+      constructor(info, pipe) {
+        super();
+        this.info_ = info;
+        this.pipe_ = pipe;
+        this.router_ = new mojo.router.Router(pipe);
+        this.router_.setIncomingReceiver(this);
+        this.opened_ = false;
+        this.currentConfiguration_ = undefined;
+        this.claimedInterfaces_ = new Map();
+      }
+
+      getDeviceInfo() {
+        return Promise.resolve({ info: this.info_ });
+      }
+
+      getConfiguration() {
+        if (this.currentConfiguration_ === undefined) {
+          return Promise.resolve({ value: 0 });
+        } else {
+          return Promise.resolve({
+              value: this.currentConfiguration_.configuration_value });
+        }
+      }
+
+      open() {
+        // TODO(reillyg): Check if the device is opened and return
+        // OpenDeviceError.ALREADY_OPEN.
+        this.opened_ = true;
+        return Promise.resolve({ error: device.OpenDeviceError.OK });
+      }
+
+      close() {
+        this.opened_ = false;
+        return Promise.resolve({});
+      }
+
+      setConfiguration(value) {
+        if (!this.opened_)
+          return Promise.resolve({ success: false });
+
+        let selected_configuration = this.info_.configurations.find(
+            configuration => configuration.configuration_value == value);
+        if (selected_configuration !== undefined) {
+          this.currentConfiguration_ = selected_configuration;
+          return Promise.resolve({ success: true });
+        } else {
+          return Promise.resolve({ success: false });
+        }
+      }
+
+      claimInterface(interfaceNumber) {
+        if (!this.opened_)
+          return Promise.resolve({ success: false });
+
+        if (this.currentConfiguration_ === undefined)
+          return Promise.resolve({ success: false });
+
+        if (this.claimedInterfaces_.has(interfaceNumber))
+          return Promise.resolve({ success: false });
+
+        if (this.currentConfiguration_.interfaces.some(
+                iface => iface.interface_number == interfaceNumber)) {
+          this.claimedInterfaces_.set(interfaceNumber, 0);
+          return Promise.resolve({ success: true });
+        } else {
+          return Promise.resolve({ success: false });
+        }
+      }
+
+      releaseInterface(interfaceNumber) {
+        if (!this.opened_)
+          return Promise.resolve({ success: false });
+
+        if (this.currentConfiguration_ === undefined)
+          return Promise.resolve({ success: false });
+
+        if (this.claimedInterfaces_.has(interfaceNumber)) {
+          this.claimedInterfaces_.delete(interfaceNumber);
+          return Promise.resolve({ success: true });
+        } else {
+          return Promise.resolve({ success: false });
+        }
+      }
+
+      setInterfaceAlternateSetting(interfaceNumber, alternateSetting) {
+        if (!this.opened_ || this.currentConfiguration_ === undefined)
+          return Promise.resolve({ success: false });
+
+        if (!this.claimedInterfaces_.has(interfaceNumber))
+          return Promise.resolve({ success: false });
+
+        let iface = this.currentConfiguration_.interfaces.find(
+            iface => iface.interface_number == interfaceNumber);
+        if (iface === undefined)
+          return Promise.resolve({ success: false });
+
+        if (iface.alternates.some(
+               x => x.alternate_setting == alternateSetting)) {
+          this.claimedInterfaces_.set(interfaceNumber, alternateSetting);
+          return Promise.resolve({ success: true });
+        } else {
+          return Promise.resolve({ success: false });
+        }
+      }
+
+      reset() { throw 'Not implemented!'; }
+      clearHalt(endpoint) { throw 'Not implemented!'; }
+
+      controlTransferIn(params, length, timeout) {
+        return Promise.resolve({
+          status: device.TransferStatus.OK,
+          data: [length >> 8, length & 0xff, params.request, params.value >> 8,
+                 params.value & 0xff, params.index >> 8, params.index & 0xff]
+        });
+      }
+
+      controlTransferOut(params, data, timeout) {
+        throw 'Not implemented!';
+      }
+      genericTransferIn(endpointNumber, length, timeout) {
+        throw 'Not implemented!';
+      }
+      genericTransferOut(endpointNumber, data, timeout) {
+        throw 'Not implemented!';
+      }
+      isochronousTransferIn(endpointNumber, numPackets, packetLength,
+                            timeout) {
+        throw 'Not implemented!';
+      }
+      isochronousTransferOut(endpointNumber, packets, timeout) {
+        throw 'Not implemented!';
+      }
+    };
+
+    class MockDeviceManager extends deviceManager.DeviceManager.stubClass {
+      constructor() {
+        super();
+        this.router_ = null;
+        this.mockDevices_ = new Map();
+        this.addedDevices_ = [];
+        this.removedDevices_ = [];
+        this.deviceChangePromiseResolvers_ = [];
+      }
+
+      reset() {
+        this.mockDevices_.forEach(device => {
+          for (var handle of device.handles)
+            mojo.core.close(handle.pipe_);
+          this.removedDevices_.push(device.info);
+        });
+        this.mockDevices_.clear();
+        this.maybeResolveDeviceChangePromise();
+      }
+
+      addMockDevice(info) {
+        let device = {
+          info: info,
+          handles: []
+        };
+        this.mockDevices_.set(info.guid, device);
+        this.addedDevices_.push(info);
+        this.maybeResolveDeviceChangePromise();
+      }
+
+      removeMockDevice(info) {
+        let device = this.mockDevices_.get(info.guid);
+        for (var handle of device.handles)
+          mojo.core.close(handle.pipe_);
+        this.mockDevices_.delete(info.guid);
+        this.removedDevices_.push(info);
+        this.maybeResolveDeviceChangePromise();
+      }
+
+      bindToPipe(pipe) {
+        assert_equals(this.router_, null);
+        this.router_ = new mojo.router.Router(pipe);
+        this.router_.setIncomingReceiver(this);
+      }
+
+      getDevices(options) {
+        let devices = [];
+        this.mockDevices_.forEach(device => {
+          devices.push(device.info);
+        });
+        return Promise.resolve({ results: devices });
+      }
+
+      getDeviceChanges() {
+        let promise = new Promise((resolve, reject) => {
+          this.deviceChangePromiseResolvers_.push(resolve);
+        });
+        this.maybeResolveDeviceChangePromise();
+        return promise;
+      }
+
+      maybeResolveDeviceChangePromise() {
+        if (this.addedDevices_.length == 0 &&
+            this.removedDevices_.length == 0) {
+          return;
+        }
+
+        let resolve = this.deviceChangePromiseResolvers_.shift();
+        if (resolve === undefined)
+          return;
+
+        resolve({
+          changes: {
+            devices_added: this.addedDevices_,
+            devices_removed: this.removedDevices_
+          }
+        });
+        this.addedDevices_ = [];
+        this.removedDevices_ = [];
+      }
+
+      getDevice(guid, pipe) {
+        let device = this.mockDevices_.get(guid);
+        if (device !== undefined) {
+          var mock = new MockDevice(device.info, pipe);
+          device.handles.push(mock);
+        }
+      }
+    }
+
+    let mockDeviceManager = new MockDeviceManager;
+    mojo.serviceRegistry.addServiceOverrideForTesting(
+        deviceManager.DeviceManager.name,
+        pipe => {
+          mockDeviceManager.bindToPipe(pipe);
+        });
+
+    mojo.serviceRegistry.addServiceOverrideForTesting(
+        permissionProvider.PermissionProvider.name,
+        pipe => {
+          console.log('Connected to PermissionProvider!');
+        });
+
+    return fakeUsbDevices().then(fakeDevices => Promise.resolve({
+      DeviceManager: deviceManager.DeviceManager,
+      Device: device.Device,
+      PermissionProvider: permissionProvider.PermissionProvider,
+      mockDeviceManager: mockDeviceManager,
+      fakeDevices: fakeDevices,
+      assertDeviceInfoEquals: assertDeviceInfoEquals,
+      assertConfigurationInfoEquals: assertConfigurationInfoEquals,
+    }));
+  });
+}
+
+function usb_test(func, name, properties) {
+  mojo_test(mojo => usbMocks(mojo).then(usb => {
+    let result = Promise.resolve(func(usb));
+    let cleanUp = () => usb.mockDeviceManager.reset();
+    return result.then(cleanUp, cleanUp);
+  }), name, properties);
+}
diff --git a/third_party/WebKit/LayoutTests/usb/usb.html b/third_party/WebKit/LayoutTests/usb/usb.html
new file mode 100644
index 0000000..9d0fbc56
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/usb/usb.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="../resources/mojo-helpers.js"></script>
+<script src="resources/device.mojom.js"></script>
+<script src="resources/device_manager.mojom.js"></script>
+<script src="resources/permission_provider.mojom.js"></script>
+<script src="resources/fake-devices.js"></script>
+<script src="resources/usb-helpers.js"></script>
+<script>
+'use strict';
+
+usb_test(usb => {
+  usb.mockDeviceManager.addMockDevice(usb.fakeDevices[0]);
+
+  return navigator.usb.getDevices().then(devices => {
+    assert_equals(devices.length, 1);
+    usb.assertDeviceInfoEquals(devices[0], usb.fakeDevices[0]);
+  });
+}, 'getDevices returns devices exposed by the DeviceManager service.');
+
+usb_test(usb => {
+  let promise = new Promise((resolve, reject) => {
+    navigator.usb.addEventListener('connect', e => {
+      usb.assertDeviceInfoEquals(e.device, usb.fakeDevices[0]);
+      resolve();
+    });
+  });
+
+  usb.mockDeviceManager.addMockDevice(usb.fakeDevices[0]);
+  return promise;
+}, 'onconnect event is trigged by adding a device');
+
+usb_test(usb => {
+  let promise = new Promise((resolve, reject) => {
+    navigator.usb.addEventListener('disconnect', e => {
+      usb.assertDeviceInfoEquals(e.device, usb.fakeDevices[0]);
+      resolve();
+    });
+  });
+
+  usb.mockDeviceManager.addMockDevice(usb.fakeDevices[0]);
+  usb.mockDeviceManager.removeMockDevice(usb.fakeDevices[0]);
+  return promise;
+}, 'ondisconnect event is triggered by removing a device');
+</script>
diff --git a/third_party/WebKit/LayoutTests/usb/usbDevice.html b/third_party/WebKit/LayoutTests/usb/usbDevice.html
new file mode 100644
index 0000000..34f7e55
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/usb/usbDevice.html
@@ -0,0 +1,105 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="../resources/mojo-helpers.js"></script>
+<script src="resources/device.mojom.js"></script>
+<script src="resources/device_manager.mojom.js"></script>
+<script src="resources/permission_provider.mojom.js"></script>
+<script src="resources/fake-devices.js"></script>
+<script src="resources/usb-helpers.js"></script>
+<script>
+'use strict';
+
+usb_test(usb => {
+  usb.mockDeviceManager.addMockDevice(usb.fakeDevices[0]);
+  return navigator.usb.getDevices().then(devices => {
+    assert_equals(devices.length, 1);
+    let device = devices[0];
+    return device.open().then(() => device.close());
+  });
+}, 'a device can be opened and closed');
+
+usb_test(usb => {
+  usb.mockDeviceManager.addMockDevice(usb.fakeDevices[0]);
+  return navigator.usb.getDevices().then(devices => {
+    assert_equals(devices.length, 1);
+    let device = devices[0];
+    return device.open()
+      .then(() => device.setConfiguration(1))
+      .then(() => device.getConfiguration())
+      .then(config => {
+         usb.assertConfigurationInfoEquals(
+             config, usb.fakeDevices[0].configurations[0]);
+      })
+      .then(() => device.close());
+  });
+}, 'device configuration can be set and queried');
+
+usb_test(usb => {
+  usb.mockDeviceManager.addMockDevice(usb.fakeDevices[0]);
+  return navigator.usb.getDevices().then(devices => {
+    assert_equals(devices.length, 1);
+    let device = devices[0];
+    return device.open()
+      .then(() => device.getConfiguration()
+        .then(() => {
+          assert_true(false, 'getConfiguration should reject');
+        })
+        .catch(error => {
+          assert_equals(error.code, DOMException.NOT_FOUND_ERR);
+          return Promise.resolve();
+        }))
+      .then(() => device.close());
+  });
+}, 'querying an unset configuration raises NotFoundError');
+
+usb_test(usb => {
+  usb.mockDeviceManager.addMockDevice(usb.fakeDevices[0]);
+  return navigator.usb.getDevices().then(devices => {
+    assert_equals(devices.length, 1);
+    let device = devices[0];
+    return device.open()
+      .then(() => device.setConfiguration(1))
+      .then(() => device.claimInterface(0))
+      .then(() => device.releaseInterface(0))
+      .then(() => device.close());
+  });
+}, 'an interface can be claimed and released');
+
+usb_test(usb => {
+  usb.mockDeviceManager.addMockDevice(usb.fakeDevices[0]);
+  return navigator.usb.getDevices().then(devices => {
+    assert_equals(devices.length, 1);
+    let device = devices[0];
+    return device.open()
+      .then(() => device.setConfiguration(2))
+      .then(() => device.claimInterface(0))
+      .then(() => device.setInterface(0, 1))
+      .then(() => device.close());
+  });
+}, 'can select an alternate interface');
+
+usb_test(usb => {
+  usb.mockDeviceManager.addMockDevice(usb.fakeDevices[0]);
+  return navigator.usb.getDevices().then(devices => {
+    assert_equals(devices.length, 1);
+    let device = devices[0];
+    return device.open()
+      .then(() => device.controlTransferIn({
+        requestType: "vendor",
+        recipient: "device",
+        request: 0x42,
+        value: 0x1234,
+        index: 0x5678
+      }, 7))
+      .then(result => {
+        assert_equals("ok", result.status);
+        assert_equals(7, result.data.byteLength);
+        assert_equals(0x07, result.data.getUint16(0));
+        assert_equals(0x42, result.data.getUint8(2));
+        assert_equals(0x1234, result.data.getUint16(3));
+        assert_equals(0x5678, result.data.getUint16(5));
+      });
+  });
+}, 'can issue IN control transfer');
+</script>
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 3362c1ce..4eea35b 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -229,6 +229,15 @@
 interface FormData
     method append
     method constructor
+    method delete
+    method entries
+    method forEach
+    method get
+    method getAll
+    method has
+    method keys
+    method set
+    method values
 interface Headers
     method append
     method constructor
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
index b3f3b7fa..96511b1 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -228,6 +228,15 @@
 [Worker] interface FormData
 [Worker]     method append
 [Worker]     method constructor
+[Worker]     method delete
+[Worker]     method entries
+[Worker]     method forEach
+[Worker]     method get
+[Worker]     method getAll
+[Worker]     method has
+[Worker]     method keys
+[Worker]     method set
+[Worker]     method values
 [Worker] interface Headers
 [Worker]     method append
 [Worker]     method constructor
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
index 39b4216f..9a64338 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -488,6 +488,17 @@
     method constructor
     setter buffer
     setter normalize
+interface Credential
+    getter iconURL
+    getter id
+    getter name
+    getter type
+    method constructor
+interface CredentialsContainer
+    method constructor
+    method get
+    method requireUserMediation
+    method store
 interface Crypto
     getter subtle
     method constructor
@@ -1085,6 +1096,10 @@
     method constructor
     method dispatchEvent
     method removeEventListener
+interface FederatedCredential : Credential
+    getter protocol
+    getter provider
+    method constructor
 interface File : Blob
     getter lastModified
     getter lastModifiedDate
@@ -1160,6 +1175,15 @@
 interface FormData
     method append
     method constructor
+    method delete
+    method entries
+    method forEach
+    method get
+    method getAll
+    method has
+    method keys
+    method set
+    method values
 interface GainNode : AudioNode
     getter gain
     method constructor
@@ -3027,6 +3051,7 @@
     getter appVersion
     getter bluetooth
     getter cookieEnabled
+    getter credentials
     getter doNotTrack
     getter geolocation
     getter hardwareConcurrency
@@ -3192,6 +3217,14 @@
 interface PageTransitionEvent : Event
     getter persisted
     method constructor
+interface PasswordCredential : Credential
+    getter additionalData
+    getter idName
+    getter passwordName
+    method constructor
+    setter additionalData
+    setter idName
+    setter passwordName
 interface Path2D
     method arc
     method arcTo
@@ -3613,11 +3646,6 @@
     method constructor
 interface SVGElement : Element
     getter className
-    getter offsetHeight
-    getter offsetLeft
-    getter offsetParent
-    getter offsetTop
-    getter offsetWidth
     getter onabort
     getter onblur
     getter oncancel
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
index cc05d981..e42ee415 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -216,6 +216,15 @@
 [Worker] interface FormData
 [Worker]     method append
 [Worker]     method constructor
+[Worker]     method delete
+[Worker]     method entries
+[Worker]     method forEach
+[Worker]     method get
+[Worker]     method getAll
+[Worker]     method has
+[Worker]     method keys
+[Worker]     method set
+[Worker]     method values
 [Worker] interface Headers
 [Worker]     method append
 [Worker]     method constructor
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/scroll-behavior/smooth-scroll/main-thread-scrolling-reason-added-expected.txt b/third_party/WebKit/LayoutTests/virtual/threaded/fast/scroll-behavior/smooth-scroll/main-thread-scrolling-reason-added-expected.txt
new file mode 100644
index 0000000..26d9497
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/threaded/fast/scroll-behavior/smooth-scroll/main-thread-scrolling-reason-added-expected.txt
@@ -0,0 +1,13 @@
+This test verifies that smooth scrolls initiated on the main thread add the appropriate main thread scrolling reason.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS internals.getScrollAnimationState(document) == RUNNING_ON_COMPOSITOR is true
+PASS internals.mainThreadScrollingReasons(document) == ANIMATING_TEXT is true
+PASS document.scrollingElement.scrollTop == 40 became true
+PASS internals.mainThreadScrollingReasons(document) == '' is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/scroll-behavior/smooth-scroll/main-thread-scrolling-reason-added.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/scroll-behavior/smooth-scroll/main-thread-scrolling-reason-added.html
new file mode 100644
index 0000000..1b906f7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/threaded/fast/scroll-behavior/smooth-scroll/main-thread-scrolling-reason-added.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<script src="../../../../../resources/js-test.js"></script>
+<style>
+body {
+    width: 2000px;
+    height: 2000px;
+}
+</style>
+
+<script>
+var jsTestIsAsync = true;
+
+description("This test verifies that smooth scrolls initiated on the main " +
+            "thread add the appropriate main thread scrolling reason.");
+
+// From ScrollingCoordinator::mainThreadScrollingReasonsAsText.
+var ANIMATING_TEXT = 'Animating scroll on main thread';
+var RUNNING_ON_COMPOSITOR = 2;
+
+function finishTest() {
+  requestAnimationFrame(function() {
+    // Check that main thread scrolling reason is removed.
+    shouldBeTrue("internals.mainThreadScrollingReasons(document) == ''");
+    finishJSTest();
+  });
+}
+
+function runTest() {
+    if (document.scrollingElement.scrollTop == 0) {
+        requestAnimationFrame(runTest);
+    } else {
+        // Check that initiated by main thread and running on the compositor.
+        shouldBeTrue("internals.getScrollAnimationState(document) " +
+          "== RUNNING_ON_COMPOSITOR");
+        // Check that main thread scrolling reason is added.
+        shouldBeTrue("internals.mainThreadScrollingReasons(document) " +
+          "== ANIMATING_TEXT");
+        shouldBecomeEqual("document.scrollingElement.scrollTop == 40",
+          "true", finishTest);
+    }
+}
+
+onload = function() {
+    if (!window.eventSender || !window.internals) {
+        debug("This test requires window.eventSender.")
+        finishJSTest();
+        return;
+    }
+    internals.settings.setScrollAnimatorEnabled(true);
+
+    document.scrollingElement.scrollTop = 0;
+
+    // Scroll 1 ticks down.
+    eventSender.mouseMoveTo(20, 20);
+    eventSender.mouseScrollBy(0, -1);
+    runTest();
+};
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/scroll-behavior/smooth-scroll/main-thread-scrolling-reason-correctness-expected.txt b/third_party/WebKit/LayoutTests/virtual/threaded/fast/scroll-behavior/smooth-scroll/main-thread-scrolling-reason-correctness-expected.txt
new file mode 100644
index 0000000..e462223
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/threaded/fast/scroll-behavior/smooth-scroll/main-thread-scrolling-reason-correctness-expected.txt
@@ -0,0 +1,16 @@
+This test verifies that the ScrollAnimator can schedule animations on the compositor when it adds a temporary main thread scrolling reason.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS internals.getScrollAnimationState(document) == RUNNING_ON_COMPOSITOR is true
+PASS internals.mainThreadScrollingReasons(document) == ANIMATING_TEXT is true
+PASS internals.getScrollAnimationState(document) == RUNNING_ON_COMPOSITOR_BUT_NEEDS_UPDATE is true
+PASS internals.mainThreadScrollingReasons(document) == ANIMATING_TEXT is true
+PASS needsUpdateOrRunningOnCompositor(document) is true
+PASS document.scrollingElement.scrollTop == 80 became true
+PASS internals.mainThreadScrollingReasons(document) == '' is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/scroll-behavior/smooth-scroll/main-thread-scrolling-reason-correctness.html b/third_party/WebKit/LayoutTests/virtual/threaded/fast/scroll-behavior/smooth-scroll/main-thread-scrolling-reason-correctness.html
new file mode 100644
index 0000000..2c78532
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/threaded/fast/scroll-behavior/smooth-scroll/main-thread-scrolling-reason-correctness.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<script src="../../../../../resources/js-test.js"></script>
+<style>
+body {
+    width: 2000px;
+    height: 2000px;
+}
+</style>
+
+<script>
+var jsTestIsAsync = true;
+
+description("This test verifies that the ScrollAnimator can schedule " +
+    "animations on the compositor when it adds a temporary main thread " +
+    "scrolling reason.");
+
+// From ScrollingCoordinator::mainThreadScrollingReasonsAsText.
+var ANIMATING_TEXT = 'Animating scroll on main thread';
+// From ScrollAnimatorCompositorCoordinator::RunState.
+var RUNNING_ON_COMPOSITOR = 2;
+var RUNNING_ON_COMPOSITOR_BUT_NEEDS_UPDATE = 3;
+
+function finishTest() {
+  requestAnimationFrame(function() {
+    // Check that main thread scrolling reason is removed.
+    shouldBeTrue("internals.mainThreadScrollingReasons(document) == ''");
+    finishJSTest();
+  });
+}
+
+function needsUpdateOrRunningOnCompositor(node) {
+    var state = internals.getScrollAnimationState(node);
+    return state == RUNNING_ON_COMPOSITOR ||
+        state == RUNNING_ON_COMPOSITOR_BUT_NEEDS_UPDATE;
+}
+
+function runTest() {
+    if (document.scrollingElement.scrollTop == 0) {
+        requestAnimationFrame(runTest);
+    } else {
+        // Check that initiated by main thread and running on the compositor.
+        shouldBeTrue("internals.getScrollAnimationState(document) " +
+          "== RUNNING_ON_COMPOSITOR");
+        // Check that main thread scrolling reason is added.
+        shouldBeTrue("internals.mainThreadScrollingReasons(document) " +
+          "== ANIMATING_TEXT");
+
+        // Scroll 1 more tick down.
+        eventSender.mouseScrollBy(0, -1);
+        shouldBeTrue("internals.getScrollAnimationState(document) " +
+          "== RUNNING_ON_COMPOSITOR_BUT_NEEDS_UPDATE");
+
+        requestAnimationFrame(function() {
+            // Check that the temporary main thread scrolling is still there
+            // and running on the compositor.
+            shouldBeTrue("internals.mainThreadScrollingReasons(document) " +
+              "== ANIMATING_TEXT");
+            shouldBeTrue("needsUpdateOrRunningOnCompositor(document)");
+            shouldBecomeEqual("document.scrollingElement.scrollTop == 80",
+              "true", finishTest);
+        });
+    }
+}
+
+onload = function() {
+    if (!window.eventSender || !window.internals) {
+        debug("This test requires window.eventSender.")
+        finishJSTest();
+        return;
+    }
+    internals.settings.setScrollAnimatorEnabled(true);
+
+    document.scrollingElement.scrollTop = 0;
+
+    // Scroll 1 ticks down.
+    eventSender.mouseMoveTo(20, 20);
+    eventSender.mouseScrollBy(0, -1);
+    runTest();
+};
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/web-animations-api/animation-state-changes-negative-playback-rate.html b/third_party/WebKit/LayoutTests/web-animations-api/animation-state-changes-negative-playback-rate.html
index 1c0a651..bc3422d 100644
--- a/third_party/WebKit/LayoutTests/web-animations-api/animation-state-changes-negative-playback-rate.html
+++ b/third_party/WebKit/LayoutTests/web-animations-api/animation-state-changes-negative-playback-rate.html
@@ -29,14 +29,6 @@
   return animation;
 }
 
-function pendingStartTimeAndCurrentTimeAnimation() {
-  var animation = idleAnimation();
-  animation.play();
-  animation.pause();
-  animation.play();
-  return animation;
-}
-
 function pausedAnimation() {
   var animation = idleAnimation();
   animation.pause();
@@ -66,13 +58,6 @@
 }, "pending startTime");
 
 test(function() {
-  var animation = pendingStartTimeAndCurrentTimeAnimation();
-  assert_unresolved(animation.startTime);
-  assert_unresolved(animation.currentTime);
-  assert_equals(animation.playState, 'pending');
-}, "pending startTime and currentTime");
-
-test(function() {
   var animation = runningAnimation();
   assert_equals(animation.startTime, document.timeline.currentTime - (animation.playbackRate * animation.currentTime));
   assert_equals(animation.currentTime, duration);
@@ -105,7 +90,7 @@
   var animation = idleAnimation();
   animation.pause();
   assert_unresolved(animation.startTime);
-  assert_unresolved(animation.currentTime);
+  assert_equals(animation.currentTime, duration);
   assert_equals(animation.playState, 'pending');
 }, "idle -> pause()");
 
@@ -161,7 +146,7 @@
   var animation = pendingStartTimeAnimation();
   animation.pause();
   assert_unresolved(animation.startTime);
-  assert_unresolved(animation.currentTime);
+  assert_equals(animation.currentTime, duration);
   assert_equals(animation.playState, 'pending');
 }, "pending startTime -> pause()");
 
@@ -206,62 +191,6 @@
 }, "pending startTime -> set startTime");
 
 test(function() {
-  var animation = pendingStartTimeAndCurrentTimeAnimation();
-  animation.play();
-  assert_unresolved(animation.startTime);
-  assert_unresolved(animation.currentTime);
-  assert_equals(animation.playState, 'pending');
-}, "pending startTime & currentTime -> play()");
-
-test(function() {
-  var animation = pendingStartTimeAndCurrentTimeAnimation();
-  animation.pause();
-  assert_unresolved(animation.startTime);
-  assert_unresolved(animation.currentTime);
-  assert_equals(animation.playState, 'pending');
-}, "pending startTime & currentTime -> pause()");
-
-test(function() {
-  var animation = pendingStartTimeAndCurrentTimeAnimation();
-  animation.cancel();
-  assert_unresolved(animation.startTime);
-  assert_unresolved(animation.currentTime);
-  assert_equals(animation.playState, 'idle');
-}, "pending startTime & currentTime -> cancel()");
-
-test(function() {
-  var animation = pendingStartTimeAndCurrentTimeAnimation();
-  animation.finish();
-  assert_equals(animation.startTime, document.timeline.currentTime - (animation.playbackRate * animation.currentTime));
-  assert_equals(animation.currentTime, 0);
-  assert_equals(animation.playState, 'finished');
-}, "pending startTime & currentTime -> finish()");
-
-test(function() {
-  var animation = pendingStartTimeAndCurrentTimeAnimation();
-  animation.reverse();
-  assert_unresolved(animation.startTime);
-  assert_unresolved(animation.currentTime);
-  assert_equals(animation.playState, 'pending');
-}, "pending startTime & currentTime -> reverse()");
-
-test(function() {
-  var animation = pendingStartTimeAndCurrentTimeAnimation();
-  animation.currentTime = 1000;
-  assert_unresolved(animation.startTime);
-  assert_equals(animation.currentTime, 1000);
-  assert_equals(animation.playState, 'pending');
-}, "pending startTime & currentTime -> set currentTime");
-
-test(function() {
-  var animation = pendingStartTimeAndCurrentTimeAnimation();
-  animation.startTime = document.timeline.currentTime + duration;
-  assert_equals(animation.startTime, document.timeline.currentTime + duration);
-  assert_equals(animation.currentTime, duration);
-  assert_equals(animation.playState, 'running');
-}, "pending startTime & currentTime -> set startTime");
-
-test(function() {
   var animation = runningAnimation();
   var startTime = animation.startTime;
   var currentTime = animation.currentTime;
@@ -275,7 +204,7 @@
   var animation = runningAnimation();
   animation.pause();
   assert_unresolved(animation.startTime);
-  assert_unresolved(animation.currentTime);
+  assert_equals(animation.currentTime, duration);
   assert_equals(animation.playState, 'pending');
 }, "running -> pause()");
 
@@ -299,7 +228,7 @@
   var animation = runningAnimation();
   animation.reverse();
   assert_unresolved(animation.startTime);
-  assert_unresolved(animation.currentTime);
+  assert_equals(animation.currentTime, 0);
   assert_equals(animation.playState, 'pending');
 }, "running -> reverse()");
 
@@ -387,7 +316,7 @@
   var animation = finishedAnimation();
   animation.pause();
   assert_unresolved(animation.startTime);
-  assert_unresolved(animation.currentTime);
+  assert_equals(animation.currentTime, 0);
   assert_equals(animation.playState, 'pending');
 }, "finished -> pause()");
 
diff --git a/third_party/WebKit/LayoutTests/web-animations-api/animation-state-changes.html b/third_party/WebKit/LayoutTests/web-animations-api/animation-state-changes.html
index 64bac24..ba22634 100644
--- a/third_party/WebKit/LayoutTests/web-animations-api/animation-state-changes.html
+++ b/third_party/WebKit/LayoutTests/web-animations-api/animation-state-changes.html
@@ -65,13 +65,6 @@
 }, "pending startTime");
 
 test(function() {
-  var animation = pendingStartTimeAndCurrentTimeAnimation();
-  assert_unresolved(animation.startTime);
-  assert_unresolved(animation.currentTime);
-  assert_equals(animation.playState, 'pending');
-}, "pending startTime and currentTime");
-
-test(function() {
   var animation = runningAnimation();
   assert_equals(animation.startTime, document.timeline.currentTime - animation.currentTime);
   assert_equals(animation.currentTime, 0);
@@ -104,7 +97,7 @@
   var animation = idleAnimation();
   animation.pause();
   assert_unresolved(animation.startTime);
-  assert_unresolved(animation.currentTime);
+  assert_equals(animation.currentTime, 0);
   assert_equals(animation.playState, 'pending');
 }, "idle -> pause()");
 
@@ -160,7 +153,7 @@
   var animation = pendingStartTimeAnimation();
   animation.pause();
   assert_unresolved(animation.startTime);
-  assert_unresolved(animation.currentTime);
+  assert_equals(animation.currentTime, 0);
   assert_equals(animation.playState, 'pending');
 }, "pending startTime -> pause()");
 
@@ -205,62 +198,6 @@
 }, "pending startTime -> set startTime");
 
 test(function() {
-  var animation = pendingStartTimeAndCurrentTimeAnimation();
-  animation.play();
-  assert_unresolved(animation.startTime);
-  assert_unresolved(animation.currentTime);
-  assert_equals(animation.playState, 'pending');
-}, "pending startTime & currentTime -> play()");
-
-test(function() {
-  var animation = pendingStartTimeAndCurrentTimeAnimation();
-  animation.pause();
-  assert_unresolved(animation.startTime);
-  assert_unresolved(animation.currentTime);
-  assert_equals(animation.playState, 'pending');
-}, "pending startTime & currentTime -> pause()");
-
-test(function() {
-  var animation = pendingStartTimeAndCurrentTimeAnimation();
-  animation.cancel();
-  assert_unresolved(animation.startTime);
-  assert_unresolved(animation.currentTime);
-  assert_equals(animation.playState, 'idle');
-}, "pending startTime & currentTime -> cancel()");
-
-test(function() {
-  var animation = pendingStartTimeAndCurrentTimeAnimation();
-  animation.finish();
-  assert_equals(animation.startTime, document.timeline.currentTime - animation.currentTime);
-  assert_equals(animation.currentTime, duration);
-  assert_equals(animation.playState, 'finished');
-}, "pending startTime & currentTime -> finish()");
-
-test(function() {
-  var animation = pendingStartTimeAndCurrentTimeAnimation();
-  animation.reverse();
-  assert_unresolved(animation.startTime);
-  assert_unresolved(animation.currentTime);
-  assert_equals(animation.playState, 'pending');
-}, "pending startTime & currentTime -> reverse()");
-
-test(function() {
-  var animation = pendingStartTimeAndCurrentTimeAnimation();
-  animation.currentTime = 1000;
-  assert_unresolved(animation.startTime);
-  assert_equals(animation.currentTime, 1000);
-  assert_equals(animation.playState, 'pending');
-}, "pending startTime & currentTime -> set currentTime");
-
-test(function() {
-  var animation = pendingStartTimeAndCurrentTimeAnimation();
-  animation.startTime = document.timeline.currentTime;
-  assert_equals(animation.startTime, document.timeline.currentTime);
-  assert_equals(animation.currentTime, 0);
-  assert_equals(animation.playState, 'running');
-}, "pending startTime & currentTime -> set startTime");
-
-test(function() {
   var animation = runningAnimation();
   var startTime = animation.startTime;
   var currentTime = animation.currentTime;
@@ -274,7 +211,7 @@
   var animation = runningAnimation();
   animation.pause();
   assert_unresolved(animation.startTime);
-  assert_unresolved(animation.currentTime);
+  assert_equals(animation.currentTime, 0);
   assert_equals(animation.playState, 'pending');
 }, "running -> pause()");
 
@@ -298,7 +235,7 @@
   var animation = runningAnimation();
   animation.reverse();
   assert_unresolved(animation.startTime);
-  assert_unresolved(animation.currentTime);
+  assert_equals(animation.currentTime, duration);
   assert_equals(animation.playState, 'pending');
 }, "running -> reverse()");
 
@@ -386,7 +323,7 @@
   var animation = finishedAnimation();
   animation.pause();
   assert_unresolved(animation.startTime);
-  assert_unresolved(animation.currentTime);
+  assert_equals(animation.currentTime, duration);
   assert_equals(animation.playState, 'pending');
 }, "finished -> pause()");
 
@@ -421,4 +358,35 @@
   assert_equals(animation.currentTime, 1000);
   assert_equals(animation.playState, 'running');
 }, "finished -> set currentTime");
+
+{
+  let test = async_test("pending (play) -> ready.then()");
+  let animation = idleAnimation();
+  animation.play();
+  let animationCurrentTime = animation.currentTime;
+  let timelineCurrentTime = document.timeline.currentTime;
+  animation.ready.then(() => {
+    test.step(() => {
+      assert_equals(animation.playState, 'running');
+      assert_greater_than_equal(animation.startTime, timelineCurrentTime);
+      assert_greater_than_equal(animation.currentTime, animationCurrentTime);
+    });
+    test.done();
+  });
+}
+
+{
+  let test = async_test("pending (pause) -> ready.then()");
+  let animation = runningAnimation();
+  animation.pause();
+  let animationCurrentTime = animation.currentTime;
+  animation.ready.then(() => {
+    test.step(() => {
+      assert_equals(animation.playState, 'paused');
+      assert_unresolved(animation.startTime);
+      assert_greater_than_equal(animation.currentTime, animationCurrentTime);
+    });
+    test.done();
+  });
+}
 </script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/periodicwave-normalization.html b/third_party/WebKit/LayoutTests/webaudio/periodicwave-normalization.html
index 7ed2702..fac71d16 100644
--- a/third_party/WebKit/LayoutTests/webaudio/periodicwave-normalization.html
+++ b/third_party/WebKit/LayoutTests/webaudio/periodicwave-normalization.html
@@ -13,7 +13,7 @@
       window.jsTestIsAsync = true;
 
       var sampleRate = 48000;
-      var renderFrames = sampleRate;
+      var renderFrames = 6000;
       var context;
       var audit = Audit.createTaskRunner();
 
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
index 226173a..21a72e7 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -446,7 +446,7 @@
 [Worker]     setter onclose
 [Worker]     setter onerror
 [Worker]     setter onshow
-[Worker] interface OffScreenCanvas
+[Worker] interface OffscreenCanvasTemp
 [Worker]     getter height
 [Worker]     getter width
 [Worker]     method constructor
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 7e722a12..92fe5643 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -3679,12 +3679,6 @@
 interface NumberValue : StyleValue
     getter value
     method constructor
-interface OffScreenCanvas
-    getter height
-    getter width
-    method constructor
-    setter height
-    setter width
 interface OfflineAudioCompletionEvent : Event
     getter renderedBuffer
     method constructor
@@ -3695,6 +3689,12 @@
     method startRendering
     method suspend
     setter oncomplete
+interface OffscreenCanvasTemp
+    getter height
+    getter width
+    method constructor
+    setter height
+    setter width
 interface Option
     method constructor
 interface OscillatorNode : AudioSourceNode
@@ -4193,11 +4193,6 @@
     method constructor
 interface SVGElement : Element
     getter className
-    getter offsetHeight
-    getter offsetLeft
-    getter offsetParent
-    getter offsetTop
-    getter offsetWidth
     getter onabort
     getter onautocomplete
     getter onautocompleteerror
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
index 2893651..17cc445 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -434,7 +434,7 @@
 [Worker]     setter onclose
 [Worker]     setter onerror
 [Worker]     setter onshow
-[Worker] interface OffScreenCanvas
+[Worker] interface OffscreenCanvasTemp
 [Worker]     getter height
 [Worker]     getter width
 [Worker]     method constructor
diff --git a/third_party/WebKit/Source/bindings/core/v8/ActiveDOMCallback.cpp b/third_party/WebKit/Source/bindings/core/v8/ActiveDOMCallback.cpp
index 392f9bc0..7ad6a7a 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ActiveDOMCallback.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ActiveDOMCallback.cpp
@@ -55,7 +55,7 @@
 {
     ExecutionContext* context = executionContext();
     if (context && context->isWorkerGlobalScope()) {
-        WorkerOrWorkletScriptController* scriptController = toWorkerGlobalScope(context)->script();
+        WorkerOrWorkletScriptController* scriptController = toWorkerGlobalScope(context)->scriptController();
         if (!scriptController || scriptController->isExecutionForbidden() || scriptController->isExecutionTerminating())
             return true;
     }
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScheduledAction.cpp b/third_party/WebKit/Source/bindings/core/v8/ScheduledAction.cpp
index b2512ed5..e217b8a5 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScheduledAction.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScheduledAction.cpp
@@ -135,7 +135,7 @@
         createLocalHandlesForArgs(&info);
         V8ScriptRunner::callFunction(m_function.newLocal(m_scriptState->isolate()), worker, m_scriptState->context()->Global(), info.size(), info.data(), m_scriptState->isolate());
     } else {
-        worker->script()->evaluate(m_code);
+        worker->scriptController()->evaluate(m_code);
     }
 }
 
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptController.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptController.cpp
index 813421b..155f3c61 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptController.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptController.cpp
@@ -84,11 +84,10 @@
 
 namespace blink {
 
-bool ScriptController::canAccessFromCurrentOrigin(LocalFrame *frame)
+bool ScriptController::canAccessFromCurrentOrigin(v8::Isolate* isolate, Frame* frame)
 {
     if (!frame)
         return false;
-    v8::Isolate* isolate = toIsolate(frame);
     return !isolate->InContext() || BindingSecurity::shouldAllowAccessToFrame(isolate, callingDOMWindow(isolate), frame, ReportSecurityError);
 }
 
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptController.h b/third_party/WebKit/Source/bindings/core/v8/ScriptController.h
index 78a6ca90..09f290d 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptController.h
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptController.h
@@ -123,7 +123,7 @@
     void enableEval();
     void disableEval(const String& errorMessage);
 
-    static bool canAccessFromCurrentOrigin(LocalFrame*);
+    static bool canAccessFromCurrentOrigin(v8::Isolate*, Frame*);
 
     static void setCaptureCallStackForUncaughtExceptions(v8::Isolate*, bool);
     void collectIsolatedContexts(Vector<std::pair<ScriptState*, SecurityOrigin*>>&);
diff --git a/third_party/WebKit/Source/bindings/core/v8/ToV8.cpp b/third_party/WebKit/Source/bindings/core/v8/ToV8.cpp
index 1b49308..237003b 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ToV8.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ToV8.cpp
@@ -51,11 +51,11 @@
     if (UNLIKELY(!impl))
         return v8::Null(isolate);
 
-    WorkerOrWorkletScriptController* script = impl->script();
-    if (!script)
+    WorkerOrWorkletScriptController* scriptController = impl->scriptController();
+    if (!scriptController)
         return v8::Null(isolate);
 
-    v8::Local<v8::Object> global = script->context()->Global();
+    v8::Local<v8::Object> global = scriptController->context()->Global();
     ASSERT(!global.IsEmpty());
     return global;
 }
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8AbstractEventListener.cpp b/third_party/WebKit/Source/bindings/core/v8/V8AbstractEventListener.cpp
index a6c7caf..e6cbbd5 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8AbstractEventListener.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8AbstractEventListener.cpp
@@ -141,7 +141,7 @@
 
         if (!tryCatch.CanContinue()) { // Result of TerminateExecution().
             if (scriptState->executionContext()->isWorkerGlobalScope())
-                toWorkerGlobalScope(scriptState->executionContext())->script()->forbidExecution();
+                toWorkerGlobalScope(scriptState->executionContext())->scriptController()->forbidExecution();
             return;
         }
         tryCatch.Reset();
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8Binding.cpp b/third_party/WebKit/Source/bindings/core/v8/V8Binding.cpp
index a8759f4..2d02265e 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8Binding.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8Binding.cpp
@@ -787,7 +787,7 @@
         if (LocalFrame* frame = toDocument(context)->frame())
             return toV8Context(frame, world);
     } else if (context->isWorkerGlobalScope()) {
-        if (WorkerOrWorkletScriptController* script = toWorkerOrWorkletGlobalScope(context)->script()) {
+        if (WorkerOrWorkletScriptController* script = toWorkerOrWorkletGlobalScope(context)->scriptController()) {
             if (script->scriptState()->contextIsValid())
                 return script->scriptState()->context();
         }
@@ -949,7 +949,7 @@
     return m_resourceName;
 }
 
-PassRefPtr<TracedValue> devToolsTraceEventData(v8::Isolate* isolate, ExecutionContext* context, v8::Local<v8::Function> function)
+PassOwnPtr<TracedValue> devToolsTraceEventData(v8::Isolate* isolate, ExecutionContext* context, v8::Local<v8::Function> function)
 {
     DevToolsFunctionInfo info(function);
     return InspectorFunctionCallEvent::data(context, info.scriptId(), info.resourceName(), info.lineNumber());
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8Binding.h b/third_party/WebKit/Source/bindings/core/v8/V8Binding.h
index 75c6ba90..35200541 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8Binding.h
+++ b/third_party/WebKit/Source/bindings/core/v8/V8Binding.h
@@ -1070,7 +1070,7 @@
     mutable v8::Local<v8::Function> m_function;
 };
 
-PassRefPtr<TracedValue> devToolsTraceEventData(v8::Isolate*, ExecutionContext*, v8::Local<v8::Function>);
+PassOwnPtr<TracedValue> devToolsTraceEventData(v8::Isolate*, ExecutionContext*, v8::Local<v8::Function>);
 
 // Callback functions used by generated code.
 CORE_EXPORT void v8ConstructorAttributeGetter(v8::Local<v8::Name> propertyName, const v8::PropertyCallbackInfo<v8::Value>&);
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp b/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp
index 638e0e9..c7d55df 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp
@@ -285,7 +285,7 @@
         return;
 
     ASSERT(executionContext->isWorkerGlobalScope());
-    WorkerOrWorkletScriptController* scriptController = toWorkerGlobalScope(executionContext)->script();
+    WorkerOrWorkletScriptController* scriptController = toWorkerGlobalScope(executionContext)->scriptController();
     ASSERT(scriptController);
 
     promiseRejectHandler(data, *scriptController->rejectedPromises(), String());
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8WorkerGlobalScopeEventListener.cpp b/third_party/WebKit/Source/bindings/core/v8/V8WorkerGlobalScopeEventListener.cpp
index ceaa250..4955654 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8WorkerGlobalScopeEventListener.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8WorkerGlobalScopeEventListener.cpp
@@ -54,7 +54,7 @@
     // See issue 889829.
     RefPtrWillBeRawPtr<V8AbstractEventListener> protect(this);
 
-    WorkerOrWorkletScriptController* script = toWorkerGlobalScope(scriptState->executionContext())->script();
+    WorkerOrWorkletScriptController* script = toWorkerGlobalScope(scriptState->executionContext())->scriptController();
     if (!script)
         return;
 
diff --git a/third_party/WebKit/Source/bindings/scripts/v8_utilities.py b/third_party/WebKit/Source/bindings/scripts/v8_utilities.py
index 88580d90..1e8733a 100644
--- a/third_party/WebKit/Source/bindings/scripts/v8_utilities.py
+++ b/third_party/WebKit/Source/bindings/scripts/v8_utilities.py
@@ -186,7 +186,7 @@
     'ScriptState': 'scriptState',
     'ExecutionContext': 'executionContext',
     'ScriptArguments': 'scriptArguments.release()',
-    'ActiveWindow': 'callingDOMWindow(info.GetIsolate())',
+    'ActiveWindow': 'currentDOMWindow(info.GetIsolate())',
     'FirstWindow': 'enteredDOMWindow(info.GetIsolate())',
     'Document': 'document',
     'ThisValue': 'ScriptValue(scriptState, info.This())',
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceDocument.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceDocument.cpp
index a303cea..6066aa8d 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceDocument.cpp
+++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestInterfaceDocument.cpp
@@ -61,7 +61,7 @@
     V8StringResource<> cppValue = v8Value;
     if (!cppValue.prepare())
         return;
-    impl->setHref(callingDOMWindow(info.GetIsolate()), enteredDOMWindow(info.GetIsolate()), cppValue);
+    impl->setHref(currentDOMWindow(info.GetIsolate()), enteredDOMWindow(info.GetIsolate()), cppValue);
 }
 
 static void locationAttributeSetterCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestNode.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestNode.cpp
index 92a966c6..690b725 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestNode.cpp
+++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestNode.cpp
@@ -112,7 +112,7 @@
     if (!cppValue.prepare())
         return;
     ExecutionContext* executionContext = currentExecutionContext(info.GetIsolate());
-    impl->setHrefCallWith(executionContext, callingDOMWindow(info.GetIsolate()), enteredDOMWindow(info.GetIsolate()), cppValue);
+    impl->setHrefCallWith(executionContext, currentDOMWindow(info.GetIsolate()), enteredDOMWindow(info.GetIsolate()), cppValue);
 }
 
 static void hrefCallWithAttributeSetterCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp
index 88f60b5..c968062b 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp
+++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp
@@ -3107,7 +3107,7 @@
     if (!cppValue.prepare())
         return;
     ExecutionContext* executionContext = currentExecutionContext(info.GetIsolate());
-    impl->setHrefCallWith(executionContext, callingDOMWindow(info.GetIsolate()), enteredDOMWindow(info.GetIsolate()), cppValue);
+    impl->setHrefCallWith(executionContext, currentDOMWindow(info.GetIsolate()), enteredDOMWindow(info.GetIsolate()), cppValue);
 }
 
 static void locationWithCallWithAttributeSetterCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
@@ -4231,7 +4231,7 @@
     V8StringResource<> cppValue = v8Value;
     if (!cppValue.prepare())
         return;
-    impl->setSetterCallWithActiveWindowAndFirstWindowStringAttribute(callingDOMWindow(info.GetIsolate()), enteredDOMWindow(info.GetIsolate()), cppValue);
+    impl->setSetterCallWithActiveWindowAndFirstWindowStringAttribute(currentDOMWindow(info.GetIsolate()), enteredDOMWindow(info.GetIsolate()), cppValue);
 }
 
 static void setterCallWithActiveWindowAndFirstWindowStringAttributeAttributeSetterCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
@@ -9359,7 +9359,7 @@
 static void callWithActiveWindowMethod(const v8::FunctionCallbackInfo<v8::Value>& info)
 {
     TestObject* impl = V8TestObject::toImpl(info.Holder());
-    impl->callWithActiveWindow(callingDOMWindow(info.GetIsolate()));
+    impl->callWithActiveWindow(currentDOMWindow(info.GetIsolate()));
 }
 
 static void callWithActiveWindowMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
@@ -9370,7 +9370,7 @@
 static void callWithActiveWindowScriptWindowMethod(const v8::FunctionCallbackInfo<v8::Value>& info)
 {
     TestObject* impl = V8TestObject::toImpl(info.Holder());
-    impl->callWithActiveWindowScriptWindow(callingDOMWindow(info.GetIsolate()), enteredDOMWindow(info.GetIsolate()));
+    impl->callWithActiveWindowScriptWindow(currentDOMWindow(info.GetIsolate()), enteredDOMWindow(info.GetIsolate()));
 }
 
 static void callWithActiveWindowScriptWindowMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
diff --git a/third_party/WebKit/Source/build/features.gypi b/third_party/WebKit/Source/build/features.gypi
index 9554976..341e29c 100644
--- a/third_party/WebKit/Source/build/features.gypi
+++ b/third_party/WebKit/Source/build/features.gypi
@@ -70,11 +70,6 @@
           'WTF_USE_QCMSLIB=1'
         ],
       }],
-      ['OS=="mac"', {
-        'feature_defines': [
-          'WTF_USE_NEW_THEME=1'
-        ],
-      }],
       # Mac OS X uses Accelerate.framework FFT by default instead of FFmpeg.
       ['OS!="mac" and OS!="android"', {
         'feature_defines': [
diff --git a/third_party/WebKit/Source/config.gni b/third_party/WebKit/Source/config.gni
index 9f210232..3132bf20 100644
--- a/third_party/WebKit/Source/config.gni
+++ b/third_party/WebKit/Source/config.gni
@@ -67,10 +67,6 @@
   ]
 }
 
-if (is_mac) {
-  feature_defines_list += [ "WTF_USE_NEW_THEME=1" ]
-}
-
 if (use_webaudio_ffmpeg) {
   feature_defines_list += [ "WTF_USE_WEBAUDIO_FFMPEG=1" ]
 }
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index f2c0082..a205950 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -263,6 +263,7 @@
 
   if (is_win) {
     cflags += [ "/wd4334" ]
+    sources -= [ "layout/LayoutThemeFontProviderDefault.cpp" ]
   } else {  # !is_win
     sources -= [
       "layout/LayoutThemeFontProviderWin.cpp",
@@ -270,14 +271,12 @@
       "layout/LayoutThemeWin.h",
     ]
   }
+
   if (!is_linux) {
     sources -= [
       "layout/LayoutThemeLinux.cpp",
       "layout/LayoutThemeLinux.h",
     ]
-    if (!is_android) {
-      sources -= [ "layout/LayoutThemeFontProviderLinux.cpp" ]
-    }
   }
 
   if (!is_android) {
@@ -288,14 +287,6 @@
   }
 
   if (is_mac) {
-    sources -= [
-      "layout/LayoutThemeDefault.cpp",
-      "layout/LayoutThemeDefault.h",
-      "layout/LayoutThemeFontProvider.cpp",
-      "layout/LayoutThemeFontProvider.h",
-      "paint/ThemePainterDefault.cpp",
-      "paint/ThemePainterDefault.h",
-    ]
     libs += [ "Carbon.framework" ]
   } else {  # !is_mac
     sources -= [ "editing/commands/SmartReplaceCF.cpp" ]
diff --git a/third_party/WebKit/Source/core/animation/Animation.cpp b/third_party/WebKit/Source/core/animation/Animation.cpp
index 918f402..794a0bf 100644
--- a/third_party/WebKit/Source/core/animation/Animation.cpp
+++ b/third_party/WebKit/Source/core/animation/Animation.cpp
@@ -224,8 +224,7 @@
 {
     PlayStateUpdateScope updateScope(*this, TimingUpdateOnDemand);
 
-    // TODO(dstockwell): remove m_currentTimePending
-    if (playStateInternal() == Idle || m_currentTimePending || (!m_held && !hasStartTime()))
+    if (playStateInternal() == Idle || (!m_held && !hasStartTime()))
         return std::numeric_limits<double>::quiet_NaN();
 
     return currentTimeInternal() * 1000;
diff --git a/third_party/WebKit/Source/core/animation/AnimationTest.cpp b/third_party/WebKit/Source/core/animation/AnimationTest.cpp
index 31d4f74..1fb0761 100644
--- a/third_party/WebKit/Source/core/animation/AnimationTest.cpp
+++ b/third_party/WebKit/Source/core/animation/AnimationTest.cpp
@@ -818,7 +818,7 @@
     EXPECT_TRUE(std::isnan(animation->startTime()));
     animation->pause();
     EXPECT_EQ(Animation::Pending, animation->playStateInternal());
-    EXPECT_TRUE(std::isnan(animation->currentTime()));
+    EXPECT_EQ(0, animation->currentTime());
     EXPECT_TRUE(std::isnan(animation->startTime()));
 }
 
diff --git a/third_party/WebKit/Source/core/animation/CSSColorInterpolationType.cpp b/third_party/WebKit/Source/core/animation/CSSColorInterpolationType.cpp
index 70300df4..eb51dfd 100644
--- a/third_party/WebKit/Source/core/animation/CSSColorInterpolationType.cpp
+++ b/third_party/WebKit/Source/core/animation/CSSColorInterpolationType.cpp
@@ -69,7 +69,7 @@
 {
     if (color.isCurrentColor())
         return createInterpolableColorForIndex(Currentcolor);
-    return createInterpolableColor(color.color());
+    return createInterpolableColor(color.getColor());
 }
 
 PassOwnPtr<InterpolableValue> CSSColorInterpolationType::maybeCreateInterpolableColor(const CSSValue& value)
@@ -112,7 +112,7 @@
             currentStyleColor = currentColorGetter(CSSPropertyWebkitTextFillColor, *state.style());
         if (currentStyleColor.isCurrentColor())
             currentStyleColor = currentColorGetter(CSSPropertyColor, *state.style());
-        addPremultipliedColor(red, green, blue, alpha, currentcolorFraction, currentStyleColor.color());
+        addPremultipliedColor(red, green, blue, alpha, currentcolorFraction, currentStyleColor.getColor());
     }
     const TextLinkColors& colors = state.document().textLinkColors();
     if (double webkitActivelinkFraction = toInterpolableNumber(list.get(WebkitActivelink))->value())
diff --git a/third_party/WebKit/Source/core/animation/CSSLengthInterpolationType.cpp b/third_party/WebKit/Source/core/animation/CSSLengthInterpolationType.cpp
index cdaadc6..8a97b542 100644
--- a/third_party/WebKit/Source/core/animation/CSSLengthInterpolationType.cpp
+++ b/third_party/WebKit/Source/core/animation/CSSLengthInterpolationType.cpp
@@ -29,7 +29,7 @@
     }
     static bool hasPercentage(const NonInterpolableValue* nonInterpolableValue)
     {
-        ASSERT(!nonInterpolableValue || nonInterpolableValue->type() == CSSLengthNonInterpolableValue::staticType);
+        ASSERT(!nonInterpolableValue || nonInterpolableValue->getType() == CSSLengthNonInterpolableValue::staticType);
         return static_cast<bool>(nonInterpolableValue);
     }
 
diff --git a/third_party/WebKit/Source/core/animation/EffectInput.cpp b/third_party/WebKit/Source/core/animation/EffectInput.cpp
index 04fad6a5..b05cc6c 100644
--- a/third_party/WebKit/Source/core/animation/EffectInput.cpp
+++ b/third_party/WebKit/Source/core/animation/EffectInput.cpp
@@ -135,7 +135,7 @@
 
     // TODO(alancutter): Remove this once composited animations no longer depend on AnimatableValues.
     if (encounteredCompositableProperty && element->inActiveDocument())
-        element->document().updateLayoutTreeForNodeIfNeeded(element);
+        element->document().updateLayoutTreeForNode(element);
 
     StringKeyframeEffectModel* keyframeEffectModel = StringKeyframeEffectModel::create(keyframes);
     if (!RuntimeEnabledFeatures::cssAdditiveAnimationsEnabled()) {
diff --git a/third_party/WebKit/Source/core/animation/KeyframeEffect.h b/third_party/WebKit/Source/core/animation/KeyframeEffect.h
index 5131503..e0366a4 100644
--- a/third_party/WebKit/Source/core/animation/KeyframeEffect.h
+++ b/third_party/WebKit/Source/core/animation/KeyframeEffect.h
@@ -69,7 +69,7 @@
     const EffectModel* model() const { return m_model.get(); }
     EffectModel* model() { return m_model.get(); }
     void setModel(EffectModel* model) { m_model = model; }
-    Priority priority() const { return m_priority; }
+    Priority getPriority() const { return m_priority; }
     Element* target() const { return m_target; }
 
     void notifySampledEffectRemovedFromAnimationStack();
diff --git a/third_party/WebKit/Source/core/animation/LengthBoxStyleInterpolation.cpp b/third_party/WebKit/Source/core/animation/LengthBoxStyleInterpolation.cpp
index 6db5bf9..6b995d1 100644
--- a/third_party/WebKit/Source/core/animation/LengthBoxStyleInterpolation.cpp
+++ b/third_party/WebKit/Source/core/animation/LengthBoxStyleInterpolation.cpp
@@ -23,8 +23,8 @@
 
 PassRefPtr<LengthBoxStyleInterpolation> LengthBoxStyleInterpolation::maybeCreateFrom(CSSValue& start, CSSValue& end, CSSPropertyID id)
 {
-    bool startRect = start.isQuadValue() && toCSSQuadValue(start).serializationType() == CSSQuadValue::SerializationType::SerializeAsRect;
-    bool endRect = end.isQuadValue() && toCSSQuadValue(end).serializationType() == CSSQuadValue::SerializationType::SerializeAsRect;
+    bool startRect = start.isQuadValue() && toCSSQuadValue(start).serializationType() == CSSQuadValue::TypeForSerialization::SerializeAsRect;
+    bool endRect = end.isQuadValue() && toCSSQuadValue(end).serializationType() == CSSQuadValue::TypeForSerialization::SerializeAsRect;
 
     if (startRect && endRect)
         return adoptRef(new LengthBoxStyleInterpolation(lengthBoxtoInterpolableValue(start, end, false), lengthBoxtoInterpolableValue(end, start, true), id, &start, &end));
diff --git a/third_party/WebKit/Source/core/animation/NonInterpolableValue.h b/third_party/WebKit/Source/core/animation/NonInterpolableValue.h
index d90296b..50eeffc8 100644
--- a/third_party/WebKit/Source/core/animation/NonInterpolableValue.h
+++ b/third_party/WebKit/Source/core/animation/NonInterpolableValue.h
@@ -15,20 +15,20 @@
     virtual ~NonInterpolableValue() { }
 
     typedef const void* Type;
-    virtual Type type() const = 0;
+    virtual Type getType() const = 0;
 };
 
 // These macros provide safe downcasts of NonInterpolableValue subclasses with debug assertions.
 // See CSSValueInterpolationType.cpp for example usage.
 #define DECLARE_NON_INTERPOLABLE_VALUE_TYPE() \
-    static Type staticType; \
-    Type type() const final { return staticType; }
+    static Type staticType;                   \
+    Type getType() const final { return staticType; }
 
 #define DEFINE_NON_INTERPOLABLE_VALUE_TYPE(T) \
     NonInterpolableValue::Type T::staticType = &T::staticType;
 
 #define DEFINE_NON_INTERPOLABLE_VALUE_TYPE_CASTS(T) \
-    DEFINE_TYPE_CASTS(T, NonInterpolableValue, value, value->type() == T::staticType, value.type() == T::staticType);
+    DEFINE_TYPE_CASTS(T, NonInterpolableValue, value, value->getType() == T::staticType, value.getType() == T::staticType);
 
 } // namespace blink
 
diff --git a/third_party/WebKit/Source/core/animation/PathInterpolationFunctions.cpp b/third_party/WebKit/Source/core/animation/PathInterpolationFunctions.cpp
index ba307bd..9976dbf 100644
--- a/third_party/WebKit/Source/core/animation/PathInterpolationFunctions.cpp
+++ b/third_party/WebKit/Source/core/animation/PathInterpolationFunctions.cpp
@@ -148,9 +148,9 @@
     underlyingValueOwner.mutableValue().nonInterpolableValue = value.nonInterpolableValue.get();
 }
 
-PassRefPtr<SVGPathByteStream> PathInterpolationFunctions::appliedValue(const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue)
+PassOwnPtr<SVGPathByteStream> PathInterpolationFunctions::appliedValue(const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue)
 {
-    RefPtr<SVGPathByteStream> pathByteStream = SVGPathByteStream::create();
+    OwnPtr<SVGPathByteStream> pathByteStream = SVGPathByteStream::create();
     InterpolatedSVGPathSource source(
         toInterpolableList(*toInterpolableList(interpolableValue).get(PathArgsIndex)),
         toSVGPathNonInterpolableValue(nonInterpolableValue)->pathSegTypes());
diff --git a/third_party/WebKit/Source/core/animation/PathInterpolationFunctions.h b/third_party/WebKit/Source/core/animation/PathInterpolationFunctions.h
index 29398e6..c027779 100644
--- a/third_party/WebKit/Source/core/animation/PathInterpolationFunctions.h
+++ b/third_party/WebKit/Source/core/animation/PathInterpolationFunctions.h
@@ -12,7 +12,7 @@
 
 class PathInterpolationFunctions {
 public:
-    static PassRefPtr<SVGPathByteStream> appliedValue(const InterpolableValue&, const NonInterpolableValue*);
+    static PassOwnPtr<SVGPathByteStream> appliedValue(const InterpolableValue&, const NonInterpolableValue*);
 
     static void composite(UnderlyingValueOwner&, double underlyingFraction, const InterpolationType&, const InterpolationValue&);
 
diff --git a/third_party/WebKit/Source/core/animation/SampledEffect.cpp b/third_party/WebKit/Source/core/animation/SampledEffect.cpp
index bad5be9..9124135 100644
--- a/third_party/WebKit/Source/core/animation/SampledEffect.cpp
+++ b/third_party/WebKit/Source/core/animation/SampledEffect.cpp
@@ -9,7 +9,7 @@
 SampledEffect::SampledEffect(KeyframeEffect* effect)
     : m_effect(effect)
     , m_sequenceNumber(effect->animation()->sequenceNumber())
-    , m_priority(effect->priority())
+    , m_priority(effect->getPriority())
 {
 }
 
diff --git a/third_party/WebKit/Source/core/animation/animatable/AnimatableColor.h b/third_party/WebKit/Source/core/animation/animatable/AnimatableColor.h
index e634005..3c16fa35 100644
--- a/third_party/WebKit/Source/core/animation/animatable/AnimatableColor.h
+++ b/third_party/WebKit/Source/core/animation/animatable/AnimatableColor.h
@@ -61,7 +61,7 @@
 class CORE_EXPORT AnimatableColor final : public AnimatableValue {
 public:
     static PassRefPtr<AnimatableColor> create(const AnimatableColorImpl&, const AnimatableColorImpl& visitedLinkColor);
-    Color color() const { return m_color.toColor(); }
+    Color getColor() const { return m_color.toColor(); }
     Color visitedLinkColor() const { return m_visitedLinkColor.toColor(); }
 
 protected:
diff --git a/third_party/WebKit/Source/core/animation/animatable/AnimatablePath.cpp b/third_party/WebKit/Source/core/animation/animatable/AnimatablePath.cpp
index 21f06be..35c994f 100644
--- a/third_party/WebKit/Source/core/animation/animatable/AnimatablePath.cpp
+++ b/third_party/WebKit/Source/core/animation/animatable/AnimatablePath.cpp
@@ -39,7 +39,7 @@
     if (usesDefaultInterpolationWith(value))
         return defaultInterpolateTo(this, value, fraction);
 
-    RefPtr<SVGPathByteStream> byteStream = SVGPathByteStream::create();
+    OwnPtr<SVGPathByteStream> byteStream = SVGPathByteStream::create();
     SVGPathByteStreamBuilder builder(*byteStream);
 
     SVGPathByteStreamSource fromSource(path()->byteStream());
diff --git a/third_party/WebKit/Source/core/animation/animatable/AnimatableSVGPaint.cpp b/third_party/WebKit/Source/core/animation/animatable/AnimatableSVGPaint.cpp
index 65716fa..5996ac7 100644
--- a/third_party/WebKit/Source/core/animation/animatable/AnimatableSVGPaint.cpp
+++ b/third_party/WebKit/Source/core/animation/animatable/AnimatableSVGPaint.cpp
@@ -56,7 +56,7 @@
     const AnimatableSVGPaint* svgPaint = toAnimatableSVGPaint(value);
     return paintType() == svgPaint->paintType()
         && visitedLinkPaintType() == svgPaint->visitedLinkPaintType()
-        && color() == svgPaint->color()
+        && getColor() == svgPaint->getColor()
         && uri() == svgPaint->uri()
         && visitedLinkURI() == svgPaint->visitedLinkURI();
 }
diff --git a/third_party/WebKit/Source/core/animation/animatable/AnimatableSVGPaint.h b/third_party/WebKit/Source/core/animation/animatable/AnimatableSVGPaint.h
index 2ebcbe6d..89e392f 100644
--- a/third_party/WebKit/Source/core/animation/animatable/AnimatableSVGPaint.h
+++ b/third_party/WebKit/Source/core/animation/animatable/AnimatableSVGPaint.h
@@ -56,7 +56,7 @@
     }
     SVGPaintType paintType() const { return m_type; }
     SVGPaintType visitedLinkPaintType() const { return m_visitedLinkType; }
-    Color color() const { return m_color->color(); }
+    Color getColor() const { return m_color->getColor(); }
     Color visitedLinkColor() const { return m_color->visitedLinkColor(); }
     const String& uri() const { return m_uri; }
     const String& visitedLinkURI() const { return m_visitedLinkURI; }
diff --git a/third_party/WebKit/Source/core/animation/animatable/AnimatableValueTestHelper.cpp b/third_party/WebKit/Source/core/animation/animatable/AnimatableValueTestHelper.cpp
index 9cb8b3d8..a6d251b 100644
--- a/third_party/WebKit/Source/core/animation/animatable/AnimatableValueTestHelper.cpp
+++ b/third_party/WebKit/Source/core/animation/animatable/AnimatableValueTestHelper.cpp
@@ -46,7 +46,7 @@
 void PrintTo(const AnimatableColor& animColor, ::std::ostream* os)
 {
     *os << "AnimatableColor("
-        << animColor.color().serialized().utf8().data() << ", "
+        << animColor.getColor().serialized().utf8().data() << ", "
         << animColor.visitedLinkColor().serialized().utf8().data() << ")";
 }
 
diff --git a/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp b/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp
index 660a9ba..0659006b 100644
--- a/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp
+++ b/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp
@@ -778,7 +778,7 @@
         const Timing& timing = animationNode.specifiedTiming();
         double elapsedTime = timing.iterationDuration;
         const AtomicString& eventType = EventTypeNames::transitionend;
-        String pseudoElement = PseudoElement::pseudoElementNameForEvents(pseudoId());
+        String pseudoElement = PseudoElement::pseudoElementNameForEvents(getPseudoId());
         RefPtrWillBeRawPtr<TransitionEvent> event = TransitionEvent::create(eventType, propertyName, elapsedTime, pseudoElement);
         event->setTarget(eventTarget());
         document().enqueueAnimationFrameEvent(event);
diff --git a/third_party/WebKit/Source/core/animation/css/CSSAnimations.h b/third_party/WebKit/Source/core/animation/css/CSSAnimations.h
index 7529699..0bf7df3d 100644
--- a/third_party/WebKit/Source/core/animation/css/CSSAnimations.h
+++ b/third_party/WebKit/Source/core/animation/css/CSSAnimations.h
@@ -183,7 +183,7 @@
     private:
         const Element& transitionTarget() const { return *m_transitionTarget; }
         EventTarget* eventTarget() const;
-        PseudoId pseudoId() const { return m_transitionTarget->pseudoId(); }
+        PseudoId getPseudoId() const { return m_transitionTarget->getPseudoId(); }
         Document& document() const { return m_transitionTarget->document(); }
 
         RawPtrWillBeMember<Element> m_transitionTarget;
diff --git a/third_party/WebKit/Source/core/clipboard/DataObjectItem.cpp b/third_party/WebKit/Source/core/clipboard/DataObjectItem.cpp
index 5c9cd25..84fcd56 100644
--- a/third_party/WebKit/Source/core/clipboard/DataObjectItem.cpp
+++ b/third_party/WebKit/Source/core/clipboard/DataObjectItem.cpp
@@ -83,7 +83,7 @@
     return new DataObjectItem(StringKind, type, sequenceNumber);
 }
 
-DataObjectItem::DataObjectItem(Kind kind, const String& type)
+DataObjectItem::DataObjectItem(ItemKind kind, const String& type)
     : m_source(InternalSource)
     , m_kind(kind)
     , m_type(type)
@@ -91,7 +91,7 @@
 {
 }
 
-DataObjectItem::DataObjectItem(Kind kind, const String& type, uint64_t sequenceNumber)
+DataObjectItem::DataObjectItem(ItemKind kind, const String& type, uint64_t sequenceNumber)
     : m_source(PasteboardSource)
     , m_kind(kind)
     , m_type(type)
diff --git a/third_party/WebKit/Source/core/clipboard/DataObjectItem.h b/third_party/WebKit/Source/core/clipboard/DataObjectItem.h
index e22645e..e6ae093 100644
--- a/third_party/WebKit/Source/core/clipboard/DataObjectItem.h
+++ b/third_party/WebKit/Source/core/clipboard/DataObjectItem.h
@@ -44,7 +44,7 @@
 
 class CORE_EXPORT DataObjectItem : public GarbageCollectedFinalized<DataObjectItem> {
 public:
-    enum Kind {
+    enum ItemKind {
         StringKind,
         FileKind
     };
@@ -56,7 +56,7 @@
     static DataObjectItem* createFromSharedBuffer(const String& filename, PassRefPtr<SharedBuffer>);
     static DataObjectItem* createFromPasteboard(const String& type, uint64_t sequenceNumber);
 
-    Kind kind() const { return m_kind; }
+    ItemKind kind() const { return m_kind; }
     String type() const { return m_type; }
     String getAsString() const;
     Blob* getAsFile() const;
@@ -75,11 +75,11 @@
         InternalSource,
     };
 
-    DataObjectItem(Kind, const String& type);
-    DataObjectItem(Kind, const String& type, uint64_t sequenceNumber);
+    DataObjectItem(ItemKind, const String& type);
+    DataObjectItem(ItemKind, const String& type, uint64_t sequenceNumber);
 
     DataSource m_source;
-    Kind m_kind;
+    ItemKind m_kind;
     String m_type;
 
     String m_data;
diff --git a/third_party/WebKit/Source/core/core.gyp b/third_party/WebKit/Source/core/core.gyp
index 602a1b6..c9abcf9 100644
--- a/third_party/WebKit/Source/core/core.gyp
+++ b/third_party/WebKit/Source/core/core.gyp
@@ -345,13 +345,11 @@
         ['OS=="win" and buildtype=="Official"', {
           'msvs_shard': 5,
         }],
-        ['use_default_render_theme==0 and OS != "android"', {
+        ['OS=="win"', {
           'sources!': [
-            'layout/LayoutThemeDefault.cpp',
-            'layout/LayoutThemeDefault.h',
+            'layout/LayoutThemeFontProviderDefault.cpp',
           ],
-        }],
-        ['OS!="win"', {
+        },{ # OS!="win"
           'sources!': [
             'layout/LayoutThemeFontProviderWin.cpp',
             'layout/LayoutThemeWin.cpp',
@@ -363,13 +361,7 @@
             ['include', '<(DEPTH)/third_party/WebKit/Source/build/win/Precompile.cpp'],
           ],
         }],
-        ['OS=="mac"', {
-          'sources!': [
-            # LayoutThemeFontProvider is used by LayoutThemeDefault.
-            'layout/LayoutThemeFontProvider.cpp',
-            'layout/LayoutThemeFontProvider.h',
-          ],
-        },{ # OS!="mac"
+        ['OS!="mac"', {
           'sources!': [
             'layout/LayoutThemeMac.h',
             'layout/LayoutThemeMac.mm',
@@ -381,11 +373,6 @@
             'layout/LayoutThemeLinux.h',
           ],
         }],
-        ['OS != "linux" and OS != "android"', {
-          'sources!': [
-            'layout/LayoutThemeFontProviderLinux.cpp',
-          ],
-        }],
         ['OS!="android"', {
           'sources!': [
             'layout/LayoutThemeAndroid.cpp',
@@ -434,8 +421,6 @@
             ['include', 'platform/mac/WebCoreTextRenderer\\.mm$'],
             ['include', 'platform/text/mac/ShapeArabic\\.c$'],
             ['include', 'platform/text/mac/String(Impl)?Mac\\.mm$'],
-            # Use USE_NEW_THEME on Mac.
-            ['include', 'platform/Theme\\.cpp$'],
           ],
         }, { # OS!="mac"
           'sources!': [
@@ -447,12 +432,6 @@
             ['include', '<(DEPTH)/third_party/WebKit/Source/build/win/Precompile.cpp'],
           ],
         }],
-        ['use_default_render_theme==0 and OS != "android"', {
-          'sources!': [
-            'paint/ThemePainterDefault.cpp',
-            'paint/ThemePainterDefault.h',
-          ],
-        }],
       ],
       # Disable c4267 warnings until we fix size_t to int truncations.
       'msvs_disabled_warnings': [ 4267, 4334, ],
@@ -615,14 +594,6 @@
             'testing/v8',
           ],
           'conditions': [
-            ['use_default_render_theme==0 and OS != "android"', {
-              'sources!': [
-                'layout/LayoutThemeDefault.cpp',
-                'layout/LayoutThemeDefault.h',
-                'paint/ThemePainterDefault.cpp',
-                'paint/ThemePainterDefault.h',
-              ],
-            }],
             ['OS=="win"', {
               # In generated bindings code: 'switch contains default but no
               # case'.
@@ -642,6 +613,9 @@
                   },
                 },
               },
+              'sources!': [
+                'layout/LayoutThemeFontProviderDefault.cpp',
+              ],
             }, {
               'sources!': [
                 'layout/LayoutThemeFontProviderWin.cpp',
@@ -658,16 +632,6 @@
               ],
             }],
             ['OS=="mac"', {
-              'sources!': [
-                # LayoutThemeSkia is not used on mac since LayoutThemeMac
-                # does not reference the Skia code that is used by Windows, Linux and Android.
-                'layout/LayoutThemeSkia.cpp',
-                'layout/LayoutThemeSkia.h',
-
-                # LayoutThemeFontProvider is used by LayoutThemeSkia.
-                'layout/LayoutThemeFontProvider.cpp',
-                'layout/LayoutThemeFontProvider.h',
-              ],
               'link_settings': {
                 'libraries': [
                   '$(SDKROOT)/System/Library/Frameworks/Carbon.framework',
@@ -686,11 +650,6 @@
                 'layout/LayoutThemeLinux.h',
               ],
             }],
-            ['OS != "linux" and OS != "android"', {
-              'sources!': [
-                'layout/LayoutThemeFontProviderLinux.cpp',
-              ],
-            }],
             ['OS=="android"', {
               'cflags': [
                 # WebCore does not work with strict aliasing enabled.
diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi
index 3199fdc..01f9609c 100644
--- a/third_party/WebKit/Source/core/core.gypi
+++ b/third_party/WebKit/Source/core/core.gypi
@@ -242,7 +242,7 @@
             'html/TimeRanges.idl',
             'html/ValidityState.idl',
             'html/VoidCallback.idl',
-            'html/canvas/OffScreenCanvas.idl',
+            'html/canvas/OffscreenCanvasTemp.idl',
             'html/track/AudioTrack.idl',
             'html/track/AudioTrackList.idl',
             'html/track/TextTrack.idl',
@@ -501,8 +501,11 @@
         ],
         'webcore_rendering_files': [
             'layout/api/HitTestAction.h',
+            'layout/api/LayoutBoxItem.h',
             'layout/api/LayoutBoxModel.h',
             'layout/api/LayoutItem.h',
+            'layout/api/LayoutTextFragmentItem.h',
+            'layout/api/LayoutTextItem.h',
             'layout/api/LineLayoutAPIShim.h',
             'layout/api/LineLayoutBlockFlow.h',
             'layout/api/LineLayoutBox.h',
@@ -679,12 +682,14 @@
             'layout/LayoutThemeDefault.h',
             'layout/LayoutThemeFontProvider.cpp',
             'layout/LayoutThemeFontProvider.h',
-            'layout/LayoutThemeFontProviderLinux.cpp',
+            'layout/LayoutThemeFontProviderDefault.cpp',
             'layout/LayoutThemeFontProviderWin.cpp',
             'layout/LayoutThemeLinux.cpp',
             'layout/LayoutThemeLinux.h',
             'layout/LayoutThemeMac.h',
             'layout/LayoutThemeMac.mm',
+            'layout/LayoutThemeMobile.cpp',
+            'layout/LayoutThemeMobile.h',
             'layout/LayoutThemeWin.cpp',
             'layout/LayoutThemeWin.h',
             'layout/LayoutTreeAsText.cpp',
@@ -2948,8 +2953,8 @@
             'html/canvas/CanvasRenderingContext.cpp',
             'html/canvas/CanvasRenderingContext.h',
             'html/canvas/CanvasRenderingContextFactory.h',
-            'html/canvas/OffScreenCanvas.cpp',
-            'html/canvas/OffScreenCanvas.h',
+            'html/canvas/OffscreenCanvasTemp.cpp',
+            'html/canvas/OffscreenCanvasTemp.h',
             'html/forms/BaseButtonInputType.cpp',
             'html/forms/BaseButtonInputType.h',
             'html/forms/BaseCheckableInputType.cpp',
@@ -3976,8 +3981,10 @@
             'layout/LayoutMultiColumnFlowThreadTest.cpp',
             'layout/LayoutObjectTest.cpp',
             'layout/LayoutPartTest.cpp',
+            'layout/LayoutProgressTest.cpp',
             'layout/LayoutTableCellTest.cpp',
             'layout/LayoutTableRowTest.cpp',
+            'layout/LayoutTableSectionTest.cpp',
             'layout/LayoutTestHelper.cpp',
             'layout/LayoutTestHelper.h',
             'layout/LayoutThemeTest.cpp',
diff --git a/third_party/WebKit/Source/core/css/BasicShapeFunctions.cpp b/third_party/WebKit/Source/core/css/BasicShapeFunctions.cpp
index 04169d6..31d495c 100644
--- a/third_party/WebKit/Source/core/css/BasicShapeFunctions.cpp
+++ b/third_party/WebKit/Source/core/css/BasicShapeFunctions.cpp
@@ -220,7 +220,7 @@
         const CSSBasicShapePolygonValue& polygonValue = toCSSBasicShapePolygonValue(basicShapeValue);
         RefPtr<BasicShapePolygon> polygon = BasicShapePolygon::create();
 
-        polygon->setWindRule(polygonValue.windRule());
+        polygon->setWindRule(polygonValue.getWindRule());
         const WillBeHeapVector<RefPtrWillBeMember<CSSPrimitiveValue>>& values = polygonValue.values();
         for (unsigned i = 0; i < values.size(); i += 2)
             polygon->appendPoint(convertToLength(state, values.at(i).get()), convertToLength(state, values.at(i + 1).get()));
diff --git a/third_party/WebKit/Source/core/css/CSSBasicShapeValues.h b/third_party/WebKit/Source/core/css/CSSBasicShapeValues.h
index 1a088c95..1edd223 100644
--- a/third_party/WebKit/Source/core/css/CSSBasicShapeValues.h
+++ b/third_party/WebKit/Source/core/css/CSSBasicShapeValues.h
@@ -115,7 +115,7 @@
 
     // TODO(sashab): Remove this and pass it as an argument in the constructor.
     void setWindRule(WindRule w) { m_windRule = w; }
-    WindRule windRule() const { return m_windRule; }
+    WindRule getWindRule() const { return m_windRule; }
 
     String customCSSText() const;
     bool equals(const CSSBasicShapePolygonValue&) const;
diff --git a/third_party/WebKit/Source/core/css/CSSComputedStyleDeclaration.cpp b/third_party/WebKit/Source/core/css/CSSComputedStyleDeclaration.cpp
index cd02c7f..ba99dbe 100644
--- a/third_party/WebKit/Source/core/css/CSSComputedStyleDeclaration.cpp
+++ b/third_party/WebKit/Source/core/css/CSSComputedStyleDeclaration.cpp
@@ -553,7 +553,7 @@
 
     Document& document = styledNode->document();
 
-    document.updateLayoutTreeForNodeIfNeeded(styledNode);
+    document.updateLayoutTreeForNode(styledNode);
 
     // The style recalc could have caused the styled node to be discarded or replaced
     // if it was a PseudoElement so we need to update it.
diff --git a/third_party/WebKit/Source/core/css/CSSFontFace.cpp b/third_party/WebKit/Source/core/css/CSSFontFace.cpp
index eb1cc2b..b464c6a 100644
--- a/third_party/WebKit/Source/core/css/CSSFontFace.cpp
+++ b/third_party/WebKit/Source/core/css/CSSFontFace.cpp
@@ -63,7 +63,7 @@
     if (loadStatus() == FontFace::Loading) {
         if (source->isValid()) {
             setLoadStatus(FontFace::Loaded);
-        } else if (source->displayPeriod() == RemoteFontFaceSource::FailurePeriod) {
+        } else if (source->getDisplayPeriod() == RemoteFontFaceSource::FailurePeriod) {
             m_sources.clear();
             setLoadStatus(FontFace::Error);
         } else {
@@ -166,7 +166,7 @@
     setLoadStatus(FontFace::Error);
 }
 
-void CSSFontFace::setLoadStatus(FontFace::LoadStatus newStatus)
+void CSSFontFace::setLoadStatus(FontFace::LoadStatusType newStatus)
 {
     ASSERT(m_fontFace);
     if (newStatus == FontFace::Error)
diff --git a/third_party/WebKit/Source/core/css/CSSFontFace.h b/third_party/WebKit/Source/core/css/CSSFontFace.h
index 90b3b80f..662b2e0 100644
--- a/third_party/WebKit/Source/core/css/CSSFontFace.h
+++ b/third_party/WebKit/Source/core/css/CSSFontFace.h
@@ -108,7 +108,7 @@
         Vector<UnicodeRange> m_ranges; // If empty, represents the whole code space.
     };
 
-    FontFace::LoadStatus loadStatus() const { return m_fontFace->loadStatus(); }
+    FontFace::LoadStatusType loadStatus() const { return m_fontFace->loadStatus(); }
     bool maybeScheduleFontLoad(const FontDescription&, UChar32);
     bool maybeScheduleFontLoad(const FontDescription&, const FontDataRange&);
     void load();
@@ -119,7 +119,7 @@
     DECLARE_TRACE();
 
 private:
-    void setLoadStatus(FontFace::LoadStatus);
+    void setLoadStatus(FontFace::LoadStatusType);
 
     UnicodeRangeSet m_ranges;
     RawPtrWillBeMember<CSSSegmentedFontFace> m_segmentedFontFace;
diff --git a/third_party/WebKit/Source/core/css/CSSImageGeneratorValue.cpp b/third_party/WebKit/Source/core/css/CSSImageGeneratorValue.cpp
index e97f3d1..df434dd 100644
--- a/third_party/WebKit/Source/core/css/CSSImageGeneratorValue.cpp
+++ b/third_party/WebKit/Source/core/css/CSSImageGeneratorValue.cpp
@@ -127,7 +127,7 @@
 
 PassRefPtr<Image> CSSImageGeneratorValue::image(const LayoutObject* layoutObject, const IntSize& size)
 {
-    switch (classType()) {
+    switch (getClassType()) {
     case CrossfadeClass:
         return toCSSCrossfadeValue(this)->image(layoutObject, size);
     case LinearGradientClass:
@@ -142,7 +142,7 @@
 
 bool CSSImageGeneratorValue::isFixedSize() const
 {
-    switch (classType()) {
+    switch (getClassType()) {
     case CrossfadeClass:
         return toCSSCrossfadeValue(this)->isFixedSize();
     case LinearGradientClass:
@@ -157,7 +157,7 @@
 
 IntSize CSSImageGeneratorValue::fixedSize(const LayoutObject* layoutObject)
 {
-    switch (classType()) {
+    switch (getClassType()) {
     case CrossfadeClass:
         return toCSSCrossfadeValue(this)->fixedSize(layoutObject);
     case LinearGradientClass:
@@ -172,7 +172,7 @@
 
 bool CSSImageGeneratorValue::isPending() const
 {
-    switch (classType()) {
+    switch (getClassType()) {
     case CrossfadeClass:
         return toCSSCrossfadeValue(this)->isPending();
     case LinearGradientClass:
@@ -187,7 +187,7 @@
 
 bool CSSImageGeneratorValue::knownToBeOpaque(const LayoutObject* layoutObject) const
 {
-    switch (classType()) {
+    switch (getClassType()) {
     case CrossfadeClass:
         return toCSSCrossfadeValue(this)->knownToBeOpaque(layoutObject);
     case LinearGradientClass:
@@ -202,7 +202,7 @@
 
 void CSSImageGeneratorValue::loadSubimages(Document* document)
 {
-    switch (classType()) {
+    switch (getClassType()) {
     case CrossfadeClass:
         toCSSCrossfadeValue(this)->loadSubimages(document);
         break;
diff --git a/third_party/WebKit/Source/core/css/CSSPathValue.cpp b/third_party/WebKit/Source/core/css/CSSPathValue.cpp
index 552e796..aeb606ed 100644
--- a/third_party/WebKit/Source/core/css/CSSPathValue.cpp
+++ b/third_party/WebKit/Source/core/css/CSSPathValue.cpp
@@ -9,24 +9,21 @@
 
 namespace blink {
 
-PassRefPtrWillBeRawPtr<CSSPathValue> CSSPathValue::create(PassRefPtr<SVGPathByteStream> pathByteStream, StylePath* cachedPath)
+PassRefPtrWillBeRawPtr<CSSPathValue> CSSPathValue::create(PassRefPtr<StylePath> stylePath)
 {
-    return adoptRefWillBeNoop(new CSSPathValue(pathByteStream, cachedPath));
+    return adoptRefWillBeNoop(new CSSPathValue(stylePath));
 }
 
-PassRefPtrWillBeRawPtr<CSSPathValue> CSSPathValue::create(const String& pathString)
+PassRefPtrWillBeRawPtr<CSSPathValue> CSSPathValue::create(PassOwnPtr<SVGPathByteStream> pathByteStream)
 {
-    RefPtr<SVGPathByteStream> byteStream = SVGPathByteStream::create();
-    buildByteStreamFromString(pathString, *byteStream);
-    return CSSPathValue::create(byteStream.release());
+    return CSSPathValue::create(StylePath::create(pathByteStream));
 }
 
-CSSPathValue::CSSPathValue(PassRefPtr<SVGPathByteStream> pathByteStream, StylePath* cachedPath)
+CSSPathValue::CSSPathValue(PassRefPtr<StylePath> stylePath)
     : CSSValue(PathClass)
-    , m_pathByteStream(pathByteStream)
-    , m_cachedPath(cachedPath)
+    , m_stylePath(stylePath)
 {
-    ASSERT(m_pathByteStream);
+    ASSERT(m_stylePath);
 }
 
 CSSPathValue::~CSSPathValue()
@@ -37,7 +34,7 @@
 
 PassRefPtrWillBeRawPtr<CSSPathValue> createPathValue()
 {
-    RefPtr<SVGPathByteStream> pathByteStream = SVGPathByteStream::create();
+    OwnPtr<SVGPathByteStream> pathByteStream = SVGPathByteStream::create();
     // Need to be registered as LSan ignored, as it will be reachable and
     // separately referred to by emptyPathValue() callers.
     LEAK_SANITIZER_IGNORE_OBJECT(pathByteStream.get());
@@ -52,11 +49,9 @@
     return empty.get();
 }
 
-StylePath* CSSPathValue::cachedPath() const
+StylePath* CSSPathValue::stylePath() const
 {
-    if (!m_cachedPath)
-        m_cachedPath = StylePath::create(m_pathByteStream);
-    return m_cachedPath.get();
+    return m_stylePath.get();
 }
 
 String CSSPathValue::customCSSText() const
@@ -66,7 +61,7 @@
 
 bool CSSPathValue::equals(const CSSPathValue& other) const
 {
-    return *m_pathByteStream == *other.m_pathByteStream;
+    return byteStream() == other.byteStream();
 }
 
 DEFINE_TRACE_AFTER_DISPATCH(CSSPathValue)
@@ -76,7 +71,7 @@
 
 String CSSPathValue::pathString() const
 {
-    return buildStringFromByteStream(*m_pathByteStream);
+    return buildStringFromByteStream(byteStream());
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/css/CSSPathValue.h b/third_party/WebKit/Source/core/css/CSSPathValue.h
index eefeb1b..5f735ca6 100644
--- a/third_party/WebKit/Source/core/css/CSSPathValue.h
+++ b/third_party/WebKit/Source/core/css/CSSPathValue.h
@@ -6,6 +6,7 @@
 #define CSSPathValue_h
 
 #include "core/css/CSSValue.h"
+#include "core/style/StylePath.h"
 #include "core/svg/SVGPathByteStream.h"
 #include "wtf/PassRefPtr.h"
 #include "wtf/RefPtr.h"
@@ -16,27 +17,26 @@
 
 class CSSPathValue : public CSSValue {
 public:
-    static PassRefPtrWillBeRawPtr<CSSPathValue> create(PassRefPtr<SVGPathByteStream>, StylePath* = nullptr);
-    static PassRefPtrWillBeRawPtr<CSSPathValue> create(const String&);
+    static PassRefPtrWillBeRawPtr<CSSPathValue> create(PassRefPtr<StylePath>);
+    static PassRefPtrWillBeRawPtr<CSSPathValue> create(PassOwnPtr<SVGPathByteStream>);
     ~CSSPathValue();
 
     static CSSPathValue* emptyPathValue();
 
-    StylePath* cachedPath() const;
+    StylePath* stylePath() const;
     String customCSSText() const;
 
     bool equals(const CSSPathValue&) const;
 
     DECLARE_TRACE_AFTER_DISPATCH();
 
-    const SVGPathByteStream& byteStream() const { return *m_pathByteStream; }
+    const SVGPathByteStream& byteStream() const { return m_stylePath->byteStream(); }
     String pathString() const;
 
 private:
-    CSSPathValue(PassRefPtr<SVGPathByteStream>, StylePath*);
+    CSSPathValue(PassRefPtr<StylePath>);
 
-    RefPtr<SVGPathByteStream> m_pathByteStream;
-    mutable RefPtr<StylePath> m_cachedPath;
+    RefPtr<StylePath> m_stylePath;
 };
 
 DEFINE_CSS_VALUE_TYPE_CASTS(CSSPathValue, isPathValue());
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.in b/third_party/WebKit/Source/core/css/CSSProperties.in
index 1e236971..f0eac64 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.in
+++ b/third_party/WebKit/Source/core/css/CSSProperties.in
@@ -464,7 +464,7 @@
 grid runtime_flag=CSSGridLayout, longhands=grid-template-columns;grid-template-rows;grid-template-areas;grid-auto-flow;grid-auto-columns;grid-auto-rows;grid-column-gap;grid-row-gap
 grid-area runtime_flag=CSSGridLayout, longhands=grid-row-start;grid-column-start;grid-row-end;grid-column-end
 grid-column runtime_flag=CSSGridLayout, longhands=grid-column-start;grid-column-end
-grid-gap runtime_flag=CSSGridLayout, longhands=grid-column-gap;grid-row-gap
+grid-gap runtime_flag=CSSGridLayout, longhands=grid-row-gap;grid-column-gap
 grid-row runtime_flag=CSSGridLayout, longhands=grid-row-start;grid-row-end
 grid-template runtime_flag=CSSGridLayout, longhands=grid-template-columns;grid-template-rows;grid-template-areas
 list-style longhands=list-style-type;list-style-position;list-style-image
diff --git a/third_party/WebKit/Source/core/css/CSSPropertySourceData.h b/third_party/WebKit/Source/core/css/CSSPropertySourceData.h
index 3817beb..50440f8 100644
--- a/third_party/WebKit/Source/core/css/CSSPropertySourceData.h
+++ b/third_party/WebKit/Source/core/css/CSSPropertySourceData.h
@@ -133,12 +133,12 @@
 using SelectorRangeList = WillBeHeapVector<SourceRange>;
 
 struct CSSRuleSourceData : public RefCountedWillBeGarbageCollected<CSSRuleSourceData> {
-    static PassRefPtrWillBeRawPtr<CSSRuleSourceData> create(StyleRule::Type type)
+    static PassRefPtrWillBeRawPtr<CSSRuleSourceData> create(StyleRule::RuleType type)
     {
         return adoptRefWillBeNoop(new CSSRuleSourceData(type));
     }
 
-    CSSRuleSourceData(StyleRule::Type type)
+    CSSRuleSourceData(StyleRule::RuleType type)
         : type(type)
     {
         if (type == StyleRule::Style || type == StyleRule::FontFace || type == StyleRule::Page || type == StyleRule::Keyframe)
@@ -149,7 +149,7 @@
 
     DECLARE_TRACE();
 
-    StyleRule::Type type;
+    StyleRule::RuleType type;
 
     // Range of the selector list in the enclosing source.
     SourceRange ruleHeaderRange;
diff --git a/third_party/WebKit/Source/core/css/CSSQuadValue.cpp b/third_party/WebKit/Source/core/css/CSSQuadValue.cpp
index 7c21360..8dd35c4 100644
--- a/third_party/WebKit/Source/core/css/CSSQuadValue.cpp
+++ b/third_party/WebKit/Source/core/css/CSSQuadValue.cpp
@@ -15,7 +15,7 @@
     String bottom = m_bottom->cssText();
     String left = m_left->cssText();
 
-    if (m_serializationType == SerializationType::SerializeAsRect)
+    if (m_serializationType == TypeForSerialization::SerializeAsRect)
         return "rect(" + top + ' ' + right + ' ' + bottom + ' ' + left + ')';
 
     StringBuilder result;
diff --git a/third_party/WebKit/Source/core/css/CSSQuadValue.h b/third_party/WebKit/Source/core/css/CSSQuadValue.h
index 32693f1..538b75e 100644
--- a/third_party/WebKit/Source/core/css/CSSQuadValue.h
+++ b/third_party/WebKit/Source/core/css/CSSQuadValue.h
@@ -30,12 +30,12 @@
 
 class CORE_EXPORT CSSQuadValue : public CSSValue {
 public:
-    enum SerializationType {
+    enum TypeForSerialization {
         SerializeAsRect,
         SerializeAsQuad
     };
 
-    static PassRefPtrWillBeRawPtr<CSSQuadValue> create(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> top, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> right, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> bottom, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> left, SerializationType serializationType)
+    static PassRefPtrWillBeRawPtr<CSSQuadValue> create(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> top, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> right, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> bottom, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> left, TypeForSerialization serializationType)
     {
         return adoptRefWillBeNoop(new CSSQuadValue(top, right, bottom, left, serializationType));
     }
@@ -45,7 +45,7 @@
     CSSPrimitiveValue* bottom() const { return m_bottom.get(); }
     CSSPrimitiveValue* left() const { return m_left.get(); }
 
-    SerializationType serializationType() { return m_serializationType; }
+    TypeForSerialization serializationType() { return m_serializationType; }
 
     String customCSSText() const;
 
@@ -60,7 +60,7 @@
     DECLARE_TRACE_AFTER_DISPATCH();
 
 protected:
-    CSSQuadValue(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> top, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> right, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> bottom, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> left, SerializationType serializationType)
+    CSSQuadValue(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> top, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> right, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> bottom, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> left, TypeForSerialization serializationType)
         : CSSValue(QuadClass)
         , m_serializationType(serializationType)
         , m_top(top)
@@ -69,7 +69,7 @@
         , m_left(left) { }
 
 private:
-    SerializationType m_serializationType;
+    TypeForSerialization m_serializationType;
     RefPtrWillBeMember<CSSPrimitiveValue> m_top;
     RefPtrWillBeMember<CSSPrimitiveValue> m_right;
     RefPtrWillBeMember<CSSPrimitiveValue> m_bottom;
diff --git a/third_party/WebKit/Source/core/css/CSSSelector.cpp b/third_party/WebKit/Source/core/css/CSSSelector.cpp
index 4a2e23e..016e1cf1 100644
--- a/third_party/WebKit/Source/core/css/CSSSelector.cpp
+++ b/third_party/WebKit/Source/core/css/CSSSelector.cpp
@@ -100,7 +100,7 @@
     case Id:
         return 0x010000;
     case PseudoClass:
-        switch (pseudoType()) {
+        switch (getPseudoType()) {
         case PseudoHost:
         case PseudoHostContext:
             // We dynamically compute the specificity of :host and :host-context
@@ -148,7 +148,7 @@
             s += tagQName().localName() == starAtom ? 0 : 4;
             break;
         case PagePseudoClass:
-            switch (component->pseudoType()) {
+            switch (component->getPseudoType()) {
             case PseudoFirstPage:
                 s += 2;
                 break;
@@ -416,7 +416,7 @@
     printf("%*sm_match: %d\n", indent, "", m_match);
     if (m_match != Tag)
         printf("%*svalue(): %s\n", indent, "", value().ascii().data());
-    printf("%*spseudoType(): %d\n", indent, "", pseudoType());
+    printf("%*sgetPseudoType(): %d\n", indent, "", getPseudoType());
     if (m_match == Tag)
         printf("%*stagQName().localName: %s\n", indent, "", tagQName().localName().ascii().data());
     printf("%*sisAttributeSelector(): %d\n", indent, "", isAttributeSelector());
@@ -569,7 +569,7 @@
             || sel1->relation() != sel2->relation()
             || sel1->m_match != sel2->m_match
             || sel1->value() != sel2->value()
-            || sel1->pseudoType() != sel2->pseudoType()
+            || sel1->getPseudoType() != sel2->getPseudoType()
             || sel1->argument() != sel2->argument()) {
             return false;
         }
@@ -613,7 +613,7 @@
             str.append(':');
             str.append(cs->serializingValue());
 
-            switch (cs->pseudoType()) {
+            switch (cs->getPseudoType()) {
             case PseudoNthChild:
             case PseudoNthLastChild:
             case PseudoNthOfType:
@@ -691,7 +691,7 @@
             }
             if (cs->m_match != AttributeSet) {
                 serializeString(cs->serializingValue(), str);
-                if (cs->attributeMatchType() == CaseInsensitive)
+                if (cs->attributeMatch() == CaseInsensitive)
                     str.appendLiteral(" i");
                 str.append(']');
             }
@@ -739,7 +739,7 @@
 {
     createRareData();
     m_data.m_rareData->m_attribute = value;
-    m_data.m_rareData->m_bits.m_attributeMatchType = matchType;
+    m_data.m_rareData->m_bits.m_attributeMatch = matchType;
 }
 
 void CSSSelector::setArgument(const AtomicString& value)
@@ -776,7 +776,7 @@
         break;
     }
 
-    switch (selector->pseudoType()) {
+    switch (selector->getPseudoType()) {
     case CSSSelector::PseudoEmpty:
     case CSSSelector::PseudoLink:
     case CSSSelector::PseudoVisited:
@@ -833,13 +833,13 @@
     // Determine if this selector will match a link in visited, unvisited or any state, or never.
     // :visited never matches other elements than the innermost link element.
     for (const CSSSelector* current = this; current; current = current->tagHistory()) {
-        switch (current->pseudoType()) {
+        switch (current->getPseudoType()) {
         case PseudoNot:
             {
                 // :not(:visited) is equivalent to :link. Parser enforces that :not can't nest.
                 ASSERT(current->selectorList());
                 for (const CSSSelector* subSelector = current->selectorList()->first(); subSelector; subSelector = subSelector->tagHistory()) {
-                    PseudoType subType = subSelector->pseudoType();
+                    PseudoType subType = subSelector->getPseudoType();
                     if (subType == PseudoVisited)
                         linkMatchType &= ~MatchVisited;
                     else if (subType == PseudoLink)
@@ -857,7 +857,7 @@
             // We don't support :link and :visited inside :-webkit-any.
             break;
         }
-        Relation relation = current->relation();
+        RelationType relation = current->relation();
         if (relation == SubSelector)
             continue;
         if (relation != Descendant && relation != Child)
diff --git a/third_party/WebKit/Source/core/css/CSSSelector.h b/third_party/WebKit/Source/core/css/CSSSelector.h
index c0544d0d..7b887ca 100644
--- a/third_party/WebKit/Source/core/css/CSSSelector.h
+++ b/third_party/WebKit/Source/core/css/CSSSelector.h
@@ -92,7 +92,7 @@
     unsigned specificity() const;
 
     /* how the attribute value has to match.... Default is Exact */
-    enum Match {
+    enum MatchType {
         Unknown,
         Tag, // Example: div
         Id, // Example: #id
@@ -110,7 +110,7 @@
         FirstAttributeSelectorMatch = AttributeExact,
     };
 
-    enum Relation {
+    enum RelationType {
         SubSelector, // No combinator
         Descendant, // "Space" combinator
         Child, // > combinator
@@ -211,7 +211,7 @@
         CaseInsensitive,
     };
 
-    PseudoType pseudoType() const { return static_cast<PseudoType>(m_pseudoType); }
+    PseudoType getPseudoType() const { return static_cast<PseudoType>(m_pseudoType); }
     void updatePseudoType(const AtomicString&, bool hasArguments);
 
     static PseudoType parsePseudoType(const AtomicString&, bool hasArguments);
@@ -231,7 +231,7 @@
     // how you use the returned QualifiedName.
     // http://www.w3.org/TR/css3-selectors/#attrnmsp
     const QualifiedName& attribute() const;
-    AttributeMatchType attributeMatchType() const;
+    AttributeMatchType attributeMatch() const;
     // Returns the argument of a parameterized selector. For example, :lang(en-US) would have an argument of en-US.
     // Note that :nth-* selectors don't store an argument and just store the numbers.
     const AtomicString& argument() const { return m_hasRareData ? m_data.m_rareData->m_argument : nullAtom; }
@@ -257,18 +257,18 @@
     bool isHostPseudoClass() const { return m_pseudoType == PseudoHost || m_pseudoType == PseudoHostContext; }
     bool isInsertionPointCrossing() const { return m_pseudoType == PseudoHostContext || m_pseudoType == PseudoContent; }
 
-    Relation relation() const { return static_cast<Relation>(m_relation); }
-    void setRelation(Relation relation)
+    RelationType relation() const { return static_cast<RelationType>(m_relation); }
+    void setRelation(RelationType relation)
     {
         m_relation = relation;
-        ASSERT(static_cast<Relation>(m_relation) == relation); // using a bitfield.
+        ASSERT(static_cast<RelationType>(m_relation) == relation); // using a bitfield.
     }
 
-    Match match() const { return static_cast<Match>(m_match); }
-    void setMatch(Match match)
+    MatchType match() const { return static_cast<MatchType>(m_match); }
+    void setMatch(MatchType match)
     {
         m_match = match;
-        ASSERT(static_cast<Match>(m_match) == match); // using a bitfield.
+        ASSERT(static_cast<MatchType>(m_match) == match); // using a bitfield.
     }
 
     bool isLastInSelectorList() const { return m_isLastInSelectorList; }
@@ -291,8 +291,8 @@
     bool matchesPseudoElement() const;
 
 private:
-    unsigned m_relation               : 3; // enum Relation
-    unsigned m_match                  : 4; // enum Match
+    unsigned m_relation               : 3; // enum RelationType
+    unsigned m_match                  : 4; // enum MatchType
     unsigned m_pseudoType             : 8; // enum PseudoType
     unsigned m_isLastInSelectorList   : 1;
     unsigned m_isLastInTagHistory     : 1;
@@ -328,7 +328,7 @@
                 int m_a; // Used for :nth-*
                 int m_b; // Used for :nth-*
             } m_nth;
-            AttributeMatchType m_attributeMatchType; // used for attribute selector (with value)
+            AttributeMatchType m_attributeMatch; // used for attribute selector (with value)
         } m_bits;
         QualifiedName m_attribute; // used for attribute selector
         AtomicString m_argument; // Used for :contains, :lang, :nth-*
@@ -357,11 +357,11 @@
     return m_data.m_rareData->m_attribute;
 }
 
-inline CSSSelector::AttributeMatchType CSSSelector::attributeMatchType() const
+inline CSSSelector::AttributeMatchType CSSSelector::attributeMatch() const
 {
     ASSERT(isAttributeSelector());
     ASSERT(m_hasRareData);
-    return m_data.m_rareData->m_bits.m_attributeMatchType;
+    return m_data.m_rareData->m_bits.m_attributeMatch;
 }
 
 inline bool CSSSelector::isASCIILower(const AtomicString& value)
diff --git a/third_party/WebKit/Source/core/css/CSSSelectorList.cpp b/third_party/WebKit/Source/core/css/CSSSelectorList.cpp
index 361d99bc..bf1a5ab 100644
--- a/third_party/WebKit/Source/core/css/CSSSelectorList.cpp
+++ b/third_party/WebKit/Source/core/css/CSSSelectorList.cpp
@@ -161,21 +161,21 @@
 bool CSSSelectorList::selectorHasSlottedPseudo(size_t index) const
 {
     return forEachTagSelector([](const CSSSelector& selector) ->  bool {
-        return selector.pseudoType() == CSSSelector::PseudoSlotted;
+        return selector.getPseudoType() == CSSSelector::PseudoSlotted;
     }, selectorAt(index));
 }
 
 bool CSSSelectorList::selectorUsesDeepCombinatorOrShadowPseudo(size_t index) const
 {
     return forEachTagSelector([](const CSSSelector& selector) -> bool {
-        return selector.relation() == CSSSelector::ShadowDeep || selector.pseudoType() == CSSSelector::PseudoShadow;
+        return selector.relation() == CSSSelector::ShadowDeep || selector.getPseudoType() == CSSSelector::PseudoShadow;
     }, selectorAt(index));
 }
 
 bool CSSSelectorList::selectorNeedsUpdatedDistribution(size_t index) const
 {
     return forEachTagSelector([](const CSSSelector& selector) -> bool {
-        return selector.relationIsAffectedByPseudoContent() || selector.pseudoType() == CSSSelector::PseudoSlotted || selector.pseudoType() == CSSSelector::PseudoHostContext;
+        return selector.relationIsAffectedByPseudoContent() || selector.getPseudoType() == CSSSelector::PseudoSlotted || selector.getPseudoType() == CSSSelector::PseudoHostContext;
     }, selectorAt(index));
 }
 
diff --git a/third_party/WebKit/Source/core/css/CSSValue.cpp b/third_party/WebKit/Source/core/css/CSSValue.cpp
index 7a300481d..4f3dd601 100644
--- a/third_party/WebKit/Source/core/css/CSSValue.cpp
+++ b/third_party/WebKit/Source/core/css/CSSValue.cpp
@@ -77,13 +77,13 @@
 {
     if (isValueList())
         return toCSSValueList(this)->hasFailedOrCanceledSubresources();
-    if (classType() == FontFaceSrcClass)
+    if (getClassType() == FontFaceSrcClass)
         return toCSSFontFaceSrcValue(this)->hasFailedOrCanceledSubresources();
-    if (classType() == ImageClass)
+    if (getClassType() == ImageClass)
         return toCSSImageValue(this)->hasFailedOrCanceledSubresources();
-    if (classType() == CrossfadeClass)
+    if (getClassType() == CrossfadeClass)
         return toCSSCrossfadeValue(this)->hasFailedOrCanceledSubresources();
-    if (classType() == ImageSetClass)
+    if (getClassType() == ImageSetClass)
         return toCSSImageSetValue(this)->hasFailedOrCanceledSubresources();
 
     return false;
@@ -98,7 +98,7 @@
 bool CSSValue::equals(const CSSValue& other) const
 {
     if (m_classType == other.m_classType) {
-        switch (classType()) {
+        switch (getClassType()) {
         case BasicShapeCircleClass:
             return compareCSSValues<CSSBasicShapeCircleValue>(*this, other);
         case BasicShapeEllipseClass:
@@ -184,7 +184,7 @@
 
 String CSSValue::cssText() const
 {
-    switch (classType()) {
+    switch (getClassType()) {
     case BasicShapeCircleClass:
         return toCSSBasicShapeCircleValue(this)->customCSSText();
     case BasicShapeEllipseClass:
@@ -268,7 +268,7 @@
 
 void CSSValue::destroy()
 {
-    switch (classType()) {
+    switch (getClassType()) {
     case BasicShapeCircleClass:
         delete toCSSBasicShapeCircleValue(this);
         return;
@@ -389,7 +389,7 @@
 
 void CSSValue::finalizeGarbageCollectedObject()
 {
-    switch (classType()) {
+    switch (getClassType()) {
     case BasicShapeCircleClass:
         toCSSBasicShapeCircleValue(this)->~CSSBasicShapeCircleValue();
         return;
@@ -510,7 +510,7 @@
 
 DEFINE_TRACE(CSSValue)
 {
-    switch (classType()) {
+    switch (getClassType()) {
     case BasicShapeCircleClass:
         toCSSBasicShapeCircleValue(this)->traceAfterDispatch(visitor);
         return;
diff --git a/third_party/WebKit/Source/core/css/CSSValue.h b/third_party/WebKit/Source/core/css/CSSValue.h
index 69c3d0a..e5d7588 100644
--- a/third_party/WebKit/Source/core/css/CSSValue.h
+++ b/third_party/WebKit/Source/core/css/CSSValue.h
@@ -191,7 +191,7 @@
         SlashSeparator
     };
 
-    ClassType classType() const { return static_cast<ClassType>(m_classType); }
+    ClassType getClassType() const { return static_cast<ClassType>(m_classType); }
 
     explicit CSSValue(ClassType classType)
         : m_primitiveUnitType(0)
diff --git a/third_party/WebKit/Source/core/css/ElementRuleCollector.cpp b/third_party/WebKit/Source/core/css/ElementRuleCollector.cpp
index db7f630..177cc70 100644
--- a/third_party/WebKit/Source/core/css/ElementRuleCollector.cpp
+++ b/third_party/WebKit/Source/core/css/ElementRuleCollector.cpp
@@ -285,7 +285,7 @@
     // Now transfer the set of matched rules over to our list of declarations.
     for (unsigned i = 0; i < m_matchedRules.size(); i++) {
         const RuleData* ruleData = m_matchedRules[i].ruleData();
-        m_result.addMatchedProperties(&ruleData->rule()->properties(), ruleData->linkMatchType(), ruleData->propertyWhitelistType(m_matchingUARules));
+        m_result.addMatchedProperties(&ruleData->rule()->properties(), ruleData->linkMatchType(), ruleData->propertyWhitelist(m_matchingUARules));
     }
 }
 
diff --git a/third_party/WebKit/Source/core/css/FontFace.cpp b/third_party/WebKit/Source/core/css/FontFace.cpp
index 11a1c2a6..3c49e50 100644
--- a/third_party/WebKit/Source/core/css/FontFace.cpp
+++ b/third_party/WebKit/Source/core/css/FontFace.cpp
@@ -327,7 +327,7 @@
     return emptyString();
 }
 
-void FontFace::setLoadStatus(LoadStatus status)
+void FontFace::setLoadStatus(LoadStatusType status)
 {
     m_status = status;
     ASSERT(m_status != Error || m_error);
diff --git a/third_party/WebKit/Source/core/css/FontFace.h b/third_party/WebKit/Source/core/css/FontFace.h
index ce45e4428..d243d62f7 100644
--- a/third_party/WebKit/Source/core/css/FontFace.h
+++ b/third_party/WebKit/Source/core/css/FontFace.h
@@ -60,7 +60,7 @@
     DEFINE_WRAPPERTYPEINFO();
     WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(FontFace);
 public:
-    enum LoadStatus { Unloaded, Loading, Loaded, Error };
+    enum LoadStatusType { Unloaded, Loading, Loaded, Error };
 
     static PassRefPtrWillBeRawPtr<FontFace> create(ExecutionContext*, const AtomicString& family, StringOrArrayBufferOrArrayBufferView&, const FontFaceDescriptors&);
     static PassRefPtrWillBeRawPtr<FontFace> create(Document*, const StyleRuleFontFace*);
@@ -89,8 +89,8 @@
 
     ScriptPromise load(ScriptState*);
 
-    LoadStatus loadStatus() const { return m_status; }
-    void setLoadStatus(LoadStatus);
+    LoadStatusType loadStatus() const { return m_status; }
+    void setLoadStatus(LoadStatusType);
     void setError(DOMException* = nullptr);
     DOMException* error() const { return m_error; }
     FontTraits traits() const;
@@ -140,7 +140,7 @@
     RefPtrWillBeMember<CSSValue> m_variant;
     RefPtrWillBeMember<CSSValue> m_featureSettings;
     RefPtrWillBeMember<CSSValue> m_display;
-    LoadStatus m_status;
+    LoadStatusType m_status;
     PersistentWillBeMember<DOMException> m_error;
 
     PersistentWillBeMember<LoadedProperty> m_loadedProperty;
diff --git a/third_party/WebKit/Source/core/css/MediaQuery.cpp b/third_party/WebKit/Source/core/css/MediaQuery.cpp
index faa0e20..07552af 100644
--- a/third_party/WebKit/Source/core/css/MediaQuery.cpp
+++ b/third_party/WebKit/Source/core/css/MediaQuery.cpp
@@ -79,13 +79,13 @@
     return adoptPtrWillBeNoop(new MediaQuery(MediaQuery::Not, MediaTypeNames::all, ExpressionHeapVector()));
 }
 
-PassOwnPtrWillBeRawPtr<MediaQuery> MediaQuery::create(Restrictor restrictor, String mediaType, ExpressionHeapVector expressions)
+PassOwnPtrWillBeRawPtr<MediaQuery> MediaQuery::create(RestrictorType restrictor, String mediaType, ExpressionHeapVector expressions)
 {
     return adoptPtrWillBeNoop(new MediaQuery(restrictor, std::move(mediaType), std::move(expressions)));
 }
 
-MediaQuery::MediaQuery(Restrictor r, String mediaType, ExpressionHeapVector expressions)
-    : m_restrictor(r)
+MediaQuery::MediaQuery(RestrictorType restrictor, String mediaType, ExpressionHeapVector expressions)
+    : m_restrictor(restrictor)
     , m_mediaType(attemptStaticStringCreation(mediaType.lower()))
     , m_expressions(std::move(expressions))
 {
diff --git a/third_party/WebKit/Source/core/css/MediaQuery.h b/third_party/WebKit/Source/core/css/MediaQuery.h
index d5f9b11..2820d2d8 100644
--- a/third_party/WebKit/Source/core/css/MediaQuery.h
+++ b/third_party/WebKit/Source/core/css/MediaQuery.h
@@ -45,16 +45,16 @@
 class CORE_EXPORT MediaQuery : public NoBaseWillBeGarbageCollectedFinalized<MediaQuery> {
     USING_FAST_MALLOC_WILL_BE_REMOVED(MediaQuery);
 public:
-    enum Restrictor {
+    enum RestrictorType {
         Only, Not, None
     };
 
-    static PassOwnPtrWillBeRawPtr<MediaQuery> create(Restrictor, String mediaType, ExpressionHeapVector);
+    static PassOwnPtrWillBeRawPtr<MediaQuery> create(RestrictorType, String mediaType, ExpressionHeapVector);
     static PassOwnPtrWillBeRawPtr<MediaQuery> createNotAll();
 
     ~MediaQuery();
 
-    Restrictor restrictor() const { return m_restrictor; }
+    RestrictorType restrictor() const { return m_restrictor; }
     const ExpressionHeapVector& expressions() const { return m_expressions; }
     const String& mediaType() const { return m_mediaType; }
     bool operator==(const MediaQuery& other) const;
@@ -65,12 +65,12 @@
     DECLARE_TRACE();
 
 private:
-    MediaQuery(Restrictor, String mediaType, ExpressionHeapVector);
+    MediaQuery(RestrictorType, String mediaType, ExpressionHeapVector);
     MediaQuery(const MediaQuery&);
 
     MediaQuery& operator=(const MediaQuery&) = delete;
 
-    Restrictor m_restrictor;
+    RestrictorType m_restrictor;
     String m_mediaType;
     ExpressionHeapVector m_expressions;
     String m_serializationCache;
diff --git a/third_party/WebKit/Source/core/css/MediaQueryEvaluator.cpp b/third_party/WebKit/Source/core/css/MediaQueryEvaluator.cpp
index acf67048..2fbde7bb 100644
--- a/third_party/WebKit/Source/core/css/MediaQueryEvaluator.cpp
+++ b/third_party/WebKit/Source/core/css/MediaQueryEvaluator.cpp
@@ -115,7 +115,7 @@
         || equalIgnoringCase(mediaTypeToMatch, mediaType());
 }
 
-static bool applyRestrictor(MediaQuery::Restrictor r, bool value)
+static bool applyRestrictor(MediaQuery::RestrictorType r, bool value)
 {
     return r == MediaQuery::Not ? !value : value;
 }
diff --git a/third_party/WebKit/Source/core/css/PageRuleCollector.cpp b/third_party/WebKit/Source/core/css/PageRuleCollector.cpp
index da1a6e76..b7f11de 100644
--- a/third_party/WebKit/Source/core/css/PageRuleCollector.cpp
+++ b/third_party/WebKit/Source/core/css/PageRuleCollector.cpp
@@ -93,7 +93,7 @@
                 return false;
         }
 
-        CSSSelector::PseudoType pseudoType = component->pseudoType();
+        CSSSelector::PseudoType pseudoType = component->getPseudoType();
         if ((pseudoType == CSSSelector::PseudoLeftPage && !isLeftPage)
             || (pseudoType == CSSSelector::PseudoRightPage && isLeftPage)
             || (pseudoType == CSSSelector::PseudoFirstPage && !isFirstPage))
diff --git a/third_party/WebKit/Source/core/css/RemoteFontFaceSource.h b/third_party/WebKit/Source/core/css/RemoteFontFaceSource.h
index 219836e6..c9102ffe 100644
--- a/third_party/WebKit/Source/core/css/RemoteFontFaceSource.h
+++ b/third_party/WebKit/Source/core/css/RemoteFontFaceSource.h
@@ -34,7 +34,7 @@
     bool isLoading() const override;
     bool isLoaded() const override;
     bool isValid() const override;
-    DisplayPeriod displayPeriod() const { return m_period; }
+    DisplayPeriod getDisplayPeriod() const { return m_period; }
 
     void beginLoadIfNeeded() override;
 
diff --git a/third_party/WebKit/Source/core/css/RuleFeature.cpp b/third_party/WebKit/Source/core/css/RuleFeature.cpp
index 7eee870..9b08b98 100644
--- a/third_party/WebKit/Source/core/css/RuleFeature.cpp
+++ b/third_party/WebKit/Source/core/css/RuleFeature.cpp
@@ -49,7 +49,7 @@
 
 #if ENABLE(ASSERT)
 
-bool supportsInvalidation(CSSSelector::Match match)
+bool supportsInvalidation(CSSSelector::MatchType match)
 {
     switch (match) {
     case CSSSelector::Tag:
@@ -187,7 +187,7 @@
         return false;
     }
 
-    switch (selector.pseudoType()) {
+    switch (selector.getPseudoType()) {
     case CSSSelector::PseudoFirstLine:
     case CSSSelector::PseudoFirstLetter:
         // FIXME: Most pseudo classes/elements above can be supported and moved
@@ -198,7 +198,7 @@
         // :host-context matches an ancestor of the shadow host.
         return true;
     default:
-        ASSERT(supportsInvalidation(selector.pseudoType()));
+        ASSERT(supportsInvalidation(selector.getPseudoType()));
         return false;
     }
 }
@@ -296,11 +296,11 @@
         features.attributes.append(selector.attribute().localName());
         return true;
     }
-    if (selector.pseudoType() == CSSSelector::PseudoWebKitCustomElement) {
+    if (selector.getPseudoType() == CSSSelector::PseudoWebKitCustomElement) {
         features.customPseudoElement = true;
         return true;
     }
-    if (selector.pseudoType() == CSSSelector::PseudoBefore || selector.pseudoType() == CSSSelector::PseudoAfter)
+    if (selector.getPseudoType() == CSSSelector::PseudoBefore || selector.getPseudoType() == CSSSelector::PseudoAfter)
         features.hasBeforeOrAfter = true;
     return false;
 }
@@ -314,7 +314,7 @@
     if (selector.match() == CSSSelector::Id)
         return &ensureIdInvalidationSet(selector.value(), type);
     if (selector.match() == CSSSelector::PseudoClass) {
-        switch (selector.pseudoType()) {
+        switch (selector.getPseudoType()) {
         case CSSSelector::PseudoEmpty:
         case CSSSelector::PseudoLink:
         case CSSSelector::PseudoVisited:
@@ -342,7 +342,7 @@
         case CSSSelector::PseudoInRange:
         case CSSSelector::PseudoOutOfRange:
         case CSSSelector::PseudoUnresolved:
-            return &ensurePseudoInvalidationSet(selector.pseudoType(), type);
+            return &ensurePseudoInvalidationSet(selector.getPseudoType(), type);
         default:
             break;
         }
@@ -420,15 +420,15 @@
                 return std::make_pair(&selector, ForceSubtree);
             }
             if (const CSSSelectorList* selectorList = current->selectorList()) {
-                if (current->pseudoType() == CSSSelector::PseudoSlotted) {
+                if (current->getPseudoType() == CSSSelector::PseudoSlotted) {
                     ASSERT(position == Subject);
                     features.invalidatesSlotted = true;
                 }
-                ASSERT(supportsInvalidationWithSelectorList(current->pseudoType()));
+                ASSERT(supportsInvalidationWithSelectorList(current->getPseudoType()));
                 const CSSSelector* subSelector = selectorList->first();
                 bool allSubSelectorsHaveFeatures = !!subSelector;
                 for (; subSelector; subSelector = CSSSelectorList::next(*subSelector)) {
-                    auto result = extractInvalidationSetFeatures(*subSelector, features, position, current->pseudoType());
+                    auto result = extractInvalidationSetFeatures(*subSelector, features, position, current->getPseudoType());
                     if (result.first) {
                         // A non-null selector return means the sub-selector contained a
                         // selector which requiresSubtreeInvalidation(). Return the rightmost
@@ -522,7 +522,7 @@
             if (current->isInsertionPointCrossing())
                 descendantFeatures.insertionPointCrossing = true;
             if (const CSSSelectorList* selectorList = current->selectorList()) {
-                ASSERT(supportsInvalidationWithSelectorList(current->pseudoType()));
+                ASSERT(supportsInvalidationWithSelectorList(current->getPseudoType()));
                 for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(*subSelector))
                     addFeaturesToInvalidationSets(subSelector, siblingFeatures, descendantFeatures);
             }
@@ -582,11 +582,11 @@
 RuleFeatureSet::SelectorPreMatch RuleFeatureSet::collectFeaturesFromSelector(const CSSSelector& selector, RuleFeatureSet::FeatureMetadata& metadata)
 {
     unsigned maxDirectAdjacentSelectors = 0;
-    CSSSelector::Relation relation = CSSSelector::Descendant;
+    CSSSelector::RelationType relation = CSSSelector::Descendant;
     bool foundHostPseudo = false;
 
     for (const CSSSelector* current = &selector; current; current = current->tagHistory()) {
-        switch (current->pseudoType()) {
+        switch (current->getPseudoType()) {
         case CSSSelector::PseudoFirstLine:
             metadata.usesFirstLineRules = true;
             break;
@@ -623,7 +623,7 @@
             break;
         }
 
-        if (current->relationIsAffectedByPseudoContent() || current->pseudoType() == CSSSelector::PseudoSlotted)
+        if (current->relationIsAffectedByPseudoContent() || current->getPseudoType() == CSSSelector::PseudoSlotted)
             metadata.foundInsertionPointCrossing = true;
 
         relation = current->relation();
diff --git a/third_party/WebKit/Source/core/css/RuleSet.cpp b/third_party/WebKit/Source/core/css/RuleSet.cpp
index ba97888f6..fddc6659 100644
--- a/third_party/WebKit/Source/core/css/RuleSet.cpp
+++ b/third_party/WebKit/Source/core/css/RuleSet.cpp
@@ -78,7 +78,7 @@
             return true;
         if (selectorListContainsUncommonAttributeSelector(current))
             return true;
-        if (current->relationIsAffectedByPseudoContent() || current->pseudoType() == CSSSelector::PseudoSlotted)
+        if (current->relationIsAffectedByPseudoContent() || current->getPseudoType() == CSSSelector::PseudoSlotted)
             return false;
         if (current->relation() != CSSSelector::SubSelector) {
             current = current->tagHistory();
@@ -98,9 +98,9 @@
 static inline PropertyWhitelistType determinePropertyWhitelistType(const AddRuleFlags addRuleFlags, const CSSSelector& selector)
 {
     for (const CSSSelector* component = &selector; component; component = component->tagHistory()) {
-        if (component->pseudoType() == CSSSelector::PseudoCue || (component->match() == CSSSelector::PseudoElement && component->value() == TextTrackCue::cueShadowPseudoId()))
+        if (component->getPseudoType() == CSSSelector::PseudoCue || (component->match() == CSSSelector::PseudoElement && component->value() == TextTrackCue::cueShadowPseudoId()))
             return PropertyWhitelistCue;
-        if (component->pseudoType() == CSSSelector::PseudoFirstLetter)
+        if (component->getPseudoType() == CSSSelector::PseudoFirstLetter)
             return PropertyWhitelistFirstLetter;
     }
     return PropertyWhitelistNone;
@@ -115,7 +115,7 @@
     , m_containsUncommonAttributeSelector(blink::containsUncommonAttributeSelector(selector()))
     , m_linkMatchType(selector().computeLinkMatchType())
     , m_hasDocumentSecurityOrigin(addRuleFlags & RuleHasDocumentSecurityOrigin)
-    , m_propertyWhitelistType(determinePropertyWhitelistType(addRuleFlags, selector()))
+    , m_propertyWhitelist(determinePropertyWhitelistType(addRuleFlags, selector()))
 {
     SelectorFilter::collectIdentifierHashes(selector(), m_descendantSelectorIdentifierHashes, maximumIdentifierCount);
 }
@@ -144,7 +144,7 @@
     default:
         break;
     }
-    if (selector->pseudoType() == CSSSelector::PseudoWebKitCustomElement)
+    if (selector->getPseudoType() == CSSSelector::PseudoWebKitCustomElement)
         customPseudoElementName = selector->value();
 }
 
@@ -183,7 +183,7 @@
         return true;
     }
 
-    switch (component.pseudoType()) {
+    switch (component.getPseudoType()) {
     case CSSSelector::PseudoCue:
         m_cuePseudoRules.append(ruleData);
         return true;
diff --git a/third_party/WebKit/Source/core/css/RuleSet.h b/third_party/WebKit/Source/core/css/RuleSet.h
index 12dd72a..7f74542 100644
--- a/third_party/WebKit/Source/core/css/RuleSet.h
+++ b/third_party/WebKit/Source/core/css/RuleSet.h
@@ -86,7 +86,7 @@
     unsigned specificity() const { return m_specificity; }
     unsigned linkMatchType() const { return m_linkMatchType; }
     bool hasDocumentSecurityOrigin() const { return m_hasDocumentSecurityOrigin; }
-    PropertyWhitelistType propertyWhitelistType(bool isMatchingUARules = false) const { return isMatchingUARules ? PropertyWhitelistNone : static_cast<PropertyWhitelistType>(m_propertyWhitelistType); }
+    PropertyWhitelistType propertyWhitelist(bool isMatchingUARules = false) const { return isMatchingUARules ? PropertyWhitelistNone : static_cast<PropertyWhitelistType>(m_propertyWhitelist); }
     // Try to balance between memory usage (there can be lots of RuleData objects) and good filtering performance.
     static const unsigned maximumIdentifierCount = 4;
     const unsigned* descendantSelectorIdentifierHashes() const { return m_descendantSelectorIdentifierHashes; }
@@ -104,7 +104,7 @@
     unsigned m_containsUncommonAttributeSelector : 1;
     unsigned m_linkMatchType : 2; //  CSSSelector::LinkMatchMask
     unsigned m_hasDocumentSecurityOrigin : 1;
-    unsigned m_propertyWhitelistType : 2;
+    unsigned m_propertyWhitelist : 2;
     // Use plain array instead of a Vector to minimize memory overhead.
     unsigned m_descendantSelectorIdentifierHashes[maximumIdentifierCount];
 };
diff --git a/third_party/WebKit/Source/core/css/SelectorChecker.cpp b/third_party/WebKit/Source/core/css/SelectorChecker.cpp
index aae1bd5..2396d13 100644
--- a/third_party/WebKit/Source/core/css/SelectorChecker.cpp
+++ b/third_party/WebKit/Source/core/css/SelectorChecker.cpp
@@ -267,7 +267,7 @@
 {
     SelectorCheckingContext nextContext = prepareNextContextForRelation(context);
 
-    CSSSelector::Relation relation = context.selector->relation();
+    CSSSelector::RelationType relation = context.selector->relation();
 
     // Disable :visited matching when we see the first link or try to match anything else than an ancestors.
     if (!context.isSubSelector && (context.element->isLink() || (relation != CSSSelector::Descendant && relation != CSSSelector::Child)))
@@ -288,7 +288,7 @@
             return SelectorFailsCompletely;
         }
 
-        if (nextContext.selector->pseudoType() == CSSSelector::PseudoShadow)
+        if (nextContext.selector->getPseudoType() == CSSSelector::PseudoShadow)
             return matchForPseudoShadow(nextContext, context.element->containingShadowRoot(), result);
 
         for (nextContext.element = parentElement(context); nextContext.element; nextContext.element = parentElement(nextContext)) {
@@ -304,7 +304,7 @@
             if (context.selector->relationIsAffectedByPseudoContent())
                 return matchForPseudoContent(nextContext, *context.element, result);
 
-            if (nextContext.selector->pseudoType() == CSSSelector::PseudoShadow)
+            if (nextContext.selector->getPseudoType() == CSSSelector::PseudoShadow)
                 return matchForPseudoShadow(nextContext, context.element->parentNode(), result);
 
             nextContext.element = parentElement(context);
@@ -314,7 +314,7 @@
         }
     case CSSSelector::DirectAdjacent:
         // Shadow roots can't have sibling elements
-        if (nextContext.selector->pseudoType() == CSSSelector::PseudoShadow)
+        if (nextContext.selector->getPseudoType() == CSSSelector::PseudoShadow)
             return SelectorFailsCompletely;
 
         if (m_mode == ResolvingStyle) {
@@ -328,7 +328,7 @@
 
     case CSSSelector::IndirectAdjacent:
         // Shadow roots can't have sibling elements
-        if (nextContext.selector->pseudoType() == CSSSelector::PseudoShadow)
+        if (nextContext.selector->getPseudoType() == CSSSelector::PseudoShadow)
             return SelectorFailsCompletely;
 
         if (m_mode == ResolvingStyle) {
@@ -345,7 +345,7 @@
 
     case CSSSelector::ShadowPseudo:
         {
-            if (!m_isUARule && context.selector->pseudoType() == CSSSelector::PseudoShadow)
+            if (!m_isUARule && context.selector->getPseudoType() == CSSSelector::PseudoShadow)
                 Deprecation::countDeprecation(context.element->document(), UseCounter::CSSSelectorPseudoShadow);
             // If we're in the same tree-scope as the scoping element, then following a shadow descendant combinator would escape that and thus the scope.
             if (context.scope && context.scope->shadowHost() && context.scope->shadowHost()->treeScope() == context.element->treeScope())
@@ -437,7 +437,7 @@
     return containsHTMLSpaceTemplate<UChar>(string.characters16(), string.length());
 }
 
-static bool attributeValueMatches(const Attribute& attributeItem, CSSSelector::Match match, const AtomicString& selectorValue, TextCaseSensitivity caseSensitivity)
+static bool attributeValueMatches(const Attribute& attributeItem, CSSSelector::MatchType match, const AtomicString& selectorValue, TextCaseSensitivity caseSensitivity)
 {
     // TODO(esprehn): How do we get here with a null value?
     const AtomicString& value = attributeItem.value();
@@ -502,7 +502,7 @@
     return true;
 }
 
-static bool anyAttributeMatches(Element& element, CSSSelector::Match match, const CSSSelector& selector)
+static bool anyAttributeMatches(Element& element, CSSSelector::MatchType match, const CSSSelector& selector)
 {
     const QualifiedName& selectorAttr = selector.attribute();
     ASSERT(selectorAttr.localName() != starAtom); // Should not be possible from the CSS grammar.
@@ -512,7 +512,7 @@
     element.synchronizeAttribute(selectorAttr.localName());
 
     const AtomicString& selectorValue = selector.value();
-    TextCaseSensitivity caseSensitivity = (selector.attributeMatchType() == CSSSelector::CaseInsensitive) ? TextCaseASCIIInsensitive : TextCaseSensitive;
+    TextCaseSensitivity caseSensitivity = (selector.attributeMatch() == CSSSelector::CaseInsensitive) ? TextCaseASCIIInsensitive : TextCaseSensitive;
 
     AttributeCollection attributes = element.attributesWithoutUpdate();
     for (const auto& attributeItem: attributes) {
@@ -604,13 +604,13 @@
         // :not cannot nest. I don't really know why this is a
         // restriction in CSS3, but it is, so let's honor it.
         // the parser enforces that this never occurs
-        ASSERT(subContext.selector->pseudoType() != CSSSelector::PseudoNot);
+        ASSERT(subContext.selector->getPseudoType() != CSSSelector::PseudoNot);
         // We select between :visited and :link when applying. We don't know which one applied (or not) yet.
-        if (subContext.selector->pseudoType() == CSSSelector::PseudoVisited || (subContext.selector->pseudoType() == CSSSelector::PseudoLink && subContext.visitedMatchType == VisitedMatchEnabled))
+        if (subContext.selector->getPseudoType() == CSSSelector::PseudoVisited || (subContext.selector->getPseudoType() == CSSSelector::PseudoLink && subContext.visitedMatchType == VisitedMatchEnabled))
             return true;
         // context.scope is not available if m_mode == SharingRules.
         // We cannot determine whether :host or :scope matches a given element or not.
-        if (m_mode == SharingRules && (subContext.selector->isHostPseudoClass() || subContext.selector->pseudoType() == CSSSelector::PseudoScope))
+        if (m_mode == SharingRules && (subContext.selector->isHostPseudoClass() || subContext.selector->getPseudoType() == CSSSelector::PseudoScope))
             return true;
         if (!checkOne(subContext, result))
             return true;
@@ -629,7 +629,7 @@
         return checkScrollbarPseudoClass(context, result);
     }
 
-    switch (selector.pseudoType()) {
+    switch (selector.getPseudoType()) {
     case CSSSelector::PseudoNot:
         return checkPseudoNot(context, result);
     case CSSSelector::PseudoEmpty:
@@ -953,7 +953,7 @@
     const CSSSelector& selector = *context.selector;
     Element& element = *context.element;
 
-    switch (selector.pseudoType()) {
+    switch (selector.getPseudoType()) {
     case CSSSelector::PseudoCue:
         {
             SelectorCheckingContext subContext(context);
@@ -994,7 +994,7 @@
         if (m_mode == SharingRules)
             return true;
         ASSERT(m_mode != QueryingRules);
-        result.dynamicPseudo = CSSSelector::pseudoId(selector.pseudoType());
+        result.dynamicPseudo = CSSSelector::pseudoId(selector.getPseudoType());
         ASSERT(result.dynamicPseudo != NOPSEUDO);
         return true;
     }
@@ -1044,7 +1044,7 @@
             hostContext.treatShadowHostAsNormalScope = false;
             hostContext.scope = nullptr;
 
-            if (selector.pseudoType() == CSSSelector::PseudoHost)
+            if (selector.getPseudoType() == CSSSelector::PseudoHost)
                 break;
 
             hostContext.inRightmostCompound = false;
@@ -1064,18 +1064,18 @@
 {
     const CSSSelector& selector = *context.selector;
 
-    if (selector.pseudoType() == CSSSelector::PseudoNot)
+    if (selector.getPseudoType() == CSSSelector::PseudoNot)
         return checkPseudoNot(context, result);
 
     // FIXME: This is a temporary hack for resizers and scrollbar corners. Eventually :window-inactive should become a real
     // pseudo class and just apply to everything.
-    if (selector.pseudoType() == CSSSelector::PseudoWindowInactive)
+    if (selector.getPseudoType() == CSSSelector::PseudoWindowInactive)
         return !context.element->document().page()->focusController().isActive();
 
     if (!m_scrollbar)
         return false;
 
-    switch (selector.pseudoType()) {
+    switch (selector.getPseudoType()) {
     case CSSSelector::PseudoEnabled:
         return m_scrollbar->enabled();
     case CSSSelector::PseudoDisabled:
diff --git a/third_party/WebKit/Source/core/css/SelectorFilter.cpp b/third_party/WebKit/Source/core/css/SelectorFilter.cpp
index be4b594..61580269 100644
--- a/third_party/WebKit/Source/core/css/SelectorFilter.cpp
+++ b/third_party/WebKit/Source/core/css/SelectorFilter.cpp
@@ -133,7 +133,7 @@
 {
     unsigned* hash = identifierHashes;
     unsigned* end = identifierHashes + maximumIdentifierCount;
-    CSSSelector::Relation relation = selector.relation();
+    CSSSelector::RelationType relation = selector.relation();
     if (selector.relationIsAffectedByPseudoContent()) {
         // Disable fastRejectSelector.
         *identifierHashes = 0;
diff --git a/third_party/WebKit/Source/core/css/StyleColor.h b/third_party/WebKit/Source/core/css/StyleColor.h
index c3cb0bc..0bd696d 100644
--- a/third_party/WebKit/Source/core/css/StyleColor.h
+++ b/third_party/WebKit/Source/core/css/StyleColor.h
@@ -45,7 +45,7 @@
     static StyleColor currentColor() { return StyleColor(); }
 
     bool isCurrentColor() const { return m_currentColor; }
-    Color color() const { ASSERT(!isCurrentColor()); return m_color; }
+    Color getColor() const { ASSERT(!isCurrentColor()); return m_color; }
 
     Color resolve(Color currentColor) const { return m_currentColor ? currentColor : m_color; }
 
@@ -60,7 +60,7 @@
 {
     if (a.isCurrentColor() || b.isCurrentColor())
         return a.isCurrentColor() && b.isCurrentColor();
-    return a.color() == b.color();
+    return a.getColor() == b.getColor();
 }
 
 inline bool operator!=(const StyleColor& a, const StyleColor& b)
diff --git a/third_party/WebKit/Source/core/css/StyleRule.cpp b/third_party/WebKit/Source/core/css/StyleRule.cpp
index 7ff3eff76..636f2cbb 100644
--- a/third_party/WebKit/Source/core/css/StyleRule.cpp
+++ b/third_party/WebKit/Source/core/css/StyleRule.cpp
@@ -341,7 +341,7 @@
     StyleRuleBase::traceAfterDispatch(visitor);
 }
 
-StyleRuleGroup::StyleRuleGroup(Type type, WillBeHeapVector<RefPtrWillBeMember<StyleRuleBase>>& adoptRule)
+StyleRuleGroup::StyleRuleGroup(RuleType type, WillBeHeapVector<RefPtrWillBeMember<StyleRuleBase>>& adoptRule)
     : StyleRuleBase(type)
 {
     m_childRules.swap(adoptRule);
diff --git a/third_party/WebKit/Source/core/css/StyleRule.h b/third_party/WebKit/Source/core/css/StyleRule.h
index a631def..4f46bea0 100644
--- a/third_party/WebKit/Source/core/css/StyleRule.h
+++ b/third_party/WebKit/Source/core/css/StyleRule.h
@@ -37,7 +37,7 @@
 class CORE_EXPORT StyleRuleBase : public RefCountedWillBeGarbageCollectedFinalized<StyleRuleBase> {
     USING_FAST_MALLOC_WITH_TYPE_NAME_WILL_BE_REMOVED(blink::StyleRuleBase);
 public:
-    enum Type {
+    enum RuleType {
         Charset,
         Style,
         Import,
@@ -51,7 +51,7 @@
         Viewport,
     };
 
-    Type type() const { return static_cast<Type>(m_type); }
+    RuleType type() const { return static_cast<RuleType>(m_type); }
 
     bool isCharsetRule() const { return type() == Charset; }
     bool isFontFaceRule() const { return type() == FontFace; }
@@ -90,7 +90,7 @@
     ~StyleRuleBase() { }
 
 protected:
-    StyleRuleBase(Type type) : m_type(type) { }
+    StyleRuleBase(RuleType type) : m_type(type) { }
     StyleRuleBase(const StyleRuleBase& o) : m_type(o.m_type) { }
 
 private:
@@ -193,7 +193,7 @@
     DECLARE_TRACE_AFTER_DISPATCH();
 
 protected:
-    StyleRuleGroup(Type, WillBeHeapVector<RefPtrWillBeMember<StyleRuleBase>>& adoptRule);
+    StyleRuleGroup(RuleType, WillBeHeapVector<RefPtrWillBeMember<StyleRuleBase>>& adoptRule);
     StyleRuleGroup(const StyleRuleGroup&);
 
 private:
diff --git a/third_party/WebKit/Source/core/css/invalidation/InvalidationSet.cpp b/third_party/WebKit/Source/core/css/invalidation/InvalidationSet.cpp
index 8178f36..925ad85 100644
--- a/third_party/WebKit/Source/core/css/invalidation/InvalidationSet.cpp
+++ b/third_party/WebKit/Source/core/css/invalidation/InvalidationSet.cpp
@@ -288,7 +288,7 @@
 #ifndef NDEBUG
 void InvalidationSet::show() const
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->beginArray("InvalidationSet");
     toTracedValue(value.get());
     value->endArray();
diff --git a/third_party/WebKit/Source/core/css/invalidation/StyleSheetInvalidationAnalysis.cpp b/third_party/WebKit/Source/core/css/invalidation/StyleSheetInvalidationAnalysis.cpp
index 89db72f..ce959ed2 100644
--- a/third_party/WebKit/Source/core/css/invalidation/StyleSheetInvalidationAnalysis.cpp
+++ b/third_party/WebKit/Source/core/css/invalidation/StyleSheetInvalidationAnalysis.cpp
@@ -55,7 +55,7 @@
                 scopeSelector = current;
             else if (current->match() == CSSSelector::Class && (!scopeSelector || scopeSelector->match() != CSSSelector::Id))
                 scopeSelector = current;
-            CSSSelector::Relation relation = current->relation();
+            CSSSelector::RelationType relation = current->relation();
             // FIXME: it would be better to use setNeedsStyleRecalc for all shadow hosts matching
             // scopeSelector. Currently requests full style recalc.
             if (relation == CSSSelector::ShadowDeep || relation == CSSSelector::ShadowPseudo)
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp b/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp
index 7c76bf1..b20276b 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSParserImpl.cpp
@@ -41,7 +41,7 @@
 bool CSSParserImpl::parseValue(MutableStylePropertySet* declaration, CSSPropertyID unresolvedProperty, const String& string, bool important, const CSSParserContext& context)
 {
     CSSParserImpl parser(context);
-    StyleRule::Type ruleType = StyleRule::Style;
+    StyleRule::RuleType ruleType = StyleRule::Style;
     if (declaration->cssParserMode() == CSSViewportRuleMode)
         ruleType = StyleRule::Viewport;
     CSSTokenizer::Scope scope(string);
@@ -114,7 +114,7 @@
 bool CSSParserImpl::parseDeclarationList(MutableStylePropertySet* declaration, const String& string, const CSSParserContext& context)
 {
     CSSParserImpl parser(context);
-    StyleRule::Type ruleType = StyleRule::Style;
+    StyleRule::RuleType ruleType = StyleRule::Style;
     if (declaration->cssParserMode() == CSSViewportRuleMode)
         ruleType = StyleRule::Viewport;
     CSSTokenizer::Scope scope(string);
@@ -652,7 +652,7 @@
     return StyleRule::create(std::move(selectorList), createStylePropertySet(m_parsedProperties, m_context.mode()));
 }
 
-void CSSParserImpl::consumeDeclarationList(CSSParserTokenRange range, StyleRule::Type ruleType)
+void CSSParserImpl::consumeDeclarationList(CSSParserTokenRange range, StyleRule::RuleType ruleType)
 {
     ASSERT(m_parsedProperties.isEmpty());
 
@@ -702,7 +702,7 @@
     }
 }
 
-void CSSParserImpl::consumeDeclaration(CSSParserTokenRange range, StyleRule::Type ruleType)
+void CSSParserImpl::consumeDeclaration(CSSParserTokenRange range, StyleRule::RuleType ruleType)
 {
     CSSParserTokenRange rangeCopy = range; // For inspector callbacks
 
@@ -755,7 +755,7 @@
         m_parsedProperties.append(CSSProperty(CSSPropertyVariable, value.release(), important));
 }
 
-void CSSParserImpl::consumeDeclarationValue(CSSParserTokenRange range, CSSPropertyID unresolvedProperty, bool important, StyleRule::Type ruleType)
+void CSSParserImpl::consumeDeclarationValue(CSSParserTokenRange range, CSSPropertyID unresolvedProperty, bool important, StyleRule::RuleType ruleType)
 {
     CSSPropertyParser::parseValue(unresolvedProperty, important, range, m_context, m_parsedProperties, ruleType);
 }
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserImpl.h b/third_party/WebKit/Source/core/css/parser/CSSParserImpl.h
index 75246ac..882cbb4 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSParserImpl.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSParserImpl.h
@@ -97,9 +97,9 @@
     PassRefPtrWillBeRawPtr<StyleRuleKeyframe> consumeKeyframeStyleRule(CSSParserTokenRange prelude, CSSParserTokenRange block);
     PassRefPtrWillBeRawPtr<StyleRule> consumeStyleRule(CSSParserTokenRange prelude, CSSParserTokenRange block);
 
-    void consumeDeclarationList(CSSParserTokenRange, StyleRule::Type);
-    void consumeDeclaration(CSSParserTokenRange, StyleRule::Type);
-    void consumeDeclarationValue(CSSParserTokenRange, CSSPropertyID, bool important, StyleRule::Type);
+    void consumeDeclarationList(CSSParserTokenRange, StyleRule::RuleType);
+    void consumeDeclaration(CSSParserTokenRange, StyleRule::RuleType);
+    void consumeDeclarationValue(CSSParserTokenRange, CSSPropertyID, bool important, StyleRule::RuleType);
     void consumeVariableValue(CSSParserTokenRange, const AtomicString& propertyName, bool important);
 
     static PassOwnPtr<Vector<double>> consumeKeyframeKeyList(CSSParserTokenRange);
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserObserver.h b/third_party/WebKit/Source/core/css/parser/CSSParserObserver.h
index 7d49565..784bbe9 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSParserObserver.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSParserObserver.h
@@ -35,7 +35,7 @@
 class CSSParserObserver {
     STACK_ALLOCATED();
 public:
-    virtual void startRuleHeader(StyleRule::Type, unsigned offset) = 0;
+    virtual void startRuleHeader(StyleRule::RuleType, unsigned offset) = 0;
     virtual void endRuleHeader(unsigned offset) = 0;
     virtual void observeSelector(unsigned startOffset, unsigned endOffset) = 0;
     virtual void startRuleBody(unsigned offset) = 0;
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserSelector.cpp b/third_party/WebKit/Source/core/css/parser/CSSParserSelector.cpp
index bd3cd467..e93c566 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSParserSelector.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSParserSelector.cpp
@@ -80,7 +80,7 @@
     return false;
 }
 
-void CSSParserSelector::appendTagHistory(CSSSelector::Relation relation, PassOwnPtr<CSSParserSelector> selector)
+void CSSParserSelector::appendTagHistory(CSSSelector::RelationType relation, PassOwnPtr<CSSParserSelector> selector)
 {
     CSSParserSelector* end = this;
     while (end->tagHistory())
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserSelector.h b/third_party/WebKit/Source/core/css/parser/CSSParserSelector.h
index af6b5884..fcd2f6d 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSParserSelector.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSParserSelector.h
@@ -39,13 +39,13 @@
 
     PassOwnPtr<CSSSelector> releaseSelector() { return m_selector.release(); }
 
-    CSSSelector::Relation relation() const { return m_selector->relation(); }
+    CSSSelector::RelationType relation() const { return m_selector->relation(); }
     void setValue(const AtomicString& value, bool matchLowerCase = false) { m_selector->setValue(value, matchLowerCase); }
     void setAttribute(const QualifiedName& value, CSSSelector::AttributeMatchType matchType) { m_selector->setAttribute(value, matchType); }
     void setArgument(const AtomicString& value) { m_selector->setArgument(value); }
     void setNth(int a, int b) { m_selector->setNth(a, b); }
-    void setMatch(CSSSelector::Match value) { m_selector->setMatch(value); }
-    void setRelation(CSSSelector::Relation value) { m_selector->setRelation(value); }
+    void setMatch(CSSSelector::MatchType value) { m_selector->setMatch(value); }
+    void setRelation(CSSSelector::RelationType value) { m_selector->setRelation(value); }
     void setForPage() { m_selector->setForPage(); }
     void setRelationIsAffectedByPseudoContent() { m_selector->setRelationIsAffectedByPseudoContent(); }
     bool relationIsAffectedByPseudoContent() const { return m_selector->relationIsAffectedByPseudoContent(); }
@@ -57,8 +57,8 @@
 
     bool isHostPseudoSelector() const;
 
-    CSSSelector::Match match() const { return m_selector->match(); }
-    CSSSelector::PseudoType pseudoType() const { return m_selector->pseudoType(); }
+    CSSSelector::MatchType match() const { return m_selector->match(); }
+    CSSSelector::PseudoType pseudoType() const { return m_selector->getPseudoType(); }
     const CSSSelectorList* selectorList() const { return m_selector->selectorList(); }
 
     bool needsImplicitShadowCombinatorForMatching() const { return pseudoType() == CSSSelector::PseudoWebKitCustomElement || pseudoType() == CSSSelector::PseudoCue || pseudoType() == CSSSelector::PseudoShadow || pseudoType() == CSSSelector::PseudoSlotted; }
@@ -68,7 +68,7 @@
     CSSParserSelector* tagHistory() const { return m_tagHistory.get(); }
     void setTagHistory(PassOwnPtr<CSSParserSelector> selector) { m_tagHistory = selector; }
     void clearTagHistory() { m_tagHistory.clear(); }
-    void appendTagHistory(CSSSelector::Relation, PassOwnPtr<CSSParserSelector>);
+    void appendTagHistory(CSSSelector::RelationType, PassOwnPtr<CSSParserSelector>);
     PassOwnPtr<CSSParserSelector> releaseTagHistory();
     void prependTagSelector(const QualifiedName&, bool tagIsImplicit = false);
 
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserToken.h b/third_party/WebKit/Source/core/css/parser/CSSParserToken.h
index 811db85..9ee58f4 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSParserToken.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSParserToken.h
@@ -135,8 +135,8 @@
     NumericSign numericSign() const;
     NumericValueType numericValueType() const;
     double numericValue() const;
-    HashTokenType hashTokenType() const { ASSERT(m_type == HashToken); return m_hashTokenType; }
-    BlockType blockType() const { return static_cast<BlockType>(m_blockType); }
+    HashTokenType getHashTokenType() const { ASSERT(m_type == HashToken); return m_hashTokenType; }
+    BlockType getBlockType() const { return static_cast<BlockType>(m_blockType); }
     CSSPrimitiveValue::UnitType unitType() const { return static_cast<CSSPrimitiveValue::UnitType>(m_unit); }
     UChar32 unicodeRangeStart() const { ASSERT(m_type == UnicodeRangeToken); return m_unicodeRange.start; }
     UChar32 unicodeRangeEnd() const { ASSERT(m_type == UnicodeRangeToken); return m_unicodeRange.end; }
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserTokenRange.cpp b/third_party/WebKit/Source/core/css/parser/CSSParserTokenRange.cpp
index 7381a7c..bda8767 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSParserTokenRange.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSParserTokenRange.cpp
@@ -28,14 +28,14 @@
 
 CSSParserTokenRange CSSParserTokenRange::consumeBlock()
 {
-    ASSERT(peek().blockType() == CSSParserToken::BlockStart);
+    ASSERT(peek().getBlockType() == CSSParserToken::BlockStart);
     const CSSParserToken* start = &peek() + 1;
     unsigned nestingLevel = 0;
     do {
         const CSSParserToken& token = consume();
-        if (token.blockType() == CSSParserToken::BlockStart)
+        if (token.getBlockType() == CSSParserToken::BlockStart)
             nestingLevel++;
-        else if (token.blockType() == CSSParserToken::BlockEnd)
+        else if (token.getBlockType() == CSSParserToken::BlockEnd)
             nestingLevel--;
     } while (nestingLevel && m_first < m_last);
 
@@ -51,9 +51,9 @@
     unsigned nestingLevel = 0;
     do {
         const CSSParserToken& token = consume();
-        if (token.blockType() == CSSParserToken::BlockStart)
+        if (token.getBlockType() == CSSParserToken::BlockStart)
             nestingLevel++;
-        else if (token.blockType() == CSSParserToken::BlockEnd)
+        else if (token.getBlockType() == CSSParserToken::BlockEnd)
             nestingLevel--;
     } while (nestingLevel && m_first < m_last);
 }
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
index aec521309..50f616a 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -67,7 +67,7 @@
 
 bool CSSPropertyParser::parseValue(CSSPropertyID unresolvedProperty, bool important,
     const CSSParserTokenRange& range, const CSSParserContext& context,
-    WillBeHeapVector<CSSProperty, 256>& parsedProperties, StyleRule::Type ruleType)
+    WillBeHeapVector<CSSProperty, 256>& parsedProperties, StyleRule::RuleType ruleType)
 {
     if (hasInvalidNumericValues(range))
         return false;
@@ -1956,7 +1956,7 @@
         return nullptr;
     String pathString = functionArgs.consumeIncludingWhitespace().value();
 
-    RefPtr<SVGPathByteStream> byteStream = SVGPathByteStream::create();
+    OwnPtr<SVGPathByteStream> byteStream = SVGPathByteStream::create();
     if (buildByteStreamFromString(pathString, *byteStream) != SVGParseStatus::NoError
         || !functionArgs.atEnd())
         return nullptr;
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
index a406cea..674bd11d 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
@@ -76,7 +76,7 @@
 
     static bool parseValue(CSSPropertyID, bool important,
         const CSSParserTokenRange&, const CSSParserContext&,
-        WillBeHeapVector<CSSProperty, 256>&, StyleRule::Type);
+        WillBeHeapVector<CSSProperty, 256>&, StyleRule::RuleType);
 
     static bool isSystemColor(CSSValueID);
     static bool isColorKeyword(CSSValueID);
diff --git a/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp
index 105b5e4..74fb2f83 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp
@@ -19,7 +19,7 @@
     for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector)) {
         for (const CSSSelector* current = selector; current ; current = current->tagHistory()) {
             UseCounter::Feature feature = UseCounter::NumberOfFeatures;
-            switch (current->pseudoType()) {
+            switch (current->getPseudoType()) {
             case CSSSelector::PseudoUnresolved:
                 feature = UseCounter::CSSSelectorPseudoUnresolved;
                 break;
@@ -172,7 +172,7 @@
     for (CSSParserSelector* simple = selector.get(); simple && !previousCompoundFlags; simple = simple->tagHistory())
         previousCompoundFlags |= extractCompoundFlags(*simple, m_context.mode());
 
-    while (CSSSelector::Relation combinator = consumeCombinator(range)) {
+    while (CSSSelector::RelationType combinator = consumeCombinator(range)) {
         OwnPtr<CSSParserSelector> nextSelector = consumeCompoundSelector(range);
         if (!nextSelector)
             return combinator == CSSSelector::Descendant ? selector.release() : nullptr;
@@ -265,7 +265,7 @@
         ASSERT(simpleSelector.selectorList());
         ASSERT(simpleSelector.selectorList()->first());
         ASSERT(!simpleSelector.selectorList()->first()->tagHistory());
-        pseudo = simpleSelector.selectorList()->first()->pseudoType();
+        pseudo = simpleSelector.selectorList()->first()->getPseudoType();
     }
     return isPseudoClassValidAfterPseudoElement(pseudo, compoundPseudoElement);
 }
@@ -380,7 +380,7 @@
 PassOwnPtr<CSSParserSelector> CSSSelectorParser::consumeId(CSSParserTokenRange& range)
 {
     ASSERT(range.peek().type() == HashToken);
-    if (range.peek().hashTokenType() != HashTokenId)
+    if (range.peek().getHashTokenType() != HashTokenId)
         return nullptr;
     OwnPtr<CSSParserSelector> selector = CSSParserSelector::create();
     selector->setMatch(CSSSelector::Id);
@@ -553,9 +553,9 @@
     return nullptr;
 }
 
-CSSSelector::Relation CSSSelectorParser::consumeCombinator(CSSParserTokenRange& range)
+CSSSelector::RelationType CSSSelectorParser::consumeCombinator(CSSParserTokenRange& range)
 {
-    CSSSelector::Relation fallbackResult = CSSSelector::SubSelector;
+    CSSSelector::RelationType fallbackResult = CSSSelector::SubSelector;
     while (range.peek().type() == WhitespaceToken) {
         range.consume();
         fallbackResult = CSSSelector::Descendant;
@@ -588,7 +588,7 @@
     return CSSSelector::ShadowDeep;
 }
 
-CSSSelector::Match CSSSelectorParser::consumeAttributeMatch(CSSParserTokenRange& range)
+CSSSelector::MatchType CSSSelectorParser::consumeAttributeMatch(CSSParserTokenRange& range)
 {
     const CSSParserToken& token = range.consumeIncludingWhitespace();
     switch (token.type()) {
diff --git a/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.h b/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.h
index f07f053..4c6b768 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.h
@@ -44,8 +44,8 @@
     PassOwnPtr<CSSParserSelector> consumePseudo(CSSParserTokenRange&);
     PassOwnPtr<CSSParserSelector> consumeAttribute(CSSParserTokenRange&);
 
-    CSSSelector::Relation consumeCombinator(CSSParserTokenRange&);
-    CSSSelector::Match consumeAttributeMatch(CSSParserTokenRange&);
+    CSSSelector::RelationType consumeCombinator(CSSParserTokenRange&);
+    CSSSelector::MatchType consumeAttributeMatch(CSSParserTokenRange&);
     CSSSelector::AttributeMatchType consumeAttributeFlags(CSSParserTokenRange&);
 
     const AtomicString& defaultNamespace() const;
diff --git a/third_party/WebKit/Source/core/css/parser/CSSTokenizerTest.cpp b/third_party/WebKit/Source/core/css/parser/CSSTokenizerTest.cpp
index a96db8a..5532fb08 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSTokenizerTest.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSTokenizerTest.cpp
@@ -49,7 +49,7 @@
         break;
     case HashToken:
         ASSERT_EQ(String(expected.value()), String(actual.value()));
-        ASSERT_EQ(expected.hashTokenType(), actual.hashTokenType());
+        ASSERT_EQ(expected.getHashTokenType(), actual.getHashTokenType());
         break;
     default:
         break;
diff --git a/third_party/WebKit/Source/core/css/parser/CSSVariableParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSVariableParser.cpp
index 297ff31..f025509 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSVariableParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSVariableParser.cpp
@@ -29,7 +29,7 @@
 bool classifyBlock(CSSParserTokenRange range, bool& hasReferences, bool isTopLevelBlock = true)
 {
     while (!range.atEnd()) {
-        if (range.peek().blockType() == CSSParserToken::BlockStart) {
+        if (range.peek().getBlockType() == CSSParserToken::BlockStart) {
             const CSSParserToken& token = range.peek();
             CSSParserTokenRange block = range.consumeBlock();
             if (token.functionId() == CSSValueVar) {
@@ -43,7 +43,7 @@
             continue;
         }
 
-        ASSERT(range.peek().blockType() != CSSParserToken::BlockEnd);
+        ASSERT(range.peek().getBlockType() != CSSParserToken::BlockEnd);
 
         const CSSParserToken& token = range.consume();
         switch (token.type()) {
diff --git a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
index e299b5e..79a5db7d 100644
--- a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
@@ -1386,23 +1386,23 @@
     if (!validUnit(value, FLength | FNonNeg))
         return false;
 
-    RefPtrWillBeRawPtr<CSSPrimitiveValue> columnGap = createPrimitiveNumericValue(value);
-    RefPtrWillBeRawPtr<CSSPrimitiveValue> rowGap = nullptr;
+    RefPtrWillBeRawPtr<CSSPrimitiveValue> rowGap = createPrimitiveNumericValue(value);
+    RefPtrWillBeRawPtr<CSSPrimitiveValue> columnGap = nullptr;
 
     value = m_valueList->next();
     if (value) {
         if (!validUnit(value, FLength | FNonNeg))
             return false;
 
-        rowGap = createPrimitiveNumericValue(value);
+        columnGap = createPrimitiveNumericValue(value);
         if (m_valueList->next())
             return false;
     } else {
-        rowGap = columnGap;
+        columnGap = rowGap;
     }
 
-    addProperty(CSSPropertyGridColumnGap, columnGap, important);
     addProperty(CSSPropertyGridRowGap, rowGap, important);
+    addProperty(CSSPropertyGridColumnGap, columnGap, important);
 
     return true;
 }
diff --git a/third_party/WebKit/Source/core/css/parser/MediaQueryBlockWatcher.cpp b/third_party/WebKit/Source/core/css/parser/MediaQueryBlockWatcher.cpp
index 1ee384b0..7494712 100644
--- a/third_party/WebKit/Source/core/css/parser/MediaQueryBlockWatcher.cpp
+++ b/third_party/WebKit/Source/core/css/parser/MediaQueryBlockWatcher.cpp
@@ -15,9 +15,9 @@
 
 void MediaQueryBlockWatcher::handleToken(const CSSParserToken& token)
 {
-    if (token.blockType() == CSSParserToken::BlockStart) {
+    if (token.getBlockType() == CSSParserToken::BlockStart) {
         ++m_blockLevel;
-    } else if (token.blockType() == CSSParserToken::BlockEnd) {
+    } else if (token.getBlockType() == CSSParserToken::BlockEnd) {
         ASSERT(m_blockLevel);
         --m_blockLevel;
     }
diff --git a/third_party/WebKit/Source/core/css/parser/MediaQueryParser.cpp b/third_party/WebKit/Source/core/css/parser/MediaQueryParser.cpp
index cfb23db..5dadb44 100644
--- a/third_party/WebKit/Source/core/css/parser/MediaQueryParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/MediaQueryParser.cpp
@@ -51,7 +51,7 @@
 
 MediaQueryParser::~MediaQueryParser() { }
 
-void MediaQueryParser::setStateAndRestrict(State state, MediaQuery::Restrictor restrictor)
+void MediaQueryParser::setStateAndRestrict(State state, MediaQuery::RestrictorType restrictor)
 {
     m_mediaQueryData.setRestrictor(restrictor);
     m_state = state;
@@ -188,7 +188,7 @@
 
 void MediaQueryParser::skipUntilBlockEnd(CSSParserTokenType type, const CSSParserToken& token)
 {
-    if (token.blockType() == CSSParserToken::BlockEnd && !m_blockWatcher.blockLevel())
+    if (token.getBlockType() == CSSParserToken::BlockEnd && !m_blockWatcher.blockLevel())
         m_state = SkipUntilComma;
 }
 
@@ -196,7 +196,7 @@
 
 void MediaQueryParser::handleBlocks(const CSSParserToken& token)
 {
-    if (token.blockType() == CSSParserToken::BlockStart
+    if (token.getBlockType() == CSSParserToken::BlockStart
         && (token.type() != LeftParenthesisToken || m_blockWatcher.blockLevel()))
             m_state = SkipUntilBlockEnd;
 }
diff --git a/third_party/WebKit/Source/core/css/parser/MediaQueryParser.h b/third_party/WebKit/Source/core/css/parser/MediaQueryParser.h
index 6744e7d..bb05cba0 100644
--- a/third_party/WebKit/Source/core/css/parser/MediaQueryParser.h
+++ b/third_party/WebKit/Source/core/css/parser/MediaQueryParser.h
@@ -22,7 +22,7 @@
     STACK_ALLOCATED();
     WTF_MAKE_NONCOPYABLE(MediaQueryData);
 private:
-    MediaQuery::Restrictor m_restrictor;
+    MediaQuery::RestrictorType m_restrictor;
     String m_mediaType;
     ExpressionHeapVector m_expressions;
     String m_mediaFeature;
@@ -41,9 +41,9 @@
     {
         return (m_restrictor != MediaQuery::None || m_mediaTypeSet || m_expressions.size() > 0);
     }
-    inline MediaQuery::Restrictor restrictor() { return m_restrictor; }
+    inline MediaQuery::RestrictorType restrictor() { return m_restrictor; }
 
-    inline void setRestrictor(MediaQuery::Restrictor restrictor) { m_restrictor = restrictor; }
+    inline void setRestrictor(MediaQuery::RestrictorType restrictor) { m_restrictor = restrictor; }
 
     inline void setMediaFeature(const String& str) { m_mediaFeature = str; }
 };
@@ -83,7 +83,7 @@
 
     using State = void (MediaQueryParser::*)(CSSParserTokenType, const CSSParserToken&);
 
-    void setStateAndRestrict(State, MediaQuery::Restrictor);
+    void setStateAndRestrict(State, MediaQuery::RestrictorType);
     void handleBlocks(const CSSParserToken&);
 
     State m_state;
diff --git a/third_party/WebKit/Source/core/css/resolver/AnimatedStyleBuilder.cpp b/third_party/WebKit/Source/core/css/resolver/AnimatedStyleBuilder.cpp
index b396723..1e95f74 100644
--- a/third_party/WebKit/Source/core/css/resolver/AnimatedStyleBuilder.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/AnimatedStyleBuilder.cpp
@@ -293,7 +293,7 @@
     ComputedStyle* style = state.style();
     switch (property) {
     case CSSPropertyBackgroundColor:
-        style->setBackgroundColor(toAnimatableColor(value)->color());
+        style->setBackgroundColor(toAnimatableColor(value)->getColor());
         style->setVisitedLinkBackgroundColor(toAnimatableColor(value)->visitedLinkColor());
         return;
     case CSSPropertyBackgroundImage:
@@ -313,7 +313,7 @@
         style->accessSVGStyle().setBaselineShiftValue(animatableValueToLength(value, state));
         return;
     case CSSPropertyBorderBottomColor:
-        style->setBorderBottomColor(toAnimatableColor(value)->color());
+        style->setBorderBottomColor(toAnimatableColor(value)->getColor());
         style->setVisitedLinkBorderBottomColor(toAnimatableColor(value)->visitedLinkColor());
         return;
     case CSSPropertyBorderBottomLeftRadius:
@@ -339,21 +339,21 @@
         style->setBorderImageWidth(animatableValueToBorderImageLengthBox(value, state));
         return;
     case CSSPropertyBorderLeftColor:
-        style->setBorderLeftColor(toAnimatableColor(value)->color());
+        style->setBorderLeftColor(toAnimatableColor(value)->getColor());
         style->setVisitedLinkBorderLeftColor(toAnimatableColor(value)->visitedLinkColor());
         return;
     case CSSPropertyBorderLeftWidth:
         style->setBorderLeftWidth(animatableLineWidthClamp<unsigned>(value));
         return;
     case CSSPropertyBorderRightColor:
-        style->setBorderRightColor(toAnimatableColor(value)->color());
+        style->setBorderRightColor(toAnimatableColor(value)->getColor());
         style->setVisitedLinkBorderRightColor(toAnimatableColor(value)->visitedLinkColor());
         return;
     case CSSPropertyBorderRightWidth:
         style->setBorderRightWidth(animatableLineWidthClamp<unsigned>(value));
         return;
     case CSSPropertyBorderTopColor:
-        style->setBorderTopColor(toAnimatableColor(value)->color());
+        style->setBorderTopColor(toAnimatableColor(value)->getColor());
         style->setVisitedLinkBorderTopColor(toAnimatableColor(value)->visitedLinkColor());
         return;
     case CSSPropertyBorderTopLeftRadius:
@@ -375,7 +375,7 @@
         style->setClip(animatableValueToLengthBox(value, state));
         return;
     case CSSPropertyColor:
-        style->setColor(toAnimatableColor(value)->color());
+        style->setColor(toAnimatableColor(value)->getColor());
         style->setVisitedLinkColor(toAnimatableColor(value)->visitedLinkColor());
         return;
     case CSSPropertyFillOpacity:
@@ -384,7 +384,7 @@
     case CSSPropertyFill:
         {
             const AnimatableSVGPaint* svgPaint = toAnimatableSVGPaint(value);
-            style->accessSVGStyle().setFillPaint(svgPaint->paintType(), svgPaint->color(), svgPaint->uri(), true, false);
+            style->accessSVGStyle().setFillPaint(svgPaint->paintType(), svgPaint->getColor(), svgPaint->uri(), true, false);
             style->accessSVGStyle().setFillPaint(svgPaint->visitedLinkPaintType(), svgPaint->visitedLinkColor(), svgPaint->visitedLinkURI(), false, true);
         }
         return;
@@ -398,7 +398,7 @@
         style->setFlexBasis(animatableValueToLength(value, state, ValueRangeNonNegative));
         return;
     case CSSPropertyFloodColor:
-        style->setFloodColor(toAnimatableColor(value)->color());
+        style->setFloodColor(toAnimatableColor(value)->getColor());
         return;
     case CSSPropertyFloodOpacity:
         style->setFloodOpacity(clampTo<float>(toAnimatableDouble(value)->toDouble(), 0, 1));
@@ -422,7 +422,7 @@
         style->setLeft(animatableValueToLength(value, state));
         return;
     case CSSPropertyLightingColor:
-        style->setLightingColor(toAnimatableColor(value)->color());
+        style->setLightingColor(toAnimatableColor(value)->getColor());
         return;
     case CSSPropertyLineHeight:
         if (value->isLength())
@@ -471,7 +471,7 @@
         style->setOrphans(clampTo<short>(round(toAnimatableDouble(value)->toDouble()), 1));
         return;
     case CSSPropertyOutlineColor:
-        style->setOutlineColor(toAnimatableColor(value)->color());
+        style->setOutlineColor(toAnimatableColor(value)->getColor());
         style->setVisitedLinkOutlineColor(toAnimatableColor(value)->visitedLinkColor());
         return;
     case CSSPropertyOutlineOffset:
@@ -499,7 +499,7 @@
         style->setStrokeWidth(animatableValueToUnzoomedLength(value, state, ValueRangeNonNegative));
         return;
     case CSSPropertyStopColor:
-        style->setStopColor(toAnimatableColor(value)->color());
+        style->setStopColor(toAnimatableColor(value)->getColor());
         return;
     case CSSPropertyStopOpacity:
         style->setStopOpacity(clampTo<float>(toAnimatableDouble(value)->toDouble(), 0, 1));
@@ -519,12 +519,12 @@
     case CSSPropertyStroke:
         {
             const AnimatableSVGPaint* svgPaint = toAnimatableSVGPaint(value);
-            style->accessSVGStyle().setStrokePaint(svgPaint->paintType(), svgPaint->color(), svgPaint->uri(), true, false);
+            style->accessSVGStyle().setStrokePaint(svgPaint->paintType(), svgPaint->getColor(), svgPaint->uri(), true, false);
             style->accessSVGStyle().setStrokePaint(svgPaint->visitedLinkPaintType(), svgPaint->visitedLinkColor(), svgPaint->visitedLinkURI(), false, true);
         }
         return;
     case CSSPropertyTextDecorationColor:
-        style->setTextDecorationColor(toAnimatableColor(value)->color());
+        style->setTextDecorationColor(toAnimatableColor(value)->getColor());
         style->setVisitedLinkTextDecorationColor(toAnimatableColor(value)->visitedLinkColor());
         return;
     case CSSPropertyTextIndent:
@@ -552,7 +552,7 @@
         style->setColumnGap(clampTo(toAnimatableDouble(value)->toDouble(), 0));
         return;
     case CSSPropertyColumnRuleColor:
-        style->setColumnRuleColor(toAnimatableColor(value)->color());
+        style->setColumnRuleColor(toAnimatableColor(value)->getColor());
         style->setVisitedLinkColumnRuleColor(toAnimatableColor(value)->visitedLinkColor());
         return;
     case CSSPropertyColumnWidth:
@@ -608,7 +608,7 @@
         style->setShapeImageThreshold(clampTo<float>(toAnimatableDouble(value)->toDouble(), 0, 1));
         return;
     case CSSPropertyWebkitTextStrokeColor:
-        style->setTextStrokeColor(toAnimatableColor(value)->color());
+        style->setTextStrokeColor(toAnimatableColor(value)->getColor());
         style->setVisitedLinkTextStrokeColor(toAnimatableColor(value)->visitedLinkColor());
         return;
     case CSSPropertyTransform: {
diff --git a/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp b/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp
index 21ba3a2..ace65cc 100644
--- a/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp
@@ -113,7 +113,7 @@
     CSSParserContext context(HTMLStandardMode, nullptr);
     WillBeHeapVector<CSSProperty, 256> parsedProperties;
     // TODO(timloh): This should be CSSParser::parseSingleValue and not need a vector.
-    if (!CSSPropertyParser::parseValue(id, false, CSSParserTokenRange(tokens), context, parsedProperties, StyleRule::Type::Style))
+    if (!CSSPropertyParser::parseValue(id, false, CSSParserTokenRange(tokens), context, parsedProperties, StyleRule::RuleType::Style))
         return cssValuePool().createUnsetValue();
     ASSERT(parsedProperties.size() == 1);
     return parsedProperties[0].value();
@@ -129,7 +129,7 @@
 
         WillBeHeapVector<CSSProperty, 256> parsedProperties;
 
-        if (CSSPropertyParser::parseValue(id, false, CSSParserTokenRange(tokens), context, parsedProperties, StyleRule::Type::Style)) {
+        if (CSSPropertyParser::parseValue(id, false, CSSParserTokenRange(tokens), context, parsedProperties, StyleRule::RuleType::Style)) {
             unsigned parsedPropertiesCount = parsedProperties.size();
             for (unsigned i = 0; i < parsedPropertiesCount; ++i)
                 StyleBuilder::applyProperty(parsedProperties[i].id(), state, parsedProperties[i].value());
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp
index 75fd9d03..51b57ac 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/StyleBuilderConverter.cpp
@@ -977,7 +977,7 @@
 
 PassRefPtr<StylePath> StyleBuilderConverter::convertPath(StyleResolverState&, const CSSValue& value)
 {
-    return toCSSPathValue(value).cachedPath();
+    return toCSSPathValue(value).stylePath();
 }
 
 PassRefPtr<StylePath> StyleBuilderConverter::convertPathOrNone(StyleResolverState& state, const CSSValue& value)
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleResolverStats.cpp b/third_party/WebKit/Source/core/css/resolver/StyleResolverStats.cpp
index 5572b87..9bc076a 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleResolverStats.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/StyleResolverStats.cpp
@@ -63,9 +63,9 @@
     return allCountersEnabled;
 }
 
-PassRefPtr<TracedValue> StyleResolverStats::toTracedValue() const
+PassOwnPtr<TracedValue> StyleResolverStats::toTracedValue() const
 {
-    RefPtr<TracedValue> tracedValue = TracedValue::create();
+    OwnPtr<TracedValue> tracedValue = TracedValue::create();
     tracedValue->setInteger("sharedStyleLookups", sharedStyleLookups);
     tracedValue->setInteger("sharedStyleCandidates", sharedStyleCandidates);
     tracedValue->setInteger("sharedStyleFound", sharedStyleFound);
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleResolverStats.h b/third_party/WebKit/Source/core/css/resolver/StyleResolverStats.h
index 1ab28fc..8e0f820 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleResolverStats.h
+++ b/third_party/WebKit/Source/core/css/resolver/StyleResolverStats.h
@@ -47,7 +47,7 @@
 
     void reset();
     bool allCountersEnabled() const;
-    PassRefPtr<TracedValue> toTracedValue() const;
+    PassOwnPtr<TracedValue> toTracedValue() const;
 
     unsigned sharedStyleLookups;
     unsigned sharedStyleCandidates;
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 534e58b..26eaa978 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -346,9 +346,11 @@
 
 static bool isOriginPotentiallyTrustworthy(SecurityOrigin* origin, String* errorMessage)
 {
+    if (origin->isPotentiallyTrustworthy())
+        return true;
     if (errorMessage)
-        return origin->isPotentiallyTrustworthy(*errorMessage);
-    return origin->isPotentiallyTrustworthy();
+        *errorMessage = origin->isPotentiallyTrustworthyErrorMessage();
+    return false;
 }
 
 uint64_t Document::s_globalTreeVersion = 0;
@@ -1212,7 +1214,7 @@
 {
     if (RuntimeEnabledFeatures::scrollTopLeftInteropEnabled()) {
         if (inQuirksMode()) {
-            updateLayoutTreeIfNeeded();
+            updateLayoutTree();
             HTMLBodyElement* body = firstBodyElement();
             if (body && body->layoutObject() && body->layoutObject()->hasOverflowClip())
                 return nullptr;
@@ -1718,7 +1720,7 @@
 }
 #endif
 
-void Document::updateLayoutTreeIfNeeded()
+void Document::updateLayoutTree()
 {
     ASSERT(isMainThread());
 
@@ -1909,12 +1911,12 @@
     return false;
 }
 
-void Document::updateLayoutTreeForNodeIfNeeded(Node* node)
+void Document::updateLayoutTreeForNode(Node* node)
 {
     ASSERT(node);
     if (!needsLayoutTreeUpdateForNode(*node))
         return;
-    updateLayoutTreeIfNeeded();
+    updateLayoutTree();
 }
 
 void Document::updateLayout()
@@ -1933,7 +1935,7 @@
     if (HTMLFrameOwnerElement* owner = ownerElement())
         owner->document().updateLayout();
 
-    updateLayoutTreeIfNeeded();
+    updateLayoutTree();
 
     if (!isActive())
         return;
@@ -1982,7 +1984,7 @@
 
 void Document::clearFocusedElementTimerFired(Timer<Document>*)
 {
-    updateLayoutTreeIfNeeded();
+    updateLayoutTree();
     m_clearFocusedElementTimer.stop();
 
     if (m_focusedElement && !m_focusedElement->isFocusable())
@@ -2016,10 +2018,10 @@
             // pending, some nodes may not have had their real style calculated yet. Normally this
             // gets cleaned when style sheets arrive but here we need up-to-date style immediately.
             setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::CleanupPlaceholderStyles));
-            updateLayoutTreeIfNeeded();
+            updateLayoutTree();
         }
     }
-    updateLayoutTreeIfNeeded();
+    updateLayoutTree();
 }
 
 void Document::updateLayoutIgnorePendingStylesheets(Document::RunPostLayoutTasks runPostLayoutTasks)
@@ -2700,7 +2702,7 @@
     // necessary and can in fact be actively harmful if pages are loading at a rate of > 60fps
     // (if your platform is syncing flushes and limiting them to 60fps).
     if (!ownerElement() || (ownerElement()->layoutObject() && !ownerElement()->layoutObject()->needsLayout())) {
-        updateLayoutTreeIfNeeded();
+        updateLayoutTree();
 
         // Always do a layout after loading if needed.
         if (view() && layoutView() && (!layoutView()->firstChild() || layoutView()->needsLayout()))
@@ -3625,7 +3627,7 @@
     }
 
     if (newFocusedElement)
-        updateLayoutTreeForNodeIfNeeded(newFocusedElement.get());
+        updateLayoutTreeForNode(newFocusedElement.get());
     if (newFocusedElement && newFocusedElement->isFocusable()) {
         if (newFocusedElement->isRootEditableElement() && !acceptsEditingFocus(*newFocusedElement)) {
             // delegate blocks focus change
@@ -3707,7 +3709,7 @@
         frameHost()->chromeClient().focusedNodeChanged(oldFocusedElement.get(), m_focusedElement.get());
 
 SetFocusedElementDone:
-    updateLayoutTreeIfNeeded();
+    updateLayoutTree();
     if (LocalFrame* frame = this->frame())
         frame->selection().didChangeFocus();
     return !focusChangeBlocked;
@@ -4485,7 +4487,7 @@
     if (!frame || frame->document() != document)
         return Editor::Command();
 
-    document->updateLayoutTreeIfNeeded();
+    document->updateLayoutTree();
     return frame->editor().command(commandName, CommandFromDOM);
 }
 
@@ -4802,7 +4804,7 @@
         // we force the styles to be up to date before calling FrameLoader::finishedParsing().
         // See https://bugs.webkit.org/show_bug.cgi?id=36864 starting around comment 35.
         if (mainResourceWasAlreadyRequested)
-            updateLayoutTreeIfNeeded();
+            updateLayoutTree();
 
         frame->loader().finishedParsing();
 
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h
index 0476926..b144a8f3 100644
--- a/third_party/WebKit/Source/core/dom/Document.h
+++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -427,10 +427,10 @@
     bool needsLayoutTreeUpdateForNode(const Node&) const;
     // Update ComputedStyles and attach LayoutObjects if necessary, but don't
     // lay out.
-    void updateLayoutTreeIfNeeded();
-    // Same as updateLayoutTreeIfNeeded except ignoring pending stylesheets.
+    void updateLayoutTree();
+    // Same as updateLayoutTree() except ignoring pending stylesheets.
     void updateLayoutTreeIgnorePendingStylesheets();
-    void updateLayoutTreeForNodeIfNeeded(Node*);
+    void updateLayoutTreeForNode(Node*);
     void updateLayout();
     void layoutUpdated();
     enum RunPostLayoutTasks {
diff --git a/third_party/WebKit/Source/core/dom/DocumentStatisticsCollector.cpp b/third_party/WebKit/Source/core/dom/DocumentStatisticsCollector.cpp
index dd117f69..bcdc71e72 100644
--- a/third_party/WebKit/Source/core/dom/DocumentStatisticsCollector.cpp
+++ b/third_party/WebKit/Source/core/dom/DocumentStatisticsCollector.cpp
@@ -235,7 +235,7 @@
     double startTime = monotonicallyIncreasingTime();
 
     // This should be cheap since collectStatistics is only called right after layout.
-    document.updateLayoutTreeIfNeeded();
+    document.updateLayoutTree();
 
     // Traverse the DOM tree and collect statistics.
     collectFeatures(*body, features);
diff --git a/third_party/WebKit/Source/core/dom/DocumentTest.cpp b/third_party/WebKit/Source/core/dom/DocumentTest.cpp
index 8f13cb93d..72fa382 100644
--- a/third_party/WebKit/Source/core/dom/DocumentTest.cpp
+++ b/third_party/WebKit/Source/core/dom/DocumentTest.cpp
@@ -301,12 +301,12 @@
     EXPECT_FALSE(document().view()->frameTimingRequestsDirty());
 
     // Just calling update should have no effect.
-    document().updateLayoutTreeIfNeeded();
+    document().updateLayoutTree();
     EXPECT_FALSE(document().view()->frameTimingRequestsDirty());
 
     // Calling update with a style change should flag Frame Timing as dirty.
     document().setChildNeedsStyleRecalc();
-    document().updateLayoutTreeIfNeeded();
+    document().updateLayoutTree();
     EXPECT_TRUE(document().view()->frameTimingRequestsDirty());
 }
 
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp
index 8533007..fe83bc5c 100644
--- a/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -108,6 +108,7 @@
 #include "core/inspector/InspectorInstrumentation.h"
 #include "core/layout/LayoutTextFragment.h"
 #include "core/layout/LayoutView.h"
+#include "core/layout/api/LayoutBoxItem.h"
 #include "core/loader/DocumentLoader.h"
 #include "core/page/ChromeClient.h"
 #include "core/page/FocusController.h"
@@ -565,15 +566,15 @@
     } else {
         if (!layoutObject())
             return;
-        LayoutBox* curBox = layoutObject()->enclosingBox();
+        LayoutBoxItem curBox = LayoutBoxItem(toLayoutBox(layoutObject())).enclosingBox();
         // FIXME: Native scrollers should only consume the scroll they
         // apply. See crbug.com/457765.
-        if (deltaX && curBox->scroll(ScrollLeft, ScrollByPrecisePixel, deltaX).didScroll) {
+        if (deltaX && curBox.scroll(ScrollLeft, ScrollByPrecisePixel, deltaX).didScroll) {
             scrollState.consumeDeltaNative(scrollState.deltaX(), 0);
             scrolled = true;
         }
 
-        if (deltaY && curBox->scroll(ScrollUp, ScrollByPrecisePixel, deltaY).didScroll) {
+        if (deltaY && curBox.scroll(ScrollUp, ScrollByPrecisePixel, deltaY).didScroll) {
             scrollState.consumeDeltaNative(0, scrollState.deltaY());
             scrolled = true;
         }
diff --git a/third_party/WebKit/Source/core/dom/FirstLetterPseudoElement.cpp b/third_party/WebKit/Source/core/dom/FirstLetterPseudoElement.cpp
index 936dd56..3573b029 100644
--- a/third_party/WebKit/Source/core/dom/FirstLetterPseudoElement.cpp
+++ b/third_party/WebKit/Source/core/dom/FirstLetterPseudoElement.cpp
@@ -29,6 +29,7 @@
 #include "core/layout/LayoutObjectInlines.h"
 #include "core/layout/LayoutText.h"
 #include "core/layout/LayoutTextFragment.h"
+#include "core/layout/api/LayoutTextFragmentItem.h"
 #include "wtf/TemporaryChange.h"
 #include "wtf/text/WTFString.h"
 #include "wtf/text/icu/UnicodeIcu.h"
@@ -184,17 +185,17 @@
     for (auto child = layoutObject()->slowFirstChild(); child; child = child->nextSibling()) {
         if (!child->isText() || !toLayoutText(child)->isTextFragment())
             continue;
-        LayoutTextFragment* childFragment = toLayoutTextFragment(child);
-        if (childFragment->firstLetterPseudoElement() != this)
+        LayoutTextFragmentItem childFragment = LayoutTextFragmentItem(toLayoutTextFragment(child));
+        if (childFragment.firstLetterPseudoElement() != this)
             continue;
 
-        childFragment->setTextFragment(oldText.impl()->substring(0, length), 0, length);
-        childFragment->dirtyLineBoxes();
+        childFragment.setTextFragment(oldText.impl()->substring(0, length), 0, length);
+        childFragment.dirtyLineBoxes();
 
         // Make sure the first-letter layoutObject is set to require a layout as it
         // needs to re-create the line boxes. The remaining text layoutObject
         // will be marked by the LayoutText::setText.
-        childFragment->setNeedsLayoutAndPrefWidthsRecalc(LayoutInvalidationReason::TextChanged);
+        childFragment.setNeedsLayoutAndPrefWidthsRecalc(LayoutInvalidationReason::TextChanged);
         break;
     }
 }
diff --git a/third_party/WebKit/Source/core/dom/Fullscreen.cpp b/third_party/WebKit/Source/core/dom/Fullscreen.cpp
index 1644cda..0828863a 100644
--- a/third_party/WebKit/Source/core/dom/Fullscreen.cpp
+++ b/third_party/WebKit/Source/core/dom/Fullscreen.cpp
@@ -446,7 +446,7 @@
 
     // FIXME: This should not call updateStyleIfNeeded.
     document()->setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::FullScreen));
-    document()->updateLayoutTreeIfNeeded();
+    document()->updateLayoutTree();
 
     m_fullScreenElement->didBecomeFullscreenElement();
 
diff --git a/third_party/WebKit/Source/core/dom/Node.cpp b/third_party/WebKit/Source/core/dom/Node.cpp
index 5821e59..9c6de0c2 100644
--- a/third_party/WebKit/Source/core/dom/Node.cpp
+++ b/third_party/WebKit/Source/core/dom/Node.cpp
@@ -528,13 +528,13 @@
 
 bool Node::isContentEditable(UserSelectAllTreatment treatment) const
 {
-    document().updateLayoutTreeIfNeeded();
+    document().updateLayoutTree();
     return hasEditableStyle(Editable, treatment);
 }
 
 bool Node::isContentRichlyEditable() const
 {
-    document().updateLayoutTreeIfNeeded();
+    document().updateLayoutTree();
     return hasEditableStyle(RichlyEditable, UserSelectAllIsAlwaysNonEditable);
 }
 
diff --git a/third_party/WebKit/Source/core/dom/Node.h b/third_party/WebKit/Source/core/dom/Node.h
index ffd5a7c..5656b031 100644
--- a/third_party/WebKit/Source/core/dom/Node.h
+++ b/third_party/WebKit/Source/core/dom/Node.h
@@ -234,7 +234,9 @@
     virtual PassRefPtrWillBeRawPtr<Node> cloneNode(bool deep) = 0;
     void normalize();
 
-    bool isSameNode(Node* other) const { return this == other; }
+    // TODO(yosin): Once we drop |Node.prototype.isSameNode()|, we should
+    // get rid of |isSameNodeDeprecated()|.
+    bool isSameNodeDeprecated(Node* other) const { return this == other; }
     bool isEqualNode(Node*) const;
     bool isDefaultNamespace(const AtomicString& namespaceURI) const;
     const AtomicString& lookupPrefix(const AtomicString& namespaceURI) const;
@@ -253,11 +255,11 @@
     bool isHTMLElement() const { return getFlag(IsHTMLFlag); }
     bool isSVGElement() const { return getFlag(IsSVGFlag); }
 
-    bool isPseudoElement() const { return pseudoId() != NOPSEUDO; }
-    bool isBeforePseudoElement() const { return pseudoId() == BEFORE; }
-    bool isAfterPseudoElement() const { return pseudoId() == AFTER; }
-    bool isFirstLetterPseudoElement() const { return pseudoId() == FIRST_LETTER; }
-    virtual PseudoId pseudoId() const { return NOPSEUDO; }
+    bool isPseudoElement() const { return getPseudoId() != NOPSEUDO; }
+    bool isBeforePseudoElement() const { return getPseudoId() == BEFORE; }
+    bool isAfterPseudoElement() const { return getPseudoId() == AFTER; }
+    bool isFirstLetterPseudoElement() const { return getPseudoId() == FIRST_LETTER; }
+    virtual PseudoId getPseudoId() const { return NOPSEUDO; }
 
     bool isCustomElement() const { return getFlag(CustomElementFlag); }
     enum CustomElementState {
diff --git a/third_party/WebKit/Source/core/dom/Node.idl b/third_party/WebKit/Source/core/dom/Node.idl
index e3aaa0a..264cfa5 100644
--- a/third_party/WebKit/Source/core/dom/Node.idl
+++ b/third_party/WebKit/Source/core/dom/Node.idl
@@ -81,5 +81,5 @@
 
     // FIXME: isSameNode has been removed from the spec:
     // https://www.w3.org/Bugs/Public/show_bug.cgi?id=27424
-    [MeasureAs=NodeIsSameNode] boolean isSameNode(Node? other);
+    [MeasureAs=NodeIsSameNode, ImplementedAs=isSameNodeDeprecated] boolean isSameNode(Node? other);
 };
diff --git a/third_party/WebKit/Source/core/dom/PseudoElement.cpp b/third_party/WebKit/Source/core/dom/PseudoElement.cpp
index 524549f..df7043e 100644
--- a/third_party/WebKit/Source/core/dom/PseudoElement.cpp
+++ b/third_party/WebKit/Source/core/dom/PseudoElement.cpp
@@ -177,7 +177,7 @@
     // The ::backdrop element is parented to the LayoutView, not to the node
     // that it's associated with. We need to make sure ::backdrop sends the
     // events to the parent node correctly.
-    if (pseudoId() == BACKDROP)
+    if (getPseudoId() == BACKDROP)
         return parentOrShadowHostNode();
 
     ASSERT(layoutObject());
diff --git a/third_party/WebKit/Source/core/dom/PseudoElement.h b/third_party/WebKit/Source/core/dom/PseudoElement.h
index 940543b..f0a77ae 100644
--- a/third_party/WebKit/Source/core/dom/PseudoElement.h
+++ b/third_party/WebKit/Source/core/dom/PseudoElement.h
@@ -43,7 +43,7 @@
 
     bool canStartSelection() const override { return false; }
     bool canContainRangeEndPoint() const override { return false; }
-    PseudoId pseudoId() const override { return m_pseudoId; }
+    PseudoId getPseudoId() const override { return m_pseudoId; }
 
     static String pseudoElementNameForEvents(PseudoId);
 
diff --git a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
index 910288e..3c86d58 100644
--- a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
+++ b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
@@ -463,14 +463,9 @@
 
     ScriptRunner::ExecutionType runOrder = m_willExecuteInOrder ? ScriptRunner::IN_ORDER_EXECUTION : ScriptRunner::ASYNC_EXECUTION;
     if (m_resource->errorOccurred()) {
-        dispatchErrorEvent();
-        // The error handler can move the HTMLScriptElement to a new document.
-        // In that case, we must notify the ScriptRunner of the new document,
-        // not the ScriptRunner of the old docuemnt.
-        contextDocument = m_element->document().contextDocument().get();
-        if (!contextDocument)
-            return;
         contextDocument->scriptRunner()->notifyScriptLoadError(this, runOrder);
+        dispatchErrorEvent();
+        detach();
         return;
     }
     contextDocument->scriptRunner()->notifyScriptReady(this, runOrder);
diff --git a/third_party/WebKit/Source/core/dom/ScriptRunner.cpp b/third_party/WebKit/Source/core/dom/ScriptRunner.cpp
index c10c779a..b3312a67 100644
--- a/third_party/WebKit/Source/core/dom/ScriptRunner.cpp
+++ b/third_party/WebKit/Source/core/dom/ScriptRunner.cpp
@@ -223,7 +223,6 @@
         RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(foundLoader);
         break;
     }
-    scriptLoader->detach();
     m_document->decrementLoadEventDelayCount();
 }
 
diff --git a/third_party/WebKit/Source/core/dom/StaticNodeList.h b/third_party/WebKit/Source/core/dom/StaticNodeList.h
index a1bebef..83d8ba4 100644
--- a/third_party/WebKit/Source/core/dom/StaticNodeList.h
+++ b/third_party/WebKit/Source/core/dom/StaticNodeList.h
@@ -33,7 +33,6 @@
 #include "wtf/PassRefPtr.h"
 #include "wtf/RefPtr.h"
 #include "wtf/Vector.h"
-#include <v8.h>
 
 namespace blink {
 
@@ -58,11 +57,6 @@
     DECLARE_VIRTUAL_TRACE();
 
 private:
-    ptrdiff_t AllocationSize()
-    {
-        return m_nodes.capacity() * sizeof(RefPtrWillBeMember<NodeType>);
-    }
-
     WillBeHeapVector<RefPtrWillBeMember<NodeType>> m_nodes;
 };
 
@@ -74,14 +68,12 @@
 {
     RefPtrWillBeRawPtr<StaticNodeTypeList<NodeType>> nodeList = adoptRefWillBeNoop(new StaticNodeTypeList<NodeType>);
     nodeList->m_nodes.swap(nodes);
-    v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(nodeList->AllocationSize());
     return nodeList.release();
 }
 
 template <typename NodeType>
 StaticNodeTypeList<NodeType>::~StaticNodeTypeList()
 {
-    v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(-AllocationSize());
 }
 
 template <typename NodeType>
diff --git a/third_party/WebKit/Source/core/dom/Text.cpp b/third_party/WebKit/Source/core/dom/Text.cpp
index 647966b8..f1647b7 100644
--- a/third_party/WebKit/Source/core/dom/Text.cpp
+++ b/third_party/WebKit/Source/core/dom/Text.cpp
@@ -34,6 +34,7 @@
 #include "core/events/ScopedEventQueue.h"
 #include "core/layout/LayoutText.h"
 #include "core/layout/LayoutTextCombine.h"
+#include "core/layout/api/LayoutTextItem.h"
 #include "core/layout/svg/LayoutSVGInlineText.h"
 #include "core/svg/SVGForeignObjectElement.h"
 #include "wtf/text/CString.h"
@@ -377,11 +378,11 @@
 
 void Text::recalcTextStyle(StyleRecalcChange change, Text* nextTextSibling)
 {
-    if (LayoutText* layoutObject = this->layoutObject()) {
+    if (LayoutTextItem layoutItem = LayoutTextItem(this->layoutObject())) {
         if (change != NoChange || needsStyleRecalc())
-            layoutObject->setStyle(document().ensureStyleResolver().styleForText(this));
+            layoutItem.setStyle(document().ensureStyleResolver().styleForText(this));
         if (needsStyleRecalc())
-            layoutObject->setText(dataImpl());
+            layoutItem.setText(dataImpl());
         clearNeedsStyleRecalc();
     } else if (needsStyleRecalc() || needsWhitespaceLayoutObject()) {
         reattach();
@@ -409,7 +410,7 @@
         lazyReattachIfAttached();
         // FIXME: Editing should be updated so this is not neccesary.
         if (recalcStyleBehavior == DeprecatedRecalcStyleImmediatlelyForEditing)
-            document().updateLayoutTreeIfNeeded();
+            document().updateLayoutTree();
         return;
     }
     textLayoutObject->setTextWithOffset(dataImpl(), offsetOfReplacedData, lengthOfReplacedData);
diff --git a/third_party/WebKit/Source/core/editing/DragCaretController.cpp b/third_party/WebKit/Source/core/editing/DragCaretController.cpp
index a9dfc12..23ddbe9 100644
--- a/third_party/WebKit/Source/core/editing/DragCaretController.cpp
+++ b/third_party/WebKit/Source/core/editing/DragCaretController.cpp
@@ -64,7 +64,7 @@
     if (m_position.isNull() || m_position.isOrphan()) {
         clearCaretRect();
     } else {
-        document->updateLayoutTreeIfNeeded();
+        document->updateLayoutTree();
         updateCaretRect(m_position);
     }
 }
diff --git a/third_party/WebKit/Source/core/editing/Editor.cpp b/third_party/WebKit/Source/core/editing/Editor.cpp
index b013bcc4..95e8f53 100644
--- a/third_party/WebKit/Source/core/editing/Editor.cpp
+++ b/third_party/WebKit/Source/core/editing/Editor.cpp
@@ -113,6 +113,7 @@
 // we should use the target control's selection for this editing operation.
 VisibleSelection Editor::selectionForCommand(Event* event)
 {
+    frame().selection().updateIfNeeded();
     VisibleSelection selection = frame().selection().selection();
     if (!event)
         return selection;
@@ -830,7 +831,7 @@
     VisiblePosition caret = frame().selection().selection().visibleStart();
     bool alignToEdge = isEndOfEditableOrNonEditableContent(caret);
     ASSERT(frame().document());
-    if (!TypingCommand::insertLineBreak(*frame().document(), 0))
+    if (!TypingCommand::insertLineBreak(*frame().document()))
         return false;
     revealSelectionAfterEditingOperation(alignToEdge ? ScrollAlignment::alignToEdgeIfNeeded : ScrollAlignment::alignCenterIfNeeded);
 
@@ -849,7 +850,7 @@
     bool alignToEdge = isEndOfEditableOrNonEditableContent(caret);
     ASSERT(frame().document());
     EditingState editingState;
-    if (!TypingCommand::insertParagraphSeparator(*frame().document(), 0))
+    if (!TypingCommand::insertParagraphSeparator(*frame().document()))
         return false;
     revealSelectionAfterEditingOperation(alignToEdge ? ScrollAlignment::alignToEdgeIfNeeded : ScrollAlignment::alignCenterIfNeeded);
 
@@ -1036,7 +1037,7 @@
             return;
         focusedElement->setAttribute(dirAttr, direction == LeftToRightWritingDirection ? "ltr" : "rtl");
         focusedElement->dispatchInputEvent();
-        frame().document()->updateLayoutTreeIfNeeded();
+        frame().document()->updateLayoutTree();
         return;
     }
 
@@ -1336,7 +1337,7 @@
 void Editor::tidyUpHTMLStructure(Document& document)
 {
     // hasEditableStyle() needs up-to-date ComputedStyle.
-    document.updateLayoutTreeIfNeeded();
+    document.updateLayoutTree();
     bool needsValidStructure = document.hasEditableStyle() || (document.documentElement() && document.documentElement()->hasEditableStyle());
     if (!needsValidStructure)
         return;
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.cpp b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
index fd90957a..f9e3ba0 100644
--- a/third_party/WebKit/Source/core/editing/FrameSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
@@ -914,7 +914,7 @@
     if (Element* element = document->focusedElement())
         element->focusStateChanged();
 
-    document->updateLayoutTreeIfNeeded();
+    document->updateLayoutTree();
 
     // Because LayoutObject::selectionBackgroundColor() and
     // LayoutObject::selectionForegroundColor() check if the frame is active,
diff --git a/third_party/WebKit/Source/core/editing/InputMethodController.cpp b/third_party/WebKit/Source/core/editing/InputMethodController.cpp
index efcf4a2..7aeb0d1 100644
--- a/third_party/WebKit/Source/core/editing/InputMethodController.cpp
+++ b/third_party/WebKit/Source/core/editing/InputMethodController.cpp
@@ -238,7 +238,7 @@
     // Updates styles before setting selection for composition to prevent
     // inserting the previous composition text into text nodes oddly.
     // See https://bugs.webkit.org/show_bug.cgi?id=46868
-    frame().document()->updateLayoutTreeIfNeeded();
+    frame().document()->updateLayoutTree();
 
     selectComposition();
 
diff --git a/third_party/WebKit/Source/core/editing/commands/ApplyBlockElementCommand.cpp b/third_party/WebKit/Source/core/editing/commands/ApplyBlockElementCommand.cpp
index f6e5d64..c2419e1 100644
--- a/third_party/WebKit/Source/core/editing/commands/ApplyBlockElementCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/ApplyBlockElementCommand.cpp
@@ -192,7 +192,7 @@
     start = startOfParagraph(endOfCurrentParagraph).deepEquivalent();
     end = endOfCurrentParagraph.deepEquivalent();
 
-    document().updateLayoutTreeIfNeeded();
+    document().updateLayoutTree();
 
     bool isStartAndEndOnSameNode = false;
     if (const ComputedStyle* startStyle = computedStyleOfEnclosingTextNode(start)) {
@@ -222,7 +222,7 @@
         }
     }
 
-    document().updateLayoutTreeIfNeeded();
+    document().updateLayoutTree();
 
     if (const ComputedStyle* endStyle = computedStyleOfEnclosingTextNode(end)) {
         bool isEndAndEndOfLastParagraphOnSameNode = computedStyleOfEnclosingTextNode(m_endOfLastParagraph) && end.anchorNode() == m_endOfLastParagraph.anchorNode();
diff --git a/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp b/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp
index a072725..18fe906 100644
--- a/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp
@@ -1086,7 +1086,7 @@
 {
     ASSERT(node);
 
-    node->document().updateLayoutTreeIfNeeded();
+    node->document().updateLayoutTree();
 
     if (!style || style->isEmpty() || !node->layoutObject() || isHTMLIFrameElement(*node))
         return;
diff --git a/third_party/WebKit/Source/core/editing/commands/DeleteSelectionCommand.cpp b/third_party/WebKit/Source/core/editing/commands/DeleteSelectionCommand.cpp
index 7407dc120..d7e92b0 100644
--- a/third_party/WebKit/Source/core/editing/commands/DeleteSelectionCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/DeleteSelectionCommand.cpp
@@ -470,7 +470,7 @@
         return;
 
     // Never remove the start block unless it's a table, in which case we won't merge content in.
-    if (startNode->isSameNode(m_startBlock.get()) && !startOffset && canHaveChildrenForEditing(startNode) && !isHTMLTableElement(*startNode)) {
+    if (startNode == m_startBlock.get() && !startOffset && canHaveChildrenForEditing(startNode) && !isHTMLTableElement(*startNode)) {
         startOffset = 0;
         startNode = NodeTraversal::next(*startNode);
         if (!startNode)
diff --git a/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp b/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
index d7b2d693..240080b 100644
--- a/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
@@ -558,7 +558,7 @@
         // InsertLineBreak is not implemented in IE or Firefox, so this behavior is only needed for
         // backward compatibility with ourselves, and for consistency with other commands.
         ASSERT(frame.document());
-        return TypingCommand::insertLineBreak(*frame.document(), 0);
+        return TypingCommand::insertLineBreak(*frame.document());
     }
     ASSERT_NOT_REACHED();
     return false;
@@ -585,7 +585,7 @@
 static bool executeInsertParagraph(LocalFrame& frame, Event*, EditorCommandSource, const String&)
 {
     ASSERT(frame.document());
-    return TypingCommand::insertParagraphSeparator(*frame.document(), 0);
+    return TypingCommand::insertParagraphSeparator(*frame.document());
 }
 
 static bool executeInsertTab(LocalFrame& frame, Event* event, EditorCommandSource, const String&)
diff --git a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
index d75b458..a4ce811 100644
--- a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
@@ -208,16 +208,16 @@
     applyTextInsertionCommand(frame.get(), cmd, selectionForInsertion, currentSelection);
 }
 
-bool TypingCommand::insertLineBreak(Document& document, Options options)
+bool TypingCommand::insertLineBreak(Document& document)
 {
     if (RefPtrWillBeRawPtr<TypingCommand> lastTypingCommand = lastTypingCommandIfStillOpenForTyping(document.frame())) {
-        lastTypingCommand->setShouldRetainAutocorrectionIndicator(options & RetainAutocorrectionIndicator);
+        lastTypingCommand->setShouldRetainAutocorrectionIndicator(false);
         EditingState editingState;
         lastTypingCommand->insertLineBreak(&editingState);
         return !editingState.isAborted();
     }
 
-    return TypingCommand::create(document, InsertLineBreak, "", options)->apply();
+    return TypingCommand::create(document, InsertLineBreak, "", 0)->apply();
 }
 
 bool TypingCommand::insertParagraphSeparatorInQuotedContent(Document& document)
@@ -231,16 +231,16 @@
     return TypingCommand::create(document, InsertParagraphSeparatorInQuotedContent)->apply();
 }
 
-bool TypingCommand::insertParagraphSeparator(Document& document, Options options)
+bool TypingCommand::insertParagraphSeparator(Document& document)
 {
     if (RefPtrWillBeRawPtr<TypingCommand> lastTypingCommand = lastTypingCommandIfStillOpenForTyping(document.frame())) {
-        lastTypingCommand->setShouldRetainAutocorrectionIndicator(options & RetainAutocorrectionIndicator);
+        lastTypingCommand->setShouldRetainAutocorrectionIndicator(false);
         EditingState editingState;
         lastTypingCommand->insertParagraphSeparator(&editingState);
         return !editingState.isAborted();
     }
 
-    return TypingCommand::create(document, InsertParagraphSeparator, "", options)->apply();
+    return TypingCommand::create(document, InsertParagraphSeparator, "", 0)->apply();
 }
 
 PassRefPtrWillBeRawPtr<TypingCommand> TypingCommand::lastTypingCommandIfStillOpenForTyping(LocalFrame* frame)
diff --git a/third_party/WebKit/Source/core/editing/commands/TypingCommand.h b/third_party/WebKit/Source/core/editing/commands/TypingCommand.h
index ea175263..a2fc7f7 100644
--- a/third_party/WebKit/Source/core/editing/commands/TypingCommand.h
+++ b/third_party/WebKit/Source/core/editing/commands/TypingCommand.h
@@ -58,13 +58,12 @@
     typedef unsigned Options;
 
     static void deleteSelection(Document&, Options = 0);
-    static void deleteKeyPressed(Document&, Options = 0, TextGranularity = CharacterGranularity);
+    static void deleteKeyPressed(Document&, Options, TextGranularity = CharacterGranularity);
     static void forwardDeleteKeyPressed(Document&, EditingState*, Options = 0, TextGranularity = CharacterGranularity);
     static void insertText(Document&, const String&, Options, TextCompositionType = TextCompositionNone);
     static void insertText(Document&, const String&, const VisibleSelection&, Options, TextCompositionType = TextCompositionNone);
-    static bool insertLineBreak(Document&, Options);
-    // TODO(tkent): |Options| argument should be removed. It's always 0.
-    static bool insertParagraphSeparator(Document&, Options);
+    static bool insertLineBreak(Document&);
+    static bool insertParagraphSeparator(Document&);
     static bool insertParagraphSeparatorInQuotedContent(Document&);
     static void closeTyping(LocalFrame*);
 
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
index fca8c4b2..b7211a6 100644
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
@@ -674,10 +674,11 @@
         node->layoutObject()->setShouldDoFullPaintInvalidation();
 }
 
-void DocumentMarkerController::setMarkersActive(Range* range, bool active)
+bool DocumentMarkerController::setMarkersActive(Range* range, bool active)
 {
     if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
-        return;
+        return false;
+
     ASSERT(!m_markers.isEmpty());
 
     Node* startContainer = range->startContainer();
@@ -685,23 +686,25 @@
 
     Node* pastLastNode = range->pastLastNode();
 
+    bool markerFound = false;
     for (Node* node = range->firstNode(); node != pastLastNode; node = NodeTraversal::next(*node)) {
         int startOffset = node == startContainer ? range->startOffset() : 0;
         int endOffset = node == endContainer ? range->endOffset() : INT_MAX;
-        setMarkersActive(node, startOffset, endOffset, active);
+        markerFound |= setMarkersActive(node, startOffset, endOffset, active);
     }
+    return markerFound;
 }
 
-void DocumentMarkerController::setMarkersActive(Node* node, unsigned startOffset, unsigned endOffset, bool active)
+bool DocumentMarkerController::setMarkersActive(Node* node, unsigned startOffset, unsigned endOffset, bool active)
 {
     MarkerLists* markers = m_markers.get(node);
     if (!markers)
-        return;
+        return false;
 
     bool docDirty = false;
     OwnPtrWillBeMember<MarkerList>& list = (*markers)[MarkerTypeToMarkerIndex(DocumentMarker::TextMatch)];
     if (!list)
-        return;
+        return false;
     MarkerList::iterator startPos = std::upper_bound(list->begin(), list->end(), startOffset, endsBefore);
     for (MarkerList::iterator marker = startPos; marker != list->end(); ++marker) {
 
@@ -716,6 +719,7 @@
     // repaint the affected node
     if (docDirty && node->layoutObject())
         node->layoutObject()->setShouldDoFullPaintInvalidation();
+    return docDirty;
 }
 
 #ifndef NDEBUG
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.h b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.h
index 7cdfc11..decf631 100644
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.h
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.h
@@ -80,8 +80,10 @@
     void removeMarkers(const MarkerRemoverPredicate& shouldRemoveMarker);
     void repaintMarkers(DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers());
     void shiftMarkers(Node*, unsigned startOffset, int delta);
-    void setMarkersActive(Range*, bool);
-    void setMarkersActive(Node*, unsigned startOffset, unsigned endOffset, bool);
+    // Returns true if markers within a range are found.
+    bool setMarkersActive(Range*, bool);
+    // Returns true if markers within a range defined by a node, |startOffset| and |endOffset| are found.
+    bool setMarkersActive(Node*, unsigned startOffset, unsigned endOffset, bool);
     bool hasMarkers(Node* node) const { return m_markers.contains(node); }
 
     DocumentMarker* markerContainingPoint(const LayoutPoint&, DocumentMarker::MarkerType);
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerControllerTest.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerControllerTest.cpp
index 199c7b9..07f81c7 100644
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerControllerTest.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerControllerTest.cpp
@@ -252,4 +252,21 @@
     EXPECT_EQ(2u, markerController().markers().size());
 }
 
+TEST_F(DocumentMarkerControllerTest, SetMarkerActiveTest)
+{
+    setBodyInnerHTML("<b>foo</b>");
+    RefPtrWillBeRawPtr<Element> bElement = toElement(document().body()->firstChild());
+    EphemeralRange ephemeralRange = EphemeralRange::rangeOfContents(*bElement);
+    Position startBElement = toPositionInDOMTree(ephemeralRange.startPosition());
+    Position endBElement = toPositionInDOMTree(ephemeralRange.endPosition());
+    RefPtrWillBeRawPtr<Range> range = Range::create(document(), startBElement, endBElement);
+    // Try to make active a marker that doesn't exist.
+    EXPECT_FALSE(markerController().setMarkersActive(range.get(), true));
+
+    // Add a marker and try it once more.
+    markerController().addTextMatchMarker(range.get(), false);
+    EXPECT_EQ(1u, markerController().markers().size());
+    EXPECT_TRUE(markerController().setMarkersActive(range.get(), true));
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/events/EventTypeNames.in b/third_party/WebKit/Source/core/events/EventTypeNames.in
index dd2d97c..3518856 100644
--- a/third_party/WebKit/Source/core/events/EventTypeNames.in
+++ b/third_party/WebKit/Source/core/events/EventTypeNames.in
@@ -256,10 +256,6 @@
 webkitTransitionEnd
 webkitfullscreenchange
 webkitfullscreenerror
-webkitkeyadded
-webkitkeyerror
-webkitkeymessage
-webkitneedkey
 webkitprerenderdomcontentloaded
 webkitprerenderload
 webkitprerenderstart
diff --git a/third_party/WebKit/Source/core/fetch/CSSStyleSheetResource.cpp b/third_party/WebKit/Source/core/fetch/CSSStyleSheetResource.cpp
index 29a0bfc03..50649c2 100644
--- a/third_party/WebKit/Source/core/fetch/CSSStyleSheetResource.cpp
+++ b/third_party/WebKit/Source/core/fetch/CSSStyleSheetResource.cpp
@@ -81,7 +81,7 @@
 
 void CSSStyleSheetResource::didAddClient(ResourceClient* c)
 {
-    ASSERT(c->resourceClientType() == StyleSheetResourceClient::expectedType());
+    ASSERT(StyleSheetResourceClient::isExpectedType(c));
     // Resource::didAddClient() must be before setCSSStyleSheet(),
     // because setCSSStyleSheet() may cause scripts to be executed, which could destroy 'c' if it is an instance of HTMLLinkElement.
     // see the comment of HTMLLinkElement::setCSSStyleSheet.
diff --git a/third_party/WebKit/Source/core/fetch/DocumentResource.h b/third_party/WebKit/Source/core/fetch/DocumentResource.h
index fbbf7e54..296ca45 100644
--- a/third_party/WebKit/Source/core/fetch/DocumentResource.h
+++ b/third_party/WebKit/Source/core/fetch/DocumentResource.h
@@ -72,8 +72,8 @@
 class DocumentResourceClient : public ResourceClient {
 public:
     ~DocumentResourceClient() override {}
-    static ResourceClientType expectedType() { return DocumentType; }
-    ResourceClientType resourceClientType() const override { return expectedType(); }
+    static bool isExpectedType(ResourceClient* client) { return client->resourceClientType() == DocumentType; }
+    ResourceClientType resourceClientType() const final { return DocumentType; }
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/fetch/FontResource.cpp b/third_party/WebKit/Source/core/fetch/FontResource.cpp
index f349b91e..51d6faa 100644
--- a/third_party/WebKit/Source/core/fetch/FontResource.cpp
+++ b/third_party/WebKit/Source/core/fetch/FontResource.cpp
@@ -113,7 +113,7 @@
 
 void FontResource::didAddClient(ResourceClient* c)
 {
-    ASSERT(c->resourceClientType() == FontResourceClient::expectedType());
+    ASSERT(FontResourceClient::isExpectedType(c));
     Resource::didAddClient(c);
     if (!isLoading())
         static_cast<FontResourceClient*>(c)->fontLoaded(this);
diff --git a/third_party/WebKit/Source/core/fetch/FontResource.h b/third_party/WebKit/Source/core/fetch/FontResource.h
index 3bda896..e104dff 100644
--- a/third_party/WebKit/Source/core/fetch/FontResource.h
+++ b/third_party/WebKit/Source/core/fetch/FontResource.h
@@ -103,8 +103,8 @@
 class FontResourceClient : public ResourceClient {
 public:
     ~FontResourceClient() override {}
-    static ResourceClientType expectedType() { return FontType; }
-    ResourceClientType resourceClientType() const final { return expectedType(); }
+    static bool isExpectedType(ResourceClient* client) { return client->resourceClientType() == FontType; }
+    ResourceClientType resourceClientType() const final { return FontType; }
     virtual void fontLoaded(FontResource*) {}
     virtual void didStartFontLoad(FontResource*) {}
     virtual void fontLoadShortLimitExceeded(FontResource*) {}
diff --git a/third_party/WebKit/Source/core/fetch/ImageResource.cpp b/third_party/WebKit/Source/core/fetch/ImageResource.cpp
index 30e1386..d0a45f2 100644
--- a/third_party/WebKit/Source/core/fetch/ImageResource.cpp
+++ b/third_party/WebKit/Source/core/fetch/ImageResource.cpp
@@ -118,7 +118,7 @@
         m_image->setData(m_data, true);
     }
 
-    ASSERT(c->resourceClientType() == ImageResourceClient::expectedType());
+    ASSERT(ImageResourceClient::isExpectedType(c));
     if (m_image && !m_image->isNull())
         static_cast<ImageResourceClient*>(c)->imageChanged(this);
 
@@ -128,7 +128,7 @@
 void ImageResource::didRemoveClient(ResourceClient* c)
 {
     ASSERT(c);
-    ASSERT(c->resourceClientType() == ImageResourceClient::expectedType());
+    ASSERT(ImageResourceClient::isExpectedType(c));
 
     Resource::didRemoveClient(c);
 }
diff --git a/third_party/WebKit/Source/core/fetch/ImageResourceClient.h b/third_party/WebKit/Source/core/fetch/ImageResourceClient.h
index 46e407c..32fac1f 100644
--- a/third_party/WebKit/Source/core/fetch/ImageResourceClient.h
+++ b/third_party/WebKit/Source/core/fetch/ImageResourceClient.h
@@ -35,8 +35,8 @@
 class CORE_EXPORT ImageResourceClient : public ResourceClient {
 public:
     ~ImageResourceClient() override {}
-    static ResourceClientType expectedType() { return ImageType; }
-    ResourceClientType resourceClientType() const final { return expectedType(); }
+    static bool isExpectedType(ResourceClient* client) { return client->resourceClientType() == ImageType; }
+    ResourceClientType resourceClientType() const final { return ImageType; }
 
     // Called whenever a frame of an image changes, either because we got more data from the network or
     // because we are animating. If not null, the IntRect is the changed rect of the image.
diff --git a/third_party/WebKit/Source/core/fetch/RawResource.cpp b/third_party/WebKit/Source/core/fetch/RawResource.cpp
index 30a96b0..af353d5 100644
--- a/third_party/WebKit/Source/core/fetch/RawResource.cpp
+++ b/third_party/WebKit/Source/core/fetch/RawResource.cpp
@@ -108,7 +108,7 @@
     // this resource to be evicted from the cache and all clients to be removed,
     // so a protector is necessary.
     RefPtrWillBeRawPtr<RawResource> protect(this);
-    ASSERT(c->resourceClientType() == RawResourceClient::expectedType());
+    ASSERT(RawResourceClient::isExpectedType(c));
     RawResourceClient* client = static_cast<RawResourceClient*>(c);
     for (const auto& redirect : redirectChain()) {
         ResourceRequest request(redirect.m_request);
diff --git a/third_party/WebKit/Source/core/fetch/RawResource.h b/third_party/WebKit/Source/core/fetch/RawResource.h
index 16ae1067..56ac47f 100644
--- a/third_party/WebKit/Source/core/fetch/RawResource.h
+++ b/third_party/WebKit/Source/core/fetch/RawResource.h
@@ -104,8 +104,8 @@
 class CORE_EXPORT RawResourceClient : public ResourceClient {
 public:
     ~RawResourceClient() override {}
-    static ResourceClientType expectedType() { return RawResourceType; }
-    ResourceClientType resourceClientType() const final { return expectedType(); }
+    static bool isExpectedType(ResourceClient* client) { return client->resourceClientType() == RawResourceType; }
+    ResourceClientType resourceClientType() const final { return RawResourceType; }
 
     virtual void dataSent(Resource*, unsigned long long /* bytesSent */, unsigned long long /* totalBytesToBeSent */) { }
     virtual void responseReceived(Resource*, const ResourceResponse&, PassOwnPtr<WebDataConsumerHandle>) { }
diff --git a/third_party/WebKit/Source/core/fetch/ResourceClient.h b/third_party/WebKit/Source/core/fetch/ResourceClient.h
index 7fc1f5e..be914a5 100644
--- a/third_party/WebKit/Source/core/fetch/ResourceClient.h
+++ b/third_party/WebKit/Source/core/fetch/ResourceClient.h
@@ -48,8 +48,8 @@
     virtual ~ResourceClient() { }
     virtual void notifyFinished(Resource*) { }
 
-    static ResourceClientType expectedType() { return BaseResourceType; }
-    virtual ResourceClientType resourceClientType() const { return expectedType(); }
+    static bool isExpectedType(ResourceClient*) { return true; }
+    virtual ResourceClientType resourceClientType() const { return BaseResourceType; }
 
     virtual ResourcePriority computeResourcePriority() const { return ResourcePriority(); }
 
diff --git a/third_party/WebKit/Source/core/fetch/ResourceClientWalker.h b/third_party/WebKit/Source/core/fetch/ResourceClientWalker.h
index 5096b05..0dbbc23d 100644
--- a/third_party/WebKit/Source/core/fetch/ResourceClientWalker.h
+++ b/third_party/WebKit/Source/core/fetch/ResourceClientWalker.h
@@ -51,7 +51,7 @@
         while (m_index < size) {
             ResourceClient* next = m_clientVector[m_index++];
             if (m_clientSet.contains(next)) {
-                ASSERT(T::expectedType() == ResourceClient::expectedType() || next->resourceClientType() == T::expectedType());
+                ASSERT(T::isExpectedType(next));
                 return static_cast<T*>(next);
             }
         }
diff --git a/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp b/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp
index d6b9675..7325d3ff 100644
--- a/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp
+++ b/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp
@@ -296,9 +296,9 @@
     m_validatedURLs.add(request.resourceRequest().url());
 }
 
-static PassRefPtr<TracedValue> urlForTraceEvent(const KURL& url)
+static PassOwnPtr<TracedValue> urlForTraceEvent(const KURL& url)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("url", url.string());
     return value.release();
 }
diff --git a/third_party/WebKit/Source/core/fetch/ScriptResource.cpp b/third_party/WebKit/Source/core/fetch/ScriptResource.cpp
index c85a6c7..2b5eaed 100644
--- a/third_party/WebKit/Source/core/fetch/ScriptResource.cpp
+++ b/third_party/WebKit/Source/core/fetch/ScriptResource.cpp
@@ -64,7 +64,7 @@
 
 void ScriptResource::didAddClient(ResourceClient* client)
 {
-    ASSERT(client->resourceClientType() == ScriptResourceClient::expectedType());
+    ASSERT(ScriptResourceClient::isExpectedType(client));
     Resource::didAddClient(client);
 }
 
diff --git a/third_party/WebKit/Source/core/fetch/ScriptResource.h b/third_party/WebKit/Source/core/fetch/ScriptResource.h
index 9f0b9a20..a97b8c3 100644
--- a/third_party/WebKit/Source/core/fetch/ScriptResource.h
+++ b/third_party/WebKit/Source/core/fetch/ScriptResource.h
@@ -46,8 +46,8 @@
 class CORE_EXPORT ScriptResourceClient : public ResourceClient {
 public:
     ~ScriptResourceClient() override {}
-    static ResourceClientType expectedType() { return ScriptType; }
-    ResourceClientType resourceClientType() const final { return expectedType(); }
+    static bool isExpectedType(ResourceClient* client) { return client->resourceClientType() == ScriptType; }
+    ResourceClientType resourceClientType() const final { return ScriptType; }
 
     virtual void notifyAppendData(ScriptResource* resource) { }
 };
diff --git a/third_party/WebKit/Source/core/fetch/StyleSheetResourceClient.h b/third_party/WebKit/Source/core/fetch/StyleSheetResourceClient.h
index f9c3ffa..36c1298f 100644
--- a/third_party/WebKit/Source/core/fetch/StyleSheetResourceClient.h
+++ b/third_party/WebKit/Source/core/fetch/StyleSheetResourceClient.h
@@ -36,8 +36,8 @@
 class StyleSheetResourceClient : public ResourceClient {
 public:
     ~StyleSheetResourceClient() override {}
-    static ResourceClientType expectedType() { return StyleSheetType; }
-    ResourceClientType resourceClientType() const final { return expectedType(); }
+    static bool isExpectedType(ResourceClient* client) { return client->resourceClientType() == StyleSheetType; }
+    ResourceClientType resourceClientType() const final { return StyleSheetType; }
     virtual void setCSSStyleSheet(const String& /* href */, const KURL& /* baseURL */, const String& /* charset */, const CSSStyleSheetResource*) {}
     virtual void setXSLStyleSheet(const String& /* href */, const KURL& /* baseURL */, const String& /* sheet */) {}
 };
diff --git a/third_party/WebKit/Source/core/fetch/XSLStyleSheetResource.cpp b/third_party/WebKit/Source/core/fetch/XSLStyleSheetResource.cpp
index 1aab297..a4a25cbb 100644
--- a/third_party/WebKit/Source/core/fetch/XSLStyleSheetResource.cpp
+++ b/third_party/WebKit/Source/core/fetch/XSLStyleSheetResource.cpp
@@ -68,7 +68,7 @@
 
 void XSLStyleSheetResource::didAddClient(ResourceClient* c)
 {
-    ASSERT(c->resourceClientType() == StyleSheetResourceClient::expectedType());
+    ASSERT(StyleSheetResourceClient::isExpectedType(c));
     Resource::didAddClient(c);
     if (!isLoading())
         static_cast<StyleSheetResourceClient*>(c)->setXSLStyleSheet(m_resourceRequest.url(), m_response.url(), m_sheet);
diff --git a/third_party/WebKit/Source/core/frame/DOMTimer.cpp b/third_party/WebKit/Source/core/frame/DOMTimer.cpp
index 78da1a7..5914cd4 100644
--- a/third_party/WebKit/Source/core/frame/DOMTimer.cpp
+++ b/third_party/WebKit/Source/core/frame/DOMTimer.cpp
@@ -150,7 +150,7 @@
     m_action.clear();
 }
 
-WebTaskRunner* DOMTimer::timerTaskRunner()
+WebTaskRunner* DOMTimer::timerTaskRunner() const
 {
     return executionContext()->timers()->timerTaskRunner();
 }
diff --git a/third_party/WebKit/Source/core/frame/DOMTimer.h b/third_party/WebKit/Source/core/frame/DOMTimer.h
index 59236c8..2ae8eb4c 100644
--- a/third_party/WebKit/Source/core/frame/DOMTimer.h
+++ b/third_party/WebKit/Source/core/frame/DOMTimer.h
@@ -72,7 +72,7 @@
     DOMTimer(ExecutionContext*, PassOwnPtrWillBeRawPtr<ScheduledAction>, int interval, bool singleShot, int timeoutID);
     void fired() override;
 
-    WebTaskRunner* timerTaskRunner() override;
+    WebTaskRunner* timerTaskRunner() const override;
 
     int m_timeoutID;
     int m_nestingLevel;
diff --git a/third_party/WebKit/Source/core/frame/DOMWindowTimers.cpp b/third_party/WebKit/Source/core/frame/DOMWindowTimers.cpp
index d4ecbc9..cc713a8 100644
--- a/third_party/WebKit/Source/core/frame/DOMWindowTimers.cpp
+++ b/third_party/WebKit/Source/core/frame/DOMWindowTimers.cpp
@@ -54,7 +54,7 @@
     }
     if (executionContext->isWorkerGlobalScope()) {
         WorkerGlobalScope* workerGlobalScope = static_cast<WorkerGlobalScope*>(executionContext);
-        if (!workerGlobalScope->script())
+        if (!workerGlobalScope->scriptController())
             return false;
         ContentSecurityPolicy* policy = workerGlobalScope->contentSecurityPolicy();
         if (isEval && policy && !policy->allowEval(scriptState, ContentSecurityPolicy::SendReport, ContentSecurityPolicy::WillNotThrowException))
diff --git a/third_party/WebKit/Source/core/frame/Deprecation.cpp b/third_party/WebKit/Source/core/frame/Deprecation.cpp
index f925991..c8ed596 100644
--- a/third_party/WebKit/Source/core/frame/Deprecation.cpp
+++ b/third_party/WebKit/Source/core/frame/Deprecation.cpp
@@ -270,6 +270,10 @@
     case UseCounter::EncryptedMediaInsecureOrigin:
         return "requestMediaKeySystemAccess() is deprecated on insecure origins in the specification. Support will be removed in the future. You should consider switching your application to a secure origin, such as HTTPS. See https://goo.gl/rStTGz for more details.";
 
+    case UseCounter::ApplicationCacheManifestSelectInsecureOrigin:
+    case UseCounter::ApplicationCacheAPIInsecureOrigin:
+        return "Use of the Application Cache is deprecated on insecure origins. Support will be removed in the future. You should consider switching your application to a secure origin, such as HTTPS. See https://goo.gl/rStTGz for more details.";
+
     case UseCounter::ElementCreateShadowRootMultiple:
         return "Calling Element.createShadowRoot() for an element which already hosts a shadow root is deprecated. See https://www.chromestatus.com/features/4668884095336448 for more details.";
 
@@ -301,21 +305,6 @@
     case UseCounter::BluetoothDeviceConnectGATT:
         return replacedWillBeRemoved("'BluetoothDevice.connectGATT'", "'BluetoothDevice.gatt.connect'", 52, "5264933985976320");
 
-    case UseCounter::V8SVGElement_OffsetParent_AttributeGetter:
-        return willBeRemoved("'SVGElement.offsetParent'", 50, "5724912467574784");
-
-    case UseCounter::V8SVGElement_OffsetTop_AttributeGetter:
-        return willBeRemoved("'SVGElement.offsetTop'", 50, "5724912467574784");
-
-    case UseCounter::V8SVGElement_OffsetLeft_AttributeGetter:
-        return willBeRemoved("'SVGElement.offsetLeft'", 50, "5724912467574784");
-
-    case UseCounter::V8SVGElement_OffsetWidth_AttributeGetter:
-        return willBeRemoved("'SVGElement.offsetWidth'", 50, "5724912467574784");
-
-    case UseCounter::V8SVGElement_OffsetHeight_AttributeGetter:
-        return willBeRemoved("'SVGElement.offsetHeight'", 50, "5724912467574784");
-
     case UseCounter::MediaStreamTrackGetSources:
         return "MediaStreamTrack.getSources is deprecated. See https://www.chromestatus.com/feature/4765305641369600 for more details.";
 
diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp
index ae4738f..05c65b4a 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -793,7 +793,7 @@
         document->evaluateMediaQueryList();
     }
 
-    document->updateLayoutTreeIfNeeded();
+    document->updateLayoutTree();
     lifecycle().advanceTo(DocumentLifecycle::StyleClean);
 
     if (m_frame->isMainFrame() && !m_viewportScrollableArea) {
@@ -826,13 +826,13 @@
     m_analyzer->reset();
 }
 
-PassRefPtr<TracedValue> FrameView::analyzerCounters()
+PassOwnPtr<TracedValue> FrameView::analyzerCounters()
 {
     if (!m_analyzer)
         return TracedValue::create();
-    RefPtr<TracedValue> value = m_analyzer->toTracedValue();
+    OwnPtr<TracedValue> value = m_analyzer->toTracedValue();
     value->setString("host", layoutView()->document().location()->host());
-    return value;
+    return value.release();
 }
 
 #define PERFORM_LAYOUT_TRACE_CATEGORIES "blink,benchmark," TRACE_DISABLED_BY_DEFAULT("blink.debug.layout")
@@ -1137,6 +1137,20 @@
 
 FloatSize FrameView::viewportSizeForViewportUnits() const
 {
+    float zoom = frame().pageZoomFactor();
+
+    if (m_frame->settings() && !RuntimeEnabledFeatures::inertTopControlsEnabled()) {
+        FloatSize viewportSize;
+
+        LayoutView* layoutView = this->layoutView();
+        if (!layoutView)
+            return viewportSize;
+
+        viewportSize.setWidth(layoutView->viewWidth(IncludeScrollbars) / zoom);
+        viewportSize.setHeight(layoutView->viewHeight(IncludeScrollbars) / zoom);
+        return viewportSize;
+    }
+
     FloatSize size(layoutSize(IncludeScrollbars));
 
     // We use the layoutSize rather than frameRect to calculate viewport units
@@ -1153,8 +1167,7 @@
         size.expand(0, topControls.height() / pageScaleAtLayoutWidth);
     }
 
-    float scale = frame().pageZoomFactor();
-    size.scale(1 / scale);
+    size.scale(1 / zoom);
     return size;
 }
 
@@ -1523,7 +1536,7 @@
     m_fragmentAnchor = anchorNode;
 
     // We need to update the layout tree before scrolling.
-    m_frame->document()->updateLayoutTreeIfNeeded();
+    m_frame->document()->updateLayoutTree();
 
     // If layout is needed, we will scroll in performPostLayoutTasks. Otherwise, scroll immediately.
     LayoutView* layoutView = this->layoutView();
@@ -1759,6 +1772,8 @@
 
 void FrameView::addOrthogonalWritingModeRoot(LayoutBox& root)
 {
+    ASSERT(!root.isLayoutFullScreen() && !root.isLayoutFullScreenPlaceholder()
+        && !root.isLayoutScrollbarPart());
     m_orthogonalWritingModeRootList.add(root);
 }
 
@@ -2366,8 +2381,7 @@
     if (cornerStyle) {
         if (!m_scrollCorner)
             m_scrollCorner = LayoutScrollbarPart::createAnonymous(doc);
-        m_scrollCorner->adjustStyleBeforeSet(cornerStyle.get());
-        m_scrollCorner->setStyle(cornerStyle.release());
+        m_scrollCorner->setStyleWithWritingModeOfParent(cornerStyle.release());
         setScrollCornerNeedsPaintInvalidation();
     } else if (m_scrollCorner) {
         m_scrollCorner->destroy();
@@ -2622,7 +2636,7 @@
     // region but then become included later by the second frame adding rects to the dirty region
     // when it lays out.
 
-    m_frame->document()->updateLayoutTreeIfNeeded();
+    m_frame->document()->updateLayoutTree();
 
     if (needsLayout())
         layout();
@@ -2654,14 +2668,14 @@
     // When SVG filters are invalidated using Document::scheduleSVGFilterLayerUpdateHack() they may trigger an
     // extra style recalc. See PaintLayer::filterNeedsPaintInvalidation().
     if (m_frame->document()->hasSVGFilterElementsRequiringLayerUpdate()) {
-        m_frame->document()->updateLayoutTreeIfNeeded();
+        m_frame->document()->updateLayoutTree();
 
         if (needsLayout())
             layout();
     }
 
     // These asserts ensure that parent frames are clean, when child frames finished updating layout and style.
-    ASSERT(!needsLayout());
+    RELEASE_ASSERT(!needsLayout());
     ASSERT(!m_frame->document()->hasSVGFilterElementsRequiringLayerUpdate());
 #if ENABLE(ASSERT)
     m_frame->document()->layoutView()->assertLaidOut();
@@ -4097,7 +4111,7 @@
         // partially painted version of this frame's contents if we skipped
         // painting them while the frame was throttled.
         if (LayoutView* layoutView = this->layoutView())
-            layoutView->setShouldDoFullPaintInvalidation(PaintInvalidationBecameVisible);
+            layoutView->invalidatePaintForViewAndCompositedLayers();
     }
 }
 
diff --git a/third_party/WebKit/Source/core/frame/FrameView.h b/third_party/WebKit/Source/core/frame/FrameView.h
index c266c5a..bb4943f 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.h
+++ b/third_party/WebKit/Source/core/frame/FrameView.h
@@ -745,7 +745,7 @@
     ScrollingCoordinator* scrollingCoordinator() const;
 
     void prepareLayoutAnalyzer();
-    PassRefPtr<TracedValue> analyzerCounters();
+    PassOwnPtr<TracedValue> analyzerCounters();
 
     // LayoutObject for the viewport-defining element (see Document::viewportDefiningElement).
     LayoutObject* viewportLayoutObject();
diff --git a/third_party/WebKit/Source/core/frame/ImageBitmap.cpp b/third_party/WebKit/Source/core/frame/ImageBitmap.cpp
index 69833dd1..80a78245 100644
--- a/third_party/WebKit/Source/core/frame/ImageBitmap.cpp
+++ b/third_party/WebKit/Source/core/frame/ImageBitmap.cpp
@@ -86,16 +86,24 @@
     return newSkImageFromRaster(info, dstPixels.release(), input->width() * info.bytesPerPixel());
 }
 
-static PassRefPtr<StaticBitmapImage> cropImage(Image* image, const IntRect& cropRect, bool flipYEnabled, bool premultiplyAlphaEnabled)
+static PassRefPtr<StaticBitmapImage> cropImage(Image* image, const IntRect& cropRect, bool flipYEnabled, bool premultiplyAlphaEnabled, bool isBitmapAlreadyPremultiplied = true)
 {
     ASSERT(image);
 
     IntRect imgRect(IntPoint(), IntSize(image->width(), image->height()));
     const IntRect srcRect = intersection(imgRect, cropRect);
 
+    // In the case when cropRect doesn't intersect the source image and it requires a umpremul image
+    // We immediately return a transparent black image with cropRect.size()
+    if (srcRect.isEmpty() && !premultiplyAlphaEnabled) {
+        SkImageInfo info = SkImageInfo::Make(cropRect.width(), cropRect.height(), kN32_SkColorType, kUnpremul_SkAlphaType);
+        OwnPtr<uint8_t[]> dstPixels = adoptArrayPtr(new uint8_t[cropRect.width() * cropRect.height() * info.bytesPerPixel()]());
+        return StaticBitmapImage::create(newSkImageFromRaster(info, dstPixels.release(), cropRect.width() * info.bytesPerPixel()));
+    }
+
     RefPtr<SkImage> skiaImage = image->imageForCurrentFrame();
-    // Attempt to get raw unpremultiplied image data.
-    if (((!premultiplyAlphaEnabled && !skiaImage->isOpaque()) || !skiaImage) && image->data()) {
+    // Attempt to get raw unpremultiplied image data, executed only when skiaImage is premultiplied.
+    if (((!premultiplyAlphaEnabled && !skiaImage->isOpaque()) || !skiaImage) && image->data() && isBitmapAlreadyPremultiplied) {
         // TODO(xidachen): GammaAndColorProfileApplied needs to be changed when working on color-space conversion
         OwnPtr<ImageDecoder> decoder(ImageDecoder::create(
             *(image->data()), ImageDecoder::AlphaNotPremultiplied,
@@ -121,8 +129,6 @@
     }
 
     RefPtr<SkSurface> surface = adoptRef(SkSurface::NewRasterN32Premul(cropRect.width(), cropRect.height()));
-    // In the case where cropRect doesn't intesect the source image, we return a premultiplied transparent black SkImage.
-    // If we decide we want to grab meta data from m_image, we have to change this.
     if (srcRect.isEmpty())
         return StaticBitmapImage::create(adoptRef(surface->newImageSnapshot()));
 
@@ -150,6 +156,8 @@
 
     m_image = cropImage(image->cachedImage()->image(), cropRect, imageOrientationFlipYFlag, premultiplyAlphaEnabledFlag);
     m_image->setOriginClean(!image->wouldTaintOrigin(document->securityOrigin()));
+    if (!premultiplyAlphaEnabledFlag)
+        m_isPremultiplied = false;
 }
 
 ImageBitmap::ImageBitmap(HTMLVideoElement* video, const IntRect& cropRect, Document* document, const ImageBitmapOptions& options)
@@ -182,6 +190,8 @@
         m_image = StaticBitmapImage::create(buffer->newSkImageSnapshot(PreferNoAcceleration, SnapshotReasonUnknown));
     }
     m_image->setOriginClean(!video->wouldTaintOrigin(document->securityOrigin()));
+    if (!premultiplyAlphaEnabledFlag)
+        m_isPremultiplied = false;
 }
 
 ImageBitmap::ImageBitmap(HTMLCanvasElement* canvas, const IntRect& cropRect, const ImageBitmapOptions& options)
@@ -195,6 +205,8 @@
     if (!premultiplyAlphaEnabledFlag)
         m_image = StaticBitmapImage::create(premulSkImageToUnPremul(m_image->imageForCurrentFrame().get()));
     m_image->setOriginClean(canvas->originClean());
+    if (!premultiplyAlphaEnabledFlag)
+        m_isPremultiplied = false;
 }
 
 ImageBitmap::ImageBitmap(ImageData* data, const IntRect& cropRect, const ImageBitmapOptions& options)
@@ -227,8 +239,10 @@
     bool imageOrientationFlipYFlag;
     bool premultiplyAlphaEnabledFlag;
     parseOptions(options, imageOrientationFlipYFlag, premultiplyAlphaEnabledFlag);
-    m_image = cropImage(bitmap->bitmapImage(), cropRect, imageOrientationFlipYFlag, true);
+    m_image = cropImage(bitmap->bitmapImage(), cropRect, imageOrientationFlipYFlag, premultiplyAlphaEnabledFlag, bitmap->isPremultiplied());
     m_image->setOriginClean(bitmap->originClean());
+    if (!premultiplyAlphaEnabledFlag)
+        m_isPremultiplied = false;
 }
 
 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image, const IntRect& cropRect, const ImageBitmapOptions& options)
@@ -238,6 +252,8 @@
     parseOptions(options, imageOrientationFlipYFlag, premultiplyAlphaEnabledFlag);
     m_image = cropImage(image.get(), cropRect, imageOrientationFlipYFlag, premultiplyAlphaEnabledFlag);
     m_image->setOriginClean(image->originClean());
+    if (!premultiplyAlphaEnabledFlag)
+        m_isPremultiplied = false;
 }
 
 ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image)
@@ -305,9 +321,9 @@
     m_isNeutered = true;
 }
 
-PassOwnPtr<uint8_t[]> ImageBitmap::copyBitmapData()
+PassOwnPtr<uint8_t[]> ImageBitmap::copyBitmapData(AlphaDisposition alphaOp)
 {
-    SkImageInfo info = SkImageInfo::Make(width(), height(), kRGBA_8888_SkColorType, kUnpremul_SkAlphaType);
+    SkImageInfo info = SkImageInfo::Make(width(), height(), kRGBA_8888_SkColorType, (alphaOp == PremultiplyAlpha) ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
     OwnPtr<uint8_t[]> dstPixels = copySkImageData(m_image->imageForCurrentFrame().get(), info);
     return dstPixels.release();
 }
diff --git a/third_party/WebKit/Source/core/frame/ImageBitmap.h b/third_party/WebKit/Source/core/frame/ImageBitmap.h
index 6157bde..d7e8043 100644
--- a/third_party/WebKit/Source/core/frame/ImageBitmap.h
+++ b/third_party/WebKit/Source/core/frame/ImageBitmap.h
@@ -25,6 +25,11 @@
 class HTMLVideoElement;
 class ImageData;
 
+enum AlphaDisposition {
+    PremultiplyAlpha,
+    DontPremultiplyAlpha,
+};
+
 class CORE_EXPORT ImageBitmap final : public RefCountedWillBeGarbageCollectedFinalized<ImageBitmap>, public ScriptWrappable, public ImageLoaderClient, public CanvasImageSource, public ImageBitmapSource {
     DEFINE_WRAPPERTYPEINFO();
     WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(ImageBitmap);
@@ -38,13 +43,14 @@
     static PassRefPtrWillBeRawPtr<ImageBitmap> create(PassRefPtr<StaticBitmapImage>, const IntRect&, const ImageBitmapOptions& = ImageBitmapOptions());
 
     StaticBitmapImage* bitmapImage() const { return (m_image) ? m_image.get() : nullptr; }
-    PassOwnPtr<uint8_t[]> copyBitmapData();
+    PassOwnPtr<uint8_t[]> copyBitmapData(AlphaDisposition alphaOp = DontPremultiplyAlpha);
     unsigned long width() const;
     unsigned long height() const;
     IntSize size() const;
 
     bool isNeutered() const { return m_isNeutered; }
     bool originClean() const { return m_image->originClean(); }
+    bool isPremultiplied() const { return m_isPremultiplied; }
     PassRefPtr<StaticBitmapImage> transfer();
     void close();
 
@@ -77,6 +83,7 @@
 
     RefPtr<StaticBitmapImage> m_image;
     bool m_isNeutered = false;
+    bool m_isPremultiplied = true;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
index afca6ec6..6e447b1 100644
--- a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
@@ -791,7 +791,7 @@
         }
     }
 
-    frame()->document()->updateLayoutTreeIfNeeded();
+    frame()->document()->updateLayoutTree();
 
     FrameHost* host = frame()->host();
     if (!host)
@@ -813,7 +813,7 @@
         }
     }
 
-    frame()->document()->updateLayoutTreeIfNeeded();
+    frame()->document()->updateLayoutTree();
 
     FrameHost* host = frame()->host();
     if (!host)
@@ -835,7 +835,7 @@
         }
     }
 
-    frame()->document()->updateLayoutTreeIfNeeded();
+    frame()->document()->updateLayoutTree();
 
     FrameHost* host = frame()->host();
     if (!host)
@@ -1090,7 +1090,7 @@
 
     unsigned rulesToInclude = StyleResolver::AuthorCSSRules;
     PseudoId pseudoId = CSSSelector::pseudoId(pseudoType);
-    element->document().updateLayoutTreeIfNeeded();
+    element->document().updateLayoutTree();
     return frame()->document()->ensureStyleResolver().pseudoCSSRulesForElement(element, pseudoId, rulesToInclude);
 }
 
diff --git a/third_party/WebKit/Source/core/frame/Location.cpp b/third_party/WebKit/Source/core/frame/Location.cpp
index d4c7aba4..4196fb5 100644
--- a/third_party/WebKit/Source/core/frame/Location.cpp
+++ b/third_party/WebKit/Source/core/frame/Location.cpp
@@ -135,14 +135,14 @@
     return DOMURLUtilsReadOnly::hash(url());
 }
 
-void Location::setHref(LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, const String& url)
+void Location::setHref(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& url)
 {
     if (!m_frame)
         return;
-    setLocation(url, callingWindow, enteredWindow);
+    setLocation(url, currentWindow, enteredWindow);
 }
 
-void Location::setProtocol(LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, const String& protocol, ExceptionState& exceptionState)
+void Location::setProtocol(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& protocol, ExceptionState& exceptionState)
 {
     if (!m_frame)
         return;
@@ -151,55 +151,55 @@
         exceptionState.throwDOMException(SyntaxError, "'" + protocol + "' is an invalid protocol.");
         return;
     }
-    setLocation(url.string(), callingWindow, enteredWindow);
+    setLocation(url.string(), currentWindow, enteredWindow);
 }
 
-void Location::setHost(LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, const String& host)
+void Location::setHost(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& host)
 {
     if (!m_frame)
         return;
     KURL url = toLocalFrame(m_frame)->document()->url();
     url.setHostAndPort(host);
-    setLocation(url.string(), callingWindow, enteredWindow);
+    setLocation(url.string(), currentWindow, enteredWindow);
 }
 
-void Location::setHostname(LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, const String& hostname)
+void Location::setHostname(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& hostname)
 {
     if (!m_frame)
         return;
     KURL url = toLocalFrame(m_frame)->document()->url();
     url.setHost(hostname);
-    setLocation(url.string(), callingWindow, enteredWindow);
+    setLocation(url.string(), currentWindow, enteredWindow);
 }
 
-void Location::setPort(LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, const String& portString)
+void Location::setPort(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& portString)
 {
     if (!m_frame)
         return;
     KURL url = toLocalFrame(m_frame)->document()->url();
     url.setPort(portString);
-    setLocation(url.string(), callingWindow, enteredWindow);
+    setLocation(url.string(), currentWindow, enteredWindow);
 }
 
-void Location::setPathname(LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, const String& pathname)
+void Location::setPathname(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& pathname)
 {
     if (!m_frame)
         return;
     KURL url = toLocalFrame(m_frame)->document()->url();
     url.setPath(pathname);
-    setLocation(url.string(), callingWindow, enteredWindow);
+    setLocation(url.string(), currentWindow, enteredWindow);
 }
 
-void Location::setSearch(LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, const String& search)
+void Location::setSearch(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& search)
 {
     if (!m_frame)
         return;
     KURL url = toLocalFrame(m_frame)->document()->url();
     url.setQuery(search);
-    setLocation(url.string(), callingWindow, enteredWindow);
+    setLocation(url.string(), currentWindow, enteredWindow);
 }
 
-void Location::setHash(LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, const String& hash)
+void Location::setHash(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& hash)
 {
     if (!m_frame)
         return;
@@ -214,24 +214,24 @@
     // cases where fragment identifiers are ignored or invalid.
     if (equalIgnoringNullity(oldFragmentIdentifier, url.fragmentIdentifier()))
         return;
-    setLocation(url.string(), callingWindow, enteredWindow);
+    setLocation(url.string(), currentWindow, enteredWindow);
 }
 
-void Location::assign(LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, const String& url)
+void Location::assign(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& url)
 {
     if (!m_frame)
         return;
-    setLocation(url, callingWindow, enteredWindow);
+    setLocation(url, currentWindow, enteredWindow);
 }
 
-void Location::replace(LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, const String& url)
+void Location::replace(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String& url)
 {
     if (!m_frame)
         return;
-    setLocation(url, callingWindow, enteredWindow, SetLocation::ReplaceThisFrame);
+    setLocation(url, currentWindow, enteredWindow, SetLocation::ReplaceThisFrame);
 }
 
-void Location::reload(LocalDOMWindow* callingWindow)
+void Location::reload(LocalDOMWindow* currentWindow)
 {
     if (!m_frame)
         return;
@@ -240,13 +240,13 @@
     m_frame->reload(FrameLoadTypeReload, ClientRedirect);
 }
 
-void Location::setLocation(const String& url, LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, SetLocation locationPolicy)
+void Location::setLocation(const String& url, LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, SetLocation locationPolicy)
 {
     ASSERT(m_frame);
     if (!m_frame || !m_frame->host())
         return;
 
-    if (!callingWindow->frame() || !callingWindow->frame()->canNavigate(*m_frame))
+    if (!currentWindow->frame() || !currentWindow->frame()->canNavigate(*m_frame))
         return;
 
     Document* enteredDocument = enteredWindow->document();
@@ -257,7 +257,7 @@
     if (completedURL.isNull())
         return;
 
-    if (m_frame->domWindow()->isInsecureScriptAccess(*callingWindow, completedURL))
+    if (m_frame->domWindow()->isInsecureScriptAccess(*currentWindow, completedURL))
         return;
 
     V8DOMActivityLogger* activityLogger = V8DOMActivityLogger::currentActivityLoggerIfIsolatedWorld();
@@ -269,7 +269,7 @@
         argv.append(completedURL);
         activityLogger->logEvent("blinkSetAttribute", argv.size(), argv.data());
     }
-    m_frame->navigate(*callingWindow->document(), completedURL, locationPolicy == SetLocation::ReplaceThisFrame, UserGestureStatus::None);
+    m_frame->navigate(*currentWindow->document(), completedURL, locationPolicy == SetLocation::ReplaceThisFrame, UserGestureStatus::None);
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/Location.h b/third_party/WebKit/Source/core/frame/Location.h
index 6c6b79c..003347b3 100644
--- a/third_party/WebKit/Source/core/frame/Location.h
+++ b/third_party/WebKit/Source/core/frame/Location.h
@@ -60,26 +60,26 @@
     Frame* frame() const { return m_frame.get(); }
     void reset() { m_frame = nullptr; }
 
-    void setHref(LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, const String&);
+    void setHref(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&);
     String href() const;
 
-    void assign(LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, const String&);
-    void replace(LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, const String&);
-    void reload(LocalDOMWindow* callingWindow);
+    void assign(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&);
+    void replace(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&);
+    void reload(LocalDOMWindow* currentWindow);
 
-    void setProtocol(LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, const String&, ExceptionState&);
+    void setProtocol(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&, ExceptionState&);
     String protocol() const;
-    void setHost(LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, const String&);
+    void setHost(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&);
     String host() const;
-    void setHostname(LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, const String&);
+    void setHostname(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&);
     String hostname() const;
-    void setPort(LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, const String&);
+    void setPort(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&);
     String port() const;
-    void setPathname(LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, const String&);
+    void setPathname(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&);
     String pathname() const;
-    void setSearch(LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, const String&);
+    void setSearch(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&);
     String search() const;
-    void setHash(LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, const String&);
+    void setHash(LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, const String&);
     String hash() const;
     String origin() const;
 
@@ -96,7 +96,7 @@
     explicit Location(Frame*);
 
     enum class SetLocation { Normal, ReplaceThisFrame };
-    void setLocation(const String&, LocalDOMWindow* callingWindow, LocalDOMWindow* enteredWindow, SetLocation = SetLocation::Normal);
+    void setLocation(const String&, LocalDOMWindow* currentWindow, LocalDOMWindow* enteredWindow, SetLocation = SetLocation::Normal);
 
     const KURL& url() const;
 
diff --git a/third_party/WebKit/Source/core/frame/OriginsUsingFeatures.cpp b/third_party/WebKit/Source/core/frame/OriginsUsingFeatures.cpp
index 0b3ec59f..696e8df 100644
--- a/third_party/WebKit/Source/core/frame/OriginsUsingFeatures.cpp
+++ b/third_party/WebKit/Source/core/frame/OriginsUsingFeatures.cpp
@@ -158,6 +158,10 @@
         Platform::current()->recordRappor("PowerfulFeatureUse.Host.GetUserMedia.Insecure", origin);
     if (get(Feature::GetUserMediaSecureOrigin))
         Platform::current()->recordRappor("PowerfulFeatureUse.Host.GetUserMedia.Secure", origin);
+    if (get(Feature::ApplicationCacheManifestSelectInsecureOrigin))
+        Platform::current()->recordRappor("PowerfulFeatureUse.Host.ApplicationCacheManifestSelect.Insecure", origin);
+    if (get(Feature::ApplicationCacheAPIInsecureOrigin))
+        Platform::current()->recordRappor("PowerfulFeatureUse.Host.ApplicationCacheAPI.Insecure", origin);
 }
 
 void OriginsUsingFeatures::Value::recordNameToRappor(const String& name)
diff --git a/third_party/WebKit/Source/core/frame/OriginsUsingFeatures.h b/third_party/WebKit/Source/core/frame/OriginsUsingFeatures.h
index 4e8e449..36b9c86a 100644
--- a/third_party/WebKit/Source/core/frame/OriginsUsingFeatures.h
+++ b/third_party/WebKit/Source/core/frame/OriginsUsingFeatures.h
@@ -35,6 +35,8 @@
         GetUserMediaInsecureOrigin,
         GetUserMediaSecureOrigin,
         ElementAttachShadow,
+        ApplicationCacheManifestSelectInsecureOrigin,
+        ApplicationCacheAPIInsecureOrigin,
 
         NumberOfFeatures // This must be the last item.
     };
diff --git a/third_party/WebKit/Source/core/frame/Settings.in b/third_party/WebKit/Source/core/frame/Settings.in
index ca5ce32a..31adfc74 100644
--- a/third_party/WebKit/Source/core/frame/Settings.in
+++ b/third_party/WebKit/Source/core/frame/Settings.in
@@ -93,9 +93,6 @@
 antialiasedClips2dCanvasEnabled initial=false
 accelerated2dCanvasMSAASampleCount type=int, initial=0
 
-# WebAudio support.
-webAudioEnabled initial=false
-
 hyperlinkAuditingEnabled initial=false
 allowDisplayOfInsecureContent initial=true
 allowRunningOfInsecureContent initial=true
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h
index 529b3f6..89239e6 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.h
+++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -727,11 +727,6 @@
         HTMLKeygenElement = 886,
         // The above items are available in M45 branch.
 
-        V8SVGElement_OffsetParent_AttributeGetter = 887,
-        V8SVGElement_OffsetTop_AttributeGetter = 888,
-        V8SVGElement_OffsetLeft_AttributeGetter = 889,
-        V8SVGElement_OffsetWidth_AttributeGetter = 890,
-        V8SVGElement_OffsetHeight_AttributeGetter = 891,
         HTMLMediaElementPreloadNone = 892,
         HTMLMediaElementPreloadMetadata = 893,
         HTMLMediaElementPreloadAuto = 894,
@@ -1087,6 +1082,10 @@
         DocumentCreateEventInputEvent = 1242,
         WebAnimationHyphenatedProperty = 1243,
         FormControlsCollectionReturnsRadioNodeListForFieldSet = 1244,
+        ApplicationCacheManifestSelectInsecureOrigin = 1245,
+        ApplicationCacheManifestSelectSecureOrigin = 1246,
+        ApplicationCacheAPIInsecureOrigin = 1247,
+        ApplicationCacheAPISecureOrigin = 1248,
 
         // Add new features immediately above this line. Don't change assigned
         // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp
index 3683c1f51..a4f448be 100644
--- a/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp
+++ b/third_party/WebKit/Source/core/frame/csp/CSPDirectiveList.cpp
@@ -131,6 +131,8 @@
 
 bool CSPDirectiveList::checkDynamic(SourceListDirective* directive) const
 {
+    if (!m_policy->experimentalFeaturesEnabled())
+        return false;
     return !directive || directive->allowDynamic();
 }
 
@@ -237,7 +239,11 @@
 
 bool CSPDirectiveList::checkSourceAndReportViolation(SourceListDirective* directive, const KURL& url, const String& effectiveDirective, ContentSecurityPolicy::RedirectStatus redirectStatus) const
 {
-    if (checkSource(directive, url, redirectStatus))
+    if (!directive)
+        return true;
+
+    // We ignore URL-based whitelists if we're allowing dynamic script injection.
+    if (checkSource(directive, url, redirectStatus) && !checkDynamic(directive))
         return true;
 
     String prefix;
@@ -267,8 +273,10 @@
         prefix = "Refused to load the stylesheet '";
 
     String suffix = String();
+    if (checkDynamic(directive))
+        suffix = " 'unsafe-dynamic' is present, so host-based whitelisting is disabled.";
     if (directive == m_defaultSrc)
-        suffix = " Note that '" + effectiveDirective + "' was not explicitly set, so 'default-src' is used as a fallback.";
+        suffix = suffix + " Note that '" + effectiveDirective + "' was not explicitly set, so 'default-src' is used as a fallback.";
 
     reportViolation(directive->text(), effectiveDirective, prefix + url.elidedString() + "' because it violates the following Content Security Policy directive: \"" + directive->text() + "\"." + suffix + "\n", url);
     return denyIfEnforcingPolicy();
diff --git a/third_party/WebKit/Source/core/html/CollectionItemsCache.h b/third_party/WebKit/Source/core/html/CollectionItemsCache.h
index f288ce7..50b74cf 100644
--- a/third_party/WebKit/Source/core/html/CollectionItemsCache.h
+++ b/third_party/WebKit/Source/core/html/CollectionItemsCache.h
@@ -34,7 +34,6 @@
 
 #include "core/html/CollectionIndexCache.h"
 #include "wtf/Vector.h"
-#include <v8.h>
 
 namespace blink {
 
@@ -59,12 +58,6 @@
     void invalidate();
 
 private:
-    ptrdiff_t allocationSize() const { return m_cachedList.capacity() * sizeof(NodeType*); }
-    static void reportExtraMemoryCostForCollectionItemsCache(ptrdiff_t diff)
-    {
-        v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(diff);
-    }
-
     bool m_listValid;
     WillBeHeapVector<RawPtrWillBeMember<NodeType>> m_cachedList;
 };
@@ -78,8 +71,6 @@
 template <typename Collection, typename NodeType>
 CollectionItemsCache<Collection, NodeType>::~CollectionItemsCache()
 {
-    if (ptrdiff_t diff = allocationSize())
-        reportExtraMemoryCostForCollectionItemsCache(-diff);
 }
 
 template <typename Collection, typename NodeType>
@@ -100,13 +91,10 @@
 
     NodeType* currentNode = collection.traverseToFirst();
     unsigned currentIndex = 0;
-    ptrdiff_t oldCapacity = allocationSize();
     while (currentNode) {
         m_cachedList.append(currentNode);
         currentNode = collection.traverseForwardToOffset(currentIndex + 1, *currentNode, currentIndex);
     }
-    if (ptrdiff_t diff = allocationSize() - oldCapacity)
-        reportExtraMemoryCostForCollectionItemsCache(diff);
 
     this->setCachedNodeCount(m_cachedList.size());
     m_listValid = true;
diff --git a/third_party/WebKit/Source/core/html/HTMLAreaElement.cpp b/third_party/WebKit/Source/core/html/HTMLAreaElement.cpp
index cb3f068..c67d7d8 100644
--- a/third_party/WebKit/Source/core/html/HTMLAreaElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLAreaElement.cpp
@@ -220,7 +220,7 @@
 
 void HTMLAreaElement::updateFocusAppearance(SelectionBehaviorOnFocus selectionBehavior)
 {
-    document().updateLayoutTreeForNodeIfNeeded(this);
+    document().updateLayoutTreeForNode(this);
     if (!isFocusable())
         return;
 
diff --git a/third_party/WebKit/Source/core/html/HTMLContentElement.cpp b/third_party/WebKit/Source/core/html/HTMLContentElement.cpp
index 94e98f29..e080d413 100644
--- a/third_party/WebKit/Source/core/html/HTMLContentElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLContentElement.cpp
@@ -88,7 +88,7 @@
 
 static inline bool includesDisallowedPseudoClass(const CSSSelector& selector)
 {
-    if (selector.pseudoType() == CSSSelector::PseudoNot) {
+    if (selector.getPseudoType() == CSSSelector::PseudoNot) {
         const CSSSelector* subSelector = selector.selectorList()->first();
         return subSelector->match() == CSSSelector::PseudoClass;
     }
diff --git a/third_party/WebKit/Source/core/html/HTMLFrameElementBase.cpp b/third_party/WebKit/Source/core/html/HTMLFrameElementBase.cpp
index cfa82039..a6d0e93 100644
--- a/third_party/WebKit/Source/core/html/HTMLFrameElementBase.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLFrameElementBase.cpp
@@ -59,8 +59,7 @@
     const KURL& completeURL = document().completeURL(m_URL);
 
     if (protocolIsJavaScript(completeURL)) {
-        Document* contentDoc = this->contentDocument();
-        if (contentDoc && !ScriptController::canAccessFromCurrentOrigin(contentDoc->frame()))
+        if (contentFrame() && !ScriptController::canAccessFromCurrentOrigin(toIsolate(&document()), contentFrame()))
             return false;
     }
 
diff --git a/third_party/WebKit/Source/core/html/HTMLLabelElement.cpp b/third_party/WebKit/Source/core/html/HTMLLabelElement.cpp
index 52cadd1..d474a6f 100644
--- a/third_party/WebKit/Source/core/html/HTMLLabelElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLLabelElement.cpp
@@ -203,7 +203,7 @@
 
 void HTMLLabelElement::focus(const FocusParams& params)
 {
-    document().updateLayoutTreeForNodeIfNeeded(this);
+    document().updateLayoutTreeForNode(this);
     if (isFocusable()) {
         HTMLElement::focus(params);
         return;
diff --git a/third_party/WebKit/Source/core/html/HTMLLegendElement.cpp b/third_party/WebKit/Source/core/html/HTMLLegendElement.cpp
index 7d0f0a4..f474957 100644
--- a/third_party/WebKit/Source/core/html/HTMLLegendElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLLegendElement.cpp
@@ -55,7 +55,7 @@
 
 void HTMLLegendElement::focus(const FocusParams& params)
 {
-    document().updateLayoutTreeForNodeIfNeeded(this);
+    document().updateLayoutTreeForNode(this);
     if (isFocusable()) {
         Element::focus(params);
         return;
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
index a10491cf..31187d8 100644
--- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
@@ -111,6 +111,14 @@
 // URL protocol used to signal that the media source API is being used.
 const char mediaSourceBlobProtocol[] = "blob";
 
+enum MediaControlsShow {
+    MediaControlsShowAttribute = 0,
+    MediaControlsShowFullscreen,
+    MediaControlsShowNoScript,
+    MediaControlsShowNotShown,
+    MediaControlsShowMax
+};
+
 #if !LOG_DISABLED
 String urlForLoggingMedia(const KURL& url)
 {
@@ -2078,19 +2086,32 @@
     setBooleanAttribute(loopAttr, b);
 }
 
-bool HTMLMediaElement::shouldShowControls() const
+bool HTMLMediaElement::shouldShowControls(const RecordMetricsBehavior recordMetrics) const
 {
+    DEFINE_STATIC_LOCAL(EnumerationHistogram, showControlsHistogram, ("Media.Controls.Show", MediaControlsShowMax));
+
+    if (fastHasAttribute(controlsAttr)) {
+        if (recordMetrics == RecordMetricsBehavior::DoRecord)
+            showControlsHistogram.count(MediaControlsShowAttribute);
+        return true;
+    }
+
+    if (isFullscreen()) {
+        if (recordMetrics == RecordMetricsBehavior::DoRecord)
+            showControlsHistogram.count(MediaControlsShowFullscreen);
+        return true;
+    }
+
     LocalFrame* frame = document().frame();
-
-    // always show controls when scripting is disabled
-    if (frame && !frame->script().canExecuteScripts(NotAboutToExecuteScript))
+    if (frame && !frame->script().canExecuteScripts(NotAboutToExecuteScript)) {
+        if (recordMetrics == RecordMetricsBehavior::DoRecord)
+            showControlsHistogram.count(MediaControlsShowNoScript);
         return true;
+    }
 
-    // Always show controls when in full screen mode.
-    if (isFullscreen())
-        return true;
-
-    return fastHasAttribute(controlsAttr);
+    if (recordMetrics == RecordMetricsBehavior::DoRecord)
+        showControlsHistogram.count(MediaControlsShowNotShown);
+    return false;
 }
 
 double HTMLMediaElement::volume() const
@@ -3346,7 +3367,8 @@
 
     ensureMediaControls();
     mediaControls()->reset();
-    if (shouldShowControls())
+
+    if (shouldShowControls(RecordMetricsBehavior::DoRecord))
         mediaControls()->show();
     else
         mediaControls()->hide();
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.h b/third_party/WebKit/Source/core/html/HTMLMediaElement.h
index e6741a8..610750d1 100644
--- a/third_party/WebKit/Source/core/html/HTMLMediaElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.h
@@ -68,6 +68,11 @@
 public:
     static WebMimeRegistry::SupportsType supportsType(const ContentType&);
 
+    enum class RecordMetricsBehavior {
+        DoNotRecord,
+        DoRecord
+    };
+
     static void setMediaStreamRegistry(URLRegistry*);
     static bool isMediaStreamURL(const String& url);
 
@@ -132,7 +137,6 @@
     TimeRanges* seekable() const;
     bool ended() const;
     bool autoplay() const;
-    enum class RecordMetricsBehavior { DoNotRecord, DoRecord };
     bool shouldAutoplay(const RecordMetricsBehavior = RecordMetricsBehavior::DoNotRecord);
     bool loop() const;
     void setLoop(bool);
@@ -150,7 +154,7 @@
     void durationChanged(double duration, bool requestSeek);
 
     // controls
-    bool shouldShowControls() const;
+    bool shouldShowControls(const RecordMetricsBehavior = RecordMetricsBehavior::DoNotRecord) const;
     double volume() const;
     void setVolume(double, ExceptionState&);
     bool muted() const;
diff --git a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
index 4e2b2ef..9993267b 100644
--- a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
@@ -85,8 +85,6 @@
     , m_typeAhead(this)
     , m_size(0)
     , m_lastOnChangeOption(nullptr)
-    , m_activeSelectionAnchorIndex(-1)
-    , m_activeSelectionEndIndex(-1)
     , m_multiple(false)
     , m_activeSelectionState(false)
     , m_shouldRecalcListItems(false)
@@ -129,7 +127,7 @@
     // elements to send change events.  This produces that same behavior for
     // changes triggered by other code running on behalf of the user.
     if (!usesMenuList()) {
-        updateSelectedState(optionToListIndex(optionIndex), allowMultipleSelection, false);
+        updateSelectedState(item(optionIndex), allowMultipleSelection, false);
         setNeedsValidityCheck();
         if (fireOnChangeNow)
             listBoxOnChange();
@@ -213,7 +211,9 @@
     if (!multiple()) {
         optionSelectedByUser(listToOptionIndex(listIndex), fireOnChangeNow, false);
     } else {
-        updateSelectedState(listIndex, allowMultiplySelections, shift);
+        HTMLElement* element = listItems()[listIndex];
+        if (isHTMLOptionElement(element))
+            updateSelectedState(toHTMLOptionElement(element), allowMultiplySelections, shift);
         setNeedsValidityCheck();
         if (fireOnChangeNow)
             listBoxOnChange();
@@ -230,9 +230,15 @@
 
 int HTMLSelectElement::activeSelectionEndListIndex() const
 {
-    if (m_activeSelectionEndIndex >= 0)
-        return m_activeSelectionEndIndex;
-    return lastSelectedListIndex();
+    HTMLOptionElement* option = activeSelectionEnd();
+    return option ? option->listIndex() : -1;
+}
+
+HTMLOptionElement* HTMLSelectElement::activeSelectionEnd() const
+{
+    if (m_activeSelectionEnd)
+        return m_activeSelectionEnd.get();
+    return lastSelectedOption();
 }
 
 void HTMLSelectElement::add(const HTMLOptionElementOrHTMLOptGroupElement& element, const HTMLElementOrLong& before, ExceptionState& exceptionState)
@@ -550,17 +556,17 @@
     return isRequired();
 }
 
-// Returns the 1st valid item |skip| items from |listIndex| in direction
+// Returns the 1st valid OPTION |skip| items from |listIndex| in direction
 // |direction| if there is one.
-// Otherwise, it returns the valid item closest to that boundary which is past
+// Otherwise, it returns the valid OPTION closest to that boundary which is past
 // |listIndex| if there is one.
-// Otherwise, it returns |listIndex|.
-// Valid means that it is enabled and an option element.
-int HTMLSelectElement::nextValidIndex(int listIndex, SkipDirection direction, int skip) const
+// Otherwise, it returns nullptr.
+// Valid means that it is enabled and visible.
+HTMLOptionElement* HTMLSelectElement::nextValidOption(int listIndex, SkipDirection direction, int skip) const
 {
     ASSERT(direction == SkipBackwards || direction == SkipForwards);
     const ListItems& listItems = this->listItems();
-    int lastGoodIndex = listIndex;
+    HTMLOptionElement* lastGoodOption = nullptr;
     int size = listItems.size();
     for (listIndex += direction; listIndex >= 0 && listIndex < size; listIndex += direction) {
         --skip;
@@ -573,42 +579,40 @@
             continue;
         if (!usesMenuList() && !element->layoutObject())
             continue;
-        lastGoodIndex = listIndex;
+        lastGoodOption = toHTMLOptionElement(element);
         if (skip <= 0)
             break;
     }
-    return lastGoodIndex;
+    return lastGoodOption;
 }
 
-int HTMLSelectElement::nextSelectableListIndex(int startIndex) const
+HTMLOptionElement* HTMLSelectElement::nextSelectableOption(HTMLOptionElement* startOption) const
 {
-    return nextValidIndex(startIndex, SkipForwards, 1);
+    return nextValidOption(startOption ? startOption->listIndex() : -1, SkipForwards, 1);
 }
 
-int HTMLSelectElement::previousSelectableListIndex(int startIndex) const
+HTMLOptionElement* HTMLSelectElement::previousSelectableOption(HTMLOptionElement* startOption) const
 {
-    if (startIndex == -1)
-        startIndex = listItems().size();
-    return nextValidIndex(startIndex, SkipBackwards, 1);
+    return nextValidOption(startOption ? startOption->listIndex() : listItems().size(), SkipBackwards, 1);
 }
 
-int HTMLSelectElement::firstSelectableListIndex() const
+HTMLOptionElement* HTMLSelectElement::firstSelectableOption() const
 {
-    const ListItems& items = listItems();
-    int index = nextValidIndex(items.size(), SkipBackwards, INT_MAX);
-    if (static_cast<size_t>(index) == items.size())
-        return -1;
-    return index;
+    // TODO(tkent): This is not efficient.  nextSlectableOption(nullptr) is
+    // faster.
+    return nextValidOption(listItems().size(), SkipBackwards, INT_MAX);
 }
 
-int HTMLSelectElement::lastSelectableListIndex() const
+HTMLOptionElement* HTMLSelectElement::lastSelectableOption() const
 {
-    return nextValidIndex(-1, SkipForwards, INT_MAX);
+    // TODO(tkent): This is not efficient.  previousSlectableOption(nullptr) is
+    // faster.
+    return nextValidOption(-1, SkipForwards, INT_MAX);
 }
 
 // Returns the index of the next valid item one page away from |startIndex| in
 // direction |direction|.
-int HTMLSelectElement::nextSelectableListIndexPageAway(int startIndex, SkipDirection direction) const
+HTMLOptionElement* HTMLSelectElement::nextSelectableOptionPageAway(HTMLOptionElement* startOption, SkipDirection direction) const
 {
     const ListItems& items = listItems();
     // Can't use m_size because layoutObject forces a minimum size.
@@ -620,9 +624,10 @@
     // If there is a valid option item one page away, the index is chosen.
     // If there is no exact one page away valid option, returns startIndex or
     // the most far index.
+    int startIndex = startOption ? startOption->listIndex() : -1;
     int edgeIndex = (direction == SkipForwards) ? 0 : (items.size() - 1);
     int skipAmount = pageSize + ((direction == SkipForwards) ? startIndex : (edgeIndex - startIndex));
-    return nextValidIndex(edgeIndex, direction, skipAmount);
+    return nextValidOption(edgeIndex, direction, skipAmount);
 }
 
 void HTMLSelectElement::selectAll()
@@ -636,8 +641,8 @@
     saveLastSelection();
 
     m_activeSelectionState = true;
-    setActiveSelectionAnchorIndex(nextSelectableListIndex(-1));
-    setActiveSelectionEndIndex(previousSelectableListIndex(-1));
+    setActiveSelectionAnchor(nextSelectableOption(nullptr));
+    setActiveSelectionEnd(previousSelectableOption(nullptr));
 
     updateListBoxSelection(false, false);
     listBoxOnChange();
@@ -656,9 +661,9 @@
         m_lastOnChangeSelection.append(isHTMLOptionElement(*element) && toHTMLOptionElement(element)->selected());
 }
 
-void HTMLSelectElement::setActiveSelectionAnchorIndex(int index)
+void HTMLSelectElement::setActiveSelectionAnchor(HTMLOptionElement* option)
 {
-    m_activeSelectionAnchorIndex = index;
+    m_activeSelectionAnchor = option;
 
     // Cache the selection state so we can restore the old selection as the new
     // selection pivots around this anchor index.
@@ -676,9 +681,9 @@
     }
 }
 
-void HTMLSelectElement::setActiveSelectionEndIndex(int index)
+void HTMLSelectElement::setActiveSelectionEnd(HTMLOptionElement* option)
 {
-    m_activeSelectionEndIndex = index;
+    m_activeSelectionEnd = option;
 }
 
 void HTMLSelectElement::updateListBoxSelection(bool deselectOtherOptions, bool scroll)
@@ -686,8 +691,10 @@
     ASSERT(layoutObject());
     ASSERT(layoutObject()->isListBox() || m_multiple);
 
-    int start = std::min(m_activeSelectionAnchorIndex, m_activeSelectionEndIndex);
-    int end = std::max(m_activeSelectionAnchorIndex, m_activeSelectionEndIndex);
+    int activeSelectionAnchorIndex = m_activeSelectionAnchor ? m_activeSelectionAnchor->listIndex() : -1;
+    int activeSelectionEndIndex = m_activeSelectionEnd ? m_activeSelectionEnd->listIndex() : -1;
+    int start = std::min(activeSelectionAnchorIndex, activeSelectionEndIndex);
+    int end = std::max(activeSelectionAnchorIndex, activeSelectionEndIndex);
 
     const ListItems& items = listItems();
     for (int i = 0; i < static_cast<int>(items.size()); ++i) {
@@ -763,7 +770,7 @@
         return;
     if (usesMenuList())
         return;
-    scrollToIndex(activeSelectionEndListIndex());
+    scrollToOption(activeSelectionEnd());
     if (AXObjectCache* cache = document().existingAXObjectCache())
         cache->listboxActiveIndexChanged(this);
 }
@@ -803,10 +810,6 @@
     // is in the document or not.
 
     m_shouldRecalcListItems = true;
-    // Manual selection anchor is reset when manipulating the select
-    // programmatically.
-    m_activeSelectionAnchorIndex = -1;
-    m_activeSelectionEndIndex = -1;
     setOptionsChangedOnLayoutObject();
     if (!inDocument()) {
         if (HTMLOptionsCollection* collection = cachedCollection<HTMLOptionsCollection>(SelectOptions))
@@ -926,37 +929,28 @@
 
     if (LayoutObject* layoutObject = this->layoutObject())  {
         layoutObject->updateFromElement();
-        scrollToIndex(suggestedIndex);
+        scrollToOption(item(listToOptionIndex(suggestedIndex)));
     }
     if (popupIsVisible())
         m_popup->updateFromElement();
 }
 
-void HTMLSelectElement::scrollToIndex(int listIndex)
+void HTMLSelectElement::scrollToOption(HTMLOptionElement* option)
 {
-    if (listIndex < 0)
+    if (!option)
         return;
     if (usesMenuList())
         return;
-    const ListItems& items = listItems();
-    int listSize = static_cast<int>(items.size());
-    if (listIndex >= listSize)
-        return;
-    // TODO(tkent): The following isHTMLOptionElement check should be
-    // unnecessary. The specified listIndex must point an HTMLOptionElement, but
-    // our code about activeSelection{Anchor,End}Index is not reliable.
-    if (!isHTMLOptionElement(*items[listIndex]))
-        return;
     bool hasPendingTask = m_optionToScrollTo;
-    // We'd like to keep an HTMLOptionElement reference rather than |listIndex|
-    // because the task should work even if unselected option is inserted before
-    // |listIndex| before executing scrollToIndexTask().
-    m_optionToScrollTo = toHTMLOptionElement(items[listIndex]);
+    // We'd like to keep an HTMLOptionElement reference rather than the index of
+    // the option because the task should work even if unselected option is
+    // inserted before executing scrollToOptionTask().
+    m_optionToScrollTo = option;
     if (!hasPendingTask)
-        document().postTask(BLINK_FROM_HERE, createSameThreadTask(&HTMLSelectElement::scrollToIndexTask, PassRefPtrWillBeRawPtr<HTMLSelectElement>(this)));
+        document().postTask(BLINK_FROM_HERE, createSameThreadTask(&HTMLSelectElement::scrollToOptionTask, PassRefPtrWillBeRawPtr<HTMLSelectElement>(this)));
 }
 
-void HTMLSelectElement::scrollToIndexTask()
+void HTMLSelectElement::scrollToOptionTask()
 {
     RefPtrWillBeRawPtr<HTMLOptionElement> option = m_optionToScrollTo.release();
     if (!option || !inDocument())
@@ -975,19 +969,19 @@
 {
     ASSERT(option->ownerSelectElement() == this);
     if (optionIsSelected)
-        selectOption(option->index());
+        selectOption(option);
     else if (!usesMenuList() || multiple())
-        selectOption(-1);
+        selectOption(nullptr);
     else
-        selectOption(nextSelectableListIndex(-1));
+        selectOption(nextSelectableOption(nullptr));
 }
 
-void HTMLSelectElement::optionInserted(const HTMLOptionElement& option, bool optionIsSelected)
+void HTMLSelectElement::optionInserted(HTMLOptionElement& option, bool optionIsSelected)
 {
     ASSERT(option.ownerSelectElement() == this);
     setRecalcListItems();
     if (optionIsSelected)
-        selectOption(option.index());
+        selectOption(&option);
 }
 
 void HTMLSelectElement::optionRemoved(const HTMLOptionElement& option)
@@ -997,30 +991,38 @@
         m_lastOnChangeOption.clear();
     if (m_optionToScrollTo == &option)
         m_optionToScrollTo.clear();
+    if (m_activeSelectionAnchor == &option)
+        m_activeSelectionAnchor.clear();
+    if (m_activeSelectionEnd == &option)
+        m_activeSelectionEnd.clear();
     if (option.selected())
         setAutofilled(false);
 }
 
+void HTMLSelectElement::selectOption(int optionIndex, SelectOptionFlags flags)
+{
+    selectOption(optionIndex < 0 ? nullptr : item(optionIndex), flags);
+}
+
+void HTMLSelectElement::selectOption(HTMLOptionElement* option, SelectOptionFlags flags)
+{
+    selectOption(option, option ? option->index() : -1, flags);
+}
+
 // TODO(tkent): This function is not efficient.  It contains multiple O(N)
 // operations. crbug.com/577989.
-void HTMLSelectElement::selectOption(int optionIndex, SelectOptionFlags flags)
+void HTMLSelectElement::selectOption(HTMLOptionElement* element, int optionIndex, SelectOptionFlags flags)
 {
     TRACE_EVENT0("blink", "HTMLSelectElement::selectOption");
     bool shouldDeselect = !m_multiple || (flags & DeselectOtherOptions);
 
-    const ListItems& items = listItems();
-    // optionToListIndex is O(N).
-    int listIndex = optionToListIndex(optionIndex);
+    ASSERT((!element && optionIndex < 0) || (element && optionIndex >= 0));
 
     // selectedIndex() is O(N).
     if (isAutofilled() && selectedIndex() != optionIndex)
         setAutofilled(false);
 
-    HTMLOptionElement* element = nullptr;
-    if (listIndex >= 0) {
-        // listIndex must point an HTMLOptionElement if listIndex is not -1
-        // because optionToListIndex() returned it.
-        element = toHTMLOptionElement(items[listIndex]);
+    if (element) {
         element->setSelectedState(true);
         if (flags & MakeOptionDirty)
             element->setDirty(true);
@@ -1032,12 +1034,12 @@
 
     // We should update active selection after finishing OPTION state change
     // because setActiveSelectionAnchorIndex() stores OPTION's selection state.
-    if (listIndex >= 0) {
-        // setActiveSelectionAnchorIndex is O(N).
-        if (m_activeSelectionAnchorIndex < 0 || shouldDeselect)
-            setActiveSelectionAnchorIndex(listIndex);
-        if (m_activeSelectionEndIndex < 0 || shouldDeselect)
-            setActiveSelectionEndIndex(listIndex);
+    if (element) {
+        // setActiveSelectionAnchor is O(N).
+        if (!m_activeSelectionAnchor || shouldDeselect)
+            setActiveSelectionAnchor(element);
+        if (!m_activeSelectionEnd || shouldDeselect)
+            setActiveSelectionEnd(element);
     }
 
     // For the menu list case, this is what makes the selected element appear.
@@ -1059,9 +1061,8 @@
             // Need to check usesMenuList() again because
             // dispatchInputAndChangeEventForMenuList() might change the status.
             if (usesMenuList()) {
-                // didSetSelectedIndex() is O(N) because of listToOptionIndex
-                // and optionToListIndex.
-                toLayoutMenuList(layoutObject)->didSetSelectedIndex(listIndex);
+                // didSetSelectedIndex() is O(N) because of optionToListIndex.
+                toLayoutMenuList(layoutObject)->didSetSelectedIndex(optionIndex);
             }
         }
     }
@@ -1340,25 +1341,26 @@
         const String& keyIdentifier = keyEvent->keyIdentifier();
         bool handled = true;
         const ListItems& listItems = this->listItems();
-        int listIndex = optionToListIndex(selectedIndex());
+        HTMLOptionElement* option = selectedOption();
+        int listIndex = option ? option->listIndex() : -1;
 
         if (keyIdentifier == "Down" || keyIdentifier == "Right")
-            listIndex = nextValidIndex(listIndex, SkipForwards, 1);
+            option = nextValidOption(listIndex, SkipForwards, 1);
         else if (keyIdentifier == "Up" || keyIdentifier == "Left")
-            listIndex = nextValidIndex(listIndex, SkipBackwards, 1);
+            option = nextValidOption(listIndex, SkipBackwards, 1);
         else if (keyIdentifier == "PageDown")
-            listIndex = nextValidIndex(listIndex, SkipForwards, 3);
+            option = nextValidOption(listIndex, SkipForwards, 3);
         else if (keyIdentifier == "PageUp")
-            listIndex = nextValidIndex(listIndex, SkipBackwards, 3);
+            option = nextValidOption(listIndex, SkipBackwards, 3);
         else if (keyIdentifier == "Home")
-            listIndex = nextValidIndex(-1, SkipForwards, 1);
+            option = nextValidOption(-1, SkipForwards, 1);
         else if (keyIdentifier == "End")
-            listIndex = nextValidIndex(listItems.size(), SkipBackwards, 1);
+            option = nextValidOption(listItems.size(), SkipBackwards, 1);
         else
             handled = false;
 
-        if (handled && static_cast<size_t>(listIndex) < listItems.size())
-            selectOption(listToOptionIndex(listIndex), DeselectOtherOptions | MakeOptionDirty | DispatchInputAndChangeEvent);
+        if (handled && option)
+            selectOption(option, DeselectOtherOptions | MakeOptionDirty | DispatchInputAndChangeEvent);
 
         if (handled)
             event->setDefaultHandled();
@@ -1418,15 +1420,9 @@
     }
 }
 
-void HTMLSelectElement::updateSelectedState(int listIndex, bool multi, bool shift)
+void HTMLSelectElement::updateSelectedState(HTMLOptionElement* clickedOption, bool multi, bool shift)
 {
-    ASSERT(listIndex >= 0);
-
-    HTMLElement* clickedElement = listItems()[listIndex];
-    ASSERT(clickedElement);
-    if (isHTMLOptGroupElement(clickedElement))
-        return;
-
+    ASSERT(clickedOption);
     // Save the selection so it can be compared to the new selection when
     // dispatching change events during mouseup, or after autoscroll finishes.
     saveLastSelection();
@@ -1436,51 +1432,48 @@
     bool shiftSelect = m_multiple && shift;
     bool multiSelect = m_multiple && multi && !shift;
 
-    if (isHTMLOptionElement(*clickedElement)) {
-        HTMLOptionElement& option = toHTMLOptionElement(*clickedElement);
-        // Keep track of whether an active selection (like during drag
-        // selection), should select or deselect.
-        if (option.selected() && multiSelect) {
-            m_activeSelectionState = false;
-            option.setSelectedState(false);
-            option.setDirty(true);
-        }
+    // Keep track of whether an active selection (like during drag selection),
+    // should select or deselect.
+    if (clickedOption->selected() && multiSelect) {
+        m_activeSelectionState = false;
+        clickedOption->setSelectedState(false);
+        clickedOption->setDirty(true);
     }
 
     // If we're not in any special multiple selection mode, then deselect all
     // other items, excluding the clicked option. If no option was clicked, then
     // this will deselect all items in the list.
     if (!shiftSelect && !multiSelect)
-        deselectItemsWithoutValidation(clickedElement);
+        deselectItemsWithoutValidation(clickedOption);
 
     // If the anchor hasn't been set, and we're doing a single selection or a
     // shift selection, then initialize the anchor to the first selected index.
-    if (m_activeSelectionAnchorIndex < 0 && !multiSelect)
-        setActiveSelectionAnchorIndex(selectedIndex());
+    if (!m_activeSelectionAnchor && !multiSelect)
+        setActiveSelectionAnchor(selectedOption());
 
     // Set the selection state of the clicked option.
-    if (isHTMLOptionElement(*clickedElement) && !toHTMLOptionElement(*clickedElement).isDisabledFormControl()) {
-        toHTMLOptionElement(*clickedElement).setSelectedState(true);
-        toHTMLOptionElement(*clickedElement).setDirty(true);
+    if (!clickedOption->isDisabledFormControl()) {
+        clickedOption->setSelectedState(true);
+        clickedOption->setDirty(true);
     }
 
     // If there was no selectedIndex() for the previous initialization, or If
     // we're doing a single selection, or a multiple selection (using cmd or
     // ctrl), then initialize the anchor index to the listIndex that just got
     // clicked.
-    if (m_activeSelectionAnchorIndex < 0 || !shiftSelect)
-        setActiveSelectionAnchorIndex(listIndex);
+    if (!m_activeSelectionAnchor || !shiftSelect)
+        setActiveSelectionAnchor(clickedOption);
 
-    setActiveSelectionEndIndex(listIndex);
+    setActiveSelectionEnd(clickedOption);
     updateListBoxSelection(!multiSelect);
 }
 
-int HTMLSelectElement::listIndexForEventTargetOption(const Event& event)
+HTMLOptionElement* HTMLSelectElement::eventTargetOption(const Event& event)
 {
     Node* targetNode = event.target()->toNode();
     if (!targetNode || !isHTMLOptionElement(*targetNode))
-        return -1;
-    return listIndexForOption(toHTMLOptionElement(*targetNode));
+        return nullptr;
+    return toHTMLOptionElement(targetNode);
 }
 
 int HTMLSelectElement::listIndexForOption(const HTMLOptionElement& option)
@@ -1511,7 +1504,6 @@
 
 void HTMLSelectElement::listBoxDefaultEventHandler(Event* event)
 {
-    const ListItems& listItems = this->listItems();
     if (event->type() == EventTypeNames::gesturetap && event->isGestureEvent()) {
         focus();
         // Calling focus() may cause us to lose our layoutObject or change the
@@ -1521,10 +1513,9 @@
 
         // Convert to coords relative to the list box if needed.
         GestureEvent& gestureEvent = toGestureEvent(*event);
-        int listIndex = listIndexForEventTargetOption(gestureEvent);
-        if (listIndex >= 0) {
+        if (HTMLOptionElement* option = eventTargetOption(gestureEvent)) {
             if (!isDisabledFormControl()) {
-                updateSelectedState(listIndex, true, gestureEvent.shiftKey());
+                updateSelectedState(option, true, gestureEvent.shiftKey());
                 listBoxOnChange();
             }
             event->setDefaultHandled();
@@ -1539,13 +1530,12 @@
 
         // Convert to coords relative to the list box if needed.
         MouseEvent* mouseEvent = toMouseEvent(event);
-        int listIndex = listIndexForEventTargetOption(*mouseEvent);
-        if (listIndex >= 0) {
+        if (HTMLOptionElement* option = eventTargetOption(*mouseEvent)) {
             if (!isDisabledFormControl()) {
 #if OS(MACOSX)
-                updateSelectedState(listIndex, mouseEvent->metaKey(), mouseEvent->shiftKey());
+                updateSelectedState(option, mouseEvent->metaKey(), mouseEvent->shiftKey());
 #else
-                updateSelectedState(listIndex, mouseEvent->ctrlKey(), mouseEvent->shiftKey());
+                updateSelectedState(option, mouseEvent->ctrlKey(), mouseEvent->shiftKey());
 #endif
             }
             if (LocalFrame* frame = document().frame())
@@ -1565,19 +1555,18 @@
         if (m_lastOnChangeSelection.isEmpty())
             return;
 
-        int listIndex = listIndexForEventTargetOption(*mouseEvent);
-        if (listIndex >= 0) {
+        if (HTMLOptionElement* option = eventTargetOption(*mouseEvent)) {
             if (!isDisabledFormControl()) {
                 if (m_multiple) {
                     // Only extend selection if there is something selected.
-                    if (m_activeSelectionAnchorIndex < 0)
+                    if (!m_activeSelectionAnchor)
                         return;
 
-                    setActiveSelectionEndIndex(listIndex);
+                    setActiveSelectionEnd(option);
                     updateListBoxSelection(false);
                 } else {
-                    setActiveSelectionAnchorIndex(listIndex);
-                    setActiveSelectionEndIndex(listIndex);
+                    setActiveSelectionAnchor(option);
+                    setActiveSelectionEnd(option);
                     updateListBoxSelection(true);
                 }
             }
@@ -1595,62 +1584,61 @@
         const String& keyIdentifier = toKeyboardEvent(event)->keyIdentifier();
 
         bool handled = false;
-        int endIndex = 0;
-        if (m_activeSelectionEndIndex < 0) {
+        HTMLOptionElement* endOption = nullptr;
+        if (!m_activeSelectionEnd) {
             // Initialize the end index
             if (keyIdentifier == "Down" || keyIdentifier == "PageDown") {
-                int startIndex = lastSelectedListIndex();
+                HTMLOptionElement* startOption = lastSelectedOption();
                 handled = true;
                 if (keyIdentifier == "Down")
-                    endIndex = nextSelectableListIndex(startIndex);
+                    endOption = nextSelectableOption(startOption);
                 else
-                    endIndex = nextSelectableListIndexPageAway(startIndex, SkipForwards);
+                    endOption = nextSelectableOptionPageAway(startOption, SkipForwards);
             } else if (keyIdentifier == "Up" || keyIdentifier == "PageUp") {
-                int startIndex = optionToListIndex(selectedIndex());
+                HTMLOptionElement* startOption = selectedOption();
                 handled = true;
                 if (keyIdentifier == "Up")
-                    endIndex = previousSelectableListIndex(startIndex);
+                    endOption = previousSelectableOption(startOption);
                 else
-                    endIndex = nextSelectableListIndexPageAway(startIndex, SkipBackwards);
+                    endOption = nextSelectableOptionPageAway(startOption, SkipBackwards);
             }
         } else {
             // Set the end index based on the current end index.
             if (keyIdentifier == "Down") {
-                endIndex = nextSelectableListIndex(m_activeSelectionEndIndex);
+                endOption = nextSelectableOption(m_activeSelectionEnd.get());
                 handled = true;
             } else if (keyIdentifier == "Up") {
-                endIndex = previousSelectableListIndex(m_activeSelectionEndIndex);
+                endOption = previousSelectableOption(m_activeSelectionEnd.get());
                 handled = true;
             } else if (keyIdentifier == "PageDown") {
-                endIndex = nextSelectableListIndexPageAway(m_activeSelectionEndIndex, SkipForwards);
+                endOption = nextSelectableOptionPageAway(m_activeSelectionEnd.get(), SkipForwards);
                 handled = true;
             } else if (keyIdentifier == "PageUp") {
-                endIndex = nextSelectableListIndexPageAway(m_activeSelectionEndIndex, SkipBackwards);
+                endOption = nextSelectableOptionPageAway(m_activeSelectionEnd.get(), SkipBackwards);
                 handled = true;
             }
         }
         if (keyIdentifier == "Home") {
-            endIndex = firstSelectableListIndex();
+            endOption = firstSelectableOption();
             handled = true;
         } else if (keyIdentifier == "End") {
-            endIndex = lastSelectableListIndex();
+            endOption = lastSelectableOption();
             handled = true;
         }
 
         if (isSpatialNavigationEnabled(document().frame())) {
             // Check if the selection moves to the boundary.
-            if (keyIdentifier == "Left" || keyIdentifier == "Right" || ((keyIdentifier == "Down" || keyIdentifier == "Up") && endIndex == m_activeSelectionEndIndex))
+            if (keyIdentifier == "Left" || keyIdentifier == "Right" || ((keyIdentifier == "Down" || keyIdentifier == "Up") && endOption == m_activeSelectionEnd))
                 return;
         }
 
-        if (endIndex >= 0 && handled) {
+        if (endOption && handled) {
             // Save the selection so it can be compared to the new selection
             // when dispatching change events immediately after making the new
             // selection.
             saveLastSelection();
 
-            ASSERT_UNUSED(listItems, !listItems.size() || static_cast<size_t>(endIndex) < listItems.size());
-            setActiveSelectionEndIndex(endIndex);
+            setActiveSelectionEnd(endOption);
 
             bool selectNewItem = !m_multiple || toKeyboardEvent(event)->shiftKey() || !isSpatialNavigationEnabled(document().frame());
             if (selectNewItem)
@@ -1658,13 +1646,13 @@
             // If the anchor is unitialized, or if we're going to deselect all
             // other options, then set the anchor index equal to the end index.
             bool deselectOthers = !m_multiple || (!toKeyboardEvent(event)->shiftKey() && selectNewItem);
-            if (m_activeSelectionAnchorIndex < 0 || deselectOthers) {
+            if (!m_activeSelectionAnchor || deselectOthers) {
                 if (deselectOthers)
                     deselectItemsWithoutValidation();
-                setActiveSelectionAnchorIndex(m_activeSelectionEndIndex);
+                setActiveSelectionAnchor(m_activeSelectionEnd.get());
             }
 
-            scrollToIndex(endIndex);
+            scrollToOption(endOption);
             if (selectNewItem) {
                 updateListBoxSelection(deselectOthers);
                 listBoxOnChange();
@@ -1687,7 +1675,7 @@
         } else if (m_multiple && keyCode == ' ' && isSpatialNavigationEnabled(document().frame())) {
             // Use space to toggle selection change.
             m_activeSelectionState = !m_activeSelectionState;
-            updateSelectedState(listToOptionIndex(m_activeSelectionEndIndex), true /*multi*/, false /*shift*/);
+            updateSelectedState(m_activeSelectionEnd.get(), true /*multi*/, false /*shift*/);
             listBoxOnChange();
             event->setDefaultHandled();
         }
@@ -1722,15 +1710,15 @@
     HTMLFormControlElementWithState::defaultEventHandler(event);
 }
 
-int HTMLSelectElement::lastSelectedListIndex() const
+HTMLOptionElement* HTMLSelectElement::lastSelectedOption() const
 {
     const ListItems& items = listItems();
     for (size_t i = items.size(); i;) {
         HTMLElement* element = items[--i];
         if (isHTMLOptionElement(*element) && toHTMLOptionElement(element)->selected())
-            return i;
+            return toHTMLOptionElement(element);
     }
-    return -1;
+    return nullptr;
 }
 
 int HTMLSelectElement::indexOfSelectedOption() const
@@ -1809,7 +1797,7 @@
     updateListItemSelectedStates();
     if (usesMenuList())
         return;
-    scrollToIndex(optionToListIndex(selectedIndex()));
+    scrollToOption(selectedOption());
     if (AXObjectCache* cache = document().existingAXObjectCache())
         cache->listboxActiveIndexChanged(this);
 }
@@ -1845,6 +1833,8 @@
     visitor->trace(m_listItems);
 #endif
     visitor->trace(m_lastOnChangeOption);
+    visitor->trace(m_activeSelectionAnchor);
+    visitor->trace(m_activeSelectionEnd);
     visitor->trace(m_optionToScrollTo);
     visitor->trace(m_popup);
     HTMLFormControlElementWithState::trace(visitor);
@@ -1871,13 +1861,10 @@
 {
     if (!isSpatialNavigationEnabled(document().frame()))
         return nullptr;
-    int focusedIndex = activeSelectionEndListIndex();
-    if (focusedIndex < 0)
-        focusedIndex = firstSelectableListIndex();
-    if (focusedIndex < 0)
-        return nullptr;
-    HTMLElement* focused = listItems()[focusedIndex];
-    return isHTMLOptionElement(focused) ? toHTMLOptionElement(focused) : nullptr;
+    HTMLOptionElement* focusedOption = activeSelectionEnd();
+    if (!focusedOption)
+        focusedOption = firstSelectableOption();
+    return focusedOption;
 }
 
 String HTMLSelectElement::itemText(const Element& element) const
diff --git a/third_party/WebKit/Source/core/html/HTMLSelectElement.h b/third_party/WebKit/Source/core/html/HTMLSelectElement.h
index ef752ae..4f561da 100644
--- a/third_party/WebKit/Source/core/html/HTMLSelectElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLSelectElement.h
@@ -26,6 +26,7 @@
 #ifndef HTMLSelectElement_h
 #define HTMLSelectElement_h
 
+#include "base/gtest_prod_util.h"
 #include "core/CoreExport.h"
 #include "core/html/HTMLContentElement.h"
 #include "core/html/HTMLFormControlElementWithState.h"
@@ -104,7 +105,7 @@
     HTMLOptionElement* item(unsigned index);
 
     void scrollToSelection();
-    void scrollToIndex(int listIndex);
+    void scrollToOption(HTMLOptionElement*);
 
     void listBoxSelectItem(int listIndex, bool allowMultiplySelections, bool shift, bool fireOnChangeNow = true);
 
@@ -114,12 +115,13 @@
     void listBoxOnChange();
     int optionToListIndex(int optionIndex) const;
     int activeSelectionEndListIndex() const;
-    void setActiveSelectionAnchorIndex(int);
-    void setActiveSelectionEndIndex(int);
+    HTMLOptionElement* activeSelectionEnd() const;
+    void setActiveSelectionAnchor(HTMLOptionElement*);
+    void setActiveSelectionEnd(HTMLOptionElement*);
 
     // For use in the implementation of HTMLOptionElement.
     void optionSelectionStateChanged(HTMLOptionElement*, bool optionIsSelected);
-    void optionInserted(const HTMLOptionElement&, bool optionIsSelected);
+    void optionInserted(HTMLOptionElement&, bool optionIsSelected);
     void optionRemoved(const HTMLOptionElement&);
     bool anonymousIndexedSetter(unsigned, PassRefPtrWillBeRawPtr<HTMLOptionElement>, ExceptionState&);
 
@@ -212,10 +214,12 @@
     };
     typedef unsigned SelectOptionFlags;
     void selectOption(int optionIndex, SelectOptionFlags = 0);
+    void selectOption(HTMLOptionElement*, SelectOptionFlags = 0);
+    void selectOption(HTMLOptionElement*, int optionIndex, SelectOptionFlags);
     void deselectItemsWithoutValidation(HTMLElement* elementToExclude = 0);
     void parseMultipleAttribute(const AtomicString&);
-    int lastSelectedListIndex() const;
-    void updateSelectedState(int listIndex, bool multi, bool shift);
+    HTMLOptionElement* lastSelectedOption() const;
+    void updateSelectedState(HTMLOptionElement*, bool multi, bool shift);
     void menuListDefaultEventHandler(Event*);
     void handlePopupOpenKeyboardEvent(Event*);
     bool shouldOpenPopupForKeyDownEvent(KeyboardEvent*);
@@ -230,15 +234,15 @@
         SkipBackwards = -1,
         SkipForwards = 1
     };
-    int nextValidIndex(int listIndex, SkipDirection, int skip) const;
-    int nextSelectableListIndex(int startIndex) const;
-    int previousSelectableListIndex(int startIndex) const;
-    int firstSelectableListIndex() const;
-    int lastSelectableListIndex() const;
-    int nextSelectableListIndexPageAway(int startIndex, SkipDirection) const;
-    int listIndexForEventTargetOption(const Event&);
+    HTMLOptionElement* nextValidOption(int listIndex, SkipDirection, int skip) const;
+    HTMLOptionElement* nextSelectableOption(HTMLOptionElement*) const;
+    HTMLOptionElement* previousSelectableOption(HTMLOptionElement*) const;
+    HTMLOptionElement* firstSelectableOption() const;
+    HTMLOptionElement* lastSelectableOption() const;
+    HTMLOptionElement* nextSelectableOptionPageAway(HTMLOptionElement*, SkipDirection) const;
+    HTMLOptionElement* eventTargetOption(const Event&);
     AutoscrollController* autoscrollController() const;
-    void scrollToIndexTask();
+    void scrollToOptionTask();
 
     void childrenChanged(const ChildrenChange&) override;
     bool areAuthorShadowsAllowed() const override { return false; }
@@ -257,8 +261,8 @@
     TypeAhead m_typeAhead;
     unsigned m_size;
     RefPtrWillBeMember<HTMLOptionElement> m_lastOnChangeOption;
-    int m_activeSelectionAnchorIndex;
-    int m_activeSelectionEndIndex;
+    RefPtrWillBeMember<HTMLOptionElement> m_activeSelectionAnchor;
+    RefPtrWillBeMember<HTMLOptionElement> m_activeSelectionEnd;
     RefPtrWillBeMember<HTMLOptionElement> m_optionToScrollTo;
     bool m_multiple;
     bool m_activeSelectionState;
@@ -269,6 +273,11 @@
     RefPtrWillBeMember<PopupMenu> m_popup;
     int m_indexToSelectOnCancel;
     bool m_popupIsVisible;
+
+    FRIEND_TEST_ALL_PREFIXES(HTMLSelectElementTest, FirstSelectableOption);
+    FRIEND_TEST_ALL_PREFIXES(HTMLSelectElementTest, LastSelectableOption);
+    FRIEND_TEST_ALL_PREFIXES(HTMLSelectElementTest, NextSelectableOption);
+    FRIEND_TEST_ALL_PREFIXES(HTMLSelectElementTest, PreviousSelectableOption);
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/html/HTMLSelectElementTest.cpp b/third_party/WebKit/Source/core/html/HTMLSelectElementTest.cpp
index 3792fc0..8fe031c 100644
--- a/third_party/WebKit/Source/core/html/HTMLSelectElementTest.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLSelectElementTest.cpp
@@ -124,6 +124,174 @@
     EXPECT_FALSE(select->popupIsVisible());
 }
 
+TEST_F(HTMLSelectElementTest, FirstSelectableOption)
+{
+    {
+        document().documentElement()->setInnerHTML("<select></select>", ASSERT_NO_EXCEPTION);
+        document().view()->updateAllLifecyclePhases();
+        HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild());
+        EXPECT_EQ(nullptr, select->firstSelectableOption());
+    }
+    {
+        document().documentElement()->setInnerHTML("<select><option id=o1></option><option id=o2></option></select>", ASSERT_NO_EXCEPTION);
+        document().view()->updateAllLifecyclePhases();
+        HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild());
+        EXPECT_EQ("o1", select->firstSelectableOption()->fastGetAttribute(HTMLNames::idAttr));
+    }
+    {
+        document().documentElement()->setInnerHTML("<select><option id=o1 disabled></option><option id=o2></option></select>", ASSERT_NO_EXCEPTION);
+        document().view()->updateAllLifecyclePhases();
+        HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild());
+        EXPECT_EQ("o2", select->firstSelectableOption()->fastGetAttribute(HTMLNames::idAttr));
+    }
+    {
+        document().documentElement()->setInnerHTML("<select><option id=o1 style='display:none'></option><option id=o2></option></select>", ASSERT_NO_EXCEPTION);
+        document().view()->updateAllLifecyclePhases();
+        HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild());
+        EXPECT_EQ("o2", select->firstSelectableOption()->fastGetAttribute(HTMLNames::idAttr));
+    }
+    {
+        document().documentElement()->setInnerHTML("<select><optgroup><option id=o1></option><option id=o2></option></optgroup></select>", ASSERT_NO_EXCEPTION);
+        document().view()->updateAllLifecyclePhases();
+        HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild());
+        EXPECT_EQ("o1", select->firstSelectableOption()->fastGetAttribute(HTMLNames::idAttr));
+    }
+}
+
+TEST_F(HTMLSelectElementTest, LastSelectableOption)
+{
+    {
+        document().documentElement()->setInnerHTML("<select></select>", ASSERT_NO_EXCEPTION);
+        document().view()->updateAllLifecyclePhases();
+        HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild());
+        EXPECT_EQ(nullptr, select->lastSelectableOption());
+    }
+    {
+        document().documentElement()->setInnerHTML("<select><option id=o1></option><option id=o2></option></select>", ASSERT_NO_EXCEPTION);
+        document().view()->updateAllLifecyclePhases();
+        HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild());
+        EXPECT_EQ("o2", select->lastSelectableOption()->fastGetAttribute(HTMLNames::idAttr));
+    }
+    {
+        document().documentElement()->setInnerHTML("<select><option id=o1></option><option id=o2 disabled></option></select>", ASSERT_NO_EXCEPTION);
+        document().view()->updateAllLifecyclePhases();
+        HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild());
+        EXPECT_EQ("o1", select->lastSelectableOption()->fastGetAttribute(HTMLNames::idAttr));
+    }
+    {
+        document().documentElement()->setInnerHTML("<select><option id=o1></option><option id=o2 style='display:none'></option></select>", ASSERT_NO_EXCEPTION);
+        document().view()->updateAllLifecyclePhases();
+        HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild());
+        EXPECT_EQ("o1", select->lastSelectableOption()->fastGetAttribute(HTMLNames::idAttr));
+    }
+    {
+        document().documentElement()->setInnerHTML("<select><optgroup><option id=o1></option><option id=o2></option></optgroup></select>", ASSERT_NO_EXCEPTION);
+        document().view()->updateAllLifecyclePhases();
+        HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild());
+        EXPECT_EQ("o2", select->lastSelectableOption()->fastGetAttribute(HTMLNames::idAttr));
+    }
+}
+
+TEST_F(HTMLSelectElementTest, NextSelectableOption)
+{
+    {
+        document().documentElement()->setInnerHTML("<select></select>", ASSERT_NO_EXCEPTION);
+        document().view()->updateAllLifecyclePhases();
+        HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild());
+        EXPECT_EQ(nullptr, select->nextSelectableOption(nullptr));
+    }
+    {
+        document().documentElement()->setInnerHTML("<select><option id=o1></option><option id=o2></option></select>", ASSERT_NO_EXCEPTION);
+        document().view()->updateAllLifecyclePhases();
+        HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild());
+        EXPECT_EQ("o1", select->nextSelectableOption(nullptr)->fastGetAttribute(HTMLNames::idAttr));
+    }
+    {
+        document().documentElement()->setInnerHTML("<select><option id=o1 disabled></option><option id=o2></option></select>", ASSERT_NO_EXCEPTION);
+        document().view()->updateAllLifecyclePhases();
+        HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild());
+        EXPECT_EQ("o2", select->nextSelectableOption(nullptr)->fastGetAttribute(HTMLNames::idAttr));
+    }
+    {
+        document().documentElement()->setInnerHTML("<select><option id=o1 style='display:none'></option><option id=o2></option></select>", ASSERT_NO_EXCEPTION);
+        document().view()->updateAllLifecyclePhases();
+        HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild());
+        EXPECT_EQ("o2", select->nextSelectableOption(nullptr)->fastGetAttribute(HTMLNames::idAttr));
+    }
+    {
+        document().documentElement()->setInnerHTML("<select><optgroup><option id=o1></option><option id=o2></option></optgroup></select>", ASSERT_NO_EXCEPTION);
+        document().view()->updateAllLifecyclePhases();
+        HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild());
+        EXPECT_EQ("o1", select->nextSelectableOption(nullptr)->fastGetAttribute(HTMLNames::idAttr));
+    }
+    {
+        document().documentElement()->setInnerHTML("<select><option id=o1></option><option id=o2></option></select>", ASSERT_NO_EXCEPTION);
+        document().view()->updateAllLifecyclePhases();
+        HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild());
+        HTMLOptionElement* option = toHTMLOptionElement(document().getElementById("o1"));
+        EXPECT_EQ("o2", select->nextSelectableOption(option)->fastGetAttribute(HTMLNames::idAttr));
+
+        EXPECT_EQ(nullptr, select->nextSelectableOption(toHTMLOptionElement(document().getElementById("o2"))));
+    }
+    {
+        document().documentElement()->setInnerHTML("<select><option id=o1></option><optgroup><option id=o2></option></optgroup></select>", ASSERT_NO_EXCEPTION);
+        document().view()->updateAllLifecyclePhases();
+        HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild());
+        HTMLOptionElement* option = toHTMLOptionElement(document().getElementById("o1"));
+        EXPECT_EQ("o2", select->nextSelectableOption(option)->fastGetAttribute(HTMLNames::idAttr));
+    }
+}
+
+TEST_F(HTMLSelectElementTest, PreviousSelectableOption)
+{
+    {
+        document().documentElement()->setInnerHTML("<select></select>", ASSERT_NO_EXCEPTION);
+        document().view()->updateAllLifecyclePhases();
+        HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild());
+        EXPECT_EQ(nullptr, select->previousSelectableOption(nullptr));
+    }
+    {
+        document().documentElement()->setInnerHTML("<select><option id=o1></option><option id=o2></option></select>", ASSERT_NO_EXCEPTION);
+        document().view()->updateAllLifecyclePhases();
+        HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild());
+        EXPECT_EQ("o2", select->previousSelectableOption(nullptr)->fastGetAttribute(HTMLNames::idAttr));
+    }
+    {
+        document().documentElement()->setInnerHTML("<select><option id=o1></option><option id=o2 disabled></option></select>", ASSERT_NO_EXCEPTION);
+        document().view()->updateAllLifecyclePhases();
+        HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild());
+        EXPECT_EQ("o1", select->previousSelectableOption(nullptr)->fastGetAttribute(HTMLNames::idAttr));
+    }
+    {
+        document().documentElement()->setInnerHTML("<select><option id=o1></option><option id=o2 style='display:none'></option></select>", ASSERT_NO_EXCEPTION);
+        document().view()->updateAllLifecyclePhases();
+        HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild());
+        EXPECT_EQ("o1", select->previousSelectableOption(nullptr)->fastGetAttribute(HTMLNames::idAttr));
+    }
+    {
+        document().documentElement()->setInnerHTML("<select><optgroup><option id=o1></option><option id=o2></option></optgroup></select>", ASSERT_NO_EXCEPTION);
+        document().view()->updateAllLifecyclePhases();
+        HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild());
+        EXPECT_EQ("o2", select->previousSelectableOption(nullptr)->fastGetAttribute(HTMLNames::idAttr));
+    }
+    {
+        document().documentElement()->setInnerHTML("<select><option id=o1></option><option id=o2></option></select>", ASSERT_NO_EXCEPTION);
+        document().view()->updateAllLifecyclePhases();
+        HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild());
+        HTMLOptionElement* option = toHTMLOptionElement(document().getElementById("o2"));
+        EXPECT_EQ("o1", select->previousSelectableOption(option)->fastGetAttribute(HTMLNames::idAttr));
+
+        EXPECT_EQ(nullptr, select->previousSelectableOption(toHTMLOptionElement(document().getElementById("o1"))));
+    }
+    {
+        document().documentElement()->setInnerHTML("<select><option id=o1></option><optgroup><option id=o2></option></optgroup></select>", ASSERT_NO_EXCEPTION);
+        document().view()->updateAllLifecyclePhases();
+        HTMLSelectElement* select = toHTMLSelectElement(document().body()->firstChild());
+        HTMLOptionElement* option = toHTMLOptionElement(document().getElementById("o2"));
+        EXPECT_EQ("o1", select->previousSelectableOption(option)->fastGetAttribute(HTMLNames::idAttr));
+    }
+}
+
 TEST_F(HTMLSelectElementTest, ActiveSelectionEndAfterOptionRemoval)
 {
     document().documentElement()->setInnerHTML("<select><optgroup><option selected>o1</option></optgroup></select>", ASSERT_NO_EXCEPTION);
diff --git a/third_party/WebKit/Source/core/html/ImageDocument.cpp b/third_party/WebKit/Source/core/html/ImageDocument.cpp
index ad9df679..7521cbd 100644
--- a/third_party/WebKit/Source/core/html/ImageDocument.cpp
+++ b/third_party/WebKit/Source/core/html/ImageDocument.cpp
@@ -319,7 +319,7 @@
     if (m_imageSizeIsKnown)
         return;
 
-    updateLayoutTreeIfNeeded();
+    updateLayoutTree();
     if (!m_imageElement->cachedImage() || m_imageElement->cachedImage()->imageSize(LayoutObject::shouldRespectImageOrientation(m_imageElement->layoutObject()), pageZoomFactor(this)).isEmpty())
         return;
 
diff --git a/third_party/WebKit/Source/core/html/canvas/OffScreenCanvas.cpp b/third_party/WebKit/Source/core/html/canvas/OffScreenCanvas.cpp
deleted file mode 100644
index ced18e86..0000000
--- a/third_party/WebKit/Source/core/html/canvas/OffScreenCanvas.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2015 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 "core/html/canvas/OffScreenCanvas.h"
-
-#include "wtf/MathExtras.h"
-
-namespace blink {
-
-OffScreenCanvas* OffScreenCanvas::create(unsigned width, unsigned height)
-{
-    return new OffScreenCanvas(IntSize(clampTo<int>(width), clampTo<int>(height)));
-}
-
-void OffScreenCanvas::setWidth(unsigned width)
-{
-    m_size.setWidth(clampTo<int>(width));
-}
-
-void OffScreenCanvas::setHeight(unsigned height)
-{
-    m_size.setHeight(clampTo<int>(height));
-}
-
-OffScreenCanvas::OffScreenCanvas(const IntSize& size)
-    : m_size(size)
-{
-}
-
-DEFINE_TRACE(OffScreenCanvas)
-{
-}
-
-} // namespace blink
diff --git a/third_party/WebKit/Source/core/html/canvas/OffscreenCanvasTemp.cpp b/third_party/WebKit/Source/core/html/canvas/OffscreenCanvasTemp.cpp
new file mode 100644
index 0000000..772c16d
--- /dev/null
+++ b/third_party/WebKit/Source/core/html/canvas/OffscreenCanvasTemp.cpp
@@ -0,0 +1,35 @@
+// Copyright 2015 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 "core/html/canvas/OffscreenCanvasTemp.h"
+
+#include "wtf/MathExtras.h"
+
+namespace blink {
+
+OffscreenCanvasTemp* OffscreenCanvasTemp::create(unsigned width, unsigned height)
+{
+    return new OffscreenCanvasTemp(IntSize(clampTo<int>(width), clampTo<int>(height)));
+}
+
+void OffscreenCanvasTemp::setWidth(unsigned width)
+{
+    m_size.setWidth(clampTo<int>(width));
+}
+
+void OffscreenCanvasTemp::setHeight(unsigned height)
+{
+    m_size.setHeight(clampTo<int>(height));
+}
+
+OffscreenCanvasTemp::OffscreenCanvasTemp(const IntSize& size)
+    : m_size(size)
+{
+}
+
+DEFINE_TRACE(OffscreenCanvasTemp)
+{
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/html/canvas/OffScreenCanvas.h b/third_party/WebKit/Source/core/html/canvas/OffscreenCanvasTemp.h
similarity index 69%
rename from third_party/WebKit/Source/core/html/canvas/OffScreenCanvas.h
rename to third_party/WebKit/Source/core/html/canvas/OffscreenCanvasTemp.h
index 1f24801..f61f156c 100644
--- a/third_party/WebKit/Source/core/html/canvas/OffScreenCanvas.h
+++ b/third_party/WebKit/Source/core/html/canvas/OffscreenCanvasTemp.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef OffScreenCanvas_h
-#define OffScreenCanvas_h
+#ifndef OffscreenCanvasTemp_h
+#define OffscreenCanvasTemp_h
 
 #include "bindings/core/v8/ScriptPromise.h"
 #include "bindings/core/v8/ScriptState.h"
@@ -14,10 +14,10 @@
 
 namespace blink {
 
-class CORE_EXPORT OffScreenCanvas final : public GarbageCollectedFinalized<OffScreenCanvas>, public ScriptWrappable {
+class CORE_EXPORT OffscreenCanvasTemp final : public GarbageCollectedFinalized<OffscreenCanvasTemp>, public ScriptWrappable {
     DEFINE_WRAPPERTYPEINFO();
 public:
-    static OffScreenCanvas* create(unsigned width, unsigned height);
+    static OffscreenCanvasTemp* create(unsigned width, unsigned height);
 
     IntSize size() const { return m_size; }
     unsigned width() const { return m_size.width(); }
@@ -29,11 +29,11 @@
     DECLARE_VIRTUAL_TRACE();
 
 private:
-    OffScreenCanvas(const IntSize&);
+    OffscreenCanvasTemp(const IntSize&);
 
     IntSize m_size;
 };
 
 } // namespace blink
 
-#endif // OffScreenCanvas_h
+#endif // OffscreenCanvasTemp_h
diff --git a/third_party/WebKit/Source/core/html/canvas/OffScreenCanvas.idl b/third_party/WebKit/Source/core/html/canvas/OffscreenCanvasTemp.idl
similarity index 92%
rename from third_party/WebKit/Source/core/html/canvas/OffScreenCanvas.idl
rename to third_party/WebKit/Source/core/html/canvas/OffscreenCanvasTemp.idl
index bfa5acc5..f94cdde2 100644
--- a/third_party/WebKit/Source/core/html/canvas/OffScreenCanvas.idl
+++ b/third_party/WebKit/Source/core/html/canvas/OffscreenCanvasTemp.idl
@@ -7,7 +7,7 @@
     GarbageCollected,
     Exposed=(Window,Worker),
     RuntimeEnabled=ExperimentalCanvasFeatures,
-] interface OffScreenCanvas {
+] interface OffscreenCanvasTemp {
     [EnforceRange] attribute unsigned long width;
     [EnforceRange] attribute unsigned long height;
 };
diff --git a/third_party/WebKit/Source/core/html/forms/RadioInputType.cpp b/third_party/WebKit/Source/core/html/forms/RadioInputType.cpp
index 2aa6c96..b724f71 100644
--- a/third_party/WebKit/Source/core/html/forms/RadioInputType.cpp
+++ b/third_party/WebKit/Source/core/html/forms/RadioInputType.cpp
@@ -85,6 +85,9 @@
 
 void RadioInputType::handleKeydownEvent(KeyboardEvent* event)
 {
+    // TODO(tkent): We should return more earlier.
+    if (!element().layoutObject())
+        return;
     BaseCheckableInputType::handleKeydownEvent(event);
     if (event->defaultHandled())
         return;
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp
index 8968613d..7e3ec7d 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp
@@ -204,9 +204,13 @@
             resourceWidth.isSet = true;
         }
 
+        Resource::Type type;
+        if (!resourceType(type))
+            return nullptr;
+
         // The element's 'referrerpolicy' attribute (if present) takes precedence over the document's referrer policy.
         ReferrerPolicy referrerPolicy = (m_referrerPolicy != ReferrerPolicyDefault && RuntimeEnabledFeatures::referrerPolicyAttributeEnabled()) ? m_referrerPolicy : documentReferrerPolicy;
-        OwnPtr<PreloadRequest> request = PreloadRequest::create(initiatorFor(m_tagImpl), position, m_urlToLoad, predictedBaseURL, resourceType(), referrerPolicy, resourceWidth, clientHintsPreferences, requestType);
+        OwnPtr<PreloadRequest> request = PreloadRequest::create(initiatorFor(m_tagImpl), position, m_urlToLoad, predictedBaseURL, type, referrerPolicy, resourceWidth, clientHintsPreferences, requestType);
         request->setCrossOrigin(m_crossOrigin);
         request->setCharset(charset());
         request->setDefer(m_defer);
@@ -362,22 +366,25 @@
         return m_charset;
     }
 
-    Resource::Type resourceType() const
+    bool resourceType(Resource::Type& type) const
     {
-        if (match(m_tagImpl, scriptTag))
-            return Resource::Script;
-        if (match(m_tagImpl, imgTag) || match(m_tagImpl, videoTag) || (match(m_tagImpl, inputTag) && m_inputIsImage))
-            return Resource::Image;
-        if (match(m_tagImpl, linkTag) && m_linkIsStyleSheet)
-            return Resource::CSSStyleSheet;
-        if (m_linkIsPreconnect)
-            return Resource::Raw;
-        if (m_linkIsPreload)
-            return LinkLoader::getTypeFromAsAttribute(m_asAttributeValue, nullptr);
-        if (match(m_tagImpl, linkTag) && m_linkIsImport)
-            return Resource::ImportResource;
-        ASSERT_NOT_REACHED();
-        return Resource::Raw;
+        if (match(m_tagImpl, scriptTag)) {
+            type = Resource::Script;
+        } else if (match(m_tagImpl, imgTag) || match(m_tagImpl, videoTag) || (match(m_tagImpl, inputTag) && m_inputIsImage)) {
+            type = Resource::Image;
+        } else if (match(m_tagImpl, linkTag) && m_linkIsStyleSheet) {
+            type = Resource::CSSStyleSheet;
+        } else if (m_linkIsPreconnect) {
+            type = Resource::Raw;
+        } else if (m_linkIsPreload) {
+            if (!LinkLoader::getResourceTypeFromAsAttribute(m_asAttributeValue, type))
+                return false;
+        } else if (match(m_tagImpl, linkTag) && m_linkIsImport) {
+            type = Resource::ImportResource;
+        } else {
+            ASSERT_NOT_REACHED();
+        }
+        return true;
     }
 
     bool shouldPreconnect() const
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.cpp b/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.cpp
index e9862a31..63e208b6 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.cpp
@@ -51,9 +51,9 @@
 
 // TODO(bmcquade): move this to a shared location if we find ourselves wanting
 // to trace similar data elsewhere in the codebase.
-PassRefPtr<TracedValue> getTraceArgsForScriptElement(Element* element, const TextPosition& textPosition)
+PassOwnPtr<TracedValue> getTraceArgsForScriptElement(Element* element, const TextPosition& textPosition)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     ScriptLoader* scriptLoader = toScriptLoaderIfPossible(element);
     if (scriptLoader && scriptLoader->resource())
         value->setString("url", scriptLoader->resource()->url().string());
diff --git a/third_party/WebKit/Source/core/html/shadow/DateTimeEditElement.cpp b/third_party/WebKit/Source/core/html/shadow/DateTimeEditElement.cpp
index 2b36b211..57febcd 100644
--- a/third_party/WebKit/Source/core/html/shadow/DateTimeEditElement.cpp
+++ b/third_party/WebKit/Source/core/html/shadow/DateTimeEditElement.cpp
@@ -573,7 +573,7 @@
     if (oldFocusedElement && oldFocusedElement->isDateTimeFieldElement()) {
         DateTimeFieldElement* oldFocusedField = static_cast<DateTimeFieldElement*>(oldFocusedElement);
         size_t index = fieldIndexOf(*oldFocusedField);
-        document().updateLayoutTreeForNodeIfNeeded(oldFocusedField);
+        document().updateLayoutTreeForNode(oldFocusedField);
         if (index != invalidFieldIndex && oldFocusedField->isFocusable()) {
             oldFocusedField->focus();
             return;
diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp
index d547f45..81e9c471 100644
--- a/third_party/WebKit/Source/core/input/EventHandler.cpp
+++ b/third_party/WebKit/Source/core/input/EventHandler.cpp
@@ -1825,7 +1825,7 @@
         return WebInputEventResult::NotHandled;
 
     ScrollResult scrollResult = scrollAreaWithWheelEvent(event, *view->scrollableArea());
-    if (m_frame->settings() && m_frame->settings()->reportWheelOverscroll())
+    if (m_frame->isMainFrame() && m_frame->settings() && m_frame->settings()->reportWheelOverscroll())
         handleOverscroll(scrollResult);
     if (scrollResult.didScroll()) {
         setFrameWasScrolledByUser();
@@ -2330,6 +2330,8 @@
 
 void EventHandler::handleOverscroll(const ScrollResult& scrollResult, const FloatPoint& position, const FloatSize& velocity)
 {
+    ASSERT(m_frame->isMainFrame());
+
     FloatSize unusedDelta(scrollResult.unusedScrollDeltaX, scrollResult.unusedScrollDeltaY);
     unusedDelta = adjustOverscroll(unusedDelta);
     resetOverscroll(scrollResult.didScrollX, scrollResult.didScrollY);
@@ -2430,9 +2432,11 @@
 
     // Try to scroll the frame view.
     ScrollResult scrollResult = m_frame->applyScrollDelta(granularity, delta, false);
-    FloatPoint position = FloatPoint(gestureEvent.position().x(), gestureEvent.position().y());
-    FloatSize velocity = FloatSize(gestureEvent.velocityX(), gestureEvent.velocityY());
-    handleOverscroll(scrollResult, position, velocity);
+    if (m_frame->isMainFrame()) {
+        FloatPoint position = FloatPoint(gestureEvent.position().x(), gestureEvent.position().y());
+        FloatSize velocity = FloatSize(gestureEvent.velocityX(), gestureEvent.velocityY());
+        handleOverscroll(scrollResult, position, velocity);
+    }
     if (scrollResult.didScroll()) {
         setFrameWasScrolledByUser();
         return WebInputEventResult::HandledSystem;
diff --git a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
index 77ceeae..413be6b 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
@@ -207,7 +207,7 @@
 
     for (auto e = elementsUnderRect.rbegin(); !foundTopElement && e != elementsUnderRect.rend(); ++e) {
         const Element* element = *e;
-        if (element->isSameNode(topElement))
+        if (element == topElement)
             foundTopElement = true;
 
         const LayoutObject* layoutObject = element->layoutObject();
@@ -871,7 +871,7 @@
     }
 
     Element* originalElement = element;
-    PseudoId elementPseudoId = element->pseudoId();
+    PseudoId elementPseudoId = element->getPseudoId();
     if (elementPseudoId) {
         element = element->parentOrShadowHostElement();
         if (!element) {
@@ -1755,7 +1755,7 @@
     // According to http://www.w3.org/TR/css3-selectors/#pseudo-elements, "Only one pseudo-element may appear per selector."
     // As such, check the last selector in the tag history.
     for (; !selector->isLastInTagHistory(); ++selector) { }
-    PseudoId selectorPseudoId = CSSSelector::pseudoId(selector->pseudoType());
+    PseudoId selectorPseudoId = CSSSelector::pseudoId(selector->getPseudoType());
 
     // FIXME: This only covers the case of matching pseudo-element selectors against PseudoElements.
     // We should come up with a solution for matching pseudo-element selectors against ordinary Elements, too.
@@ -1777,7 +1777,7 @@
         OwnPtr<protocol::Array<int>> matchingSelectors = protocol::Array<int>::create();
         const CSSSelectorList& selectorList = rule->styleRule()->selectorList();
         long index = 0;
-        PseudoId elementPseudoId = matchesForPseudoId ? matchesForPseudoId : element->pseudoId();
+        PseudoId elementPseudoId = matchesForPseudoId ? matchesForPseudoId : element->getPseudoId();
         for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector)) {
             const CSSSelector* firstTagHistorySelector = selector;
             bool matched = false;
@@ -1885,7 +1885,7 @@
 
 WillBeHeapVector<RefPtrWillBeMember<CSSStyleDeclaration>> InspectorCSSAgent::matchingStyles(Element* element)
 {
-    PseudoId pseudoId = element->pseudoId();
+    PseudoId pseudoId = element->getPseudoId();
     if (pseudoId)
         element = element->parentElement();
     StyleResolver& styleResolver = element->ownerDocument()->ensureStyleResolver();
@@ -2021,7 +2021,7 @@
 {
     // TODO: move testing from CSSAgent to layout editor.
     Element* element = elementForId(errorString, nodeId);
-    if (!element || element->pseudoId())
+    if (!element || element->getPseudoId())
         return;
 
     CSSPropertyID property = cssPropertyID(propertyName);
diff --git a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp
index f00cad0..3b216b3 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp
@@ -1500,9 +1500,9 @@
             forcePushChildren = true;
         }
 
-        if (element->pseudoId()) {
+        if (element->getPseudoId()) {
             protocol::DOM::PseudoType pseudoType;
-            if (InspectorDOMAgent::getPseudoElementType(element->pseudoId(), &pseudoType))
+            if (InspectorDOMAgent::getPseudoElementType(element->getPseudoId(), &pseudoType))
                 value->setPseudoType(pseudoType);
         } else {
             OwnPtr<protocol::Array<protocol::DOM::Node>> pseudoElements = buildArrayForPseudoElements(element, nodesMap);
diff --git a/third_party/WebKit/Source/core/inspector/InspectorHighlight.cpp b/third_party/WebKit/Source/core/inspector/InspectorHighlight.cpp
index 8badfb5..944b595 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorHighlight.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorHighlight.cpp
@@ -189,9 +189,9 @@
         }
     }
     if (pseudoElement) {
-        if (pseudoElement->pseudoId() == BEFORE)
+        if (pseudoElement->getPseudoId() == BEFORE)
             classNames.appendLiteral("::before");
-        else if (pseudoElement->pseudoId() == AFTER)
+        else if (pseudoElement->getPseudoId() == AFTER)
             classNames.appendLiteral("::after");
     }
     if (!classNames.isEmpty())
diff --git a/third_party/WebKit/Source/core/inspector/InspectorStyleSheet.cpp b/third_party/WebKit/Source/core/inspector/InspectorStyleSheet.cpp
index df32b3d7..56c8401 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorStyleSheet.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorStyleSheet.cpp
@@ -84,7 +84,7 @@
     }
 
 private:
-    void startRuleHeader(StyleRule::Type, unsigned) override;
+    void startRuleHeader(StyleRule::RuleType, unsigned) override;
     void endRuleHeader(unsigned) override;
     void observeSelector(unsigned startOffset, unsigned endOffset) override;
     void startRuleBody(unsigned) override;
@@ -110,7 +110,7 @@
     unsigned m_mediaQueryExpValueRangeStart;
 };
 
-void StyleSheetHandler::startRuleHeader(StyleRule::Type type, unsigned offset)
+void StyleSheetHandler::startRuleHeader(StyleRule::RuleType type, unsigned offset)
 {
     // Pop off data for a previous invalid rule.
     if (m_currentRuleData)
diff --git a/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp b/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp
index d60b9d4..f34ca951 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp
@@ -163,9 +163,9 @@
 } // namespace
 
 namespace InspectorScheduleStyleInvalidationTrackingEvent {
-PassRefPtr<TracedValue> fillCommonPart(Element& element, const InvalidationSet& invalidationSet, const char* invalidatedSelector)
+PassOwnPtr<TracedValue> fillCommonPart(Element& element, const InvalidationSet& invalidationSet, const char* invalidatedSelector)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("frame", toHexString(element.document().frame()));
     setNodeInfo(value.get(), &element, "nodeId", "nodeName");
     value->setString("invalidationSet", descendantInvalidationSetToIdString(invalidationSet));
@@ -181,30 +181,30 @@
 const char InspectorScheduleStyleInvalidationTrackingEvent::Id[] = "id";
 const char InspectorScheduleStyleInvalidationTrackingEvent::Pseudo[] = "pseudo";
 
-PassRefPtr<TracedValue> InspectorScheduleStyleInvalidationTrackingEvent::idChange(Element& element, const InvalidationSet& invalidationSet, const AtomicString& id)
+PassOwnPtr<TracedValue> InspectorScheduleStyleInvalidationTrackingEvent::idChange(Element& element, const InvalidationSet& invalidationSet, const AtomicString& id)
 {
-    RefPtr<TracedValue> value = fillCommonPart(element, invalidationSet, Id);
+    OwnPtr<TracedValue> value = fillCommonPart(element, invalidationSet, Id);
     value->setString("changedId", id);
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorScheduleStyleInvalidationTrackingEvent::classChange(Element& element, const InvalidationSet& invalidationSet, const AtomicString& className)
+PassOwnPtr<TracedValue> InspectorScheduleStyleInvalidationTrackingEvent::classChange(Element& element, const InvalidationSet& invalidationSet, const AtomicString& className)
 {
-    RefPtr<TracedValue> value = fillCommonPart(element, invalidationSet, Class);
+    OwnPtr<TracedValue> value = fillCommonPart(element, invalidationSet, Class);
     value->setString("changedClass", className);
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorScheduleStyleInvalidationTrackingEvent::attributeChange(Element& element, const InvalidationSet& invalidationSet, const QualifiedName& attributeName)
+PassOwnPtr<TracedValue> InspectorScheduleStyleInvalidationTrackingEvent::attributeChange(Element& element, const InvalidationSet& invalidationSet, const QualifiedName& attributeName)
 {
-    RefPtr<TracedValue> value = fillCommonPart(element, invalidationSet, Attribute);
+    OwnPtr<TracedValue> value = fillCommonPart(element, invalidationSet, Attribute);
     value->setString("changedAttribute", attributeName.toString());
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorScheduleStyleInvalidationTrackingEvent::pseudoChange(Element& element, const InvalidationSet& invalidationSet, CSSSelector::PseudoType pseudoType)
+PassOwnPtr<TracedValue> InspectorScheduleStyleInvalidationTrackingEvent::pseudoChange(Element& element, const InvalidationSet& invalidationSet, CSSSelector::PseudoType pseudoType)
 {
-    RefPtr<TracedValue> value = fillCommonPart(element, invalidationSet, Attribute);
+    OwnPtr<TracedValue> value = fillCommonPart(element, invalidationSet, Attribute);
     value->setString("changedPseudo", pseudoTypeToString(pseudoType));
     return value.release();
 }
@@ -223,9 +223,9 @@
 const char InspectorStyleInvalidatorInvalidateEvent::PreventStyleSharingForParent[] = "Prevent style sharing for parent";
 
 namespace InspectorStyleInvalidatorInvalidateEvent {
-PassRefPtr<TracedValue> fillCommonPart(Element& element, const char* reason)
+PassOwnPtr<TracedValue> fillCommonPart(Element& element, const char* reason)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("frame", toHexString(element.document().frame()));
     setNodeInfo(value.get(), &element, "nodeId", "nodeName");
     value->setString("reason", reason);
@@ -233,14 +233,14 @@
 }
 } // namespace InspectorStyleInvalidatorInvalidateEvent
 
-PassRefPtr<TracedValue> InspectorStyleInvalidatorInvalidateEvent::data(Element& element, const char* reason)
+PassOwnPtr<TracedValue> InspectorStyleInvalidatorInvalidateEvent::data(Element& element, const char* reason)
 {
     return fillCommonPart(element, reason);
 }
 
-PassRefPtr<TracedValue> InspectorStyleInvalidatorInvalidateEvent::selectorPart(Element& element, const char* reason, const InvalidationSet& invalidationSet, const String& selectorPart)
+PassOwnPtr<TracedValue> InspectorStyleInvalidatorInvalidateEvent::selectorPart(Element& element, const char* reason, const InvalidationSet& invalidationSet, const String& selectorPart)
 {
-    RefPtr<TracedValue> value = fillCommonPart(element, reason);
+    OwnPtr<TracedValue> value = fillCommonPart(element, reason);
     value->beginArray("invalidationList");
     invalidationSet.toTracedValue(value.get());
     value->endArray();
@@ -248,9 +248,9 @@
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorStyleInvalidatorInvalidateEvent::invalidationList(Element& element, const Vector<RefPtr<InvalidationSet>>& invalidationList)
+PassOwnPtr<TracedValue> InspectorStyleInvalidatorInvalidateEvent::invalidationList(Element& element, const Vector<RefPtr<InvalidationSet>>& invalidationList)
 {
-    RefPtr<TracedValue> value = fillCommonPart(element, ElementHasPendingInvalidationList);
+    OwnPtr<TracedValue> value = fillCommonPart(element, ElementHasPendingInvalidationList);
     value->beginArray("invalidationList");
     for (const auto& invalidationSet : invalidationList)
         invalidationSet->toTracedValue(value.get());
@@ -258,11 +258,11 @@
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorStyleRecalcInvalidationTrackingEvent::data(Node* node, const StyleChangeReasonForTracing& reason)
+PassOwnPtr<TracedValue> InspectorStyleRecalcInvalidationTrackingEvent::data(Node* node, const StyleChangeReasonForTracing& reason)
 {
     ASSERT(node);
 
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("frame", toHexString(node->document().frame()));
     setNodeInfo(value.get(), node, "nodeId", "nodeName");
     value->setString("reason", reason.reasonString());
@@ -272,7 +272,7 @@
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorLayoutEvent::beginData(FrameView* frameView)
+PassOwnPtr<TracedValue> InspectorLayoutEvent::beginData(FrameView* frameView)
 {
     bool isPartial;
     unsigned needsLayoutObjects;
@@ -280,7 +280,7 @@
     LocalFrame& frame = frameView->frame();
     frame.view()->countObjectsNeedingLayout(needsLayoutObjects, totalObjects, isPartial);
 
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setInteger("dirtyObjects", needsLayoutObjects);
     value->setInteger("totalObjects", totalObjects);
     value->setBoolean("partialLayout", isPartial);
@@ -314,12 +314,12 @@
     setNodeInfo(value, node, idFieldName, nameFieldName);
 }
 
-PassRefPtr<TracedValue> InspectorLayoutEvent::endData(LayoutObject* rootForThisLayout)
+PassOwnPtr<TracedValue> InspectorLayoutEvent::endData(LayoutObject* rootForThisLayout)
 {
     Vector<FloatQuad> quads;
     rootForThisLayout->absoluteQuads(quads);
 
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     if (quads.size() >= 1) {
         createQuad(value.get(), "root", quads[0]);
         setGeneratingNodeInfo(value.get(), rootForThisLayout, "rootNode");
@@ -364,10 +364,10 @@
 const char ScrollbarChanged[] = "Scrollbar changed";
 } // namespace LayoutInvalidationReason
 
-PassRefPtr<TracedValue> InspectorLayoutInvalidationTrackingEvent::data(const LayoutObject* layoutObject, LayoutInvalidationReasonForTracing reason)
+PassOwnPtr<TracedValue> InspectorLayoutInvalidationTrackingEvent::data(const LayoutObject* layoutObject, LayoutInvalidationReasonForTracing reason)
 {
     ASSERT(layoutObject);
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("frame", toHexString(layoutObject->frame()));
     setGeneratingNodeInfo(value.get(), layoutObject, "nodeId", "nodeName");
     value->setString("reason", reason);
@@ -376,21 +376,21 @@
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorPaintInvalidationTrackingEvent::data(const LayoutObject* layoutObject, const LayoutObject& paintContainer)
+PassOwnPtr<TracedValue> InspectorPaintInvalidationTrackingEvent::data(const LayoutObject* layoutObject, const LayoutObject& paintContainer)
 {
     ASSERT(layoutObject);
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("frame", toHexString(layoutObject->frame()));
     setGeneratingNodeInfo(value.get(), &paintContainer, "paintId");
     setGeneratingNodeInfo(value.get(), layoutObject, "nodeId", "nodeName");
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorScrollInvalidationTrackingEvent::data(const LayoutObject& layoutObject)
+PassOwnPtr<TracedValue> InspectorScrollInvalidationTrackingEvent::data(const LayoutObject& layoutObject)
 {
     static const char ScrollInvalidationReason[] = "Scroll with viewport-constrained element";
 
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("frame", toHexString(layoutObject.frame()));
     value->setString("reason", ScrollInvalidationReason);
     setGeneratingNodeInfo(value.get(), &layoutObject, "nodeId", "nodeName");
@@ -399,11 +399,11 @@
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorSendRequestEvent::data(unsigned long identifier, LocalFrame* frame, const ResourceRequest& request)
+PassOwnPtr<TracedValue> InspectorSendRequestEvent::data(unsigned long identifier, LocalFrame* frame, const ResourceRequest& request)
 {
     String requestId = IdentifiersFactory::requestId(identifier);
 
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("requestId", requestId);
     value->setString("frame", toHexString(frame));
     value->setString("url", request.url().string());
@@ -423,11 +423,11 @@
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorReceiveResponseEvent::data(unsigned long identifier, LocalFrame* frame, const ResourceResponse& response)
+PassOwnPtr<TracedValue> InspectorReceiveResponseEvent::data(unsigned long identifier, LocalFrame* frame, const ResourceResponse& response)
 {
     String requestId = IdentifiersFactory::requestId(identifier);
 
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("requestId", requestId);
     value->setString("frame", toHexString(frame));
     value->setInteger("statusCode", response.httpStatusCode());
@@ -435,22 +435,22 @@
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorReceiveDataEvent::data(unsigned long identifier, LocalFrame* frame, int encodedDataLength)
+PassOwnPtr<TracedValue> InspectorReceiveDataEvent::data(unsigned long identifier, LocalFrame* frame, int encodedDataLength)
 {
     String requestId = IdentifiersFactory::requestId(identifier);
 
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("requestId", requestId);
     value->setString("frame", toHexString(frame));
     value->setInteger("encodedDataLength", encodedDataLength);
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorResourceFinishEvent::data(unsigned long identifier, double finishTime, bool didFail)
+PassOwnPtr<TracedValue> InspectorResourceFinishEvent::data(unsigned long identifier, double finishTime, bool didFail)
 {
     String requestId = IdentifiersFactory::requestId(identifier);
 
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("requestId", requestId);
     value->setBoolean("didFail", didFail);
     if (finishTime)
@@ -466,9 +466,9 @@
     return frame;
 }
 
-static PassRefPtr<TracedValue> genericTimerData(ExecutionContext* context, int timerId)
+static PassOwnPtr<TracedValue> genericTimerData(ExecutionContext* context, int timerId)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setInteger("timerId", timerId);
     if (LocalFrame* frame = frameForExecutionContext(context))
         value->setString("frame", toHexString(frame));
@@ -476,27 +476,27 @@
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorTimerInstallEvent::data(ExecutionContext* context, int timerId, int timeout, bool singleShot)
+PassOwnPtr<TracedValue> InspectorTimerInstallEvent::data(ExecutionContext* context, int timerId, int timeout, bool singleShot)
 {
-    RefPtr<TracedValue> value = genericTimerData(context, timerId);
+    OwnPtr<TracedValue> value = genericTimerData(context, timerId);
     value->setInteger("timeout", timeout);
     value->setBoolean("singleShot", singleShot);
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorTimerRemoveEvent::data(ExecutionContext* context, int timerId)
+PassOwnPtr<TracedValue> InspectorTimerRemoveEvent::data(ExecutionContext* context, int timerId)
 {
     return genericTimerData(context, timerId);
 }
 
-PassRefPtr<TracedValue> InspectorTimerFireEvent::data(ExecutionContext* context, int timerId)
+PassOwnPtr<TracedValue> InspectorTimerFireEvent::data(ExecutionContext* context, int timerId)
 {
     return genericTimerData(context, timerId);
 }
 
-PassRefPtr<TracedValue> InspectorAnimationFrameEvent::data(ExecutionContext* context, int callbackId)
+PassOwnPtr<TracedValue> InspectorAnimationFrameEvent::data(ExecutionContext* context, int callbackId)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setInteger("id", callbackId);
     if (context->isDocument())
         value->setString("frame", toHexString(toDocument(context)->frame()));
@@ -506,9 +506,9 @@
     return value.release();
 }
 
-PassRefPtr<TracedValue> genericIdleCallbackEvent(ExecutionContext* context, int id)
+PassOwnPtr<TracedValue> genericIdleCallbackEvent(ExecutionContext* context, int id)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setInteger("id", id);
     if (LocalFrame* frame = frameForExecutionContext(context))
         value->setString("frame", toHexString(frame));
@@ -516,29 +516,29 @@
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorIdleCallbackRequestEvent::data(ExecutionContext* context, int id, double timeout)
+PassOwnPtr<TracedValue> InspectorIdleCallbackRequestEvent::data(ExecutionContext* context, int id, double timeout)
 {
-    RefPtr<TracedValue> value = genericIdleCallbackEvent(context, id);
+    OwnPtr<TracedValue> value = genericIdleCallbackEvent(context, id);
     value->setInteger("timeout", timeout);
-    return value;
+    return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorIdleCallbackCancelEvent::data(ExecutionContext* context, int id)
+PassOwnPtr<TracedValue> InspectorIdleCallbackCancelEvent::data(ExecutionContext* context, int id)
 {
     return genericIdleCallbackEvent(context, id);
 }
 
-PassRefPtr<TracedValue> InspectorIdleCallbackFireEvent::data(ExecutionContext* context, int id, double allottedMilliseconds, bool timedOut)
+PassOwnPtr<TracedValue> InspectorIdleCallbackFireEvent::data(ExecutionContext* context, int id, double allottedMilliseconds, bool timedOut)
 {
-    RefPtr<TracedValue> value = genericIdleCallbackEvent(context, id);
+    OwnPtr<TracedValue> value = genericIdleCallbackEvent(context, id);
     value->setDouble("allottedMilliseconds", allottedMilliseconds);
     value->setBoolean("timedOut", timedOut);
-    return value;
+    return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorParseHtmlEvent::beginData(Document* document, unsigned startLine)
+PassOwnPtr<TracedValue> InspectorParseHtmlEvent::beginData(Document* document, unsigned startLine)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setInteger("startLine", startLine);
     value->setString("frame", toHexString(document->frame()));
     value->setString("url", document->url().string());
@@ -546,23 +546,23 @@
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorParseHtmlEvent::endData(unsigned endLine)
+PassOwnPtr<TracedValue> InspectorParseHtmlEvent::endData(unsigned endLine)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setInteger("endLine", endLine);
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorParseAuthorStyleSheetEvent::data(const CSSStyleSheetResource* cachedStyleSheet)
+PassOwnPtr<TracedValue> InspectorParseAuthorStyleSheetEvent::data(const CSSStyleSheetResource* cachedStyleSheet)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("styleSheetUrl", cachedStyleSheet->url().string());
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorXhrReadyStateChangeEvent::data(ExecutionContext* context, XMLHttpRequest* request)
+PassOwnPtr<TracedValue> InspectorXhrReadyStateChangeEvent::data(ExecutionContext* context, XMLHttpRequest* request)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("url", request->url().string());
     value->setInteger("readyState", request->readyState());
     if (LocalFrame* frame = frameForExecutionContext(context))
@@ -571,9 +571,9 @@
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorXhrLoadEvent::data(ExecutionContext* context, XMLHttpRequest* request)
+PassOwnPtr<TracedValue> InspectorXhrLoadEvent::data(ExecutionContext* context, XMLHttpRequest* request)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("url", request->url().string());
     if (LocalFrame* frame = frameForExecutionContext(context))
         value->setString("frame", toHexString(frame));
@@ -598,20 +598,20 @@
 const char InspectorLayerInvalidationTrackingEvent::ReflectionLayerChanged[] = "Reflection layer change";
 const char InspectorLayerInvalidationTrackingEvent::NewCompositedLayer[] = "Assigned a new composited layer";
 
-PassRefPtr<TracedValue> InspectorLayerInvalidationTrackingEvent::data(const PaintLayer* layer, const char* reason)
+PassOwnPtr<TracedValue> InspectorLayerInvalidationTrackingEvent::data(const PaintLayer* layer, const char* reason)
 {
     const LayoutObject& paintInvalidationContainer = layer->layoutObject()->containerForPaintInvalidation();
 
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("frame", toHexString(paintInvalidationContainer.frame()));
     setGeneratingNodeInfo(value.get(), &paintInvalidationContainer, "paintId");
     value->setString("reason", reason);
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorPaintEvent::data(LayoutObject* layoutObject, const LayoutRect& clipRect, const GraphicsLayer* graphicsLayer)
+PassOwnPtr<TracedValue> InspectorPaintEvent::data(LayoutObject* layoutObject, const LayoutRect& clipRect, const GraphicsLayer* graphicsLayer)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("frame", toHexString(layoutObject->frame()));
     FloatQuad quad;
     localToPageQuad(*layoutObject, clipRect, &quad);
@@ -623,9 +623,9 @@
     return value.release();
 }
 
-PassRefPtr<TracedValue> frameEventData(LocalFrame* frame)
+PassOwnPtr<TracedValue> frameEventData(LocalFrame* frame)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("frame", toHexString(frame));
     bool isMainFrame = frame && frame->isMainFrame();
     value->setBoolean("isMainFrame", isMainFrame);
@@ -634,35 +634,35 @@
 }
 
 
-PassRefPtr<TracedValue> InspectorCommitLoadEvent::data(LocalFrame* frame)
+PassOwnPtr<TracedValue> InspectorCommitLoadEvent::data(LocalFrame* frame)
 {
     return frameEventData(frame);
 }
 
-PassRefPtr<TracedValue> InspectorMarkLoadEvent::data(LocalFrame* frame)
+PassOwnPtr<TracedValue> InspectorMarkLoadEvent::data(LocalFrame* frame)
 {
     return frameEventData(frame);
 }
 
-PassRefPtr<TracedValue> InspectorScrollLayerEvent::data(LayoutObject* layoutObject)
+PassOwnPtr<TracedValue> InspectorScrollLayerEvent::data(LayoutObject* layoutObject)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("frame", toHexString(layoutObject->frame()));
     setGeneratingNodeInfo(value.get(), layoutObject, "nodeId");
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorUpdateLayerTreeEvent::data(LocalFrame* frame)
+PassOwnPtr<TracedValue> InspectorUpdateLayerTreeEvent::data(LocalFrame* frame)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("frame", toHexString(frame));
     return value.release();
 }
 
 namespace {
-PassRefPtr<TracedValue> fillLocation(const String& url, const TextPosition& textPosition)
+PassOwnPtr<TracedValue> fillLocation(const String& url, const TextPosition& textPosition)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("url", url);
     value->setInteger("lineNumber", textPosition.m_line.oneBasedInt());
     value->setInteger("columnNumber", textPosition.m_column.oneBasedInt());
@@ -670,22 +670,22 @@
 }
 }
 
-PassRefPtr<TracedValue> InspectorEvaluateScriptEvent::data(LocalFrame* frame, const String& url, const TextPosition& textPosition)
+PassOwnPtr<TracedValue> InspectorEvaluateScriptEvent::data(LocalFrame* frame, const String& url, const TextPosition& textPosition)
 {
-    RefPtr<TracedValue> value = fillLocation(url, textPosition);
+    OwnPtr<TracedValue> value = fillLocation(url, textPosition);
     value->setString("frame", toHexString(frame));
     setCallStack(value.get());
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorCompileScriptEvent::data(const String& url, const TextPosition& textPosition)
+PassOwnPtr<TracedValue> InspectorCompileScriptEvent::data(const String& url, const TextPosition& textPosition)
 {
     return fillLocation(url, textPosition);
 }
 
-PassRefPtr<TracedValue> InspectorFunctionCallEvent::data(ExecutionContext* context, int scriptId, const String& scriptName, int scriptLine)
+PassOwnPtr<TracedValue> InspectorFunctionCallEvent::data(ExecutionContext* context, int scriptId, const String& scriptName, int scriptLine)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("scriptId", String::number(scriptId));
     value->setString("scriptName", scriptName);
     value->setInteger("scriptLine", scriptLine);
@@ -695,27 +695,27 @@
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorPaintImageEvent::data(const LayoutImage& layoutImage)
+PassOwnPtr<TracedValue> InspectorPaintImageEvent::data(const LayoutImage& layoutImage)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     setGeneratingNodeInfo(value.get(), &layoutImage, "nodeId");
     if (const ImageResource* resource = layoutImage.cachedImage())
         value->setString("url", resource->url().string());
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorPaintImageEvent::data(const LayoutObject& owningLayoutObject, const StyleImage& styleImage)
+PassOwnPtr<TracedValue> InspectorPaintImageEvent::data(const LayoutObject& owningLayoutObject, const StyleImage& styleImage)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     setGeneratingNodeInfo(value.get(), &owningLayoutObject, "nodeId");
     if (const ImageResource* resource = styleImage.cachedImage())
         value->setString("url", resource->url().string());
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorPaintImageEvent::data(const LayoutObject* owningLayoutObject, const ImageResource& imageResource)
+PassOwnPtr<TracedValue> InspectorPaintImageEvent::data(const LayoutObject* owningLayoutObject, const ImageResource& imageResource)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     setGeneratingNodeInfo(value.get(), owningLayoutObject, "nodeId");
     value->setString("url", imageResource.url().string());
     return value.release();
@@ -728,9 +728,9 @@
     return heapStatistics.used_heap_size();
 }
 
-PassRefPtr<TracedValue> InspectorUpdateCountersEvent::data()
+PassOwnPtr<TracedValue> InspectorUpdateCountersEvent::data()
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     if (isMainThread()) {
         value->setInteger("documents", InstanceCounters::counterValue(InstanceCounters::DocumentCounter));
         value->setInteger("nodes", InstanceCounters::counterValue(InstanceCounters::NodeCounter));
@@ -740,67 +740,67 @@
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorInvalidateLayoutEvent::data(LocalFrame* frame)
+PassOwnPtr<TracedValue> InspectorInvalidateLayoutEvent::data(LocalFrame* frame)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("frame", toHexString(frame));
     setCallStack(value.get());
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorRecalculateStylesEvent::data(LocalFrame* frame)
+PassOwnPtr<TracedValue> InspectorRecalculateStylesEvent::data(LocalFrame* frame)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("frame", toHexString(frame));
     setCallStack(value.get());
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorEventDispatchEvent::data(const Event& event)
+PassOwnPtr<TracedValue> InspectorEventDispatchEvent::data(const Event& event)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("type", event.type());
     setCallStack(value.get());
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorTimeStampEvent::data(ExecutionContext* context, const String& message)
+PassOwnPtr<TracedValue> InspectorTimeStampEvent::data(ExecutionContext* context, const String& message)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("message", message);
     if (LocalFrame* frame = frameForExecutionContext(context))
         value->setString("frame", toHexString(frame));
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorTracingSessionIdForWorkerEvent::data(const String& sessionId, const String& workerId, WorkerThread* workerThread)
+PassOwnPtr<TracedValue> InspectorTracingSessionIdForWorkerEvent::data(const String& sessionId, const String& workerId, WorkerThread* workerThread)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("sessionId", sessionId);
     value->setString("workerId", workerId);
     value->setDouble("workerThreadId", workerThread->platformThreadId());
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorTracingStartedInFrame::data(const String& sessionId, LocalFrame* frame)
+PassOwnPtr<TracedValue> InspectorTracingStartedInFrame::data(const String& sessionId, LocalFrame* frame)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("sessionId", sessionId);
     value->setString("page", toHexString(frame));
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorSetLayerTreeId::data(const String& sessionId, int layerTreeId)
+PassOwnPtr<TracedValue> InspectorSetLayerTreeId::data(const String& sessionId, int layerTreeId)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("sessionId", sessionId);
     value->setInteger("layerTreeId", layerTreeId);
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorAnimationEvent::data(const Animation& animation)
+PassOwnPtr<TracedValue> InspectorAnimationEvent::data(const Animation& animation)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("id", String::number(animation.sequenceNumber()));
     value->setString("state", animation.playState());
     if (const AnimationEffect* effect = animation.effect()) {
@@ -813,16 +813,16 @@
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorAnimationStateEvent::data(const Animation& animation)
+PassOwnPtr<TracedValue> InspectorAnimationStateEvent::data(const Animation& animation)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("state", animation.playState());
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorHitTestEvent::endData(const HitTestRequest& request, const HitTestLocation& location, const HitTestResult& result)
+PassOwnPtr<TracedValue> InspectorHitTestEvent::endData(const HitTestRequest& request, const HitTestLocation& location, const HitTestResult& result)
 {
-    RefPtr<TracedValue> value(TracedValue::create());
+    OwnPtr<TracedValue> value(TracedValue::create());
     value->setInteger("x", location.roundedPoint().x());
     value->setInteger("y", location.roundedPoint().y());
     if (location.isRectBasedTest())
@@ -837,7 +837,7 @@
         value->setBoolean("listBased", true);
     else if (Node* node = result.innerNode())
         setNodeInfo(value.get(), node, "nodeId", "nodeName");
-    return value;
+    return value.release();
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.h b/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.h
index e90bcebe..5cf56dae 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.h
@@ -49,8 +49,8 @@
 class XMLHttpRequest;
 
 namespace InspectorLayoutEvent {
-PassRefPtr<TracedValue> beginData(FrameView*);
-PassRefPtr<TracedValue> endData(LayoutObject* rootForThisLayout);
+PassOwnPtr<TracedValue> beginData(FrameView*);
+PassOwnPtr<TracedValue> endData(LayoutObject* rootForThisLayout);
 }
 
 namespace InspectorScheduleStyleInvalidationTrackingEvent {
@@ -59,10 +59,10 @@
 extern const char Id[];
 extern const char Pseudo[];
 
-PassRefPtr<TracedValue> attributeChange(Element&, const InvalidationSet&, const QualifiedName&);
-PassRefPtr<TracedValue> classChange(Element&, const InvalidationSet&, const AtomicString&);
-PassRefPtr<TracedValue> idChange(Element&, const InvalidationSet&, const AtomicString&);
-PassRefPtr<TracedValue> pseudoChange(Element&, const InvalidationSet&, CSSSelector::PseudoType);
+PassOwnPtr<TracedValue> attributeChange(Element&, const InvalidationSet&, const QualifiedName&);
+PassOwnPtr<TracedValue> classChange(Element&, const InvalidationSet&, const AtomicString&);
+PassOwnPtr<TracedValue> idChange(Element&, const InvalidationSet&, const AtomicString&);
+PassOwnPtr<TracedValue> pseudoChange(Element&, const InvalidationSet&, CSSSelector::PseudoType);
 } // namespace InspectorScheduleStyleInvalidationTrackingEvent
 
 #define TRACE_SCHEDULE_STYLE_INVALIDATION(element, invalidationSet, changeType, ...) \
@@ -74,7 +74,7 @@
         InspectorScheduleStyleInvalidationTrackingEvent::changeType((element), (invalidationSet), __VA_ARGS__));
 
 namespace InspectorStyleRecalcInvalidationTrackingEvent {
-PassRefPtr<TracedValue> data(Node*, const StyleChangeReasonForTracing&);
+PassOwnPtr<TracedValue> data(Node*, const StyleChangeReasonForTracing&);
 }
 
 String descendantInvalidationSetToIdString(const InvalidationSet&);
@@ -88,9 +88,9 @@
 extern const char InvalidationSetMatchedTagName[];
 extern const char PreventStyleSharingForParent[];
 
-PassRefPtr<TracedValue> data(Element&, const char* reason);
-PassRefPtr<TracedValue> selectorPart(Element&, const char* reason, const InvalidationSet&, const String&);
-PassRefPtr<TracedValue> invalidationList(Element&, const Vector<RefPtr<InvalidationSet>>&);
+PassOwnPtr<TracedValue> data(Element&, const char* reason);
+PassOwnPtr<TracedValue> selectorPart(Element&, const char* reason, const InvalidationSet&, const String&);
+PassOwnPtr<TracedValue> invalidationList(Element&, const Vector<RefPtr<InvalidationSet>>&);
 } // namespace InspectorStyleInvalidatorInvalidateEvent
 
 #define TRACE_STYLE_INVALIDATOR_INVALIDATION(element, reason) \
@@ -153,76 +153,76 @@
 typedef const char LayoutInvalidationReasonForTracing[];
 
 namespace InspectorLayoutInvalidationTrackingEvent {
-PassRefPtr<TracedValue> CORE_EXPORT data(const LayoutObject*, LayoutInvalidationReasonForTracing);
+PassOwnPtr<TracedValue> CORE_EXPORT data(const LayoutObject*, LayoutInvalidationReasonForTracing);
 }
 
 namespace InspectorPaintInvalidationTrackingEvent {
-PassRefPtr<TracedValue> data(const LayoutObject*, const LayoutObject& paintContainer);
+PassOwnPtr<TracedValue> data(const LayoutObject*, const LayoutObject& paintContainer);
 }
 
 namespace InspectorScrollInvalidationTrackingEvent {
-PassRefPtr<TracedValue> data(const LayoutObject&);
+PassOwnPtr<TracedValue> data(const LayoutObject&);
 }
 
 namespace InspectorSendRequestEvent {
-PassRefPtr<TracedValue> data(unsigned long identifier, LocalFrame*, const ResourceRequest&);
+PassOwnPtr<TracedValue> data(unsigned long identifier, LocalFrame*, const ResourceRequest&);
 }
 
 namespace InspectorReceiveResponseEvent {
-PassRefPtr<TracedValue> data(unsigned long identifier, LocalFrame*, const ResourceResponse&);
+PassOwnPtr<TracedValue> data(unsigned long identifier, LocalFrame*, const ResourceResponse&);
 }
 
 namespace InspectorReceiveDataEvent {
-PassRefPtr<TracedValue> data(unsigned long identifier, LocalFrame*, int encodedDataLength);
+PassOwnPtr<TracedValue> data(unsigned long identifier, LocalFrame*, int encodedDataLength);
 }
 
 namespace InspectorResourceFinishEvent {
-PassRefPtr<TracedValue> data(unsigned long identifier, double finishTime, bool didFail);
+PassOwnPtr<TracedValue> data(unsigned long identifier, double finishTime, bool didFail);
 }
 
 namespace InspectorTimerInstallEvent {
-PassRefPtr<TracedValue> data(ExecutionContext*, int timerId, int timeout, bool singleShot);
+PassOwnPtr<TracedValue> data(ExecutionContext*, int timerId, int timeout, bool singleShot);
 }
 
 namespace InspectorTimerRemoveEvent {
-PassRefPtr<TracedValue> data(ExecutionContext*, int timerId);
+PassOwnPtr<TracedValue> data(ExecutionContext*, int timerId);
 }
 
 namespace InspectorTimerFireEvent {
-PassRefPtr<TracedValue> data(ExecutionContext*, int timerId);
+PassOwnPtr<TracedValue> data(ExecutionContext*, int timerId);
 }
 
 namespace InspectorIdleCallbackRequestEvent {
-PassRefPtr<TracedValue> data(ExecutionContext*, int id, double timeout);
+PassOwnPtr<TracedValue> data(ExecutionContext*, int id, double timeout);
 }
 
 namespace InspectorIdleCallbackCancelEvent {
-PassRefPtr<TracedValue> data(ExecutionContext*, int id);
+PassOwnPtr<TracedValue> data(ExecutionContext*, int id);
 }
 
 namespace InspectorIdleCallbackFireEvent {
-PassRefPtr<TracedValue> data(ExecutionContext*, int id, double allottedMilliseconds, bool timedOut);
+PassOwnPtr<TracedValue> data(ExecutionContext*, int id, double allottedMilliseconds, bool timedOut);
 }
 
 namespace InspectorAnimationFrameEvent {
-PassRefPtr<TracedValue> data(ExecutionContext*, int callbackId);
+PassOwnPtr<TracedValue> data(ExecutionContext*, int callbackId);
 }
 
 namespace InspectorParseHtmlEvent {
-PassRefPtr<TracedValue> beginData(Document*, unsigned startLine);
-PassRefPtr<TracedValue> endData(unsigned endLine);
+PassOwnPtr<TracedValue> beginData(Document*, unsigned startLine);
+PassOwnPtr<TracedValue> endData(unsigned endLine);
 }
 
 namespace InspectorParseAuthorStyleSheetEvent {
-PassRefPtr<TracedValue> data(const CSSStyleSheetResource*);
+PassOwnPtr<TracedValue> data(const CSSStyleSheetResource*);
 }
 
 namespace InspectorXhrReadyStateChangeEvent {
-PassRefPtr<TracedValue> data(ExecutionContext*, XMLHttpRequest*);
+PassOwnPtr<TracedValue> data(ExecutionContext*, XMLHttpRequest*);
 }
 
 namespace InspectorXhrLoadEvent {
-PassRefPtr<TracedValue> data(ExecutionContext*, XMLHttpRequest*);
+PassOwnPtr<TracedValue> data(ExecutionContext*, XMLHttpRequest*);
 }
 
 namespace InspectorLayerInvalidationTrackingEvent {
@@ -232,7 +232,7 @@
 extern const char ReflectionLayerChanged[];
 extern const char NewCompositedLayer[];
 
-PassRefPtr<TracedValue> data(const PaintLayer*, const char* reason);
+PassOwnPtr<TracedValue> data(const PaintLayer*, const char* reason);
 }
 
 #define TRACE_LAYER_INVALIDATION(LAYER, REASON) \
@@ -244,85 +244,85 @@
         InspectorLayerInvalidationTrackingEvent::data((LAYER), (REASON)));
 
 namespace InspectorPaintEvent {
-PassRefPtr<TracedValue> data(LayoutObject*, const LayoutRect& clipRect, const GraphicsLayer*);
+PassOwnPtr<TracedValue> data(LayoutObject*, const LayoutRect& clipRect, const GraphicsLayer*);
 }
 
 namespace InspectorPaintImageEvent {
-PassRefPtr<TracedValue> data(const LayoutImage&);
-PassRefPtr<TracedValue> data(const LayoutObject&, const StyleImage&);
-PassRefPtr<TracedValue> data(const LayoutObject*, const ImageResource&);
+PassOwnPtr<TracedValue> data(const LayoutImage&);
+PassOwnPtr<TracedValue> data(const LayoutObject&, const StyleImage&);
+PassOwnPtr<TracedValue> data(const LayoutObject*, const ImageResource&);
 }
 
 namespace InspectorCommitLoadEvent {
-PassRefPtr<TracedValue> data(LocalFrame*);
+PassOwnPtr<TracedValue> data(LocalFrame*);
 }
 
 namespace InspectorMarkLoadEvent {
-PassRefPtr<TracedValue> data(LocalFrame*);
+PassOwnPtr<TracedValue> data(LocalFrame*);
 }
 
 namespace InspectorScrollLayerEvent {
-PassRefPtr<TracedValue> data(LayoutObject*);
+PassOwnPtr<TracedValue> data(LayoutObject*);
 }
 
 namespace InspectorUpdateLayerTreeEvent {
-PassRefPtr<TracedValue> data(LocalFrame*);
+PassOwnPtr<TracedValue> data(LocalFrame*);
 }
 
 namespace InspectorEvaluateScriptEvent {
-PassRefPtr<TracedValue> data(LocalFrame*, const String& url, const WTF::TextPosition&);
+PassOwnPtr<TracedValue> data(LocalFrame*, const String& url, const WTF::TextPosition&);
 }
 
 namespace InspectorCompileScriptEvent {
-PassRefPtr<TracedValue> data(const String& url, const WTF::TextPosition&);
+PassOwnPtr<TracedValue> data(const String& url, const WTF::TextPosition&);
 }
 
 namespace InspectorFunctionCallEvent {
-PassRefPtr<TracedValue> data(ExecutionContext*, int scriptId, const String& scriptName, int scriptLine);
+PassOwnPtr<TracedValue> data(ExecutionContext*, int scriptId, const String& scriptName, int scriptLine);
 }
 
 namespace InspectorUpdateCountersEvent {
-PassRefPtr<TracedValue> data();
+PassOwnPtr<TracedValue> data();
 }
 
 namespace InspectorInvalidateLayoutEvent {
-PassRefPtr<TracedValue> data(LocalFrame*);
+PassOwnPtr<TracedValue> data(LocalFrame*);
 }
 
 namespace InspectorRecalculateStylesEvent {
-PassRefPtr<TracedValue> data(LocalFrame*);
+PassOwnPtr<TracedValue> data(LocalFrame*);
 }
 
 namespace InspectorEventDispatchEvent {
-PassRefPtr<TracedValue> data(const Event&);
+PassOwnPtr<TracedValue> data(const Event&);
 }
 
 namespace InspectorTimeStampEvent {
-PassRefPtr<TracedValue> data(ExecutionContext*, const String& message);
+PassOwnPtr<TracedValue> data(ExecutionContext*, const String& message);
 }
 
 namespace InspectorTracingSessionIdForWorkerEvent {
-PassRefPtr<TracedValue> data(const String& sessionId, const String& workerId, WorkerThread*);
+PassOwnPtr<TracedValue> data(const String& sessionId, const String& workerId, WorkerThread*);
 }
 
 namespace InspectorTracingStartedInFrame {
-PassRefPtr<TracedValue> data(const String& sessionId, LocalFrame*);
+PassOwnPtr<TracedValue> data(const String& sessionId, LocalFrame*);
 }
 
 namespace InspectorSetLayerTreeId {
-PassRefPtr<TracedValue> data(const String& sessionId, int layerTreeId);
+PassOwnPtr<TracedValue> data(const String& sessionId, int layerTreeId);
 }
 
 namespace InspectorAnimationEvent {
-PassRefPtr<TracedValue> data(const Animation&);
+PassOwnPtr<TracedValue> data(const Animation&);
 }
 
 namespace InspectorAnimationStateEvent {
-PassRefPtr<TracedValue> data(const Animation&);
+PassOwnPtr<TracedValue> data(const Animation&);
 }
 
 namespace InspectorHitTestEvent {
-PassRefPtr<TracedValue> endData(const HitTestRequest&, const HitTestLocation&, const HitTestResult&);
+PassOwnPtr<TracedValue> endData(const HitTestRequest&, const HitTestLocation&, const HitTestResult&);
 }
 
 CORE_EXPORT String toHexString(const void* p);
diff --git a/third_party/WebKit/Source/core/inspector/WorkerRuntimeAgent.cpp b/third_party/WebKit/Source/core/inspector/WorkerRuntimeAgent.cpp
index e5a36e2..edd0d76 100644
--- a/third_party/WebKit/Source/core/inspector/WorkerRuntimeAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/WorkerRuntimeAgent.cpp
@@ -57,13 +57,13 @@
         return;
 
     InspectorRuntimeAgent::enable(errorString);
-    ScriptState* scriptState = m_workerGlobalScope->script()->scriptState();
+    ScriptState* scriptState = m_workerGlobalScope->scriptController()->scriptState();
     reportExecutionContextCreated(scriptState, "", m_workerGlobalScope->url(), "", "");
 }
 
 ScriptState* WorkerRuntimeAgent::defaultScriptState()
 {
-    return m_workerGlobalScope->script()->scriptState();
+    return m_workerGlobalScope->scriptController()->scriptState();
 }
 
 void WorkerRuntimeAgent::muteConsole()
diff --git a/third_party/WebKit/Source/core/layout/BidiRun.h b/third_party/WebKit/Source/core/layout/BidiRun.h
index 96628b2..0b7c58e7 100644
--- a/third_party/WebKit/Source/core/layout/BidiRun.h
+++ b/third_party/WebKit/Source/core/layout/BidiRun.h
@@ -35,9 +35,9 @@
 class InlineBox;
 
 struct BidiRun : BidiCharacterRun {
-    BidiRun(int start, int stop, LayoutObject* object, BidiContext* context, WTF::Unicode::CharDirection dir)
+    BidiRun(int start, int stop, LineLayoutItem lineLayoutItem, BidiContext* context, WTF::Unicode::CharDirection dir)
         : BidiCharacterRun(start, stop, context, dir)
-        , m_object(object)
+        , m_lineLayoutItem(lineLayoutItem)
         , m_box(nullptr)
     {
         // Stored in base class to save space.
@@ -45,10 +45,9 @@
     }
 
     BidiRun* next() { return static_cast<BidiRun*>(m_next); }
-    LayoutObject* object() { return m_object; }
 
 public:
-    LayoutObject* m_object;
+    LineLayoutItem m_lineLayoutItem;
     InlineBox* m_box;
 };
 
diff --git a/third_party/WebKit/Source/core/layout/BidiRunForLine.cpp b/third_party/WebKit/Source/core/layout/BidiRunForLine.cpp
index e6c56ee..1e5ebbbc 100644
--- a/third_party/WebKit/Source/core/layout/BidiRunForLine.cpp
+++ b/third_party/WebKit/Source/core/layout/BidiRunForLine.cpp
@@ -29,41 +29,41 @@
 
 using namespace WTF::Unicode;
 
-static LayoutObject* firstLayoutObjectForDirectionalityDetermination(
-    LayoutObject* root, LayoutObject* current = nullptr)
+static LineLayoutItem firstLayoutObjectForDirectionalityDetermination(
+    LineLayoutItem root, LineLayoutItem current = nullptr)
 {
-    LayoutObject* next = current;
+    LineLayoutItem next = current;
     while (current) {
-        if (treatAsIsolated(current->styleRef())
-            && (current->isLayoutInline() || current->isLayoutBlock())) {
+        if (treatAsIsolated(current.styleRef())
+            && (current.isLayoutInline() || current.isLayoutBlock())) {
             if (current != root)
                 current = nullptr;
             else
                 current = next;
             break;
         }
-        current = current->parent();
+        current = current.parent();
     }
 
     if (!current)
-        current = root->slowFirstChild();
+        current = root.slowFirstChild();
 
     while (current) {
         next = nullptr;
-        if (isIteratorTarget(LineLayoutItem(current)) && !(current->isText()
-            && toLayoutText(current)->isAllCollapsibleWhitespace()))
+        if (isIteratorTarget(current) && !(current.isText()
+            && LineLayoutText(current).isAllCollapsibleWhitespace()))
             break;
 
         if (!isIteratorTarget(LineLayoutItem(current))
-            && !treatAsIsolated(current->styleRef()))
-            next = current->slowFirstChild();
+            && !treatAsIsolated(current.styleRef()))
+            next = current.slowFirstChild();
 
         if (!next) {
             while (current && current != root) {
-                next = current->nextSibling();
+                next = current.nextSibling();
                 if (next)
                     break;
-                current = current->parent();
+                current = current.parent();
             }
         }
 
@@ -76,23 +76,22 @@
     return current;
 }
 
-TextDirection determinePlaintextDirectionality(LayoutObject* root,
-    LayoutObject* current, unsigned pos)
+TextDirection determinePlaintextDirectionality(LineLayoutItem root, LineLayoutItem current, unsigned pos)
 {
-    LayoutObject* firstLayoutObject = firstLayoutObjectForDirectionalityDetermination(root, current);
-    InlineIterator iter(LineLayoutItem(root), LineLayoutItem(firstLayoutObject), firstLayoutObject == current ? pos : 0);
+    LineLayoutItem firstLayoutObject = firstLayoutObjectForDirectionalityDetermination(root, current);
+    InlineIterator iter(LineLayoutItem(root), firstLayoutObject, firstLayoutObject == current ? pos : 0);
     InlineBidiResolver observer;
-    observer.setStatus(BidiStatus(root->style()->direction(),
-        isOverride(root->style()->unicodeBidi())));
+    observer.setStatus(BidiStatus(root.style()->direction(),
+        isOverride(root.style()->unicodeBidi())));
     observer.setPositionIgnoringNestedIsolates(iter);
     return observer.determineParagraphDirectionality();
 }
 
 static inline void setupResolverToResumeInIsolate(InlineBidiResolver& resolver,
-    LayoutObject* root, LayoutObject* startObject)
+    LineLayoutItem root, LineLayoutItem startObject)
 {
     if (root != startObject) {
-        LayoutObject* parent = startObject->parent();
+        LineLayoutItem parent = startObject.parent();
         setupResolverToResumeInIsolate(resolver, root, parent);
         notifyObserverEnteredObject(&resolver, LineLayoutItem(startObject));
     }
@@ -107,7 +106,7 @@
     // of the resolver owning the runs.
     ASSERT(&topResolver.runs() == &bidiRuns);
     ASSERT(topResolver.position() != endOfLine);
-    const LayoutObject* currentRoot = topResolver.position().root();
+    LineLayoutItem currentRoot = topResolver.position().root();
     topResolver.createBidiRunsForLine(endOfLine, override,
         previousLineBrokeCleanly);
 
@@ -116,9 +115,9 @@
         // resolve them all.
         BidiIsolatedRun isolatedRun = topResolver.isolatedRuns().last();
         topResolver.isolatedRuns().removeLast();
-        currentRoot = &isolatedRun.root;
+        currentRoot = isolatedRun.root;
 
-        LayoutObject* startObj = &isolatedRun.object;
+        LineLayoutItem startObj = isolatedRun.object;
 
         // Only inlines make sense with unicode-bidi: isolate (blocks are
         // already isolated).
@@ -127,9 +126,7 @@
         // change enterIsolate to take a LayoutObject and do this logic there,
         // but that would be a layering violation for BidiResolver (which knows
         // nothing about LayoutObject).
-        LayoutInline* isolatedInline = toLayoutInline(
-            highestContainingIsolateWithinRoot(LineLayoutItem(startObj),
-                LineLayoutItem(const_cast<LayoutObject*>(currentRoot))));
+        LineLayoutItem isolatedInline = highestContainingIsolateWithinRoot(startObj, currentRoot);
         ASSERT(isolatedInline);
 
         InlineBidiResolver isolatedResolver;
@@ -137,14 +134,14 @@
             isolatedResolver.midpointState();
         isolatedLineMidpointState = topResolver.midpointStateForIsolatedRun(
             isolatedRun.runToReplace);
-        EUnicodeBidi unicodeBidi = isolatedInline->style()->unicodeBidi();
+        EUnicodeBidi unicodeBidi = isolatedInline.style()->unicodeBidi();
         TextDirection direction;
         if (unicodeBidi == Plaintext) {
             direction = determinePlaintextDirectionality(isolatedInline,
                 isNewUBAParagraph ? startObj : 0);
         } else {
             ASSERT(unicodeBidi == Isolate || unicodeBidi == IsolateOverride);
-            direction = isolatedInline->style()->direction();
+            direction = isolatedInline.style()->direction();
         }
         isolatedResolver.setStatus(BidiStatus::createForIsolate(direction,
             isOverride(unicodeBidi), isolatedRun.level));
diff --git a/third_party/WebKit/Source/core/layout/BidiRunForLine.h b/third_party/WebKit/Source/core/layout/BidiRunForLine.h
index 99330294..d9504c2 100644
--- a/third_party/WebKit/Source/core/layout/BidiRunForLine.h
+++ b/third_party/WebKit/Source/core/layout/BidiRunForLine.h
@@ -24,13 +24,14 @@
 #ifndef BidiRunForLine_h
 #define BidiRunForLine_h
 
+#include "core/layout/api/LineLayoutInline.h"
 #include "core/layout/line/TrailingObjects.h"
 #include "platform/text/BidiResolver.h"
 
 namespace blink {
 
-TextDirection determinePlaintextDirectionality(LayoutObject* root,
-    LayoutObject* current = nullptr, unsigned pos = 0);
+TextDirection determinePlaintextDirectionality(LineLayoutItem root,
+    LineLayoutItem current = nullptr, unsigned pos = 0);
 
 void constructBidiRunsForLine(InlineBidiResolver&, BidiRunList<BidiRun>&,
     const InlineIterator& endOfLine, VisualDirectionOverride,
diff --git a/third_party/WebKit/Source/core/layout/HitTestResult.cpp b/third_party/WebKit/Source/core/layout/HitTestResult.cpp
index f568e2ba..dc6972d 100644
--- a/third_party/WebKit/Source/core/layout/HitTestResult.cpp
+++ b/third_party/WebKit/Source/core/layout/HitTestResult.cpp
@@ -163,7 +163,7 @@
     LayoutObject* layoutObject = this->layoutObject();
     if (!layoutObject)
         return PositionWithAffinity();
-    if (m_innerPossiblyPseudoNode->isPseudoElement() && m_innerPossiblyPseudoNode->pseudoId() == BEFORE)
+    if (m_innerPossiblyPseudoNode->isPseudoElement() && m_innerPossiblyPseudoNode->getPseudoId() == BEFORE)
         return mostForwardCaretPosition(Position(m_innerNode, PositionAnchorType::BeforeChildren));
     return layoutObject->positionForPoint(localPoint());
 }
diff --git a/third_party/WebKit/Source/core/layout/LayoutAnalyzer.cpp b/third_party/WebKit/Source/core/layout/LayoutAnalyzer.cpp
index f913922e..93eea65 100644
--- a/third_party/WebKit/Source/core/layout/LayoutAnalyzer.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutAnalyzer.cpp
@@ -104,9 +104,9 @@
     --m_depth;
 }
 
-PassRefPtr<TracedValue> LayoutAnalyzer::toTracedValue()
+PassOwnPtr<TracedValue> LayoutAnalyzer::toTracedValue()
 {
-    RefPtr<TracedValue> tracedValue(TracedValue::create());
+    OwnPtr<TracedValue> tracedValue(TracedValue::create());
     for (size_t i = 0; i < NumCounters; ++i) {
         if (m_counters[i] > 0)
             tracedValue->setInteger(nameForCounter(static_cast<Counter>(i)), m_counters[i]);
diff --git a/third_party/WebKit/Source/core/layout/LayoutAnalyzer.h b/third_party/WebKit/Source/core/layout/LayoutAnalyzer.h
index 1b9a1c1..00c7a0dd 100644
--- a/third_party/WebKit/Source/core/layout/LayoutAnalyzer.h
+++ b/third_party/WebKit/Source/core/layout/LayoutAnalyzer.h
@@ -8,7 +8,7 @@
 #include "platform/LayoutUnit.h"
 #include "wtf/Allocator.h"
 #include "wtf/Noncopyable.h"
-#include "wtf/PassRefPtr.h"
+#include "wtf/PassOwnPtr.h"
 
 namespace blink {
 
@@ -82,7 +82,7 @@
         m_counters[counter] += delta;
     }
 
-    PassRefPtr<TracedValue> toTracedValue();
+    PassOwnPtr<TracedValue> toTracedValue();
 
 private:
     const char* nameForCounter(Counter) const;
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
index e9d0074..468ccc3 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
@@ -768,10 +768,6 @@
     if (remainingLogicalHeight < lineHeight || (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex)) {
         LayoutUnit paginationStrut = calculatePaginationStrutToFitContent(logicalOffset, remainingLogicalHeight, lineHeight);
         LayoutUnit newLogicalOffset = logicalOffset + paginationStrut;
-        // The new offset may require us to insert a new row for columns (fragmentainer group).
-        // Give the multicol machinery an opportunity to do so (before checking the height of a
-        // column that wouldn't have existed yet otherwise).
-        paginatedContentWasLaidOut(newLogicalOffset + lineHeight);
         // Moving to a different page or column may mean that its height is different.
         pageLogicalHeight = pageLogicalHeightForOffset(newLogicalOffset);
         if (lineHeight > pageLogicalHeight) {
@@ -779,6 +775,7 @@
             // TODO(mstensho): Get rid of this. This is just utter weirdness, but the other browsers
             // also do something slightly similar, although in much more specific cases than we do here,
             // and printing Google Docs depends on it.
+            paginatedContentWasLaidOut(logicalOffset + lineHeight);
             return;
         }
 
@@ -802,6 +799,7 @@
             lineBox.setPaginationStrut(paginationStrut);
             lineBox.setIsFirstAfterPageBreak(true);
         }
+        paginatedContentWasLaidOut(newLogicalOffset + lineHeight);
         return;
     }
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
index 2432701a..e7e6d84 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
@@ -190,9 +190,9 @@
     void setStaticInlinePositionForChild(LayoutBox&, LayoutUnit inlinePosition);
     void updateStaticInlinePositionForChild(LayoutBox&, LayoutUnit logicalTop, IndentTextOrNot = DoNotIndentText);
 
-    static bool shouldSkipCreatingRunsForObject(LayoutObject* obj)
+    static bool shouldSkipCreatingRunsForObject(LineLayoutItem obj)
     {
-        return obj->isFloating() || (obj->isOutOfFlowPositioned() && !obj->style()->isOriginalDisplayInlineType() && !obj->container()->isLayoutInline());
+        return obj.isFloating() || (obj.isOutOfFlowPositioned() && !obj.style()->isOriginalDisplayInlineType() && !obj.container().isLayoutInline());
     }
 
     LayoutMultiColumnFlowThread* multiColumnFlowThread() const { return m_rareData ? m_rareData->m_multiColumnFlowThread : 0; }
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp
index 8db266c..14de6946 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp
@@ -58,7 +58,7 @@
 
     void addRunWithExpansions(BidiRun& run, bool& isAfterExpansion, TextJustify textJustify)
     {
-        LayoutText* text = toLayoutText(run.m_object);
+        LayoutText* text = toLayoutText(run.m_lineLayoutItem);
         unsigned opportunitiesInRun;
         if (text->is8Bit()) {
             opportunitiesInRun = Character::expansionOpportunityCount(text->characters8() + run.m_start,
@@ -92,13 +92,13 @@
             if (!r->m_box || r == trailingSpaceRun)
                 continue;
 
-            if (r->m_object->isText()) {
+            if (r->m_lineLayoutItem.isText()) {
                 unsigned opportunitiesInRun = m_runsWithExpansions[i++];
 
                 RELEASE_ASSERT(opportunitiesInRun <= m_totalOpportunities);
 
                 // Don't justify for white-space: pre.
-                if (r->m_object->style()->whiteSpace() != PRE) {
+                if (r->m_lineLayoutItem.style()->whiteSpace() != PRE) {
                     InlineTextBox* textBox = toInlineTextBox(r->m_box);
                     RELEASE_ASSERT(m_totalOpportunities);
                     int expansion = (availableLogicalWidth - totalLogicalWidth) * opportunitiesInRun / m_totalOpportunities;
@@ -132,14 +132,14 @@
 
 static inline InlineTextBox* createInlineBoxForText(BidiRun& run, bool isOnlyRun)
 {
-    ASSERT(run.m_object->isText());
-    LayoutText* text = toLayoutText(run.m_object);
-    InlineTextBox* textBox = text->createInlineTextBox(run.m_start, run.m_stop - run.m_start);
+    ASSERT(run.m_lineLayoutItem.isText());
+    LineLayoutText text = LineLayoutText(run.m_lineLayoutItem);
+    InlineTextBox* textBox = text.createInlineTextBox(run.m_start, run.m_stop - run.m_start);
     // We only treat a box as text for a <br> if we are on a line by ourself or in strict mode
     // (Note the use of strict mode.  In "almost strict" mode, we don't treat the box for <br> as text.)
-    if (text->isBR())
-        textBox->setIsText(isOnlyRun || text->document().inNoQuirksMode());
-    textBox->setDirOverride(run.dirOverride(text->style()->rtlOrdering() == VisualOrder));
+    if (text.isBR())
+        textBox->setIsText(isOnlyRun || text.document().inNoQuirksMode());
+    textBox->setDirOverride(run.dirOverride(text.style()->rtlOrdering() == VisualOrder));
     if (run.m_hasHyphen)
         textBox->setHasHyphen(true);
     return textBox;
@@ -241,17 +241,17 @@
     if (!run)
         return true;
     unsigned pos = run->stop();
-    LayoutObject* r = run->m_object;
-    if (!r->isText() || r->isBR())
+    LineLayoutItem r = run->m_lineLayoutItem;
+    if (!r.isText() || r.isBR())
         return false;
-    LayoutText* layoutText = toLayoutText(r);
-    unsigned length = layoutText->textLength();
+    LineLayoutText layoutText(r);
+    unsigned length = layoutText.textLength();
     if (pos >= length)
         return true;
 
-    if (layoutText->is8Bit())
-        return endsWithASCIISpaces(layoutText->characters8(), pos, length);
-    return endsWithASCIISpaces(layoutText->characters16(), pos, length);
+    if (layoutText.is8Bit())
+        return endsWithASCIISpaces(layoutText.characters8(), pos, length);
+    return endsWithASCIISpaces(layoutText.characters16(), pos, length);
 }
 
 RootInlineBox* LayoutBlockFlow::constructLine(BidiRunList<BidiRun>& bidiRuns, const LineInfo& lineInfo)
@@ -264,17 +264,17 @@
     for (BidiRun* r = bidiRuns.firstRun(); r; r = r->next()) {
         // Create a box for our object.
         bool isOnlyRun = (runCount == 1);
-        if (runCount == 2 && !r->m_object->isListMarker())
-            isOnlyRun = (!style()->isLeftToRightDirection() ? bidiRuns.lastRun() : bidiRuns.firstRun())->m_object->isListMarker();
+        if (runCount == 2 && !r->m_lineLayoutItem.isListMarker())
+            isOnlyRun = (!style()->isLeftToRightDirection() ? bidiRuns.lastRun() : bidiRuns.firstRun())->m_lineLayoutItem.isListMarker();
 
         if (lineInfo.isEmpty())
             continue;
 
         InlineBox* box;
-        if (r->m_object->isText())
+        if (r->m_lineLayoutItem.isText())
             box = createInlineBoxForText(*r, isOnlyRun);
         else
-            box = createInlineBoxForLayoutObject(r->m_object, false, isOnlyRun);
+            box = createInlineBoxForLayoutObject(r->m_lineLayoutItem, false, isOnlyRun);
         r->m_box = box;
 
         ASSERT(box);
@@ -288,9 +288,9 @@
         // then we need to construct inline boxes as necessary to properly enclose the
         // run's inline box. Segments can only be siblings at the root level, as
         // they are positioned separately.
-        if (!parentBox || (!parentBox->lineLayoutItem().isEqual(r->m_object->parent()))) {
+        if (!parentBox || (!parentBox->lineLayoutItem().isEqual(r->m_lineLayoutItem.parent()))) {
             // Create new inline boxes all the way back to the appropriate insertion point.
-            parentBox = createLineBoxes(r->m_object->parent(), lineInfo, box);
+            parentBox = createLineBoxes(r->m_lineLayoutItem.parent(), lineInfo, box);
         } else {
             // Append the inline box to this line.
             parentBox->addToLine(box);
@@ -300,7 +300,7 @@
 
         if (box->isInlineTextBox()) {
             if (AXObjectCache* cache = document().existingAXObjectCache())
-                cache->inlineTextBoxesUpdated(r->m_object);
+                cache->inlineTextBoxesUpdated(r->m_lineLayoutItem);
         }
     }
 
@@ -317,8 +317,8 @@
     // paint borders/margins/padding.  This knowledge will ultimately be used when
     // we determine the horizontal positions and widths of all the inline boxes on
     // the line.
-    bool isLogicallyLastRunWrapped = bidiRuns.logicallyLastRun()->m_object && bidiRuns.logicallyLastRun()->m_object->isText() ? !reachedEndOfTextRun(bidiRuns) : true;
-    lastLineBox()->determineSpacingForFlowBoxes(lineInfo.isLastLine(), isLogicallyLastRunWrapped, bidiRuns.logicallyLastRun()->m_object);
+    bool isLogicallyLastRunWrapped = bidiRuns.logicallyLastRun()->m_lineLayoutItem && bidiRuns.logicallyLastRun()->m_lineLayoutItem.isText() ? !reachedEndOfTextRun(bidiRuns) : true;
+    lastLineBox()->determineSpacingForFlowBoxes(lineInfo.isLastLine(), isLogicallyLastRunWrapped, bidiRuns.logicallyLastRun()->m_lineLayoutItem);
 
     // Now mark the line boxes as being constructed.
     lastLineBox()->setConstructed();
@@ -415,8 +415,8 @@
     int endOverhang;
     LayoutObject* nextObject = nullptr;
     for (BidiRun* runWithNextObject = run->next(); runWithNextObject; runWithNextObject = runWithNextObject->next()) {
-        if (!runWithNextObject->m_object->isOutOfFlowPositioned() && !runWithNextObject->m_box->isLineBreak()) {
-            nextObject = runWithNextObject->m_object;
+        if (!runWithNextObject->m_lineLayoutItem.isOutOfFlowPositioned() && !runWithNextObject->m_box->isLineBreak()) {
+            nextObject = runWithNextObject->m_lineLayoutItem;
             break;
         }
     }
@@ -594,8 +594,8 @@
     updateLogicalInlinePositions(this, lineLogicalLeft, lineLogicalRight, availableLogicalWidth, isFirstLine, indentText, LayoutUnit());
     bool needsWordSpacing;
 
-    if (firstRun && firstRun->m_object->isAtomicInlineLevel()) {
-        LayoutBox* layoutBox = toLayoutBox(firstRun->m_object);
+    if (firstRun && firstRun->m_lineLayoutItem.isAtomicInlineLevel()) {
+        LayoutBox* layoutBox = toLayoutBox(firstRun->m_lineLayoutItem);
         updateLogicalInlinePositions(this, lineLogicalLeft, lineLogicalRight, availableLogicalWidth, isFirstLine, indentText, layoutBox->logicalHeight());
     }
 
@@ -619,13 +619,13 @@
 
     BidiRun* r = firstRun;
     for (; r; r = r->next()) {
-        if (!r->m_box || r->m_object->isOutOfFlowPositioned() || r->m_box->isLineBreak()) {
+        if (!r->m_box || r->m_lineLayoutItem.isOutOfFlowPositioned() || r->m_box->isLineBreak()) {
             continue; // Positioned objects are only participating to figure out their
                 // correct static x position.  They have no effect on the width.
                 // Similarly, line break boxes have no effect on the width.
         }
-        if (r->m_object->isText()) {
-            LayoutText* rt = toLayoutText(r->m_object);
+        if (r->m_lineLayoutItem.isText()) {
+            LayoutText* rt = toLayoutText(r->m_lineLayoutItem);
             if (textAlign == JUSTIFY && r != trailingSpaceRun && textJustify != TextJustifyNone) {
                 if (!isAfterExpansion)
                     toInlineTextBox(r->m_box)->setCanHaveLeadingExpansion(true);
@@ -641,8 +641,8 @@
             setLogicalWidthForTextRun(lineBox, r, rt, totalLogicalWidth, lineInfo, textBoxDataMap, verticalPositionCache, wordMeasurements);
         } else {
             isAfterExpansion = false;
-            if (!r->m_object->isLayoutInline()) {
-                LayoutBox* layoutBox = toLayoutBox(r->m_object);
+            if (!r->m_lineLayoutItem.isLayoutInline()) {
+                LayoutBox* layoutBox = toLayoutBox(r->m_lineLayoutItem);
                 if (layoutBox->isRubyRun())
                     setMarginsForRubyRun(r, toLayoutRubyRun(layoutBox), previousObject, lineInfo);
                 r->m_box->setLogicalWidth(logicalWidthForChild(*layoutBox));
@@ -652,7 +652,7 @@
         }
 
         totalLogicalWidth += r->m_box->logicalWidth();
-        previousObject = r->m_object;
+        previousObject = r->m_lineLayoutItem;
     }
 
     if (isAfterExpansion)
@@ -678,15 +678,15 @@
 
         // Align positioned boxes with the top of the line box.  This is
         // a reasonable approximation of an appropriate y position.
-        if (r->m_object->isOutOfFlowPositioned())
+        if (r->m_lineLayoutItem.isOutOfFlowPositioned())
             r->m_box->setLogicalTop(logicalHeight());
 
         // Position is used to properly position both replaced elements and
         // to update the static normal flow x/y of positioned elements.
-        if (r->m_object->isText())
-            toLayoutText(r->m_object)->positionLineBox(r->m_box);
-        else if (r->m_object->isBox())
-            toLayoutBox(r->m_object)->positionLineBox(r->m_box);
+        if (r->m_lineLayoutItem.isText())
+            toLayoutText(r->m_lineLayoutItem)->positionLineBox(r->m_box);
+        else if (r->m_lineLayoutItem.isBox())
+            toLayoutBox(r->m_lineLayoutItem)->positionLineBox(r->m_box);
     }
 }
 
@@ -704,7 +704,7 @@
         return nullptr;
 
     // FIXME: Why is this only done when we had runs?
-    lineInfo.setLastLine(!end.object());
+    lineInfo.setLastLine(!end.lineLayoutItem());
 
     RootInlineBox* lineBox = constructLine(bidiRuns, lineInfo);
     if (!lineBox)
@@ -803,7 +803,7 @@
     for (; it != end; ++it) {
         FloatingObject& floatingObject = *it->get();
         // If we've reached the start of clean lines any remaining floating children belong to them.
-        if (floatingObject.layoutObject() == cleanLineStart.object() && layoutState.endLine()) {
+        if (floatingObject.layoutObject() == cleanLineStart.lineLayoutItem() && layoutState.endLine()) {
             layoutState.setEndLineMatched(layoutState.endLineMatched() || matchedEndLine(layoutState, resolver, cleanLineStart, cleanLineBidiStatus));
             if (layoutState.endLineMatched()) {
                 layoutState.setLastFloat(&floatingObject);
@@ -878,12 +878,12 @@
         // This is a short-cut for empty lines.
         if (layoutState.lineInfo().isEmpty()) {
             if (lastRootBox())
-                lastRootBox()->setLineBreakInfo(endOfLine.object(), endOfLine.offset(), resolver.status());
+                lastRootBox()->setLineBreakInfo(endOfLine.lineLayoutItem(), endOfLine.offset(), resolver.status());
             resolver.runs().deleteRuns();
         } else {
             VisualDirectionOverride override = (styleToUse.rtlOrdering() == VisualOrder ? (styleToUse.direction() == LTR ? VisualLeftToRightOverride : VisualRightToLeftOverride) : NoVisualOverride);
             if (isNewUBAParagraph && styleToUse.unicodeBidi() == Plaintext && !resolver.context()->parent()) {
-                TextDirection direction = determinePlaintextDirectionality(resolver.position().root(), resolver.position().object(), resolver.position().offset());
+                TextDirection direction = determinePlaintextDirectionality(resolver.position().root(), resolver.position().lineLayoutItem(), resolver.position().offset());
                 resolver.setStatus(BidiStatus(direction, isOverride(styleToUse.unicodeBidi())));
             }
             // FIXME: This ownership is reversed. We should own the BidiRunList and pass it to createBidiRunsForLine.
@@ -907,7 +907,7 @@
             resolver.markCurrentRunEmpty(); // FIXME: This can probably be replaced by an ASSERT (or just removed).
 
             if (lineBox) {
-                lineBox->setLineBreakInfo(endOfLine.object(), endOfLine.offset(), resolver.status());
+                lineBox->setLineBreakInfo(endOfLine.lineLayoutItem(), endOfLine.offset(), resolver.status());
                 if (layoutState.usesPaintInvalidationBounds())
                     layoutState.updatePaintInvalidationRangeFromBox(lineBox);
 
@@ -1734,7 +1734,7 @@
     } else {
         TextDirection direction = style()->direction();
         if (style()->unicodeBidi() == Plaintext)
-            direction = determinePlaintextDirectionality(this);
+            direction = determinePlaintextDirectionality(LineLayoutItem(this));
         resolver.setStatus(BidiStatus(direction, isOverride(style()->unicodeBidi())));
         InlineIterator iter = InlineIterator(LineLayoutBlockFlow(this), bidiFirstSkippingEmptyInlines(LineLayoutBlockFlow(this), resolver.runs(), &resolver), 0);
         resolver.setPosition(iter, numberOfIsolateAncestors(iter));
@@ -1842,7 +1842,7 @@
     RootInlineBox* originalEndLine = layoutState.endLine();
     RootInlineBox* line = originalEndLine;
     for (int i = 0; i < numLines && line; i++, line = line->nextRootBox()) {
-        if (line->lineBreakObj() == resolver.position().object() && line->lineBreakPos() == resolver.position().offset()) {
+        if (line->lineBreakObj() == resolver.position().lineLayoutItem() && line->lineBreakPos() == resolver.position().offset()) {
             // We have a match.
             if (line->lineBreakBidiStatus() != resolver.status())
                 return false; // ...but the bidi state doesn't match.
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
index 5eb6a702..3bc1709 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -1405,8 +1405,8 @@
     // FIXME: This test can be much more comprehensive.
     if (!hasBackground())
         return false;
-    // Table and root background painting is special.
-    if (isTable() || isLayoutView())
+    // Root background painting is special.
+    if (isLayoutView())
         return false;
     // FIXME: box-shadow is painted while background painting.
     if (style()->boxShadow())
diff --git a/third_party/WebKit/Source/core/layout/LayoutFullScreen.cpp b/third_party/WebKit/Source/core/layout/LayoutFullScreen.cpp
index 1dc384b..8be0566 100644
--- a/third_party/WebKit/Source/core/layout/LayoutFullScreen.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutFullScreen.cpp
@@ -42,6 +42,10 @@
     {
         setDocumentForAnonymous(&owner->document());
     }
+
+    // Must call setStyleWithWritingModeOfParent() instead.
+    void setStyle(PassRefPtr<ComputedStyle>) = delete;
+
 private:
     bool isOfType(LayoutObjectType type) const override { return type == LayoutObjectLayoutFullScreenPlaceholder || LayoutBlockFlow::isOfType(type); }
     void willBeDestroyed() override;
@@ -110,7 +114,7 @@
 
     fullscreenStyle->setBackgroundColor(StyleColor(Color::black));
 
-    setStyle(fullscreenStyle);
+    setStyleWithWritingModeOfParent(fullscreenStyle);
 }
 
 LayoutObject* LayoutFullScreen::wrapLayoutObject(LayoutObject* object, LayoutObject* parent, Document* document)
@@ -135,7 +139,7 @@
             // the line box tree underneath our |containingBlock| is not longer valid.
             containingBlock->deleteLineBoxTree();
 
-            parent->addChild(fullscreenLayoutObject, object);
+            parent->addChildWithWritingModeOfParent(fullscreenLayoutObject, object);
             object->remove();
 
             // Always just do a full layout to ensure that line boxes get deleted properly.
@@ -191,12 +195,13 @@
 
     if (!m_placeholder) {
         m_placeholder = new LayoutFullScreenPlaceholder(this);
-        m_placeholder->setStyle(style);
+        m_placeholder->setStyleWithWritingModeOfParent(style);
         if (parent()) {
-            parent()->addChild(m_placeholder, this);
+            parent()->addChildWithWritingModeOfParent(m_placeholder, this);
             parent()->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(LayoutInvalidationReason::Fullscreen);
         }
     } else {
         m_placeholder->setStyle(style);
+        m_placeholder->setStyleWithWritingModeOfParent(style);
     }
 }
diff --git a/third_party/WebKit/Source/core/layout/LayoutFullScreen.h b/third_party/WebKit/Source/core/layout/LayoutFullScreen.h
index 5cf4369..9e4b42c 100644
--- a/third_party/WebKit/Source/core/layout/LayoutFullScreen.h
+++ b/third_party/WebKit/Source/core/layout/LayoutFullScreen.h
@@ -48,6 +48,9 @@
 
     void updateStyle();
 
+    // Must call setStyleWithWritingModeOfParent() instead.
+    void setStyle(PassRefPtr<ComputedStyle>) = delete;
+
 private:
     LayoutFullScreen();
     void willBeDestroyed() override;
diff --git a/third_party/WebKit/Source/core/layout/LayoutMenuList.cpp b/third_party/WebKit/Source/core/layout/LayoutMenuList.cpp
index 5767913e..10c0c24 100644
--- a/third_party/WebKit/Source/core/layout/LayoutMenuList.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutMenuList.cpp
@@ -313,9 +313,9 @@
         minLogicalWidth = maxLogicalWidth;
 }
 
-void LayoutMenuList::didSetSelectedIndex(int listIndex)
+void LayoutMenuList::didSetSelectedIndex(int optionIndex)
 {
-    didUpdateActiveOption(selectElement()->listToOptionIndex(listIndex));
+    didUpdateActiveOption(optionIndex);
 }
 
 void LayoutMenuList::didUpdateActiveOption(int optionIndex)
diff --git a/third_party/WebKit/Source/core/layout/LayoutMenuList.h b/third_party/WebKit/Source/core/layout/LayoutMenuList.h
index efd19a9..808f678 100644
--- a/third_party/WebKit/Source/core/layout/LayoutMenuList.h
+++ b/third_party/WebKit/Source/core/layout/LayoutMenuList.h
@@ -40,7 +40,7 @@
 
     HTMLSelectElement* selectElement() const;
     void setOptionsChanged(bool changed) { m_optionsChanged = changed; }
-    void didSetSelectedIndex(int listIndex);
+    void didSetSelectedIndex(int optionIndex);
     String text() const;
 
     const char* name() const override { return "LayoutMenuList"; }
diff --git a/third_party/WebKit/Source/core/layout/LayoutMultiColumnSet.cpp b/third_party/WebKit/Source/core/layout/LayoutMultiColumnSet.cpp
index 14746b8..1850092 100644
--- a/third_party/WebKit/Source/core/layout/LayoutMultiColumnSet.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutMultiColumnSet.cpp
@@ -72,6 +72,32 @@
 
 LayoutUnit LayoutMultiColumnSet::pageLogicalHeightForOffset(LayoutUnit offsetInFlowThread) const
 {
+    const MultiColumnFragmentainerGroup &lastRow = lastFragmentainerGroup();
+    if (!lastRow.logicalHeight()) {
+        // In the first layout pass of an auto-height multicol container, height isn't set. No need
+        // to perform the series of complicated dance steps below to figure out that we should
+        // simply return 0. Bail now.
+        ASSERT(m_fragmentainerGroups.size() == 1);
+        return LayoutUnit();
+    }
+    if (offsetInFlowThread >= lastRow.logicalTopInFlowThread() + lastRow.logicalHeight() * usedColumnCount()) {
+        // The offset is outside the bounds of the fragmentainer groups that we have established at
+        // this point. If we're nested inside another fragmentation context, we need to calculate
+        // the height on our own.
+        const LayoutMultiColumnFlowThread* flowThread = multiColumnFlowThread();
+        if (FragmentationContext* enclosingFragmentationContext = flowThread->enclosingFragmentationContext()) {
+            // We'd ideally like to translate |offsetInFlowThread| to an offset in the coordinate
+            // space of the enclosing fragmentation context here, but that's hard, since the offset
+            // is out of bounds. So just use the bottom we have found so far.
+            LayoutUnit enclosingContextBottom = lastRow.blockOffsetInEnclosingFragmentationContext() + lastRow.logicalHeight();
+            LayoutUnit enclosingFragmentainerHeight = enclosingFragmentationContext->fragmentainerLogicalHeightAt(enclosingContextBottom);
+            // Constrain against specified height / max-height.
+            LayoutUnit currentMulticolHeight = logicalTopFromMulticolContentEdge() + lastRow.logicalTop() + lastRow.logicalHeight();
+            LayoutUnit multicolHeightWithExtraRow = currentMulticolHeight + enclosingFragmentainerHeight;
+            multicolHeightWithExtraRow = std::min(multicolHeightWithExtraRow, flowThread->maxColumnLogicalHeight());
+            return std::max(LayoutUnit(1), multicolHeightWithExtraRow - currentMulticolHeight);
+        }
+    }
     return fragmentainerGroupAtFlowThreadOffset(offsetInFlowThread).logicalHeight();
 }
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.cpp b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
index 5365263..8e93284 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
@@ -1167,12 +1167,12 @@
     value->endDictionary();
 }
 
-static PassRefPtr<TracedValue> jsonObjectForPaintInvalidationInfo(const LayoutRect& rect, const String& invalidationReason)
+static PassOwnPtr<TracedValue> jsonObjectForPaintInvalidationInfo(const LayoutRect& rect, const String& invalidationReason)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     addJsonObjectForRect(value.get(), "rect", rect);
     value->setString("invalidation_reason", invalidationReason);
-    return value;
+    return value.release();
 }
 
 LayoutRect LayoutObject::computePaintInvalidationRect(const LayoutBoxModelObject& paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState) const
@@ -1340,14 +1340,14 @@
     }
 }
 
-static PassRefPtr<TracedValue> jsonObjectForOldAndNewRects(const LayoutRect& oldRect, const LayoutPoint& oldLocation, const LayoutRect& newRect, const LayoutPoint& newLocation)
+static PassOwnPtr<TracedValue> jsonObjectForOldAndNewRects(const LayoutRect& oldRect, const LayoutPoint& oldLocation, const LayoutRect& newRect, const LayoutPoint& newLocation)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     addJsonObjectForRect(value.get(), "oldRect", oldRect);
     addJsonObjectForPoint(value.get(), "oldLocation", oldLocation);
     addJsonObjectForRect(value.get(), "newRect", newRect);
     addJsonObjectForPoint(value.get(), "newLocation", newLocation);
-    return value;
+    return value.release();
 }
 
 LayoutRect LayoutObject::selectionRectInViewCoordinates() const
@@ -1986,7 +1986,7 @@
             container->setNeedsOverflowRecalcAfterStyleChange();
     }
 
-    if (updatedDiff.needsPaintInvalidationLayer())
+    if (diff.needsPaintInvalidationLayer() || updatedDiff.needsPaintInvalidationLayer())
         setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants();
     else if (diff.needsPaintInvalidationObject() || updatedDiff.needsPaintInvalidationObject())
         setShouldDoFullPaintInvalidation();
@@ -2133,6 +2133,22 @@
     }
 }
 
+void LayoutObject::setStyleWithWritingModeOfParent(PassRefPtr<ComputedStyle> style)
+{
+    if (parent())
+        style->setWritingMode(parent()->styleRef().writingMode());
+    setStyle(style);
+}
+
+void LayoutObject::addChildWithWritingModeOfParent(LayoutObject* newChild, LayoutObject* beforeChild)
+{
+    if (newChild->mutableStyleRef().setWritingMode(styleRef().writingMode())
+        && newChild->isBoxModelObject()) {
+        newChild->setHorizontalWritingMode(isHorizontalWritingMode());
+    }
+    addChild(newChild, beforeChild);
+}
+
 void LayoutObject::updateFillImages(const FillLayer* oldLayers, const FillLayer& newLayers)
 {
     // Optimize the common case
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.h b/third_party/WebKit/Source/core/layout/LayoutObject.h
index 83a2cc3..8d06f7d 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.h
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.h
@@ -913,6 +913,9 @@
     // and so only should be called when the style is known not to have changed (or from setStyle).
     void setStyleInternal(PassRefPtr<ComputedStyle> style) { m_style = style; }
 
+    void setStyleWithWritingModeOfParent(PassRefPtr<ComputedStyle>);
+    void addChildWithWritingModeOfParent(LayoutObject* newChild, LayoutObject* beforeChild);
+
     void firstLineStyleDidChange(const ComputedStyle& oldStyle, const ComputedStyle& newStyle);
 
     // This function returns an enclosing non-anonymous LayoutBlock for this
diff --git a/third_party/WebKit/Source/core/layout/LayoutProgress.cpp b/third_party/WebKit/Source/core/layout/LayoutProgress.cpp
index 5b2c45cf..9ec5d1b 100644
--- a/third_party/WebKit/Source/core/layout/LayoutProgress.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutProgress.cpp
@@ -74,6 +74,16 @@
         && HTMLProgressElement::InvalidPosition != position());
 }
 
+bool LayoutProgress::isAnimationTimerActive() const
+{
+    return m_animationTimer.isActive();
+}
+
+bool LayoutProgress::isAnimating() const
+{
+    return m_animating;
+}
+
 void LayoutProgress::animationTimerFired(Timer<LayoutProgress>*)
 {
     setShouldDoFullPaintInvalidation();
@@ -86,7 +96,7 @@
     m_animationDuration = LayoutTheme::theme().animationDurationForProgressBar();
     m_animationRepeatInterval = LayoutTheme::theme().animationRepeatIntervalForProgressBar();
 
-    bool animating = style()->hasAppearance() && m_animationDuration > 0;
+    bool animating = !isDeterminate() && style()->hasAppearance() && m_animationDuration > 0;
     if (animating == m_animating)
         return;
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutProgress.h b/third_party/WebKit/Source/core/layout/LayoutProgress.h
index c8d8abf..1c30b8e18 100644
--- a/third_party/WebKit/Source/core/layout/LayoutProgress.h
+++ b/third_party/WebKit/Source/core/layout/LayoutProgress.h
@@ -46,6 +46,9 @@
 protected:
     void willBeDestroyed() override;
 
+    bool isAnimating() const;
+    bool isAnimationTimerActive() const;
+
 private:
     bool isOfType(LayoutObjectType type) const override { return type == LayoutObjectProgress || LayoutBlockFlow::isOfType(type); }
 
@@ -58,6 +61,8 @@
     double m_animationDuration;
     bool m_animating;
     Timer<LayoutProgress> m_animationTimer;
+
+    friend class LayoutProgressTest;
 };
 
 DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutProgress, isProgress());
diff --git a/third_party/WebKit/Source/core/layout/LayoutProgressTest.cpp b/third_party/WebKit/Source/core/layout/LayoutProgressTest.cpp
new file mode 100644
index 0000000..eaf410f
--- /dev/null
+++ b/third_party/WebKit/Source/core/layout/LayoutProgressTest.cpp
@@ -0,0 +1,46 @@
+// Copyright 2016 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 "core/layout/LayoutProgress.h"
+
+#include "core/HTMLNames.h"
+#include "core/html/HTMLElement.h"
+#include "core/layout/LayoutTestHelper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+class LayoutProgressTest : public RenderingTest {
+public:
+    static bool isAnimationTimerActive(const LayoutProgress* o) { return o->isAnimationTimerActive(); }
+    static bool isAnimatiing(const LayoutProgress* o) { return o->isAnimating(); }
+};
+
+TEST_F(LayoutProgressTest, AnimationScheduling)
+{
+    RenderingTest::setBodyInnerHTML("<progress id=\"progressElement\" value=0.3 max=1.0></progress>");
+    document().view()->updateAllLifecyclePhases();
+    Element* progressElement = document().getElementById(AtomicString("progressElement"));
+    LayoutProgress* layoutProgress = toLayoutProgress(progressElement->layoutObject());
+
+    // Verify that we do not schedule a timer for a determinant progress element
+    EXPECT_FALSE(LayoutProgressTest::isAnimationTimerActive(layoutProgress));
+    EXPECT_FALSE(LayoutProgressTest::isAnimatiing(layoutProgress));
+
+    progressElement->removeAttribute("value");
+    document().view()->updateAllLifecyclePhases();
+
+    // Verify that we schedule a timer for an indeterminant progress element
+    EXPECT_TRUE(LayoutProgressTest::isAnimationTimerActive(layoutProgress));
+    EXPECT_TRUE(LayoutProgressTest::isAnimatiing(layoutProgress));
+
+    progressElement->setAttribute(HTMLNames::valueAttr, "0.7");
+    document().view()->updateAllLifecyclePhases();
+
+    // Verify that we cancel the timer for a determinant progress element
+    EXPECT_FALSE(LayoutProgressTest::isAnimationTimerActive(layoutProgress));
+    EXPECT_FALSE(LayoutProgressTest::isAnimatiing(layoutProgress));
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutScrollbar.cpp b/third_party/WebKit/Source/core/layout/LayoutScrollbar.cpp
index d4e88f8a..140555f9 100644
--- a/third_party/WebKit/Source/core/layout/LayoutScrollbar.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutScrollbar.cpp
@@ -272,10 +272,8 @@
         partLayoutObject = 0;
     }
 
-    if (partLayoutObject) {
-        partLayoutObject->adjustStyleBeforeSet(partStyle.get());
-        partLayoutObject->setStyle(partStyle.release());
-    }
+    if (partLayoutObject)
+        partLayoutObject->setStyleWithWritingModeOfParent(partStyle.release());
 }
 
 IntRect LayoutScrollbar::buttonRect(ScrollbarPart partType) const
diff --git a/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.cpp b/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.cpp
index e04f2c3..1e8c8e4 100644
--- a/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.cpp
@@ -166,15 +166,6 @@
     clearPreferredLogicalWidthsDirty();
 }
 
-void LayoutScrollbarPart::adjustStyleBeforeSet(ComputedStyle* newStyle)
-{
-    // LayoutScrollbarPart cannot be an orthogonal writing-mode root because
-    // FrameView calls layout() for all orthogonal writing-mode roots, but
-    // LayoutScrollbarPart::layout() will crash if m_scrollbar is nullptr.
-    if (parent())
-        newStyle->setWritingMode(parent()->styleRef().writingMode());
-}
-
 void LayoutScrollbarPart::styleWillChange(StyleDifference diff, const ComputedStyle& newStyle)
 {
     LayoutBlock::styleWillChange(diff, newStyle);
diff --git a/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.h b/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.h
index 741026a..3d06335 100644
--- a/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.h
+++ b/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.h
@@ -74,7 +74,8 @@
     bool isOfType(LayoutObjectType type) const override { return type == LayoutObjectLayoutScrollbarPart || LayoutBlock::isOfType(type); }
     LayoutObject* layoutObjectOwningScrollbar() const;
 
-    void adjustStyleBeforeSet(ComputedStyle*);
+    // Must call setStyleWithWritingModeOfParent() instead.
+    void setStyle(PassRefPtr<ComputedStyle>) = delete;
 
 protected:
     void styleWillChange(StyleDifference, const ComputedStyle& newStyle) override;
diff --git a/third_party/WebKit/Source/core/layout/LayoutTable.h b/third_party/WebKit/Source/core/layout/LayoutTable.h
index b025632d..72eb662 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTable.h
+++ b/third_party/WebKit/Source/core/layout/LayoutTable.h
@@ -367,6 +367,10 @@
 
     const char* name() const override { return "LayoutTable"; }
 
+    // Whether a table has opaque foreground depends on many factors, e.g. border spacing, missing cells, etc.
+    // For simplicity, just conservatively assume foreground of all tables are not opaque.
+    bool foregroundIsKnownToBeOpaqueInRect(const LayoutRect&, unsigned) const override { return false; }
+
 protected:
     void styleDidChange(StyleDifference, const ComputedStyle* oldStyle) override;
     void simplifiedNormalFlowLayout() override;
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableRow.cpp b/third_party/WebKit/Source/core/layout/LayoutTableRow.cpp
index 3280fa9..149d4f7 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableRow.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTableRow.cpp
@@ -255,13 +255,4 @@
     addVisualOverflow(cellVisualOverflowRect);
 }
 
-bool LayoutTableRow::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const
-{
-    // If this object has layer, the area of collapsed borders should be transparent
-    // to expose the collapsed borders painted on the underlying layer.
-    if (hasLayer() && table()->collapseBorders())
-        return false;
-    return LayoutBox::backgroundIsKnownToBeOpaqueInRect(localRect);
-}
-
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableRow.h b/third_party/WebKit/Source/core/layout/LayoutTableRow.h
index 753da75..d167a9a 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableRow.h
+++ b/third_party/WebKit/Source/core/layout/LayoutTableRow.h
@@ -126,7 +126,11 @@
 
     const char* name() const override { return "LayoutTableRow"; }
 
-    bool backgroundIsKnownToBeOpaqueInRect(const LayoutRect&) const override;
+    // Whether a row has opaque background depends on many factors, e.g. border spacing,
+    // border collapsing, missing cells, etc.
+    // For simplicity, just conservatively assume all table rows are not opaque.
+    bool foregroundIsKnownToBeOpaqueInRect(const LayoutRect&, unsigned) const override { return false; }
+    bool backgroundIsKnownToBeOpaqueInRect(const LayoutRect&) const override { return false; }
 
 private:
     LayoutObjectChildList* virtualChildren() override { return children(); }
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableRowTest.cpp b/third_party/WebKit/Source/core/layout/LayoutTableRowTest.cpp
index 0b42225..e71f6186 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableRowTest.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTableRowTest.cpp
@@ -88,6 +88,27 @@
     EXPECT_FALSE(row->backgroundIsKnownToBeOpaqueInRect(LayoutRect(0, 0, 1, 1)));
 }
 
+TEST_F(LayoutTableRowTest, BackgroundIsKnownToBeOpaqueWithBorderSpacing)
+{
+    setBodyInnerHTML("<table style='border-spacing: 10px'>"
+        "<tr style='background-color: blue'><td>Cell</td></tr>"
+        "</table>");
+
+    LayoutTableRow* row = toLayoutTableRow(document().body()->firstChild()->firstChild()->firstChild()->layoutObject());
+    EXPECT_FALSE(row->backgroundIsKnownToBeOpaqueInRect(LayoutRect(0, 0, 1, 1)));
+}
+
+TEST_F(LayoutTableRowTest, BackgroundIsKnownToBeOpaqueWithEmptyCell)
+{
+    setBodyInnerHTML("<table style='border-spacing: 10px'>"
+        "<tr style='background-color: blue'><td>Cell</td></tr>"
+        "<tr style='background-color: blue'><td>Cell</td><td>Cell</td></tr>"
+        "</table>");
+
+    LayoutTableRow* row = toLayoutTableRow(document().body()->firstChild()->firstChild()->firstChild()->layoutObject());
+    EXPECT_FALSE(row->backgroundIsKnownToBeOpaqueInRect(LayoutRect(0, 0, 1, 1)));
+}
+
 } // anonymous namespace
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableSection.h b/third_party/WebKit/Source/core/layout/LayoutTableSection.h
index fb4290f5..67d7820 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableSection.h
+++ b/third_party/WebKit/Source/core/layout/LayoutTableSection.h
@@ -306,6 +306,12 @@
 
     const char* name() const override { return "LayoutTableSection"; }
 
+    // Whether a section has opaque background depends on many factors, e.g. border spacing,
+    // border collapsing, missing cells, etc.
+    // For simplicity, just conservatively assume all table sections are not opaque.
+    bool foregroundIsKnownToBeOpaqueInRect(const LayoutRect&, unsigned) const override { return false; }
+    bool backgroundIsKnownToBeOpaqueInRect(const LayoutRect&) const override { return false; }
+
 protected:
     void styleDidChange(StyleDifference, const ComputedStyle* oldStyle) override;
     bool nodeAtPoint(HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override;
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableSectionTest.cpp b/third_party/WebKit/Source/core/layout/LayoutTableSectionTest.cpp
new file mode 100644
index 0000000..306b7e2
--- /dev/null
+++ b/third_party/WebKit/Source/core/layout/LayoutTableSectionTest.cpp
@@ -0,0 +1,54 @@
+// Copyright 2016 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 "core/layout/LayoutTableSection.h"
+
+#include "core/layout/LayoutTestHelper.h"
+
+namespace blink {
+
+namespace {
+
+using LayoutTableSectionTest = RenderingTest;
+
+TEST_F(LayoutTableSectionTest, BackgroundIsKnownToBeOpaqueWithLayerAndCollapsedBorder)
+{
+    setBodyInnerHTML("<table style='border-collapse: collapse'>"
+        "  <thead style='will-change: transform; background-color: blue'>"
+        "    <tr><td>Cell</td></tr>"
+        "  </thead>"
+        "</table>");
+
+    LayoutTableSection* section = toLayoutTableSection(document().body()->firstChild()->firstChild()->layoutObject());
+    EXPECT_FALSE(section->backgroundIsKnownToBeOpaqueInRect(LayoutRect(0, 0, 1, 1)));
+}
+
+TEST_F(LayoutTableSectionTest, BackgroundIsKnownToBeOpaqueWithBorderSpacing)
+{
+    setBodyInnerHTML("<table style='border-spacing: 10px'>"
+        "  <thead style='background-color: blue'>"
+        "    <tr><td>Cell</td></tr>"
+        "  </thead>"
+        "</table>");
+
+    LayoutTableSection* section = toLayoutTableSection(document().body()->firstChild()->firstChild()->layoutObject());
+    EXPECT_FALSE(section->backgroundIsKnownToBeOpaqueInRect(LayoutRect(0, 0, 1, 1)));
+}
+
+TEST_F(LayoutTableSectionTest, BackgroundIsKnownToBeOpaqueWithEmptyCell)
+{
+    setBodyInnerHTML("<table style='border-spacing: 10px'>"
+        "  <thead style='background-color: blue'>"
+        "    <tr><td>Cell</td></tr>"
+        "    <tr><td>Cell</td><td>Cell</td></tr>"
+        "  </thead>"
+        "</table>");
+
+    LayoutTableSection* section = toLayoutTableSection(document().body()->firstChild()->firstChild()->layoutObject());
+    EXPECT_FALSE(section->backgroundIsKnownToBeOpaqueInRect(LayoutRect(0, 0, 1, 1)));
+}
+
+} // anonymous namespace
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutTheme.cpp b/third_party/WebKit/Source/core/layout/LayoutTheme.cpp
index 293daef..53729a5 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTheme.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTheme.cpp
@@ -42,12 +42,14 @@
 #include "core/html/shadow/ShadowElementNames.h"
 #include "core/html/shadow/SpinButtonElement.h"
 #include "core/html/shadow/TextControlInnerElements.h"
+#include "core/layout/LayoutThemeMobile.h"
 #include "core/page/FocusController.h"
 #include "core/page/Page.h"
 #include "core/style/ComputedStyle.h"
 #include "platform/FileMetadata.h"
 #include "platform/FloatConversion.h"
 #include "platform/RuntimeEnabledFeatures.h"
+#include "platform/Theme.h"
 #include "platform/fonts/FontSelector.h"
 #include "platform/text/PlatformLocale.h"
 #include "platform/text/StringTruncator.h"
@@ -56,21 +58,24 @@
 #include "public/platform/WebRect.h"
 #include "wtf/text/StringBuilder.h"
 
-#if USE(NEW_THEME)
-#include "platform/Theme.h"
-#endif
-
 // The methods in this file are shared by all themes on every platform.
 
 namespace blink {
 
 using namespace HTMLNames;
 
-LayoutTheme::LayoutTheme()
+LayoutTheme& LayoutTheme::theme()
+{
+    if (RuntimeEnabledFeatures::mobileLayoutThemeEnabled()) {
+        DEFINE_STATIC_REF(LayoutTheme, layoutThemeMobile, (LayoutThemeMobile::create()));
+        return *layoutThemeMobile;
+    }
+    return nativeTheme();
+}
+
+LayoutTheme::LayoutTheme(Theme* platformTheme)
     : m_hasCustomFocusRingColor(false)
-#if USE(NEW_THEME)
-    , m_platformTheme(platformTheme())
-#endif
+    , m_platformTheme(platformTheme)
 {
 }
 
@@ -103,99 +108,105 @@
         return;
     }
 
-#if USE(NEW_THEME)
-    switch (part) {
-    case CheckboxPart:
-    case InnerSpinButtonPart:
-    case RadioPart:
-    case PushButtonPart:
-    case SquareButtonPart:
-    case ButtonPart: {
-        // Border
-        LengthBox borderBox(style.borderTopWidth(), style.borderRightWidth(), style.borderBottomWidth(), style.borderLeftWidth());
-        borderBox = m_platformTheme->controlBorder(part, style.font().fontDescription(), borderBox, style.effectiveZoom());
-        if (borderBox.top().value() != static_cast<int>(style.borderTopWidth())) {
-            if (borderBox.top().value())
-                style.setBorderTopWidth(borderBox.top().value());
-            else
-                style.resetBorderTop();
-        }
-        if (borderBox.right().value() != static_cast<int>(style.borderRightWidth())) {
-            if (borderBox.right().value())
-                style.setBorderRightWidth(borderBox.right().value());
-            else
-                style.resetBorderRight();
-        }
-        if (borderBox.bottom().value() != static_cast<int>(style.borderBottomWidth())) {
-            style.setBorderBottomWidth(borderBox.bottom().value());
-            if (borderBox.bottom().value())
+    if (m_platformTheme) {
+        switch (part) {
+        case CheckboxPart:
+        case InnerSpinButtonPart:
+        case RadioPart:
+        case PushButtonPart:
+        case SquareButtonPart:
+        case ButtonPart: {
+            // Border
+            LengthBox borderBox(style.borderTopWidth(), style.borderRightWidth(), style.borderBottomWidth(), style.borderLeftWidth());
+            borderBox = m_platformTheme->controlBorder(part, style.font().fontDescription(), borderBox, style.effectiveZoom());
+            if (borderBox.top().value() != static_cast<int>(style.borderTopWidth())) {
+                if (borderBox.top().value())
+                    style.setBorderTopWidth(borderBox.top().value());
+                else
+                    style.resetBorderTop();
+            }
+            if (borderBox.right().value() != static_cast<int>(style.borderRightWidth())) {
+                if (borderBox.right().value())
+                    style.setBorderRightWidth(borderBox.right().value());
+                else
+                    style.resetBorderRight();
+            }
+            if (borderBox.bottom().value() != static_cast<int>(style.borderBottomWidth())) {
                 style.setBorderBottomWidth(borderBox.bottom().value());
-            else
-                style.resetBorderBottom();
-        }
-        if (borderBox.left().value() != static_cast<int>(style.borderLeftWidth())) {
-            style.setBorderLeftWidth(borderBox.left().value());
-            if (borderBox.left().value())
+                if (borderBox.bottom().value())
+                    style.setBorderBottomWidth(borderBox.bottom().value());
+                else
+                    style.resetBorderBottom();
+            }
+            if (borderBox.left().value() != static_cast<int>(style.borderLeftWidth())) {
                 style.setBorderLeftWidth(borderBox.left().value());
-            else
-                style.resetBorderLeft();
+                if (borderBox.left().value())
+                    style.setBorderLeftWidth(borderBox.left().value());
+                else
+                    style.resetBorderLeft();
+            }
+
+            // Padding
+            LengthBox paddingBox = m_platformTheme->controlPadding(part, style.font().fontDescription(), style.paddingBox(), style.effectiveZoom());
+            if (paddingBox != style.paddingBox())
+                style.setPaddingBox(paddingBox);
+
+            // Whitespace
+            if (m_platformTheme->controlRequiresPreWhiteSpace(part))
+                style.setWhiteSpace(PRE);
+
+            // Width / Height
+            // The width and height here are affected by the zoom.
+            // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
+            LengthSize controlSize = m_platformTheme->controlSize(part, style.font().fontDescription(), LengthSize(style.width(), style.height()), style.effectiveZoom());
+            if (controlSize.width() != style.width())
+                style.setWidth(controlSize.width());
+            if (controlSize.height() != style.height())
+                style.setHeight(controlSize.height());
+
+            // Min-Width / Min-Height
+            LengthSize minControlSize = m_platformTheme->minimumControlSize(part, style.font().fontDescription(), style.effectiveZoom());
+            if (minControlSize.width() != style.minWidth())
+                style.setMinWidth(minControlSize.width());
+            if (minControlSize.height() != style.minHeight())
+                style.setMinHeight(minControlSize.height());
+
+            // Font
+            FontDescription controlFont = m_platformTheme->controlFont(part, style.font().fontDescription(), style.effectiveZoom());
+            if (controlFont != style.font().fontDescription()) {
+                // Reset our line-height
+                style.setLineHeight(ComputedStyle::initialLineHeight());
+
+                // Now update our font.
+                if (style.setFontDescription(controlFont))
+                    style.font().update(nullptr);
+            }
         }
-
-        // Padding
-        LengthBox paddingBox = m_platformTheme->controlPadding(part, style.font().fontDescription(), style.paddingBox(), style.effectiveZoom());
-        if (paddingBox != style.paddingBox())
-            style.setPaddingBox(paddingBox);
-
-        // Whitespace
-        if (m_platformTheme->controlRequiresPreWhiteSpace(part))
-            style.setWhiteSpace(PRE);
-
-        // Width / Height
-        // The width and height here are affected by the zoom.
-        // FIXME: Check is flawed, since it doesn't take min-width/max-width into account.
-        LengthSize controlSize = m_platformTheme->controlSize(part, style.font().fontDescription(), LengthSize(style.width(), style.height()), style.effectiveZoom());
-        if (controlSize.width() != style.width())
-            style.setWidth(controlSize.width());
-        if (controlSize.height() != style.height())
-            style.setHeight(controlSize.height());
-
-        // Min-Width / Min-Height
-        LengthSize minControlSize = m_platformTheme->minimumControlSize(part, style.font().fontDescription(), style.effectiveZoom());
-        if (minControlSize.width() != style.minWidth())
-            style.setMinWidth(minControlSize.width());
-        if (minControlSize.height() != style.minHeight())
-            style.setMinHeight(minControlSize.height());
-
-        // Font
-        FontDescription controlFont = m_platformTheme->controlFont(part, style.font().fontDescription(), style.effectiveZoom());
-        if (controlFont != style.font().fontDescription()) {
-            // Reset our line-height
-            style.setLineHeight(ComputedStyle::initialLineHeight());
-
-            // Now update our font.
-            if (style.setFontDescription(controlFont))
-                style.font().update(nullptr);
+        default:
+            break;
         }
     }
-    default:
-        break;
+
+    if (!m_platformTheme) {
+        // Call the appropriate style adjustment method based off the appearance value.
+        switch (style.appearance()) {
+        case CheckboxPart:
+            return adjustCheckboxStyle(style);
+        case RadioPart:
+            return adjustRadioStyle(style);
+        case PushButtonPart:
+        case SquareButtonPart:
+        case ButtonPart:
+            return adjustButtonStyle(style);
+        case InnerSpinButtonPart:
+            return adjustInnerSpinButtonStyle(style);
+        default:
+            break;
+        }
     }
-#endif
 
     // Call the appropriate style adjustment method based off the appearance value.
     switch (style.appearance()) {
-#if !USE(NEW_THEME)
-    case CheckboxPart:
-        return adjustCheckboxStyle(style);
-    case RadioPart:
-        return adjustRadioStyle(style);
-    case PushButtonPart:
-    case SquareButtonPart:
-    case ButtonPart:
-        return adjustButtonStyle(style);
-    case InnerSpinButtonPart:
-        return adjustInnerSpinButtonStyle(style);
-#endif
     case MenulistPart:
         return adjustMenuListStyle(style, e);
     case MenulistButtonPart:
@@ -368,11 +379,9 @@
 
     const LayoutBox* box = toLayoutBox(o);
 
-#if USE(NEW_THEME)
-    return box->size().height() + box->marginTop() + m_platformTheme->baselinePositionAdjustment(o->style()->appearance()) * o->style()->effectiveZoom();
-#else
+    if (m_platformTheme)
+        return box->size().height() + box->marginTop() + m_platformTheme->baselinePositionAdjustment(o->style()->appearance()) * o->style()->effectiveZoom();
     return box->size().height() + box->marginTop();
-#endif
 }
 
 bool LayoutTheme::isControlContainer(ControlPart appearance) const
@@ -413,9 +422,8 @@
 
 void LayoutTheme::addVisualOverflow(const LayoutObject& object, IntRect& borderBox)
 {
-#if USE(NEW_THEME)
-    m_platformTheme->addVisualOverflow(object.style()->appearance(), controlStatesForLayoutObject(object), object.style()->effectiveZoom(), borderBox);
-#endif
+    if (m_platformTheme)
+        m_platformTheme->addVisualOverflow(object.style()->appearance(), controlStatesForLayoutObject(object), object.style()->effectiveZoom(), borderBox);
 }
 
 bool LayoutTheme::shouldDrawDefaultFocusRing(const LayoutObject& layoutObject) const
@@ -572,8 +580,6 @@
     return element->upDownState() == SpinButtonElement::Up;
 }
 
-#if !USE(NEW_THEME)
-
 void LayoutTheme::adjustCheckboxStyle(ComputedStyle& style) const
 {
     // A summary of the rules for checkbox designed to match WinIE:
@@ -611,7 +617,6 @@
 void LayoutTheme::adjustInnerSpinButtonStyle(ComputedStyle&) const
 {
 }
-#endif
 
 void LayoutTheme::adjustMenuListStyle(ComputedStyle&, Element*) const
 {
diff --git a/third_party/WebKit/Source/core/layout/LayoutTheme.h b/third_party/WebKit/Source/core/layout/LayoutTheme.h
index bab7c4d71..31a7cad3 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTheme.h
+++ b/third_party/WebKit/Source/core/layout/LayoutTheme.h
@@ -43,13 +43,11 @@
 
 class CORE_EXPORT LayoutTheme : public RefCounted<LayoutTheme> {
 protected:
-    LayoutTheme();
+    explicit LayoutTheme(Theme*);
 
 public:
     virtual ~LayoutTheme() { }
 
-    // This function is to be implemented in your platform-specific theme implementation to hand back the
-    // appropriate platform theme.
     static LayoutTheme& theme();
 
     virtual ThemePainter& painter() = 0;
@@ -202,7 +200,6 @@
 
     virtual bool themeDrawsFocusRing(const ComputedStyle&) const = 0;
 
-#if !USE(NEW_THEME)
     // Methods for each appearance value.
     virtual void adjustCheckboxStyle(ComputedStyle&) const;
     virtual void setCheckboxSize(ComputedStyle&) const { }
@@ -212,7 +209,6 @@
 
     virtual void adjustButtonStyle(ComputedStyle&) const;
     virtual void adjustInnerSpinButtonStyle(ComputedStyle&) const;
-#endif
 
     virtual void adjustMenuListStyle(ComputedStyle&, Element*) const;
     virtual void adjustMenuListButtonStyle(ComputedStyle&, Element*) const;
@@ -225,6 +221,8 @@
     void adjustCheckboxStyleUsingFallbackTheme(ComputedStyle&) const;
     void adjustRadioStyleUsingFallbackTheme(ComputedStyle&) const;
 
+    bool hasPlatformTheme() const { return m_platformTheme; }
+
 public:
     // Methods for state querying
     static ControlStates controlStatesForLayoutObject(const LayoutObject&);
@@ -240,6 +238,10 @@
     static bool isReadOnlyControl(const LayoutObject&);
 
 private:
+    // This function is to be implemented in your platform-specific theme implementation to hand back the
+    // appropriate platform theme.
+    static LayoutTheme& nativeTheme();
+
     Color m_customFocusRingColor;
     bool m_hasCustomFocusRingColor;
 
@@ -249,9 +251,7 @@
 
     static const RGBA32 defaultCompositionBackgroundColor = 0xFFFFDD55;
 
-#if USE(NEW_THEME)
     Theme* m_platformTheme; // The platform-specific theme.
-#endif
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutThemeAndroid.cpp b/third_party/WebKit/Source/core/layout/LayoutThemeAndroid.cpp
index fe9782e1..59f5aa7b4 100644
--- a/third_party/WebKit/Source/core/layout/LayoutThemeAndroid.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutThemeAndroid.cpp
@@ -1,43 +1,9 @@
-/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
+// Copyright 2016 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 "core/layout/LayoutThemeAndroid.h"
 
-#include "core/CSSValueKeywords.h"
-#include "core/InputTypeNames.h"
-#include "core/layout/LayoutObject.h"
-#include "core/layout/LayoutProgress.h"
-#include "core/layout/LayoutSlider.h"
-#include "platform/LayoutTestSupport.h"
-#include "platform/PlatformResourceLoader.h"
-#include "platform/graphics/Color.h"
-#include "platform/scroll/ScrollbarTheme.h"
-#include "public/platform/Platform.h"
-#include "public/platform/WebThemeEngine.h"
-#include "wtf/StdLibExtras.h"
-
 namespace blink {
 
 PassRefPtr<LayoutTheme> LayoutThemeAndroid::create()
@@ -45,7 +11,7 @@
     return adoptRef(new LayoutThemeAndroid());
 }
 
-LayoutTheme& LayoutTheme::theme()
+LayoutTheme& LayoutTheme::nativeTheme()
 {
     DEFINE_STATIC_REF(LayoutTheme, layoutTheme, (LayoutThemeAndroid::create()));
     return *layoutTheme;
@@ -55,31 +21,4 @@
 {
 }
 
-String LayoutThemeAndroid::extraMediaControlsStyleSheet()
-{
-    return loadResourceAsASCIIString(
-        RuntimeEnabledFeatures::newMediaPlaybackUiEnabled() ?
-        "mediaControlsAndroidNew.css" : "mediaControlsAndroid.css");
-}
-
-String LayoutThemeAndroid::extraDefaultStyleSheet()
-{
-    return LayoutThemeDefault::extraDefaultStyleSheet() +
-        loadResourceAsASCIIString("themeChromiumLinux.css") +
-        loadResourceAsASCIIString("themeChromiumAndroid.css");
-
-}
-
-void LayoutThemeAndroid::adjustInnerSpinButtonStyle(ComputedStyle& style) const
-{
-    if (LayoutTestSupport::isRunningLayoutTest()) {
-        // Match Linux spin button style in layout tests.
-        // FIXME: Consider removing the conditional if a future Android theme matches this.
-        IntSize size = Platform::current()->themeEngine()->getSize(WebThemeEngine::PartInnerSpinButton);
-
-        style.setWidth(Length(size.width(), Fixed));
-        style.setMinWidth(Length(size.width(), Fixed));
-    }
-}
-
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutThemeAndroid.h b/third_party/WebKit/Source/core/layout/LayoutThemeAndroid.h
index 804d073..45daca5 100644
--- a/third_party/WebKit/Source/core/layout/LayoutThemeAndroid.h
+++ b/third_party/WebKit/Source/core/layout/LayoutThemeAndroid.h
@@ -1,61 +1,20 @@
-/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
+// Copyright 2016 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 LayoutThemeAndroid_h
 #define LayoutThemeAndroid_h
 
-#include "core/layout/LayoutThemeDefault.h"
+#include "core/layout/LayoutThemeMobile.h"
 
 namespace blink {
 
-class LayoutThemeAndroid final : public LayoutThemeDefault {
+class LayoutThemeAndroid final : public LayoutThemeMobile {
 public:
     static PassRefPtr<LayoutTheme> create();
-    String extraDefaultStyleSheet() override;
-
-    void adjustInnerSpinButtonStyle(ComputedStyle&) const override;
-
-    bool delegatesMenuListRendering() const override { return true; }
-
-    String extraMediaControlsStyleSheet() override;
-
-    Color platformTapHighlightColor() const override
-    {
-        return LayoutThemeAndroid::defaultTapHighlightColor;
-    }
-
-    Color platformActiveSelectionBackgroundColor() const override
-    {
-        return LayoutThemeAndroid::defaultActiveSelectionBackgroundColor;
-    }
 
 private:
     ~LayoutThemeAndroid() override;
-
-    static const RGBA32 defaultTapHighlightColor = 0x6633b5e5;
-    static const RGBA32 defaultActiveSelectionBackgroundColor = 0x6633b5e5;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutThemeDefault.cpp b/third_party/WebKit/Source/core/layout/LayoutThemeDefault.cpp
index 8220fc7..e5aade5 100644
--- a/third_party/WebKit/Source/core/layout/LayoutThemeDefault.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutThemeDefault.cpp
@@ -70,6 +70,7 @@
 double LayoutThemeDefault::m_caretBlinkInterval;
 
 LayoutThemeDefault::LayoutThemeDefault()
+    : LayoutTheme(nullptr)
 {
     m_caretBlinkInterval = LayoutTheme::caretBlinkInterval();
 }
diff --git a/third_party/WebKit/Source/core/layout/LayoutThemeDefault.h b/third_party/WebKit/Source/core/layout/LayoutThemeDefault.h
index bb728751..844c3e17 100644
--- a/third_party/WebKit/Source/core/layout/LayoutThemeDefault.h
+++ b/third_party/WebKit/Source/core/layout/LayoutThemeDefault.h
@@ -66,6 +66,7 @@
     void setCheckboxSize(ComputedStyle&) const override;
     void setRadioSize(ComputedStyle&) const override;
     void adjustInnerSpinButtonStyle(ComputedStyle&) const override;
+    void adjustButtonStyle(ComputedStyle&) const override;
 
     bool popsMenuBySpaceKey() const final { return true; }
     bool popsMenuByReturnKey() const final { return true; }
@@ -91,7 +92,6 @@
 
     int minimumMenuListSize(const ComputedStyle&) const override;
 
-    void adjustButtonStyle(ComputedStyle&) const override;
     void adjustSearchFieldStyle(ComputedStyle&) const override;
     void adjustSearchFieldCancelButtonStyle(ComputedStyle&) const override;
     void adjustSearchFieldDecorationStyle(ComputedStyle&) const override;
diff --git a/third_party/WebKit/Source/core/layout/LayoutThemeFontProviderLinux.cpp b/third_party/WebKit/Source/core/layout/LayoutThemeFontProviderDefault.cpp
similarity index 100%
rename from third_party/WebKit/Source/core/layout/LayoutThemeFontProviderLinux.cpp
rename to third_party/WebKit/Source/core/layout/LayoutThemeFontProviderDefault.cpp
diff --git a/third_party/WebKit/Source/core/layout/LayoutThemeFontProviderWin.cpp b/third_party/WebKit/Source/core/layout/LayoutThemeFontProviderWin.cpp
index 23b0ad3c..d0253fd 100644
--- a/third_party/WebKit/Source/core/layout/LayoutThemeFontProviderWin.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutThemeFontProviderWin.cpp
@@ -28,7 +28,6 @@
 #include "core/CSSValueKeywords.h"
 #include "platform/fonts/FontCache.h"
 #include "platform/fonts/FontDescription.h"
-#include "platform/win/HWndDC.h"
 #include "wtf/text/WTFString.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/core/layout/LayoutThemeLinux.cpp b/third_party/WebKit/Source/core/layout/LayoutThemeLinux.cpp
index b250d93..0555d691 100644
--- a/third_party/WebKit/Source/core/layout/LayoutThemeLinux.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutThemeLinux.cpp
@@ -13,7 +13,7 @@
     return adoptRef(new LayoutThemeLinux());
 }
 
-LayoutTheme& LayoutTheme::theme()
+LayoutTheme& LayoutTheme::nativeTheme()
 {
     DEFINE_STATIC_REF(LayoutTheme, layoutTheme, (LayoutThemeLinux::create()));
     return *layoutTheme;
diff --git a/third_party/WebKit/Source/core/layout/LayoutThemeMac.mm b/third_party/WebKit/Source/core/layout/LayoutThemeMac.mm
index 19fc396..5a53040 100644
--- a/third_party/WebKit/Source/core/layout/LayoutThemeMac.mm
+++ b/third_party/WebKit/Source/core/layout/LayoutThemeMac.mm
@@ -31,6 +31,7 @@
 #import "core/style/ShadowList.h"
 #import "platform/LayoutTestSupport.h"
 #import "platform/PlatformResourceLoader.h"
+#import "platform/Theme.h"
 #import "platform/graphics/BitmapImage.h"
 #import "platform/mac/ColorMac.h"
 #import "platform/mac/LocalCurrentGraphicsContext.h"
@@ -116,8 +117,9 @@
 using namespace HTMLNames;
 
 LayoutThemeMac::LayoutThemeMac()
-    : m_notificationObserver(AdoptNS, [[BlinkLayoutThemeNotificationObserver alloc] initWithTheme:this])
-    , m_painter(*this)
+    : LayoutTheme(platformTheme())
+    , m_notificationObserver(AdoptNS, [[BlinkLayoutThemeNotificationObserver alloc] initWithTheme:this])
+    , m_painter(*this, platformTheme())
 {
     [[NSNotificationCenter defaultCenter] addObserver:m_notificationObserver.get()
                                              selector:@selector(systemColorsDidChange:)
@@ -473,19 +475,19 @@
 {
     ControlPart part = object.style()->appearance();
 
-#if USE(NEW_THEME)
-    switch (part) {
-    case CheckboxPart:
-    case RadioPart:
-    case PushButtonPart:
-    case SquareButtonPart:
-    case ButtonPart:
-    case InnerSpinButtonPart:
-        return LayoutTheme::addVisualOverflow(object, rect);
-    default:
-        break;
+    if (hasPlatformTheme()) {
+        switch (part) {
+        case CheckboxPart:
+        case RadioPart:
+        case PushButtonPart:
+        case SquareButtonPart:
+        case ButtonPart:
+        case InnerSpinButtonPart:
+            return LayoutTheme::addVisualOverflow(object, rect);
+        default:
+            break;
+        }
     }
-#endif
 
     float zoomLevel = object.style()->effectiveZoom();
 
@@ -1102,7 +1104,7 @@
     return view;
 }
 
-LayoutTheme& LayoutTheme::theme()
+LayoutTheme& LayoutTheme::nativeTheme()
 {
     DEFINE_STATIC_REF(LayoutTheme, layoutTheme, (LayoutThemeMac::create()));
     return *layoutTheme;
diff --git a/third_party/WebKit/Source/core/layout/LayoutThemeMobile.cpp b/third_party/WebKit/Source/core/layout/LayoutThemeMobile.cpp
new file mode 100644
index 0000000..f9322432
--- /dev/null
+++ b/third_party/WebKit/Source/core/layout/LayoutThemeMobile.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core/layout/LayoutThemeMobile.h"
+
+#include "core/CSSValueKeywords.h"
+#include "core/InputTypeNames.h"
+#include "core/layout/LayoutObject.h"
+#include "core/layout/LayoutProgress.h"
+#include "core/layout/LayoutSlider.h"
+#include "platform/LayoutTestSupport.h"
+#include "platform/PlatformResourceLoader.h"
+#include "platform/graphics/Color.h"
+#include "platform/scroll/ScrollbarTheme.h"
+#include "public/platform/Platform.h"
+#include "public/platform/WebThemeEngine.h"
+#include "wtf/StdLibExtras.h"
+
+namespace blink {
+
+PassRefPtr<LayoutTheme> LayoutThemeMobile::create()
+{
+    return adoptRef(new LayoutThemeMobile());
+}
+
+LayoutThemeMobile::~LayoutThemeMobile()
+{
+}
+
+String LayoutThemeMobile::extraMediaControlsStyleSheet()
+{
+    return loadResourceAsASCIIString(
+        RuntimeEnabledFeatures::newMediaPlaybackUiEnabled() ?
+        "mediaControlsAndroidNew.css" : "mediaControlsAndroid.css");
+}
+
+String LayoutThemeMobile::extraDefaultStyleSheet()
+{
+    return LayoutThemeDefault::extraDefaultStyleSheet() +
+        loadResourceAsASCIIString("themeChromiumLinux.css") +
+        loadResourceAsASCIIString("themeChromiumAndroid.css");
+
+}
+
+void LayoutThemeMobile::adjustInnerSpinButtonStyle(ComputedStyle& style) const
+{
+    if (LayoutTestSupport::isRunningLayoutTest()) {
+        // Match Linux spin button style in layout tests.
+        // FIXME: Consider removing the conditional if a future Android theme matches this.
+        IntSize size = Platform::current()->themeEngine()->getSize(WebThemeEngine::PartInnerSpinButton);
+
+        style.setWidth(Length(size.width(), Fixed));
+        style.setMinWidth(Length(size.width(), Fixed));
+    }
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutThemeMobile.h b/third_party/WebKit/Source/core/layout/LayoutThemeMobile.h
new file mode 100644
index 0000000..779703923
--- /dev/null
+++ b/third_party/WebKit/Source/core/layout/LayoutThemeMobile.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LayoutThemeMobile_h
+#define LayoutThemeMobile_h
+
+#include "core/layout/LayoutThemeDefault.h"
+
+namespace blink {
+
+class LayoutThemeMobile : public LayoutThemeDefault {
+public:
+    static PassRefPtr<LayoutTheme> create();
+    String extraDefaultStyleSheet() override;
+
+    void adjustInnerSpinButtonStyle(ComputedStyle&) const override;
+
+    bool delegatesMenuListRendering() const override { return true; }
+
+    String extraMediaControlsStyleSheet() override;
+
+    Color platformTapHighlightColor() const override
+    {
+        return LayoutThemeMobile::defaultTapHighlightColor;
+    }
+
+    Color platformActiveSelectionBackgroundColor() const override
+    {
+        return LayoutThemeMobile::defaultActiveSelectionBackgroundColor;
+    }
+
+protected:
+    ~LayoutThemeMobile() override;
+
+private:
+    static const RGBA32 defaultTapHighlightColor = 0x6633b5e5;
+    static const RGBA32 defaultActiveSelectionBackgroundColor = 0x6633b5e5;
+};
+
+} // namespace blink
+
+#endif // LayoutThemeMobile_h
diff --git a/third_party/WebKit/Source/core/layout/LayoutThemeWin.cpp b/third_party/WebKit/Source/core/layout/LayoutThemeWin.cpp
index 2f08cb7..b477483 100644
--- a/third_party/WebKit/Source/core/layout/LayoutThemeWin.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutThemeWin.cpp
@@ -11,7 +11,7 @@
     return adoptRef(new LayoutThemeWin());
 }
 
-LayoutTheme& LayoutTheme::theme()
+LayoutTheme& LayoutTheme::nativeTheme()
 {
     DEFINE_STATIC_REF(LayoutTheme, layoutTheme, (LayoutThemeWin::create()));
     return *layoutTheme;
diff --git a/third_party/WebKit/Source/core/layout/TracedLayoutObject.cpp b/third_party/WebKit/Source/core/layout/TracedLayoutObject.cpp
index a884afe..4c9c147a 100644
--- a/third_party/WebKit/Source/core/layout/TracedLayoutObject.cpp
+++ b/third_party/WebKit/Source/core/layout/TracedLayoutObject.cpp
@@ -99,9 +99,9 @@
 
 } // namespace
 
-PassRefPtr<TracedValue> TracedLayoutObject::create(const LayoutView& view, bool traceGeometry)
+PassOwnPtr<TracedValue> TracedLayoutObject::create(const LayoutView& view, bool traceGeometry)
 {
-    RefPtr<TracedValue> tracedValue = TracedValue::create();
+    OwnPtr<TracedValue> tracedValue = TracedValue::create();
     dumpToTracedValue(view, traceGeometry, tracedValue.get());
     return tracedValue.release();
 }
diff --git a/third_party/WebKit/Source/core/layout/TracedLayoutObject.h b/third_party/WebKit/Source/core/layout/TracedLayoutObject.h
index 54c3e71..4f03b9b 100644
--- a/third_party/WebKit/Source/core/layout/TracedLayoutObject.h
+++ b/third_party/WebKit/Source/core/layout/TracedLayoutObject.h
@@ -13,7 +13,7 @@
 
 class TracedLayoutObject {
 public:
-    static PassRefPtr<TracedValue> create(const LayoutView&, bool traceGeometry = true);
+    static PassOwnPtr<TracedValue> create(const LayoutView&, bool traceGeometry = true);
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutBoxItem.h b/third_party/WebKit/Source/core/layout/api/LayoutBoxItem.h
new file mode 100644
index 0000000..0acd83a
--- /dev/null
+++ b/third_party/WebKit/Source/core/layout/api/LayoutBoxItem.h
@@ -0,0 +1,55 @@
+// Copyright 2016 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 LayoutBoxItem_h
+#define LayoutBoxItem_h
+
+#include "core/layout/LayoutBox.h"
+#include "core/layout/api/LayoutBoxModel.h"
+#include "platform/scroll/ScrollTypes.h"
+
+namespace blink {
+
+class LayoutBoxItem : public LayoutBoxModel {
+public:
+    explicit LayoutBoxItem(LayoutBox* layoutBox)
+        : LayoutBoxModel(layoutBox)
+    {
+    }
+
+    explicit LayoutBoxItem(const LayoutItem& item)
+        : LayoutBoxModel(item)
+    {
+        ASSERT(!item || item.isBox());
+    }
+
+    explicit LayoutBoxItem(std::nullptr_t) : LayoutBoxModel(nullptr) { }
+
+    LayoutBoxItem() { }
+
+    LayoutBoxItem enclosingBox() const
+    {
+        return LayoutBoxItem(toBox()->enclosingBox());
+    }
+
+    ScrollResultOneDimensional scroll(ScrollDirectionPhysical direction, ScrollGranularity granularity, float delta = 1)
+    {
+        return toBox()->scroll(direction, granularity, delta);
+    }
+
+private:
+    LayoutBox* toBox()
+    {
+        return toLayoutBox(layoutObject());
+    }
+
+    const LayoutBox* toBox() const
+    {
+        return toLayoutBox(layoutObject());
+    }
+};
+
+} // namespace blink
+
+#endif // LayoutBoxItem_h
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutItem.h b/third_party/WebKit/Source/core/layout/api/LayoutItem.h
index e478bb8b..6a75923 100644
--- a/third_party/WebKit/Source/core/layout/api/LayoutItem.h
+++ b/third_party/WebKit/Source/core/layout/api/LayoutItem.h
@@ -5,8 +5,8 @@
 #ifndef LayoutItem_h
 #define LayoutItem_h
 
+#include "core/inspector/InspectorTraceEvents.h"
 #include "core/layout/LayoutObject.h"
-
 #include "wtf/Allocator.h"
 
 namespace blink {
@@ -36,6 +36,16 @@
         return m_layoutObject->isBoxModelObject();
     }
 
+    bool isBox() const
+    {
+        return m_layoutObject->isBox();
+    }
+
+    bool isText() const
+    {
+        return m_layoutObject->isText();
+    }
+
     bool needsLayout()
     {
         return m_layoutObject->needsLayout();
@@ -71,6 +81,11 @@
         m_layoutObject->setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants();
     }
 
+    void setNeedsLayoutAndPrefWidthsRecalc(LayoutInvalidationReasonForTracing reason)
+    {
+        m_layoutObject->setNeedsLayoutAndPrefWidthsRecalc(reason);
+    }
+
 protected:
     LayoutObject* layoutObject() { return m_layoutObject; }
     const LayoutObject* layoutObject() const { return m_layoutObject; }
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutTextFragmentItem.h b/third_party/WebKit/Source/core/layout/api/LayoutTextFragmentItem.h
new file mode 100644
index 0000000..a742e74
--- /dev/null
+++ b/third_party/WebKit/Source/core/layout/api/LayoutTextFragmentItem.h
@@ -0,0 +1,50 @@
+
+// Copyright 2016 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 LayoutTextFragmentItem_h
+#define LayoutTextFragmentItem_h
+
+#include "core/layout/LayoutTextFragment.h"
+#include "core/layout/api/LayoutTextItem.h"
+
+namespace blink {
+
+class FirstLetterPseudoElement;
+
+class LayoutTextFragmentItem : public LayoutTextItem {
+public:
+    explicit LayoutTextFragmentItem(LayoutTextFragment* layoutTextFragment)
+        : LayoutTextItem(layoutTextFragment)
+    {
+    }
+
+    explicit LayoutTextFragmentItem(const LayoutTextItem& item)
+        : LayoutTextItem(item)
+    {
+        ASSERT(!item || item.isTextFragment());
+    }
+
+    explicit LayoutTextFragmentItem(std::nullptr_t) : LayoutTextItem(nullptr) { }
+
+    LayoutTextFragmentItem() { }
+
+    void setTextFragment(PassRefPtr<StringImpl> text, unsigned start, unsigned length)
+    {
+        toTextFragment()->setTextFragment(text, start, length);
+    }
+
+    FirstLetterPseudoElement* firstLetterPseudoElement() const
+    {
+        return toTextFragment()->firstLetterPseudoElement();
+    }
+
+private:
+    LayoutTextFragment* toTextFragment() { return toLayoutTextFragment(layoutObject()); }
+    const LayoutTextFragment* toTextFragment() const { return toLayoutTextFragment(layoutObject()); }
+};
+
+} // namespace blink
+
+#endif // LayoutTextItem_h
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutTextItem.h b/third_party/WebKit/Source/core/layout/api/LayoutTextItem.h
new file mode 100644
index 0000000..2a1fa153
--- /dev/null
+++ b/third_party/WebKit/Source/core/layout/api/LayoutTextItem.h
@@ -0,0 +1,60 @@
+
+// Copyright 2016 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 LayoutTextItem_h
+#define LayoutTextItem_h
+
+#include "core/layout/LayoutText.h"
+#include "core/layout/api/LayoutItem.h"
+
+namespace blink {
+
+class ComputedStyle;
+
+class LayoutTextItem : public LayoutItem {
+public:
+    explicit LayoutTextItem(LayoutText* layoutText)
+        : LayoutItem(layoutText)
+    {
+    }
+
+    explicit LayoutTextItem(const LayoutItem& item)
+        : LayoutItem(item)
+    {
+        ASSERT(!item || item.isText());
+    }
+
+    explicit LayoutTextItem(std::nullptr_t) : LayoutItem(nullptr) { }
+
+    LayoutTextItem() { }
+
+    bool isTextFragment() const
+    {
+        return toText()->isTextFragment();
+    }
+
+    void dirtyLineBoxes()
+    {
+        toText()->dirtyLineBoxes();
+    }
+
+    void setStyle(PassRefPtr<ComputedStyle> style)
+    {
+        toText()->setStyle(style);
+    }
+
+    void setText(PassRefPtr<StringImpl> text, bool force = false)
+    {
+        toText()->setText(text, force);
+    }
+
+private:
+    LayoutText* toText() { return toLayoutText(layoutObject()); }
+    const LayoutText* toText() const { return toLayoutText(layoutObject()); }
+};
+
+} // namespace blink
+
+#endif // LayoutTextItem_h
diff --git a/third_party/WebKit/Source/core/layout/api/LineLayoutItem.h b/third_party/WebKit/Source/core/layout/api/LineLayoutItem.h
index 7730e03..8824f1d 100644
--- a/third_party/WebKit/Source/core/layout/api/LineLayoutItem.h
+++ b/third_party/WebKit/Source/core/layout/api/LineLayoutItem.h
@@ -419,7 +419,8 @@
     LayoutObject* m_layoutObject;
 
     friend class LineLayoutAPIShim;
-    friend class LineLayoutBlockFlow; // For layoutObject().
+    friend class LineLayoutBlockFlow;
+    friend class LineLayoutRubyRun;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/api/LineLayoutRubyRun.h b/third_party/WebKit/Source/core/layout/api/LineLayoutRubyRun.h
index 1fdfab9..bea7db9 100644
--- a/third_party/WebKit/Source/core/layout/api/LineLayoutRubyRun.h
+++ b/third_party/WebKit/Source/core/layout/api/LineLayoutRubyRun.h
@@ -29,7 +29,7 @@
 
     void getOverhang(bool firstLine, LineLayoutItem startLayoutItem, LineLayoutItem endLayoutItem, int& startOverhang, int& endOverhang) const
     {
-        toRubyRun()->getOverhang(firstLine, startLayoutItem, endLayoutItem, startOverhang, endOverhang);
+        toRubyRun()->getOverhang(firstLine, startLayoutItem.layoutObject(), endLayoutItem.layoutObject(), startOverhang, endOverhang);
     }
 
     LayoutRubyText* rubyText() const
@@ -42,6 +42,11 @@
         return toRubyRun()->rubyBase();
     }
 
+    bool canBreakBefore(const LazyLineBreakIterator& iterator) const
+    {
+        return toRubyRun()->canBreakBefore(iterator);
+    }
+
 private:
     LayoutRubyRun* toRubyRun()
     {
diff --git a/third_party/WebKit/Source/core/layout/api/LineLayoutText.h b/third_party/WebKit/Source/core/layout/api/LineLayoutText.h
index 7f5fe02..57dae8b 100644
--- a/third_party/WebKit/Source/core/layout/api/LineLayoutText.h
+++ b/third_party/WebKit/Source/core/layout/api/LineLayoutText.h
@@ -34,6 +34,11 @@
         return toText()->firstTextBox();
     }
 
+    InlineTextBox* createInlineTextBox(int start, unsigned short length)
+    {
+        return toText()->createInlineTextBox(start, length);
+    }
+
     void extractTextBox(InlineTextBox* inlineTextBox)
     {
         toText()->extractTextBox(inlineTextBox);
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
index 3cacebf..793cda4 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
+++ b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
@@ -209,7 +209,7 @@
     destroyGraphicsLayers();
 }
 
-PassOwnPtr<GraphicsLayer> CompositedLayerMapping::createGraphicsLayer(CompositingReasons reasons)
+PassOwnPtr<GraphicsLayer> CompositedLayerMapping::createGraphicsLayer(CompositingReasons reasons, SquashingDisallowedReasons squashingDisallowedReasons)
 {
     GraphicsLayerFactory* graphicsLayerFactory = nullptr;
     if (Page* page = layoutObject()->frame()->page())
@@ -218,6 +218,7 @@
     OwnPtr<GraphicsLayer> graphicsLayer = GraphicsLayer::create(graphicsLayerFactory, this);
 
     graphicsLayer->setCompositingReasons(reasons);
+    graphicsLayer->setSquashingDisallowedReasons(squashingDisallowedReasons);
     if (Node* owningNode = m_owningLayer.layoutObject()->generatingNode())
         graphicsLayer->setOwnerNodeId(DOMNodeIds::idForNode(owningNode));
 
@@ -226,7 +227,7 @@
 
 void CompositedLayerMapping::createPrimaryGraphicsLayer()
 {
-    m_graphicsLayer = createGraphicsLayer(m_owningLayer.compositingReasons());
+    m_graphicsLayer = createGraphicsLayer(m_owningLayer.compositingReasons(), m_owningLayer.squashingDisallowedReasons());
 
     updateOpacity(layoutObject()->styleRef());
     updateTransform(layoutObject()->styleRef());
@@ -346,6 +347,7 @@
     // All other layers owned by this mapping will have the same compositing reason
     // for their lifetime, so they are initialized only when created.
     m_graphicsLayer->setCompositingReasons(m_owningLayer.compositingReasons());
+    m_graphicsLayer->setSquashingDisallowedReasons(m_owningLayer.squashingDisallowedReasons());
 }
 
 bool CompositedLayerMapping::owningLayerClippedByLayerNotAboveCompositedAncestor(const PaintLayer* scrollParent)
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.h b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.h
index c0f063a7..30193b8e 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.h
+++ b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.h
@@ -240,7 +240,7 @@
     void createPrimaryGraphicsLayer();
     void destroyGraphicsLayers();
 
-    PassOwnPtr<GraphicsLayer> createGraphicsLayer(CompositingReasons);
+    PassOwnPtr<GraphicsLayer> createGraphicsLayer(CompositingReasons, SquashingDisallowedReasons = SquashingDisallowedReasonsNone);
     bool toggleScrollbarLayerIfNeeded(OwnPtr<GraphicsLayer>&, bool needsLayer, CompositingReasons);
 
     LayoutBoxModelObject* layoutObject() const { return m_owningLayer.layoutObject(); }
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositingLayerAssigner.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositingLayerAssigner.cpp
index 873ec4b..3bee691 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositingLayerAssigner.cpp
+++ b/third_party/WebKit/Source/core/layout/compositing/CompositingLayerAssigner.cpp
@@ -112,10 +112,10 @@
     return update;
 }
 
-CompositingReasons CompositingLayerAssigner::getReasonsPreventingSquashing(const PaintLayer* layer, const CompositingLayerAssigner::SquashingState& squashingState)
+SquashingDisallowedReasons CompositingLayerAssigner::getReasonsPreventingSquashing(const PaintLayer* layer, const CompositingLayerAssigner::SquashingState& squashingState)
 {
     if (!squashingState.haveAssignedBackingsToEntireSquashingLayerSubtree)
-        return CompositingReasonSquashingWouldBreakPaintOrder;
+        return SquashingDisallowedReasonWouldBreakPaintOrder;
 
     ASSERT(squashingState.hasMostRecentMapping);
     const PaintLayer& squashingLayer = squashingState.mostRecentMapping->owningLayer();
@@ -128,55 +128,55 @@
     //
     // compositing/video/video-controls-layer-creation.html
     if (layer->layoutObject()->isVideo() || squashingLayer.layoutObject()->isVideo())
-        return CompositingReasonSquashingVideoIsDisallowed;
+        return SquashingDisallowedReasonSquashingVideoIsDisallowed;
 
     // Don't squash iframes, frames or plugins.
     // FIXME: this is only necessary because there is frame code that assumes that composited frames are not squashed.
     if (layer->layoutObject()->isLayoutPart() || squashingLayer.layoutObject()->isLayoutPart())
-        return CompositingReasonSquashingLayoutPartIsDisallowed;
+        return SquashingDisallowedReasonSquashingLayoutPartIsDisallowed;
 
     if (layer->reflectionInfo())
-        return CompositingReasonSquashingReflectionIsDisallowed;
+        return SquashingDisallowedReasonSquashingReflectionIsDisallowed;
 
     if (squashingWouldExceedSparsityTolerance(layer, squashingState))
-        return CompositingReasonSquashingSparsityExceeded;
+        return SquashingDisallowedReasonSquashingSparsityExceeded;
 
     if (layer->layoutObject()->style()->hasBlendMode() || squashingLayer.layoutObject()->style()->hasBlendMode())
-        return CompositingReasonSquashingBlendingIsDisallowed;
+        return SquashingDisallowedReasonSquashingBlendingIsDisallowed;
 
     // FIXME: this is not efficient, since it walks up the tree. We should store these values on the CompositingInputsCache.
     if (layer->clippingContainer() != squashingLayer.clippingContainer() && !squashingLayer.compositedLayerMapping()->containingSquashedLayer(layer->clippingContainer(), squashingState.nextSquashedLayerIndex))
-        return CompositingReasonSquashingClippingContainerMismatch;
+        return SquashingDisallowedReasonClippingContainerMismatch;
 
     // Composited descendants need to be clipped by a child containment graphics layer, which would not be available if the layer is
     // squashed (and therefore has no CLM nor a child containment graphics layer).
     if (m_compositor->clipsCompositingDescendants(layer))
-        return CompositingReasonSquashedLayerClipsCompositingDescendants;
+        return SquashingDisallowedReasonSquashedLayerClipsCompositingDescendants;
 
     if (layer->scrollsWithRespectTo(&squashingLayer))
-        return CompositingReasonScrollsWithRespectToSquashingLayer;
+        return SquashingDisallowedReasonScrollsWithRespectToSquashingLayer;
 
     if (layer->scrollParent() && layer->hasCompositingDescendant())
-        return CompositingReasonScrollChildWithCompositedDescendants;
+        return SquashingDisallowedReasonScrollChildWithCompositedDescendants;
 
     if (layer->opacityAncestor() != squashingLayer.opacityAncestor())
-        return CompositingReasonSquashingOpacityAncestorMismatch;
+        return SquashingDisallowedReasonOpacityAncestorMismatch;
 
     if (layer->transformAncestor() != squashingLayer.transformAncestor())
-        return CompositingReasonSquashingTransformAncestorMismatch;
+        return SquashingDisallowedReasonTransformAncestorMismatch;
 
     if (layer->hasFilter() || layer->filterAncestor() != squashingLayer.filterAncestor())
-        return CompositingReasonSquashingFilterMismatch;
+        return SquashingDisallowedReasonFilterMismatch;
 
     if (layer->nearestFixedPositionLayer() != squashingLayer.nearestFixedPositionLayer())
-        return CompositingReasonSquashingNearestFixedPositionMismatch;
+        return SquashingDisallowedReasonNearestFixedPositionMismatch;
     ASSERT(layer->layoutObject()->style()->position() != FixedPosition);
 
     if ((squashingLayer.layoutObject()->style()->subtreeWillChangeContents() && squashingLayer.layoutObject()->style()->isRunningAnimationOnCompositor())
         || squashingLayer.layoutObject()->style()->shouldCompositeForCurrentAnimations())
-        return CompositingReasonSquashingLayerIsAnimating;
+        return SquashingDisallowedReasonSquashingLayerIsAnimating;
 
-    return CompositingReasonNone;
+    return SquashingDisallowedReasonsNone;
 }
 
 void CompositingLayerAssigner::updateSquashingAssignment(PaintLayer* layer, SquashingState& squashingState, const CompositingStateTransitionType compositedLayerUpdate,
@@ -248,9 +248,11 @@
 void CompositingLayerAssigner::assignLayersToBackingsInternal(PaintLayer* layer, SquashingState& squashingState, Vector<PaintLayer*>& layersNeedingPaintInvalidation)
 {
     if (requiresSquashing(layer->compositingReasons())) {
-        CompositingReasons reasonsPreventingSquashing = getReasonsPreventingSquashing(layer, squashingState);
-        if (reasonsPreventingSquashing)
-            layer->setCompositingReasons(layer->compositingReasons() | reasonsPreventingSquashing);
+        SquashingDisallowedReasons reasonsPreventingSquashing = getReasonsPreventingSquashing(layer, squashingState);
+        if (reasonsPreventingSquashing) {
+            layer->setCompositingReasons(layer->compositingReasons() | CompositingReasonSquashingDisallowed);
+            layer->setSquashingDisallowedReasons(reasonsPreventingSquashing);
+        }
     }
 
     CompositingStateTransitionType compositedLayerUpdate = computeCompositedLayerUpdate(layer);
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositingLayerAssigner.h b/third_party/WebKit/Source/core/layout/compositing/CompositingLayerAssigner.h
index 58eae24..a064eb2e 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositingLayerAssigner.h
+++ b/third_party/WebKit/Source/core/layout/compositing/CompositingLayerAssigner.h
@@ -30,6 +30,7 @@
 #include "core/layout/compositing/PaintLayerCompositor.h"
 #include "platform/geometry/IntRect.h"
 #include "platform/geometry/LayoutPoint.h"
+#include "platform/graphics/SquashingDisallowedReasons.h"
 #include "wtf/Allocator.h"
 
 namespace blink {
@@ -84,7 +85,7 @@
 
     void assignLayersToBackingsInternal(PaintLayer*, SquashingState&, Vector<PaintLayer*>& layersNeedingPaintInvalidation);
     void assignLayersToBackingsForReflectionLayer(PaintLayer* reflectionLayer, Vector<PaintLayer*>& layersNeedingPaintInvalidation);
-    CompositingReasons getReasonsPreventingSquashing(const PaintLayer*, const SquashingState&);
+    SquashingDisallowedReasons getReasonsPreventingSquashing(const PaintLayer*, const SquashingState&);
     bool squashingWouldExceedSparsityTolerance(const PaintLayer* candidate, const SquashingState&);
     void updateSquashingAssignment(PaintLayer*, SquashingState&, CompositingStateTransitionType, Vector<PaintLayer*>& layersNeedingPaintInvalidation);
     bool needsOwnBacking(const PaintLayer*) const;
diff --git a/third_party/WebKit/Source/core/layout/line/BreakingContext.cpp b/third_party/WebKit/Source/core/layout/line/BreakingContext.cpp
index 1b343f5..96d2e824 100644
--- a/third_party/WebKit/Source/core/layout/line/BreakingContext.cpp
+++ b/third_party/WebKit/Source/core/layout/line/BreakingContext.cpp
@@ -27,15 +27,15 @@
 
 InlineIterator BreakingContext::handleEndOfLine()
 {
-    if (m_lineBreak == m_resolver.position() && (!m_lineBreak.object() || !m_lineBreak.object().isBR())) {
+    if (m_lineBreak == m_resolver.position() && (!m_lineBreak.lineLayoutItem() || !m_lineBreak.lineLayoutItem().isBR())) {
         // we just add as much as possible
         if (m_blockStyle->whiteSpace() == PRE && !m_current.offset()) {
             m_lineBreak.moveTo(m_lastObject, m_lastObject.isText() ? m_lastObject.length() : 0);
-        } else if (m_lineBreak.object()) {
+        } else if (m_lineBreak.lineLayoutItem()) {
             // Don't ever break in the middle of a word if we can help it.
             // There's no room at all. We just have to be on this line,
             // even though we'll spill out.
-            m_lineBreak.moveTo(m_current.object(), m_current.offset());
+            m_lineBreak.moveTo(m_current.lineLayoutItem(), m_current.offset());
         }
     }
 
@@ -59,7 +59,7 @@
         do {
             m_lineBreak.setOffset(m_lineBreak.offset() - 1);
             m_lineBreak.increment();
-        } while (!m_lineBreak.atEnd() && isEmptyInline(m_lineBreak.object()));
+        } while (!m_lineBreak.atEnd() && isEmptyInline(m_lineBreak.lineLayoutItem()));
     }
 
     return m_lineBreak;
diff --git a/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h b/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h
index d8cb265..129bac52 100644
--- a/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h
+++ b/third_party/WebKit/Source/core/layout/line/BreakingContextInlineHeaders.h
@@ -58,7 +58,7 @@
         , m_current(resolver.position())
         , m_lineBreak(resolver.position())
         , m_block(block)
-        , m_lastObject(m_current.object())
+        , m_lastObject(m_current.lineLayoutItem())
         , m_nextObject(nullptr)
         , m_currentStyle(nullptr)
         , m_blockStyle(block.style())
@@ -86,7 +86,7 @@
         m_lineInfo.setPreviousLineBrokeCleanly(false);
     }
 
-    LayoutObject* currentObject() { return m_current.object(); }
+    LineLayoutItem currentItem() { return m_current.lineLayoutItem(); }
     InlineIterator lineBreak() { return m_lineBreak; }
     bool atEnd() { return m_atEnd; }
 
@@ -200,18 +200,18 @@
 
 inline bool requiresLineBox(const InlineIterator& it, const LineInfo& lineInfo = LineInfo(), WhitespacePosition whitespacePosition = LeadingWhitespace)
 {
-    if (it.object().isFloatingOrOutOfFlowPositioned())
+    if (it.lineLayoutItem().isFloatingOrOutOfFlowPositioned())
         return false;
 
-    if (it.object().isLayoutInline() && !alwaysRequiresLineBox(it.object()) && !requiresLineBoxForContent(LineLayoutInline(it.object()), lineInfo))
+    if (it.lineLayoutItem().isLayoutInline() && !alwaysRequiresLineBox(it.lineLayoutItem()) && !requiresLineBoxForContent(LineLayoutInline(it.lineLayoutItem()), lineInfo))
         return false;
 
-    if (!shouldCollapseWhiteSpace(it.object().styleRef(), lineInfo, whitespacePosition) || it.object().isBR())
+    if (!shouldCollapseWhiteSpace(it.lineLayoutItem().styleRef(), lineInfo, whitespacePosition) || it.lineLayoutItem().isBR())
         return true;
 
     UChar current = it.current();
-    bool notJustWhitespace = current != spaceCharacter && current != tabulationCharacter && current != softHyphenCharacter && (current != newlineCharacter || it.object().preservesNewline());
-    return notJustWhitespace || isEmptyInline(it.object());
+    bool notJustWhitespace = current != spaceCharacter && current != tabulationCharacter && current != softHyphenCharacter && (current != newlineCharacter || it.lineLayoutItem().preservesNewline());
+    return notJustWhitespace || isEmptyInline(it.lineLayoutItem());
 }
 
 inline void setStaticPositions(LineLayoutBlockFlow block, LineLayoutBox child, IndentTextOrNot indentText)
@@ -245,7 +245,7 @@
 inline void BreakingContext::skipTrailingWhitespace(InlineIterator& iterator, const LineInfo& lineInfo)
 {
     while (!iterator.atEnd() && !requiresLineBox(iterator, lineInfo, TrailingWhitespace)) {
-        LineLayoutItem item = iterator.object();
+        LineLayoutItem item = iterator.lineLayoutItem();
         if (item.isOutOfFlowPositioned())
             setStaticPositions(m_block, LineLayoutBox(item), DoNotIndentText);
         else if (item.isFloating())
@@ -256,15 +256,15 @@
 
 inline void BreakingContext::initializeForCurrentObject()
 {
-    m_currentStyle = m_current.object().style();
-    m_nextObject = bidiNextSkippingEmptyInlines(m_block, m_current.object());
-    if (m_nextObject && m_nextObject.parent() && !m_nextObject.parent().isDescendantOf(m_current.object().parent()))
+    m_currentStyle = m_current.lineLayoutItem().style();
+    m_nextObject = bidiNextSkippingEmptyInlines(m_block, m_current.lineLayoutItem());
+    if (m_nextObject && m_nextObject.parent() && !m_nextObject.parent().isDescendantOf(m_current.lineLayoutItem().parent()))
         m_includeEndWidth = true;
 
-    m_currWS = m_current.object().isLayoutInline() ? m_currentStyle->whiteSpace() : m_current.object().parent().style()->whiteSpace();
+    m_currWS = m_current.lineLayoutItem().isLayoutInline() ? m_currentStyle->whiteSpace() : m_current.lineLayoutItem().parent().style()->whiteSpace();
     m_lastWS = m_lastObject.isLayoutInline() ? m_lastObject.style()->whiteSpace() : m_lastObject.parent().style()->whiteSpace();
 
-    bool isSVGText = m_current.object().isSVGInlineText();
+    bool isSVGText = m_current.lineLayoutItem().isSVGInlineText();
     m_autoWrap = !isSVGText && ComputedStyle::autoWrap(m_currWS);
     m_autoWrapWasEverTrueOnLine = m_autoWrapWasEverTrueOnLine || m_autoWrap;
 
@@ -293,7 +293,7 @@
 inline void BreakingContext::handleBR(EClear& clear)
 {
     if (m_width.fitsOnLine()) {
-        LineLayoutItem br = m_current.object();
+        LineLayoutItem br = m_current.lineLayoutItem();
         m_lineBreak.moveToStartOf(br);
         m_lineBreak.increment();
 
@@ -362,7 +362,7 @@
 {
     // If our original display wasn't an inline type, then we can
     // go ahead and determine our static inline position now.
-    LineLayoutBox box(m_current.object());
+    LineLayoutBox box(m_current.lineLayoutItem());
     bool isInlineType = box.style()->isOriginalDisplayInlineType();
     if (!isInlineType) {
         m_block.setStaticInlinePositionForChild(box, m_block.startOffsetForContent());
@@ -388,7 +388,7 @@
 
 inline void BreakingContext::handleFloat()
 {
-    LineLayoutBox floatBox(m_current.object());
+    LineLayoutBox floatBox(m_current.lineLayoutItem());
     FloatingObject* floatingObject = m_block.insertFloatingObject(floatBox);
     // check if it fits in the current line.
     // If it does, position it now, otherwise, position
@@ -396,7 +396,7 @@
     // FIXME: Bug 110372: Properly position multiple stacked floats with non-rectangular shape outside.
     if (m_floatsFitOnLine && m_width.fitsOnLine(m_block.logicalWidthForFloat(*floatingObject).toFloat(), ExcludeWhitespace)) {
         m_block.positionNewFloatOnLine(*floatingObject, m_lastFloatFromPreviousLine, m_lineInfo, m_width);
-        if (m_lineBreak.object() == m_current.object()) {
+        if (m_lineBreak.lineLayoutItem() == m_current.lineLayoutItem()) {
             ASSERT(!m_lineBreak.offset());
             m_lineBreak.increment();
         }
@@ -433,11 +433,11 @@
 inline void BreakingContext::handleEmptyInline()
 {
     // This should only end up being called on empty inlines
-    ASSERT(m_current.object());
+    ASSERT(m_current.lineLayoutItem());
 
-    LineLayoutInline flowBox(m_current.object());
+    LineLayoutInline flowBox(m_current.lineLayoutItem());
 
-    bool requiresLineBox = alwaysRequiresLineBox(m_current.object());
+    bool requiresLineBox = alwaysRequiresLineBox(m_current.lineLayoutItem());
     if (requiresLineBox || requiresLineBoxForContent(flowBox, m_lineInfo)) {
         // An empty inline that only has line-height, vertical-align or font-metrics will
         // not force linebox creation (and thus affect the height of the line) if the rest of the line is empty.
@@ -447,9 +447,9 @@
             // If we are in a run of ignored spaces then ensure we get a linebox if lineboxes are eventually
             // created for the line...
             m_trailingObjects.clear();
-            ensureLineBoxInsideIgnoredSpaces(&m_lineMidpointState, m_current.object());
-        } else if (m_blockStyle->collapseWhiteSpace() && m_resolver.position().object() == m_current.object()
-            && shouldSkipWhitespaceAfterStartObject(m_block, m_current.object(), m_lineMidpointState)) {
+            ensureLineBoxInsideIgnoredSpaces(&m_lineMidpointState, m_current.lineLayoutItem());
+        } else if (m_blockStyle->collapseWhiteSpace() && m_resolver.position().lineLayoutItem() == m_current.lineLayoutItem()
+            && shouldSkipWhitespaceAfterStartObject(m_block, m_current.lineLayoutItem(), m_lineMidpointState)) {
             // If this object is at the start of the line, we need to behave like list markers and
             // start ignoring spaces.
             m_currentCharacterIsSpace = true;
@@ -457,30 +457,30 @@
         } else {
             // If we are after a trailing space but aren't ignoring spaces yet then ensure we get a linebox
             // if we encounter collapsible whitepace.
-            m_trailingObjects.appendObjectIfNeeded(m_current.object());
+            m_trailingObjects.appendObjectIfNeeded(m_current.lineLayoutItem());
         }
     }
 
-    m_width.addUncommittedWidth((inlineLogicalWidthFromAncestorsIfNeeded(m_current.object()) + borderPaddingMarginStart(flowBox) + borderPaddingMarginEnd(flowBox)).toFloat());
+    m_width.addUncommittedWidth((inlineLogicalWidthFromAncestorsIfNeeded(m_current.lineLayoutItem()) + borderPaddingMarginStart(flowBox) + borderPaddingMarginEnd(flowBox)).toFloat());
 }
 
 inline void BreakingContext::handleReplaced()
 {
-    LineLayoutBox replacedBox(m_current.object());
+    LineLayoutBox replacedBox(m_current.lineLayoutItem());
 
     if (m_atStart)
         m_width.updateAvailableWidth(replacedBox.logicalHeight());
 
     // Break on replaced elements if either has normal white-space,
     // or if the replaced element is ruby that can break before.
-    if ((m_autoWrap || ComputedStyle::autoWrap(m_lastWS)) && (!m_current.object().isImage() || m_allowImagesToBreak)
-        && (!m_current.object().isRubyRun() || toLayoutRubyRun(m_current.object())->canBreakBefore(m_layoutTextInfo.m_lineBreakIterator))) {
+    if ((m_autoWrap || ComputedStyle::autoWrap(m_lastWS)) && (!m_current.lineLayoutItem().isImage() || m_allowImagesToBreak)
+        && (!m_current.lineLayoutItem().isRubyRun() || LineLayoutRubyRun(m_current.lineLayoutItem()).canBreakBefore(m_layoutTextInfo.m_lineBreakIterator))) {
         m_width.commit();
-        m_lineBreak.moveToStartOf(m_current.object());
+        m_lineBreak.moveToStartOf(m_current.lineLayoutItem());
     }
 
     if (m_ignoringSpaces)
-        m_lineMidpointState.stopIgnoringSpaces(InlineIterator(0, m_current.object(), 0));
+        m_lineMidpointState.stopIgnoringSpaces(InlineIterator(0, m_current.lineLayoutItem(), 0));
 
     m_lineInfo.setEmpty(false, m_block, &m_width);
     m_ignoringSpaces = false;
@@ -489,21 +489,21 @@
 
     // Optimize for a common case. If we can't find whitespace after the list
     // item, then this is all moot.
-    LayoutUnit replacedLogicalWidth = m_block.logicalWidthForChild(replacedBox) + m_block.marginStartForChild(replacedBox) + m_block.marginEndForChild(replacedBox) + inlineLogicalWidthFromAncestorsIfNeeded(m_current.object());
-    if (m_current.object().isListMarker()) {
-        if (m_blockStyle->collapseWhiteSpace() && shouldSkipWhitespaceAfterStartObject(m_block, m_current.object(), m_lineMidpointState)) {
+    LayoutUnit replacedLogicalWidth = m_block.logicalWidthForChild(replacedBox) + m_block.marginStartForChild(replacedBox) + m_block.marginEndForChild(replacedBox) + inlineLogicalWidthFromAncestorsIfNeeded(m_current.lineLayoutItem());
+    if (m_current.lineLayoutItem().isListMarker()) {
+        if (m_blockStyle->collapseWhiteSpace() && shouldSkipWhitespaceAfterStartObject(m_block, m_current.lineLayoutItem(), m_lineMidpointState)) {
             // Like with inline flows, we start ignoring spaces to make sure that any
             // additional spaces we see will be discarded.
             m_currentCharacterIsSpace = true;
             m_ignoringSpaces = true;
         }
-        if (LineLayoutListMarker(m_current.object()).isInside())
+        if (LineLayoutListMarker(m_current.lineLayoutItem()).isInside())
             m_width.addUncommittedWidth(replacedLogicalWidth.toFloat());
     } else {
         m_width.addUncommittedWidth(replacedLogicalWidth.toFloat());
     }
-    if (m_current.object().isRubyRun())
-        m_width.applyOverhang(LineLayoutRubyRun(m_current.object()), m_lastObject, m_nextObject);
+    if (m_current.lineLayoutItem().isRubyRun())
+        m_width.applyOverhang(LineLayoutRubyRun(m_current.lineLayoutItem()), m_lastObject, m_nextObject);
     // Update prior line break context characters, using U+FFFD (OBJECT REPLACEMENT CHARACTER) for replaced element.
     m_layoutTextInfo.m_lineBreakIterator.updatePriorContext(replacementCharacter);
 }
@@ -545,13 +545,13 @@
     if (!m_current.offset())
         m_appliedStartWidth = false;
 
-    LineLayoutText layoutText(m_current.object());
+    LineLayoutText layoutText(m_current.lineLayoutItem());
 
     // If we have left a no-wrap inline and entered an autowrap inline while ignoring spaces
     // then we need to mark the start of the autowrap inline as a potential linebreak now.
     if (m_autoWrap && !ComputedStyle::autoWrap(m_lastWS) && m_ignoringSpaces) {
         m_width.commit();
-        m_lineBreak.moveToStartOf(m_current.object());
+        m_lineBreak.moveToStartOf(m_current.lineLayoutItem());
     }
 
     const ComputedStyle& style = layoutText.styleRef(m_lineInfo.isFirstLine());
@@ -588,7 +588,7 @@
 
     if (layoutText.isWordBreak()) {
         m_width.commit();
-        m_lineBreak.moveToStartOf(m_current.object());
+        m_lineBreak.moveToStartOf(m_current.lineLayoutItem());
         ASSERT(m_current.offset() == layoutText.textLength());
     }
 
@@ -686,7 +686,7 @@
         // For example: '<span style="margin-left: 5px;"><span style="margin-left: 10px;">FirstWord</span></span>' would
         // apply a width of 15px from the two span ancestors.
         if (!m_appliedStartWidth) {
-            m_width.addUncommittedWidth(inlineLogicalWidthFromAncestorsIfNeeded(m_current.object(), true, false).toFloat());
+            m_width.addUncommittedWidth(inlineLogicalWidthFromAncestorsIfNeeded(m_current.lineLayoutItem(), true, false).toFloat());
             m_appliedStartWidth = true;
         }
 
@@ -705,7 +705,7 @@
         if (c == newlineCharacter && m_preservesNewline) {
             if (!stoppedIgnoringSpaces && m_current.offset())
                 m_lineMidpointState.ensureCharacterGetsLineBox(m_current);
-            m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition());
+            m_lineBreak.moveTo(m_current.lineLayoutItem(), m_current.offset(), m_current.nextBreakablePosition());
             m_lineBreak.increment();
             m_lineInfo.setPreviousLineBrokeCleanly(true);
             return true;
@@ -716,14 +716,14 @@
         if (m_autoWrap && betweenWords) {
             m_width.commit();
             widthFromLastBreakingOpportunity = 0;
-            m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition());
+            m_lineBreak.moveTo(m_current.lineLayoutItem(), m_current.offset(), m_current.nextBreakablePosition());
             breakWords = false;
             widthMeasurementAtLastBreakOpportunity = lastWidthMeasurement;
         }
 
         // Remember this as a breakable position in case adding the end width forces a break.
         if (midWordBreak && !U16_IS_TRAIL(c) && !(WTF::Unicode::category(c) & (WTF::Unicode::Mark_NonSpacing | WTF::Unicode::Mark_Enclosing | WTF::Unicode::Mark_SpacingCombining))) {
-            m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition());
+            m_lineBreak.moveTo(m_current.lineLayoutItem(), m_current.offset(), m_current.nextBreakablePosition());
             midWordBreak &= (breakWords || breakAll);
         }
 
@@ -768,7 +768,7 @@
     }
     lastWidthMeasurement += lastSpaceWordSpacing;
 
-    LayoutUnit additionalWidthFromAncestors = inlineLogicalWidthFromAncestorsIfNeeded(m_current.object(), !m_appliedStartWidth, m_includeEndWidth);
+    LayoutUnit additionalWidthFromAncestors = inlineLogicalWidthFromAncestorsIfNeeded(m_current.lineLayoutItem(), !m_appliedStartWidth, m_includeEndWidth);
     m_width.addUncommittedWidth(lastWidthMeasurement + additionalWidthFromAncestors);
 
     if (m_collapseWhiteSpace && m_currentCharacterIsSpace && lastWidthMeasurement)
@@ -802,15 +802,15 @@
         prohibitBreakInside = false;
     }
     if (m_currentCharacterIsSpace && !previousCharacterIsSpace) {
-        m_startOfIgnoredSpaces.setObject(m_current.object());
+        m_startOfIgnoredSpaces.setLineLayoutItem(m_current.lineLayoutItem());
         m_startOfIgnoredSpaces.setOffset(m_current.offset());
     }
     if (!m_currentCharacterIsSpace && previousCharacterIsSpace) {
         if (m_autoWrap && m_currentStyle->breakOnlyAfterWhiteSpace())
-            m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition());
+            m_lineBreak.moveTo(m_current.lineLayoutItem(), m_current.offset(), m_current.nextBreakablePosition());
     }
     if (m_collapseWhiteSpace && m_currentCharacterIsSpace && !m_ignoringSpaces)
-        m_trailingObjects.setTrailingWhitespace(LineLayoutText(m_current.object()));
+        m_trailingObjects.setTrailingWhitespace(LineLayoutText(m_current.lineLayoutItem()));
     else if (!m_currentStyle->collapseWhiteSpace() || !m_currentCharacterIsSpace)
         m_trailingObjects.clear();
 }
@@ -820,7 +820,7 @@
 {
     m_ignoringSpaces = false;
     lastSpace = m_current.offset(); // e.g., "Foo    goo", don't add in any of the ignored spaces.
-    m_lineMidpointState.stopIgnoringSpaces(InlineIterator(0, m_current.object(), m_current.offset()));
+    m_lineMidpointState.stopIgnoringSpaces(InlineIterator(0, m_current.lineLayoutItem(), m_current.offset()));
 }
 
 inline WordMeasurement& BreakingContext::calculateWordWidth(WordMeasurements& wordMeasurements, LineLayoutText& layoutText, unsigned lastSpace, float& lastWidthMeasurement, float wordSpacingForWordMeasurement, const Font& font, float wordTrailingSpaceWidth, UChar c)
@@ -853,7 +853,7 @@
         // then move the line break to the space and skip all
         // additional whitespace.
         if (!m_width.fitsOnLine(charWidth)) {
-            m_lineBreak.moveTo(m_current.object(), m_current.offset(), m_current.nextBreakablePosition());
+            m_lineBreak.moveTo(m_current.lineLayoutItem(), m_current.offset(), m_current.nextBreakablePosition());
             skipTrailingWhitespace(m_lineBreak, m_lineInfo);
             return true;
         }
@@ -876,7 +876,7 @@
             m_lineInfo.setPreviousLineBrokeCleanly(true);
             wordMeasurement.endOffset = m_lineBreak.offset();
         }
-        if (m_lineBreak.object() && m_lineBreak.offset() && m_lineBreak.object().isText() && LineLayoutText(m_lineBreak.object()).textLength() && LineLayoutText(m_lineBreak.object()).characterAt(m_lineBreak.offset() - 1) == softHyphenCharacter)
+        if (m_lineBreak.lineLayoutItem() && m_lineBreak.offset() && m_lineBreak.lineLayoutItem().isText() && LineLayoutText(m_lineBreak.lineLayoutItem()).textLength() && LineLayoutText(m_lineBreak.lineLayoutItem()).characterAt(m_lineBreak.offset() - 1) == softHyphenCharacter)
             hyphenated = true;
         if (m_lineBreak.offset() && m_lineBreak.offset() != (unsigned)wordMeasurement.endOffset && !wordMeasurement.width) {
             if (charWidth) {
@@ -904,13 +904,13 @@
 inline void BreakingContext::commitAndUpdateLineBreakIfNeeded()
 {
     bool checkForBreak = m_autoWrap;
-    if (m_width.committedWidth() && !m_width.fitsOnLine() && m_lineBreak.object() && m_currWS == NOWRAP) {
+    if (m_width.committedWidth() && !m_width.fitsOnLine() && m_lineBreak.lineLayoutItem() && m_currWS == NOWRAP) {
         if (m_width.fitsOnLine(0, ExcludeWhitespace)) {
             m_width.commit();
             m_lineBreak.moveToStartOf(m_nextObject);
         }
         checkForBreak = true;
-    } else if (m_nextObject && m_current.object().isText() && m_nextObject.isText() && !m_nextObject.isBR() && (m_autoWrap || m_nextObject.style()->autoWrap())) {
+    } else if (m_nextObject && m_current.lineLayoutItem().isText() && m_nextObject.isText() && !m_nextObject.isBR() && (m_autoWrap || m_nextObject.style()->autoWrap())) {
         if (m_autoWrap && m_currentCharacterIsSpace) {
             checkForBreak = true;
         } else {
@@ -962,8 +962,8 @@
         m_width.fitBelowFloats(m_lineInfo.isFirstLine());
     }
 
-    if (!m_current.object().isFloatingOrOutOfFlowPositioned()) {
-        m_lastObject = m_current.object();
+    if (!m_current.lineLayoutItem().isFloatingOrOutOfFlowPositioned()) {
+        m_lastObject = m_current.lineLayoutItem();
         if (m_lastObject.isAtomicInlineLevel() && m_autoWrap && (!m_lastObject.isImage() || m_allowImagesToBreak) && (!m_lastObject.isListMarker() || LineLayoutListMarker(m_lastObject).isInside())
             && !m_lastObject.isRubyRun()) {
             m_width.commit();
diff --git a/third_party/WebKit/Source/core/layout/line/EllipsisBox.cpp b/third_party/WebKit/Source/core/layout/line/EllipsisBox.cpp
index 4cb7c30..ae1ed72 100644
--- a/third_party/WebKit/Source/core/layout/line/EllipsisBox.cpp
+++ b/third_party/WebKit/Source/core/layout/line/EllipsisBox.cpp
@@ -39,7 +39,7 @@
 {
     const ComputedStyle& style = lineLayoutItem().styleRef(isFirstLineStyle());
     const Font& font = style.font();
-    return enclosingIntRect(font.selectionRectForText(constructTextRun(font, m_str, style, TextRun::AllowTrailingExpansion), IntPoint(logicalLeft(), logicalTop() + root().selectionTopAdjustedForPrecedingBlock()), root().selectionHeightAdjustedForPrecedingBlock()));
+    return enclosingIntRect(font.selectionRectForText(constructTextRun(font, m_str, style, TextRun::AllowTrailingExpansion), IntPoint(logicalLeft(), logicalTop() + root().selectionTop()), root().selectionHeight()));
 }
 
 bool EllipsisBox::nodeAtPoint(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom)
diff --git a/third_party/WebKit/Source/core/layout/line/InlineIterator.h b/third_party/WebKit/Source/core/layout/line/InlineIterator.h
index fc408d55..b7953c92 100644
--- a/third_party/WebKit/Source/core/layout/line/InlineIterator.h
+++ b/third_party/WebKit/Source/core/layout/line/InlineIterator.h
@@ -34,7 +34,7 @@
 namespace blink {
 
 struct BidiIsolatedRun {
-    BidiIsolatedRun(LayoutObject& object, unsigned position, LayoutObject& root, BidiRun& runToReplace, unsigned char level)
+    BidiIsolatedRun(LineLayoutItem object, unsigned position, LineLayoutItem& root, BidiRun& runToReplace, unsigned char level)
         : object(object)
         , root(root)
         , runToReplace(runToReplace)
@@ -43,8 +43,8 @@
     {
     }
 
-    LayoutObject& object;
-    LayoutObject& root;
+    LineLayoutItem object;
+    LineLayoutItem root;
     BidiRun& runToReplace;
     unsigned position;
     unsigned char level;
@@ -64,7 +64,7 @@
 
     InlineIterator()
         : m_root(nullptr)
-        , m_obj(nullptr)
+        , m_lineLayoutItem(nullptr)
         , m_nextBreakablePosition(-1)
         , m_pos(0)
     {
@@ -72,7 +72,7 @@
 
     InlineIterator(LineLayoutItem root, LineLayoutItem o, unsigned p)
         : m_root(root)
-        , m_obj(o)
+        , m_lineLayoutItem(o)
         , m_nextBreakablePosition(-1)
         , m_pos(p)
     {
@@ -87,13 +87,13 @@
 
     void moveTo(LineLayoutItem object, unsigned offset, int nextBreak = -1)
     {
-        m_obj = object;
+        m_lineLayoutItem = object;
         m_pos = offset;
         m_nextBreakablePosition = nextBreak;
     }
 
-    LineLayoutItem object() const { return m_obj; }
-    void setObject(LineLayoutItem object) { m_obj = object; }
+    LineLayoutItem lineLayoutItem() const { return m_lineLayoutItem; }
+    void setLineLayoutItem(LineLayoutItem lineLayoutItem) { m_lineLayoutItem = lineLayoutItem; }
 
     int nextBreakablePosition() const { return m_nextBreakablePosition; }
     void setNextBreakablePosition(int position) { m_nextBreakablePosition = position; }
@@ -108,13 +108,13 @@
 
     inline bool atTextParagraphSeparator() const
     {
-        return m_obj && m_obj.preservesNewline() && m_obj.isText() && LineLayoutText(m_obj).textLength()
-            && !LineLayoutText(m_obj).isWordBreak() && LineLayoutText(m_obj).characterAt(m_pos) == '\n';
+        return m_lineLayoutItem && m_lineLayoutItem.preservesNewline() && m_lineLayoutItem.isText() && LineLayoutText(m_lineLayoutItem).textLength()
+            && !LineLayoutText(m_lineLayoutItem).isWordBreak() && LineLayoutText(m_lineLayoutItem).characterAt(m_pos) == '\n';
     }
 
     inline bool atParagraphSeparator() const
     {
-        return (m_obj && m_obj.isBR()) || atTextParagraphSeparator();
+        return (m_lineLayoutItem && m_lineLayoutItem.isBR()) || atTextParagraphSeparator();
     }
 
     UChar characterAt(unsigned) const;
@@ -124,7 +124,7 @@
 
 private:
     LineLayoutItem m_root;
-    LineLayoutItem m_obj;
+    LineLayoutItem m_lineLayoutItem;
 
     int m_nextBreakablePosition;
     unsigned m_pos;
@@ -132,12 +132,12 @@
 
 inline bool operator==(const InlineIterator& it1, const InlineIterator& it2)
 {
-    return it1.offset() == it2.offset() && it1.object() == it2.object();
+    return it1.offset() == it2.offset() && it1.lineLayoutItem() == it2.lineLayoutItem();
 }
 
 inline bool operator!=(const InlineIterator& it1, const InlineIterator& it2)
 {
-    return it1.offset() != it2.offset() || it1.object() != it2.object();
+    return it1.offset() != it2.offset() || it1.lineLayoutItem() != it2.lineLayoutItem();
 }
 
 static inline WTF::Unicode::CharDirection embedCharFromDirection(TextDirection dir, EUnicodeBidi unicodeBidi)
@@ -362,9 +362,9 @@
 
 inline void InlineIterator::fastIncrementInTextNode()
 {
-    ASSERT(m_obj);
-    ASSERT(m_obj.isText());
-    ASSERT(m_pos <= LineLayoutText(m_obj).textLength());
+    ASSERT(m_lineLayoutItem);
+    ASSERT(m_lineLayoutItem.isText());
+    ASSERT(m_pos <= LineLayoutText(m_lineLayoutItem).textLength());
     if (m_pos < INT_MAX)
         m_pos++;
 }
@@ -403,12 +403,12 @@
 
 static inline bool endOfLineHasIsolatedObjectAncestor(const InlineIterator& isolatedIterator, const InlineIterator& ancestorItertor)
 {
-    if (!isolatedIterator.object() || !treatAsIsolated(isolatedIterator.object().styleRef()))
+    if (!isolatedIterator.lineLayoutItem() || !treatAsIsolated(isolatedIterator.lineLayoutItem().styleRef()))
         return false;
 
-    LineLayoutItem innerIsolatedObject = isolatedIterator.object();
+    LineLayoutItem innerIsolatedObject = isolatedIterator.lineLayoutItem();
     while (innerIsolatedObject && innerIsolatedObject != isolatedIterator.root()) {
-        if (innerIsolatedObject == ancestorItertor.object())
+        if (innerIsolatedObject == ancestorItertor.lineLayoutItem())
             return true;
         innerIsolatedObject = innerIsolatedObject.parent();
     }
@@ -417,36 +417,36 @@
 
 inline void InlineIterator::increment(InlineBidiResolver* resolver, IncrementRule rule)
 {
-    if (!m_obj)
+    if (!m_lineLayoutItem)
         return;
 
     if (rule == FastIncrementInIsolatedLayout
         && resolver && resolver->inIsolate()
         && !endOfLineHasIsolatedObjectAncestor(resolver->endOfLine(), resolver->position())) {
-        moveTo(bidiNextSkippingEmptyInlines(m_root, m_obj, resolver), 0);
+        moveTo(bidiNextSkippingEmptyInlines(m_root, m_lineLayoutItem, resolver), 0);
         return;
     }
 
-    if (m_obj.isText()) {
+    if (m_lineLayoutItem.isText()) {
         fastIncrementInTextNode();
-        if (m_pos < LineLayoutText(m_obj).textLength())
+        if (m_pos < LineLayoutText(m_lineLayoutItem).textLength())
             return;
     }
     // bidiNext can return 0, so use moveTo instead of moveToStartOf
-    moveTo(bidiNextSkippingEmptyInlines(m_root, m_obj, resolver), 0);
+    moveTo(bidiNextSkippingEmptyInlines(m_root, m_lineLayoutItem, resolver), 0);
 }
 
 inline bool InlineIterator::atEnd() const
 {
-    return !m_obj;
+    return !m_lineLayoutItem;
 }
 
 inline UChar InlineIterator::characterAt(unsigned index) const
 {
-    if (!m_obj || !m_obj.isText())
+    if (!m_lineLayoutItem || !m_lineLayoutItem.isText())
         return 0;
 
-    return LineLayoutText(m_obj).characterAt(index);
+    return LineLayoutText(m_lineLayoutItem).characterAt(index);
 }
 
 inline UChar InlineIterator::current() const
@@ -467,8 +467,8 @@
     if (UChar c = current())
         return WTF::Unicode::direction(c);
 
-    if (m_obj && m_obj.isListMarker())
-        return m_obj.style()->isLeftToRightDirection() ? WTF::Unicode::LeftToRight : WTF::Unicode::RightToLeft;
+    if (m_lineLayoutItem && m_lineLayoutItem.isListMarker())
+        return m_lineLayoutItem.style()->isLeftToRightDirection() ? WTF::Unicode::LeftToRight : WTF::Unicode::RightToLeft;
 
     return WTF::Unicode::OtherNeutral;
 }
@@ -482,9 +482,9 @@
 template <>
 inline bool InlineBidiResolver::isEndOfLine(const InlineIterator& end)
 {
-    bool inEndOfLine = m_current == end || m_current.atEnd() || (inIsolate() && m_current.object() == end.object());
+    bool inEndOfLine = m_current == end || m_current.atEnd() || (inIsolate() && m_current.lineLayoutItem() == end.lineLayoutItem());
     if (inIsolate() && inEndOfLine) {
-        m_current.moveTo(m_current.object(), end.offset(), m_current.nextBreakablePosition());
+        m_current.moveTo(m_current.lineLayoutItem(), end.offset(), m_current.nextBreakablePosition());
         m_last = m_current;
         updateStatusLastFromCurrentDirection(WTF::Unicode::OtherNeutral);
     }
@@ -518,7 +518,7 @@
 inline int InlineBidiResolver::findFirstTrailingSpaceAtRun(BidiRun* run)
 {
     ASSERT(run);
-    LineLayoutItem lastObject = LineLayoutItem(run->m_object);
+    LineLayoutItem lastObject = LineLayoutItem(run->m_lineLayoutItem);
     if (!lastObject.isText())
         return run->m_stop;
 
@@ -534,7 +534,7 @@
 template <>
 inline BidiRun* InlineBidiResolver::addTrailingRun(BidiRunList<BidiRun>& runs, int start, int stop, BidiRun* run, BidiContext* context, TextDirection direction) const
 {
-    BidiRun* newTrailingRun = new BidiRun(start, stop, run->m_object, context, WTF::Unicode::OtherNeutral);
+    BidiRun* newTrailingRun = new BidiRun(start, stop, run->m_lineLayoutItem, context, WTF::Unicode::OtherNeutral);
     if (direction == LTR)
         runs.addRun(newTrailingRun);
     else
@@ -546,8 +546,8 @@
 template <>
 inline bool InlineBidiResolver::needsToApplyL1Rule(BidiRunList<BidiRun>& runs)
 {
-    if (!runs.logicallyLastRun()->m_object->style()->breakOnlyAfterWhiteSpace()
-        || !runs.logicallyLastRun()->m_object->style()->autoWrap())
+    if (!runs.logicallyLastRun()->m_lineLayoutItem.style()->breakOnlyAfterWhiteSpace()
+        || !runs.logicallyLastRun()->m_lineLayoutItem.style()->autoWrap())
         return false;
     return true;
 }
@@ -561,10 +561,10 @@
 static inline LineLayoutItem highestContainingIsolateWithinRoot(LineLayoutItem object, LineLayoutItem root)
 {
     ASSERT(object);
-    LineLayoutItem containingIsolateObj = 0;
+    LineLayoutItem containingIsolateObj(nullptr);
     while (object && object != root) {
         if (isIsolatedInline(object))
-            containingIsolateObj = object;
+            containingIsolateObj = LineLayoutItem(object);
 
         object = object.parent();
         ASSERT(object);
@@ -574,7 +574,7 @@
 
 static inline unsigned numberOfIsolateAncestors(const InlineIterator& iter)
 {
-    LineLayoutItem object = iter.object();
+    LineLayoutItem object = iter.lineLayoutItem();
     if (!object)
         return 0;
     unsigned count = 0;
@@ -595,7 +595,7 @@
     resolver.runs().addRun(isolatedRun);
     // FIXME: isolatedRuns() could be a hash of object->run and then we could cheaply
     // ASSERT here that we didn't create multiple objects for the same inline.
-    resolver.isolatedRuns().append(BidiIsolatedRun(*obj, pos, *root, *isolatedRun, resolver.context()->level()));
+    resolver.isolatedRuns().append(BidiIsolatedRun(obj, pos, root, *isolatedRun, resolver.context()->level()));
     return isolatedRun;
 }
 
@@ -696,7 +696,7 @@
     if (haveNextMidpoint)
         nextMidpoint = lineMidpointState.midpoints()[lineMidpointState.currentMidpoint()];
     if (lineMidpointState.betweenMidpoints()) {
-        if (!(haveNextMidpoint && nextMidpoint.object() == obj))
+        if (!(haveNextMidpoint && nextMidpoint.lineLayoutItem() == obj))
             return;
         // This is a new start point. Stop ignoring objects and
         // adjust our start.
@@ -706,7 +706,7 @@
         if (start < end)
             return adjustMidpointsAndAppendRunsForObjectIfNeeded(obj, start, end, root, resolver, behavior, tracker);
     } else {
-        if (!haveNextMidpoint || (obj != nextMidpoint.object())) {
+        if (!haveNextMidpoint || (obj != nextMidpoint.lineLayoutItem())) {
             appendRunObjectIfNecessary(obj, start, end, root, resolver, behavior, tracker);
             return;
         }
@@ -742,8 +742,8 @@
         // FIXME: Could this initialize from this->inIsolate() instead of walking up the layout tree?
         IsolateTracker isolateTracker(runs, numberOfIsolateAncestors(m_sor));
         int start = m_sor.offset();
-        LineLayoutItem obj = m_sor.object();
-        while (obj && obj != m_eor.object() && obj != m_endOfRunAtEndOfLine.object()) {
+        LineLayoutItem obj = m_sor.lineLayoutItem();
+        while (obj && obj != m_eor.lineLayoutItem() && obj != m_endOfRunAtEndOfLine.lineLayoutItem()) {
             if (isolateTracker.inIsolate())
                 addFakeRunIfNecessary(obj, start, obj.length(), m_sor.root(), *this, isolateTracker);
             else
@@ -752,10 +752,10 @@
             start = 0;
             obj = bidiNextSkippingEmptyInlines(m_sor.root(), obj, &isolateTracker);
         }
-        bool isEndOfLine = obj == m_endOfLine.object() && !m_endOfLine.offset();
+        bool isEndOfLine = obj == m_endOfLine.lineLayoutItem() && !m_endOfLine.offset();
         if (obj && !isEndOfLine) {
-            unsigned pos = obj == m_eor.object() ? m_eor.offset() : INT_MAX;
-            if (obj == m_endOfRunAtEndOfLine.object() && m_endOfRunAtEndOfLine.offset() <= pos) {
+            unsigned pos = obj == m_eor.lineLayoutItem() ? m_eor.offset() : INT_MAX;
+            if (obj == m_endOfRunAtEndOfLine.lineLayoutItem() && m_endOfRunAtEndOfLine.offset() <= pos) {
                 m_reachedEndOfLine = true;
                 pos = m_endOfRunAtEndOfLine.offset();
             }
@@ -771,7 +771,7 @@
             m_reachedEndOfLine = true;
         // If isolateTrack is inIsolate, the next |start of run| can not be the current isolated layoutObject.
         if (isolateTracker.inIsolate())
-            m_eor.moveTo(bidiNextSkippingEmptyInlines(m_eor.root(), m_eor.object()), 0);
+            m_eor.moveTo(bidiNextSkippingEmptyInlines(m_eor.root(), m_eor.lineLayoutItem()), 0);
         else
             m_eor.increment();
         m_sor = m_eor;
diff --git a/third_party/WebKit/Source/core/layout/line/LineBreaker.cpp b/third_party/WebKit/Source/core/layout/line/LineBreaker.cpp
index c120161..952ca52 100644
--- a/third_party/WebKit/Source/core/layout/line/LineBreaker.cpp
+++ b/third_party/WebKit/Source/core/layout/line/LineBreaker.cpp
@@ -30,7 +30,7 @@
     FloatingObject* lastFloatFromPreviousLine, LineWidth& width)
 {
     while (!resolver.position().atEnd() && !requiresLineBox(resolver.position(), lineInfo, LeadingWhitespace)) {
-        LayoutObject* object = resolver.position().object();
+        LayoutObject* object = resolver.position().lineLayoutItem();
         if (object->isOutOfFlowPositioned()) {
             setStaticPositions(m_block, LineLayoutBox(toLayoutBox(object)), width.indentText());
             if (object->style()->isOriginalDisplayInlineType()) {
@@ -71,19 +71,19 @@
 
     BreakingContext context(resolver, lineInfo, width, layoutTextInfo, lastFloatFromPreviousLine, appliedStartWidth, m_block);
 
-    while (context.currentObject()) {
+    while (context.currentItem()) {
         context.initializeForCurrentObject();
-        if (context.currentObject()->isBR()) {
+        if (context.currentItem().isBR()) {
             context.handleBR(m_clear);
-        } else if (context.currentObject()->isOutOfFlowPositioned()) {
+        } else if (context.currentItem().isOutOfFlowPositioned()) {
             context.handleOutOfFlowPositioned(m_positionedObjects);
-        } else if (context.currentObject()->isFloating()) {
+        } else if (context.currentItem().isFloating()) {
             context.handleFloat();
-        } else if (context.currentObject()->isLayoutInline()) {
+        } else if (context.currentItem().isLayoutInline()) {
             context.handleEmptyInline();
-        } else if (context.currentObject()->isAtomicInlineLevel()) {
+        } else if (context.currentItem().isAtomicInlineLevel()) {
             context.handleReplaced();
-        } else if (context.currentObject()->isText()) {
+        } else if (context.currentItem().isText()) {
             if (context.handleText(wordMeasurements, m_hyphenated)) {
                 // We've hit a hard text line break. Our line break iterator is updated, so go ahead and early return.
                 return context.lineBreak();
diff --git a/third_party/WebKit/Source/core/layout/line/RootInlineBox.cpp b/third_party/WebKit/Source/core/layout/line/RootInlineBox.cpp
index 42205c2..3014b52 100644
--- a/third_party/WebKit/Source/core/layout/line/RootInlineBox.cpp
+++ b/third_party/WebKit/Source/core/layout/line/RootInlineBox.cpp
@@ -378,31 +378,6 @@
     return prevBottom;
 }
 
-LayoutUnit RootInlineBox::selectionTopAdjustedForPrecedingBlock() const
-{
-    LayoutUnit top = selectionTop();
-
-    SelectionState blockSelectionState = root().block().selectionState();
-    if (blockSelectionState != SelectionInside && blockSelectionState != SelectionEnd)
-        return top;
-
-    LayoutSize offsetToBlockBefore;
-    if (LayoutBlock* block = root().block().blockBeforeWithinSelectionRoot(offsetToBlockBefore)) {
-        if (block->isLayoutBlockFlow()) {
-            if (RootInlineBox* lastLine = toLayoutBlockFlow(block)->lastRootBox()) {
-                SelectionState lastLineSelectionState = lastLine->selectionState();
-                if (lastLineSelectionState != SelectionInside && lastLineSelectionState != SelectionStart)
-                    return top;
-
-                LayoutUnit lastLineSelectionBottom = lastLine->selectionBottom() + offsetToBlockBefore.height();
-                top = std::max(top, lastLineSelectionBottom);
-            }
-        }
-    }
-
-    return top;
-}
-
 LayoutUnit RootInlineBox::selectionBottom() const
 {
     LayoutUnit selectionBottom = lineLayoutItem().document().inNoQuirksMode() ? m_selectionBottom : m_lineBottom;
diff --git a/third_party/WebKit/Source/core/layout/line/RootInlineBox.h b/third_party/WebKit/Source/core/layout/line/RootInlineBox.h
index 9fc46278..5836f6b 100644
--- a/third_party/WebKit/Source/core/layout/line/RootInlineBox.h
+++ b/third_party/WebKit/Source/core/layout/line/RootInlineBox.h
@@ -64,9 +64,6 @@
     LayoutUnit selectionBottom() const;
     LayoutUnit selectionHeight() const { return (selectionBottom() - selectionTop()).clampNegativeToZero(); }
 
-    LayoutUnit selectionTopAdjustedForPrecedingBlock() const;
-    LayoutUnit selectionHeightAdjustedForPrecedingBlock() const { return (selectionBottom() - selectionTopAdjustedForPrecedingBlock()).clampNegativeToZero(); }
-
     LayoutUnit blockDirectionPointInLine() const;
 
     LayoutUnit alignBoxesInBlockDirection(LayoutUnit heightOfBlock, GlyphOverflowAndFallbackFontsMap&, VerticalPositionCache&);
diff --git a/third_party/WebKit/Source/core/layout/line/TrailingObjects.cpp b/third_party/WebKit/Source/core/layout/line/TrailingObjects.cpp
index 255cf9a..ce01138 100644
--- a/third_party/WebKit/Source/core/layout/line/TrailingObjects.cpp
+++ b/third_party/WebKit/Source/core/layout/line/TrailingObjects.cpp
@@ -39,7 +39,7 @@
     if (lineMidpointState.numMidpoints() % 2) {
         // Find the trailing space object's midpoint.
         int trailingSpaceMidpoint = lineMidpointState.numMidpoints() - 1;
-        for ( ; trailingSpaceMidpoint > 0 && lineMidpointState.midpoints()[trailingSpaceMidpoint].object() != m_whitespace; --trailingSpaceMidpoint) { }
+        for ( ; trailingSpaceMidpoint > 0 && lineMidpointState.midpoints()[trailingSpaceMidpoint].lineLayoutItem() != m_whitespace; --trailingSpaceMidpoint) { }
         ASSERT(trailingSpaceMidpoint >= 0);
         if (collapseFirstSpace == CollapseFirstSpace)
             lineMidpointState.midpoints()[trailingSpaceMidpoint].setOffset(lineMidpointState.midpoints()[trailingSpaceMidpoint].offset() -1);
@@ -52,12 +52,12 @@
                 // We don't have a midpoint for this box yet.
                 ensureLineBoxInsideIgnoredSpaces(&lineMidpointState, LineLayoutItem(m_objects[i]));
             } else {
-                ASSERT(lineMidpointState.midpoints()[currentMidpoint].object() == m_objects[i]);
-                ASSERT(lineMidpointState.midpoints()[currentMidpoint + 1].object() == m_objects[i]);
+                ASSERT(lineMidpointState.midpoints()[currentMidpoint].lineLayoutItem() == m_objects[i]);
+                ASSERT(lineMidpointState.midpoints()[currentMidpoint + 1].lineLayoutItem() == m_objects[i]);
             }
             currentMidpoint += 2;
         }
-    } else if (!lBreak.object()) {
+    } else if (!lBreak.lineLayoutItem()) {
         ASSERT(collapseFirstSpace == CollapseFirstSpace);
         // Add a new end midpoint that stops right at the very end.
         unsigned length = m_whitespace.textLength();
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp
index 468b99a..1ce2aa4 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp
@@ -278,8 +278,8 @@
         return LayoutReplaced::positionForPoint(point);
 
     LayoutObject* layoutObject = closestDescendant;
-    AffineTransform transform = closestDescendant->localToParentTransform();
-    transform.translate(toLayoutSVGText(closestDescendant)->location().x(), toLayoutSVGText(closestDescendant)->location().y());
+    AffineTransform transform = layoutObject->localToParentTransform();
+    transform.translate(toLayoutSVGText(layoutObject)->location().x(), toLayoutSVGText(layoutObject)->location().y());
     while (layoutObject) {
         layoutObject = layoutObject->parent();
         if (layoutObject->isSVGRoot())
diff --git a/third_party/WebKit/Source/core/loader/LinkLoader.cpp b/third_party/WebKit/Source/core/loader/LinkLoader.cpp
index 7730c2c8..680c2ee25 100644
--- a/third_party/WebKit/Source/core/loader/LinkLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/LinkLoader.cpp
@@ -168,23 +168,26 @@
     }
 }
 
-Resource::Type LinkLoader::getTypeFromAsAttribute(const String& as, Document* document)
+bool LinkLoader::getResourceTypeFromAsAttribute(const String& as, Resource::Type& type)
 {
-    if (equalIgnoringCase(as, "image"))
-        return Resource::Image;
-    if (equalIgnoringCase(as, "script"))
-        return Resource::Script;
-    if (equalIgnoringCase(as, "style"))
-        return Resource::CSSStyleSheet;
-    if (equalIgnoringCase(as, "audio") || equalIgnoringCase(as, "video"))
-        return Resource::Media;
-    if (equalIgnoringCase(as, "font"))
-        return Resource::Font;
-    if (equalIgnoringCase(as, "track"))
-        return Resource::TextTrack;
-    if (document && !as.isEmpty())
-        document->addConsoleMessage(ConsoleMessage::create(OtherMessageSource, WarningMessageLevel, String("<link rel=preload> must have a valid `as` value")));
-    return Resource::LinkPreload;
+    if (equalIgnoringCase(as, "image")) {
+        type = Resource::Image;
+    } else if (equalIgnoringCase(as, "script")) {
+        type = Resource::Script;
+    } else if (equalIgnoringCase(as, "style")) {
+        type = Resource::CSSStyleSheet;
+    } else if (equalIgnoringCase(as, "audio") || equalIgnoringCase(as, "video")) {
+        type = Resource::Media;
+    } else if (equalIgnoringCase(as, "font")) {
+        type = Resource::Font;
+    } else if (equalIgnoringCase(as, "track")) {
+        type = Resource::TextTrack;
+    } else {
+        type = Resource::LinkPreload;
+        if (!as.isEmpty())
+            return false;
+    }
+    return true;
 }
 
 void LinkLoader::createLinkPreloadResourceClient(Resource* resource)
@@ -215,7 +218,7 @@
     }
 }
 
-static Resource* preloadIfNeeded(const LinkRelAttribute& relAttribute, const KURL& href, Document& document, const String& as, CrossOriginAttributeValue crossOrigin, LinkCaller caller)
+static Resource* preloadIfNeeded(const LinkRelAttribute& relAttribute, const KURL& href, Document& document, const String& as, CrossOriginAttributeValue crossOrigin, LinkCaller caller, bool& errorOccurred)
 {
     if (!document.loader() || !relAttribute.isLinkPreload())
         return nullptr;
@@ -228,7 +231,13 @@
     }
     if (caller == LinkCalledFromHeader)
         UseCounter::count(document, UseCounter::LinkHeaderPreload);
-    Resource::Type type = LinkLoader::getTypeFromAsAttribute(as, &document);
+    Resource::Type type;
+    if (!LinkLoader::getResourceTypeFromAsAttribute(as, type)) {
+        document.addConsoleMessage(ConsoleMessage::create(OtherMessageSource, WarningMessageLevel, String("<link rel=preload> must have a valid `as` value")));
+        errorOccurred = true;
+        return nullptr;
+    }
+
     ResourceRequest resourceRequest(document.completeURL(href));
     ResourceFetcher::determineRequestContext(resourceRequest, type, false);
     FetchRequest linkRequest(resourceRequest, FetchInitiatorTypeNames::link);
@@ -263,8 +272,9 @@
                 preconnectIfNeeded(relAttribute, url, *document, header.crossOrigin(), networkHintsInterface, LinkCalledFromHeader);
         }
         if (canLoadResources != DoNotLoadResources) {
+            bool errorOccurred = false;
             if (RuntimeEnabledFeatures::linkPreloadEnabled())
-                preloadIfNeeded(relAttribute, url, *document, header.as(), header.crossOrigin(), LinkCalledFromHeader);
+                preloadIfNeeded(relAttribute, url, *document, header.as(), header.crossOrigin(), LinkCalledFromHeader, errorOccurred);
         }
         // TODO(yoav): Add more supported headers as needed.
     }
@@ -281,8 +291,11 @@
 
     preconnectIfNeeded(relAttribute, href, document, crossOrigin, networkHintsInterface, LinkCalledFromMarkup);
 
+    bool errorOccurred = false;
     if (m_client->shouldLoadLink())
-        createLinkPreloadResourceClient(preloadIfNeeded(relAttribute, href, document, as, crossOrigin, LinkCalledFromMarkup));
+        createLinkPreloadResourceClient(preloadIfNeeded(relAttribute, href, document, as, crossOrigin, LinkCalledFromMarkup, errorOccurred));
+    if (errorOccurred)
+        m_linkLoadingErrorTimer.startOneShot(0, BLINK_FROM_HERE);
 
     if (href.isEmpty() || !href.isValid())
         released();
diff --git a/third_party/WebKit/Source/core/loader/LinkLoader.h b/third_party/WebKit/Source/core/loader/LinkLoader.h
index 6a0a6003..7b1d9e3 100644
--- a/third_party/WebKit/Source/core/loader/LinkLoader.h
+++ b/third_party/WebKit/Source/core/loader/LinkLoader.h
@@ -76,7 +76,7 @@
     bool loadLink(const LinkRelAttribute&, CrossOriginAttributeValue, const String& type, const String& as, const KURL&, Document&, const NetworkHintsInterface&);
     enum CanLoadResources { OnlyLoadResources, DoNotLoadResources, LoadResourcesAndPreconnect };
     static bool loadLinkFromHeader(const String& headerValue, const KURL& baseURL, Document*, const NetworkHintsInterface&, CanLoadResources);
-    static Resource::Type getTypeFromAsAttribute(const String& as, Document*);
+    static bool getResourceTypeFromAsAttribute(const String& as, Resource::Type&);
 
     DECLARE_TRACE();
 
diff --git a/third_party/WebKit/Source/core/loader/LinkLoaderTest.cpp b/third_party/WebKit/Source/core/loader/LinkLoaderTest.cpp
index e1244a6..c9c705b 100644
--- a/third_party/WebKit/Source/core/loader/LinkLoaderTest.cpp
+++ b/third_party/WebKit/Source/core/loader/LinkLoaderTest.cpp
@@ -102,7 +102,7 @@
         {"data://example.test/cat.woff", "font", ResourceLoadPriorityMedium, WebURLRequest::RequestContextFont, true, ""},
         // TODO(yoav): subresource should be *very* low priority (rather than low).
         {"data://example.test/cat.empty", "", ResourceLoadPriorityLow, WebURLRequest::RequestContextSubresource, true, ""},
-        {"data://example.test/cat.blob", "blabla", ResourceLoadPriorityLow, WebURLRequest::RequestContextSubresource, true, ""},
+        {"data://example.test/cat.blob", "blabla", ResourceLoadPriorityLow, WebURLRequest::RequestContextSubresource, false, ""},
         {"bla://example.test/cat.gif", "image", ResourceLoadPriorityUnresolved, WebURLRequest::RequestContextImage, false, ""},
     };
 
diff --git a/third_party/WebKit/Source/core/loader/appcache/ApplicationCache.cpp b/third_party/WebKit/Source/core/loader/appcache/ApplicationCache.cpp
index f76fbe11..84db691b 100644
--- a/third_party/WebKit/Source/core/loader/appcache/ApplicationCache.cpp
+++ b/third_party/WebKit/Source/core/loader/appcache/ApplicationCache.cpp
@@ -29,7 +29,10 @@
 #include "core/dom/Document.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/events/EventListener.h"
+#include "core/frame/Deprecation.h"
 #include "core/frame/LocalFrame.h"
+#include "core/frame/OriginsUsingFeatures.h"
+#include "core/frame/UseCounter.h"
 #include "core/loader/DocumentLoader.h"
 #include "core/loader/FrameLoader.h"
 
@@ -65,6 +68,7 @@
 
 unsigned short ApplicationCache::status() const
 {
+    recordAPIUseType();
     ApplicationCacheHost* cacheHost = applicationCacheHost();
     if (!cacheHost)
         return ApplicationCacheHost::UNCACHED;
@@ -73,6 +77,7 @@
 
 void ApplicationCache::update(ExceptionState& exceptionState)
 {
+    recordAPIUseType();
     ApplicationCacheHost* cacheHost = applicationCacheHost();
     if (!cacheHost || !cacheHost->update())
         exceptionState.throwDOMException(InvalidStateError, "there is no application cache to update.");
@@ -80,6 +85,7 @@
 
 void ApplicationCache::swapCache(ExceptionState& exceptionState)
 {
+    recordAPIUseType();
     ApplicationCacheHost* cacheHost = applicationCacheHost();
     if (!cacheHost || !cacheHost->swapCache())
         exceptionState.throwDOMException(InvalidStateError, "there is no newer application cache to swap to.");
@@ -128,4 +134,24 @@
     return EventTypeNames::error;
 }
 
+void ApplicationCache::recordAPIUseType() const
+{
+    if (!m_frame)
+        return;
+
+    Document* document = m_frame->document();
+
+    if (!document)
+        return;
+
+    if (document->isSecureContext()) {
+        UseCounter::count(document, UseCounter::ApplicationCacheAPISecureOrigin);
+        UseCounter::countCrossOriginIframe(*document, UseCounter::ApplicationCacheAPISecureOrigin);
+    } else {
+        Deprecation::countDeprecation(document, UseCounter::ApplicationCacheAPIInsecureOrigin);
+        UseCounter::countCrossOriginIframe(*document, UseCounter::ApplicationCacheAPIInsecureOrigin);
+        OriginsUsingFeatures::countAnyWorld(*document, OriginsUsingFeatures::Feature::ApplicationCacheAPIInsecureOrigin);
+    }
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/appcache/ApplicationCache.h b/third_party/WebKit/Source/core/loader/appcache/ApplicationCache.h
index c889831..032800b 100644
--- a/third_party/WebKit/Source/core/loader/appcache/ApplicationCache.h
+++ b/third_party/WebKit/Source/core/loader/appcache/ApplicationCache.h
@@ -83,6 +83,8 @@
 private:
     explicit ApplicationCache(LocalFrame*);
 
+    void recordAPIUseType() const;
+
     ApplicationCacheHost* applicationCacheHost() const;
 };
 
diff --git a/third_party/WebKit/Source/core/loader/appcache/ApplicationCacheHost.cpp b/third_party/WebKit/Source/core/loader/appcache/ApplicationCacheHost.cpp
index ad70de0..fb2e8a71 100644
--- a/third_party/WebKit/Source/core/loader/appcache/ApplicationCacheHost.cpp
+++ b/third_party/WebKit/Source/core/loader/appcache/ApplicationCacheHost.cpp
@@ -33,8 +33,11 @@
 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
 #include "core/events/ApplicationCacheErrorEvent.h"
 #include "core/events/ProgressEvent.h"
+#include "core/frame/Deprecation.h"
 #include "core/frame/LocalFrame.h"
+#include "core/frame/OriginsUsingFeatures.h"
 #include "core/frame/Settings.h"
+#include "core/frame/UseCounter.h"
 #include "core/inspector/InspectorApplicationCacheAgent.h"
 #include "core/inspector/InspectorInstrumentation.h"
 #include "core/loader/DocumentLoader.h"
@@ -115,14 +118,25 @@
 
 void ApplicationCacheHost::selectCacheWithManifest(const KURL& manifestURL)
 {
+    DCHECK(m_documentLoader);
+
+    LocalFrame* frame = m_documentLoader->frame();
+    Document* document = frame->document();
+    if (document->isSecureContext()) {
+        UseCounter::count(document, UseCounter::ApplicationCacheManifestSelectSecureOrigin);
+        UseCounter::countCrossOriginIframe(*document, UseCounter::ApplicationCacheManifestSelectSecureOrigin);
+    } else {
+        Deprecation::countDeprecation(document, UseCounter::ApplicationCacheManifestSelectInsecureOrigin);
+        UseCounter::countCrossOriginIframe(*document, UseCounter::ApplicationCacheManifestSelectInsecureOrigin);
+        OriginsUsingFeatures::countAnyWorld(*document, OriginsUsingFeatures::Feature::ApplicationCacheManifestSelectInsecureOrigin);
+    }
     if (m_host && !m_host->selectCacheWithManifest(manifestURL)) {
         // It's a foreign entry, restart the current navigation from the top
         // of the navigation algorithm. The navigation will not result in the
         // same resource being loaded, because "foreign" entries are never picked
         // during navigation.
         // see ApplicationCacheGroup::selectCache()
-        LocalFrame* frame = m_documentLoader->frame();
-        frame->navigate(*frame->document(), frame->document()->url(), true, UserGestureStatus::None);
+        frame->navigate(*document, document->url(), true, UserGestureStatus::None);
     }
 }
 
diff --git a/third_party/WebKit/Source/core/page/EventSourceTest.cpp b/third_party/WebKit/Source/core/page/EventSourceTest.cpp
deleted file mode 100644
index 221a463..0000000
--- a/third_party/WebKit/Source/core/page/EventSourceTest.cpp
+++ /dev/null
@@ -1,446 +0,0 @@
-// Copyright 2016 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 "core/page/EventSource.h"
-
-#include "bindings/core/v8/ExceptionState.h"
-#include "bindings/core/v8/ScriptState.h"
-#include "bindings/core/v8/ScriptValue.h"
-#include "bindings/core/v8/SerializedScriptValue.h"
-#include "bindings/core/v8/V8Binding.h"
-#include "core/dom/ExecutionContext.h"
-#include "core/dom/MessagePort.h"
-#include "core/events/Event.h"
-#include "core/events/EventListener.h"
-#include "core/events/MessageEvent.h"
-#include "core/loader/MockThreadableLoader.h"
-#include "core/page/EventSourceInit.h"
-#include "core/testing/DummyPageHolder.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/text/CharacterNames.h"
-
-#include <string.h>
-#include <v8.h>
-
-namespace blink {
-
-namespace {
-
-String dataAsString(ScriptState* scriptState, MessageEvent* event)
-{
-    ScriptState::Scope scope(scriptState);
-    v8::Isolate* isolate = scriptState->isolate();
-    ASSERT(MessageEvent::DataTypeSerializedScriptValue == event->dataType());
-    if (!event->dataAsSerializedScriptValue())
-        return String();
-    MessagePortArray ports = event->ports();
-    NonThrowableExceptionState es;
-    return toUSVString(isolate, event->dataAsSerializedScriptValue()->deserialize(isolate, &ports), es);
-}
-
-class FakeEventListener : public EventListener {
-public:
-    static PassRefPtrWillBeRawPtr<FakeEventListener> create()
-    {
-        return adoptRefWillBeNoop(new FakeEventListener());
-    }
-    bool operator==(const EventListener& x) const override { return &x == this; }
-    const WillBeHeapVector<RefPtrWillBeMember<Event>>& events() { return m_events; }
-    void handleEvent(ExecutionContext* executionContext, Event* event)
-    {
-        m_events.append(event);
-    }
-    DEFINE_INLINE_TRACE()
-    {
-        visitor->trace(m_events);
-        EventListener::trace(visitor);
-    }
-
-protected:
-    FakeEventListener() : EventListener(EventListener::CPPEventListenerType) {}
-    WillBeHeapVector<RefPtrWillBeMember<Event>> m_events;
-};
-
-class EventSourceTest : public ::testing::Test {
-protected:
-    EventSourceTest()
-        : m_page(DummyPageHolder::create())
-        , m_source(EventSource::create(&document(), "https://localhost/", EventSourceInit(), m_exceptionState))
-    {
-        source()->setStateForTest(EventSource::OPEN);
-        source()->setThreadableLoaderForTest(MockThreadableLoader::create());
-        source()->setParser(new EventSourceParser("https://localhost/", source()));
-        source()->setRequestInFlightForTest(true);
-    }
-    ~EventSourceTest() override
-    {
-        source()->setThreadableLoaderForTest(nullptr);
-        source()->close();
-
-        // We need this because there is
-        // listener -> event -> source -> listener
-        // reference cycle on non-oilpan build.
-        m_source->removeAllEventListeners();
-        m_source = nullptr;
-    }
-
-    void enqueue(const char* data) { client()->didReceiveData(data, strlen(data)); }
-    void enqueueOneByOne(const char* data)
-    {
-        const char*p = data;
-        while (*p != '\0')
-            client()->didReceiveData(p++, 1);
-    }
-
-    Document& document() { return m_page->document(); }
-    ScriptState* scriptState() { return ScriptState::forMainWorld(document().frame()); }
-    EventSource* source() { return m_source; }
-    ThreadableLoaderClient* client() { return m_source->asThreadableLoaderClientForTest(); }
-
-private:
-    OwnPtr<DummyPageHolder> m_page;
-    NonThrowableExceptionState m_exceptionState;
-    Persistent<EventSource> m_source;
-};
-
-TEST_F(EventSourceTest, EmptyMessageEventShouldNotBeDispatched)
-{
-    RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create();
-
-    source()->addEventListener("message", listener);
-    enqueue("\n");
-
-    EXPECT_EQ(0u, listener->events().size());
-}
-
-TEST_F(EventSourceTest, DispatchSimpleMessageEvent)
-{
-    RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create();
-
-    source()->addEventListener("message", listener);
-    enqueue("data:hello\n\n");
-
-    ASSERT_EQ(1u, listener->events().size());
-    ASSERT_EQ("message", listener->events()[0]->type());
-    RefPtrWillBeRawPtr<MessageEvent> event = static_cast<MessageEvent*>(listener->events()[0].get());
-    ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event->dataType());
-    EXPECT_EQ("hello", dataAsString(scriptState(), event.get()));
-    EXPECT_EQ(String(), event->lastEventId());
-}
-
-TEST_F(EventSourceTest, DispatchMessageEventWithLastEventId)
-{
-    RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create();
-
-    source()->addEventListener("message", listener);
-    enqueue("id:99\ndata:hello\n\n");
-
-    ASSERT_EQ(1u, listener->events().size());
-    ASSERT_EQ("message", listener->events()[0]->type());
-    RefPtrWillBeRawPtr<MessageEvent> event = static_cast<MessageEvent*>(listener->events()[0].get());
-    ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event->dataType());
-    EXPECT_EQ("hello", dataAsString(scriptState(), event.get()));
-    EXPECT_EQ("99", event->lastEventId());
-}
-
-TEST_F(EventSourceTest, DispatchMessageEventWithCustomEventType)
-{
-    RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create();
-
-    source()->addEventListener("foo", listener);
-    enqueue("event:foo\ndata:hello\n\n");
-
-    ASSERT_EQ(1u, listener->events().size());
-    ASSERT_EQ("foo", listener->events()[0]->type());
-    RefPtrWillBeRawPtr<MessageEvent> event = static_cast<MessageEvent*>(listener->events()[0].get());
-    ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event->dataType());
-    EXPECT_EQ("hello", dataAsString(scriptState(), event.get()));
-}
-
-TEST_F(EventSourceTest, RetryTakesEffectEvenWhenNotDispatching)
-{
-    RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create();
-
-    source()->addEventListener("message", listener);
-    ASSERT_NE(999u, EventSource::defaultReconnectDelay);
-
-    EXPECT_EQ(EventSource::defaultReconnectDelay, source()->reconnectDelayForTest());
-    enqueue("retry:999\n");
-    EXPECT_EQ(999u, source()->reconnectDelayForTest());
-    EXPECT_EQ(0u, listener->events().size());
-}
-
-TEST_F(EventSourceTest, EventTypeShouldBeReset)
-{
-    RefPtrWillBeRawPtr<FakeEventListener> fooListener = FakeEventListener::create();
-    RefPtrWillBeRawPtr<FakeEventListener> messageListener = FakeEventListener::create();
-
-    source()->addEventListener("foo", fooListener);
-    source()->addEventListener("message", messageListener);
-    enqueue("event:foo\ndata:hello\n\ndata:bye\n\n");
-
-    ASSERT_EQ(1u, fooListener->events().size());
-    ASSERT_EQ("foo", fooListener->events()[0]->type());
-    RefPtrWillBeRawPtr<MessageEvent> fooEvent = static_cast<MessageEvent*>(fooListener->events()[0].get());
-    ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, fooEvent->dataType());
-    EXPECT_EQ("hello", dataAsString(scriptState(), fooEvent.get()));
-
-    ASSERT_EQ(1u, messageListener->events().size());
-    ASSERT_EQ("message", messageListener->events()[0]->type());
-    RefPtrWillBeRawPtr<MessageEvent> messageEvent = static_cast<MessageEvent*>(messageListener->events()[0].get());
-    ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, messageEvent->dataType());
-    EXPECT_EQ("bye", dataAsString(scriptState(), messageEvent.get()));
-}
-
-TEST_F(EventSourceTest, DataShouldBeReset)
-{
-    RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create();
-
-    source()->addEventListener("message", listener);
-    enqueue("data:hello\n\n\n");
-
-    ASSERT_EQ(1u, listener->events().size());
-    ASSERT_EQ("message", listener->events()[0]->type());
-    RefPtrWillBeRawPtr<MessageEvent> event = static_cast<MessageEvent*>(listener->events()[0].get());
-    ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event->dataType());
-    EXPECT_EQ("hello", dataAsString(scriptState(), event.get()));
-}
-
-TEST_F(EventSourceTest, LastEventIdShouldNotBeReset)
-{
-    RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create();
-
-    source()->addEventListener("message", listener);
-    enqueue("id:99\ndata:hello\n\ndata:bye\n\n");
-
-    ASSERT_EQ(2u, listener->events().size());
-
-    ASSERT_EQ("message", listener->events()[0]->type());
-    RefPtrWillBeRawPtr<MessageEvent> event0 = static_cast<MessageEvent*>(listener->events()[0].get());
-    ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event0->dataType());
-    EXPECT_EQ("hello", dataAsString(scriptState(), event0.get()));
-    EXPECT_EQ("99", event0->lastEventId());
-
-    ASSERT_EQ("message", listener->events()[1]->type());
-    RefPtrWillBeRawPtr<MessageEvent> event1 = static_cast<MessageEvent*>(listener->events()[1].get());
-    ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event1->dataType());
-    EXPECT_EQ("bye", dataAsString(scriptState(), event1.get()));
-    EXPECT_EQ("99", event1->lastEventId());
-}
-
-TEST_F(EventSourceTest, VariousNewLinesShouldBeAllowed)
-{
-    RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create();
-
-    source()->addEventListener("message", listener);
-    enqueueOneByOne("data:hello\r\n\rdata:bye\r\r");
-
-    ASSERT_EQ(2u, listener->events().size());
-
-    ASSERT_EQ("message", listener->events()[0]->type());
-    RefPtrWillBeRawPtr<MessageEvent> event0 = static_cast<MessageEvent*>(listener->events()[0].get());
-    ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event0->dataType());
-    EXPECT_EQ("hello", dataAsString(scriptState(), event0.get()));
-
-    ASSERT_EQ("message", listener->events()[1]->type());
-    RefPtrWillBeRawPtr<MessageEvent> event1 = static_cast<MessageEvent*>(listener->events()[1].get());
-    ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event1->dataType());
-    EXPECT_EQ("bye", dataAsString(scriptState(), event1.get()));
-}
-
-TEST_F(EventSourceTest, RetryWithEmptyValueShouldRestoreDefaultValue)
-{
-    // TODO(yhirano): This is unspecified in the spec. We need to update
-    // the implementation or the spec.
-    EXPECT_EQ(EventSource::defaultReconnectDelay, source()->reconnectDelayForTest());
-    enqueue("retry: 12\n");
-    EXPECT_NE(EventSource::defaultReconnectDelay, source()->reconnectDelayForTest());
-    enqueue("retry\n");
-    EXPECT_EQ(EventSource::defaultReconnectDelay, source()->reconnectDelayForTest());
-}
-
-TEST_F(EventSourceTest, NonDigitRetryShouldBeIgnored)
-{
-    RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create();
-
-    source()->addEventListener("message", listener);
-
-    EXPECT_EQ(EventSource::defaultReconnectDelay, source()->reconnectDelayForTest());
-    enqueue("retry:123\n");
-    EXPECT_NE(EventSource::defaultReconnectDelay, source()->reconnectDelayForTest());
-    EXPECT_EQ(123u, source()->reconnectDelayForTest());
-
-    enqueue("retry:a0\n");
-    EXPECT_EQ(123u, source()->reconnectDelayForTest());
-    enqueue("retry:xi\n");
-    EXPECT_EQ(123u, source()->reconnectDelayForTest());
-
-    enqueue("retry:2a\n");
-    EXPECT_EQ(123u, source()->reconnectDelayForTest());
-
-    enqueue("retry:09a\n");
-    EXPECT_EQ(123u, source()->reconnectDelayForTest());
-
-    enqueue("retry:1\b\n");
-    EXPECT_EQ(123u, source()->reconnectDelayForTest());
-
-    enqueue("retry:  1234\n");
-    EXPECT_EQ(123u, source()->reconnectDelayForTest());
-
-    enqueue("retry:456 \n");
-    EXPECT_EQ(123u, source()->reconnectDelayForTest());
-
-    EXPECT_EQ(0u, listener->events().size());
-}
-
-TEST_F(EventSourceTest, UnrecognizedFieldShouldBeIgnored)
-{
-    RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create();
-
-    source()->addEventListener("message", listener);
-    enqueue("data:hello\nhoge:fuga\npiyo\n\n");
-
-    ASSERT_EQ(1u, listener->events().size());
-    ASSERT_EQ("message", listener->events()[0]->type());
-    RefPtrWillBeRawPtr<MessageEvent> event = static_cast<MessageEvent*>(listener->events()[0].get());
-    ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event->dataType());
-    EXPECT_EQ("hello", dataAsString(scriptState(), event.get()));
-}
-
-TEST_F(EventSourceTest, CommentShouldBeIgnored)
-{
-    RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create();
-
-    source()->addEventListener("message", listener);
-    enqueue("data:hello\n:event:a\n\n");
-
-    ASSERT_EQ(1u, listener->events().size());
-
-    ASSERT_EQ("message", listener->events()[0]->type());
-    RefPtrWillBeRawPtr<MessageEvent> event0 = static_cast<MessageEvent*>(listener->events()[0].get());
-    ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event0->dataType());
-    EXPECT_EQ("hello", dataAsString(scriptState(), event0.get()));
-}
-
-TEST_F(EventSourceTest, BOMShouldBeIgnored)
-{
-    RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create();
-
-    source()->addEventListener("message", listener);
-    enqueue("\xef\xbb\xbf" "data:hello\n\n");
-
-    ASSERT_EQ(1u, listener->events().size());
-
-    ASSERT_EQ("message", listener->events()[0]->type());
-    RefPtrWillBeRawPtr<MessageEvent> event0 = static_cast<MessageEvent*>(listener->events()[0].get());
-    ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event0->dataType());
-    EXPECT_EQ("hello", dataAsString(scriptState(), event0.get()));
-}
-
-TEST_F(EventSourceTest, ColonlessLineShouldBeTreatedAsNameOnlyField)
-{
-    RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create();
-
-    source()->addEventListener("message", listener);
-    enqueue("data:hello\nevent:a\nevent\n\n");
-
-    ASSERT_EQ(1u, listener->events().size());
-
-    ASSERT_EQ("message", listener->events()[0]->type());
-    RefPtrWillBeRawPtr<MessageEvent> event0 = static_cast<MessageEvent*>(listener->events()[0].get());
-    ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event0->dataType());
-    EXPECT_EQ("hello", dataAsString(scriptState(), event0.get()));
-}
-
-TEST_F(EventSourceTest, AtMostOneLeadingSpaceCanBeSkipped)
-{
-    RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create();
-
-    source()->addEventListener(" type ", listener);
-    enqueue("data:  hello  \nevent:  type \n\n");
-
-    ASSERT_EQ(1u, listener->events().size());
-    ASSERT_EQ(" type ", listener->events()[0]->type());
-    RefPtrWillBeRawPtr<MessageEvent> event = static_cast<MessageEvent*>(listener->events()[0].get());
-    ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event->dataType());
-    EXPECT_EQ(" hello  ", dataAsString(scriptState(), event.get()));
-}
-
-TEST_F(EventSourceTest, DataShouldAccumulate)
-{
-    RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create();
-
-    source()->addEventListener("message", listener);
-    enqueue("data:hello\ndata: world\ndata\n\n");
-
-    ASSERT_EQ(1u, listener->events().size());
-    ASSERT_EQ("message", listener->events()[0]->type());
-    RefPtrWillBeRawPtr<MessageEvent> event = static_cast<MessageEvent*>(listener->events()[0].get());
-    ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event->dataType());
-    EXPECT_EQ("hello\nworld\n", dataAsString(scriptState(), event.get()));
-}
-
-TEST_F(EventSourceTest, EventShouldNotAccumulate)
-{
-    RefPtrWillBeRawPtr<FakeEventListener> aListener = FakeEventListener::create();
-    RefPtrWillBeRawPtr<FakeEventListener> bListener = FakeEventListener::create();
-
-    source()->addEventListener("a", aListener);
-    source()->addEventListener("b", bListener);
-    enqueue("data:hello\nevent:a\nevent:b\n\n");
-
-    ASSERT_EQ(0u, aListener->events().size());
-    ASSERT_EQ(1u, bListener->events().size());
-    ASSERT_EQ("b", bListener->events()[0]->type());
-    RefPtrWillBeRawPtr<MessageEvent> event = static_cast<MessageEvent*>(bListener->events()[0].get());
-    ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event->dataType());
-    EXPECT_EQ("hello", dataAsString(scriptState(), event.get()));
-}
-
-TEST_F(EventSourceTest, FeedDataOneByOne)
-{
-    RefPtrWillBeRawPtr<FakeEventListener> aListener = FakeEventListener::create();
-    RefPtrWillBeRawPtr<FakeEventListener> bListener = FakeEventListener::create();
-    RefPtrWillBeRawPtr<FakeEventListener> messageListener = FakeEventListener::create();
-
-    source()->addEventListener("a", aListener);
-    source()->addEventListener("b", bListener);
-    source()->addEventListener("message", messageListener);
-    enqueueOneByOne("data:hello\r\ndata:world\revent:a\revent:b\nid:4\n\nid:8\ndata:bye\r\n\r");
-
-    ASSERT_EQ(0u, aListener->events().size());
-
-    ASSERT_EQ(1u, bListener->events().size());
-    ASSERT_EQ("b", bListener->events()[0]->type());
-    RefPtrWillBeRawPtr<MessageEvent> bEvent = static_cast<MessageEvent*>(bListener->events()[0].get());
-    ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, bEvent->dataType());
-    EXPECT_EQ("hello\nworld", dataAsString(scriptState(), bEvent.get()));
-    EXPECT_EQ("4", bEvent->lastEventId());
-
-    ASSERT_EQ(1u, messageListener->events().size());
-    ASSERT_EQ("message", messageListener->events()[0]->type());
-    RefPtrWillBeRawPtr<MessageEvent> messageEvent = static_cast<MessageEvent*>(messageListener->events()[0].get());
-    ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, messageEvent->dataType());
-    EXPECT_EQ("bye", dataAsString(scriptState(), messageEvent.get()));
-    EXPECT_EQ("8", messageEvent->lastEventId());
-}
-
-TEST_F(EventSourceTest, InvalidUTF8Sequence)
-{
-    RefPtrWillBeRawPtr<FakeEventListener> listener = FakeEventListener::create();
-
-    source()->addEventListener("message", listener);
-    enqueue("data:\xffhello\xc2\n\n");
-
-    ASSERT_EQ(1u, listener->events().size());
-    ASSERT_EQ("message", listener->events()[0]->type());
-    RefPtrWillBeRawPtr<MessageEvent> event = static_cast<MessageEvent*>(listener->events()[0].get());
-    ASSERT_EQ(MessageEvent::DataTypeSerializedScriptValue, event->dataType());
-    String expected = String() + replacementCharacter + "hello" + replacementCharacter;
-    EXPECT_EQ(expected, dataAsString(scriptState(), event.get()));
-}
-
-} // namespace
-
-} // namespace blink
diff --git a/third_party/WebKit/Source/core/page/FocusController.cpp b/third_party/WebKit/Source/core/page/FocusController.cpp
index b01d38e..11067ff 100644
--- a/third_party/WebKit/Source/core/page/FocusController.cpp
+++ b/third_party/WebKit/Source/core/page/FocusController.cpp
@@ -538,7 +538,10 @@
         return nullptr;
     if (node->isElementNode())
         return toElement(node);
-    return (type == WebFocusTypeForward) ? ElementTraversal::next(*node) : ElementTraversal::previous(*node);
+    // The returned element is used as an *exclusive* start element. Thus, we should return the result of ElementTraversal::previous(*node),
+    // instead of ElementTraversal::next(*node), if type == WebFocusTypeForward, and vice-versa.
+    // The caller will call ElementTraversal::{next/previous} for the returned value and get the {next|previous} element of the |node|.
+    return (type == WebFocusTypeForward) ? ElementTraversal::previous(*node) : ElementTraversal::next(*node);
 }
 
 } // anonymous namespace
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
index dcdb913..5b625b8 100644
--- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
@@ -687,10 +687,15 @@
         return;
     if (WebLayer* scrollLayer = toWebLayer(m_page->deprecatedLocalMainFrame()->view()->layerForScrolling())) {
         m_lastMainThreadScrollingReasons = mainThreadScrollingReasons;
-        if (mainThreadScrollingReasons)
+        if (mainThreadScrollingReasons) {
             scrollLayer->addMainThreadScrollingReasons(mainThreadScrollingReasons);
-        else
-            scrollLayer->clearMainThreadScrollingReasons();
+        } else {
+            // Clear all main thread scrolling reasons except the one that's set
+            // if there is a running scroll animation.
+            uint32_t mainThreadScrollingReasonsToClear = ~0u;
+            mainThreadScrollingReasonsToClear &= ~MainThreadScrollingReason::kAnimatingScrollOnMainThread;
+            scrollLayer->clearMainThreadScrollingReasons(mainThreadScrollingReasonsToClear);
+        }
     }
 }
 
@@ -1033,6 +1038,8 @@
         stringBuilder.appendLiteral("Has non-layer viewport-constrained objects, ");
     if (reasons & MainThreadScrollingReason::kThreadedScrollingDisabled)
         stringBuilder.appendLiteral("Threaded scrolling is disabled, ");
+    if (reasons & MainThreadScrollingReason::kAnimatingScrollOnMainThread)
+        stringBuilder.appendLiteral("Animating scroll on main thread, ");
 
     if (stringBuilder.length())
         stringBuilder.resize(stringBuilder.length() - 2);
@@ -1042,6 +1049,9 @@
 String ScrollingCoordinator::mainThreadScrollingReasonsAsText() const
 {
     ASSERT(m_page->deprecatedLocalMainFrame()->document()->lifecycle().state() >= DocumentLifecycle::CompositingClean);
+    if (WebLayer* scrollLayer = toWebLayer(m_page->deprecatedLocalMainFrame()->view()->layerForScrolling()))
+        return mainThreadScrollingReasonsAsText(scrollLayer->mainThreadScrollingReasons());
+
     return mainThreadScrollingReasonsAsText(m_lastMainThreadScrollingReasons);
 }
 
diff --git a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
index b0f1fd1e..f1c52bb0 100644
--- a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
@@ -481,7 +481,7 @@
     }
 
     LayoutUnit selectionBottom = m_inlineTextBox.root().selectionBottom();
-    LayoutUnit selectionTop = m_inlineTextBox.root().selectionTopAdjustedForPrecedingBlock();
+    LayoutUnit selectionTop = m_inlineTextBox.root().selectionTop();
 
     int deltaY = roundToInt(m_inlineTextBox.lineLayoutItem().style()->isFlippedLinesWritingMode() ? selectionBottom - m_inlineTextBox.logicalBottom() : m_inlineTextBox.logicalTop() - selectionTop);
     int selHeight = std::max(0, roundToInt(selectionBottom - selectionTop));
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
index 439349d..6c78b42 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -124,6 +124,7 @@
     : enclosingPaginationLayer(nullptr)
     , potentialCompositingReasonsFromStyle(CompositingReasonNone)
     , compositingReasons(CompositingReasonNone)
+    , squashingDisallowedReasons(SquashingDisallowedReasonsNone)
     , groupedMapping(nullptr)
 {
 }
@@ -1032,6 +1033,15 @@
         ensureRareData().compositingReasons = newReasons;
 }
 
+void PaintLayer::setSquashingDisallowedReasons(SquashingDisallowedReasons reasons)
+{
+    SquashingDisallowedReasons oldReasons = m_rareData ? m_rareData->squashingDisallowedReasons : SquashingDisallowedReasonsNone;
+    if (oldReasons == reasons)
+        return;
+    if (m_rareData || reasons != SquashingDisallowedReasonsNone)
+        ensureRareData().squashingDisallowedReasons = reasons;
+}
+
 void PaintLayer::setHasCompositingDescendant(bool hasCompositingDescendant)
 {
     if (m_hasCompositingDescendant == static_cast<unsigned>(hasCompositingDescendant))
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.h b/third_party/WebKit/Source/core/paint/PaintLayer.h
index 3932a00..473f458 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.h
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.h
@@ -57,6 +57,7 @@
 #include "core/paint/PaintLayerStackingNode.h"
 #include "core/paint/PaintLayerStackingNodeIterator.h"
 #include "platform/graphics/CompositingReasons.h"
+#include "platform/graphics/SquashingDisallowedReasons.h"
 #include "public/platform/WebBlendMode.h"
 #include "wtf/Allocator.h"
 #include "wtf/OwnPtr.h"
@@ -117,6 +118,10 @@
     // Once computed, indicates all that a layer needs to become composited using the CompositingReasons enum bitfield.
     CompositingReasons compositingReasons;
 
+    // This captures reasons why a paint layer might be forced to be separately
+    // composited rather than sharing a backing with another layer.
+    SquashingDisallowedReasons squashingDisallowedReasons;
+
     // If the layer paints into its own backings, this keeps track of the backings.
     // It's nullptr if the layer is not composited or paints into grouped backing.
     OwnPtr<CompositedLayerMapping> compositedLayerMapping;
@@ -590,6 +595,9 @@
     CompositingReasons compositingReasons() const { ASSERT(isAllowedToQueryCompositingState()); return m_rareData ? m_rareData->compositingReasons : CompositingReasonNone; }
     void setCompositingReasons(CompositingReasons, CompositingReasons mask = CompositingReasonAll);
 
+    SquashingDisallowedReasons squashingDisallowedReasons() const { ASSERT(isAllowedToQueryCompositingState()); return m_rareData ? m_rareData->squashingDisallowedReasons : SquashingDisallowedReasonsNone; }
+    void setSquashingDisallowedReasons(SquashingDisallowedReasons);
+
     bool hasCompositingDescendant() const { ASSERT(isAllowedToQueryCompositingState()); return m_hasCompositingDescendant; }
     void setHasCompositingDescendant(bool);
 
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerPainterTest.cpp b/third_party/WebKit/Source/core/paint/PaintLayerPainterTest.cpp
index 6db7ba21..a1fb8fe 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerPainterTest.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerPainterTest.cpp
@@ -361,4 +361,35 @@
     EXPECT_TRUE(displayItemListContains(rootPaintController().displayItemList(), backgroundDiv, DisplayItem::BoxDecorationBackground));
 }
 
+TEST_P(PaintLayerPainterTest, PaintPhasesUpdateOnLayerRemoval)
+{
+    setBodyInnerHTML(
+        "<div id='layer' style='opacity: 0.5'>"
+        "  <div style='height: 100px'>"
+        "    <div style='height: 20px; outline: 1px solid red; background-color: green'>outline and background</div>"
+        "    <div style='float: left'>float</div>"
+        "  </div>"
+        "</div>");
+
+    LayoutBlock& layerDiv = *toLayoutBlock(document().getElementById("layer")->layoutObject());
+    PaintLayer& layer = *layerDiv.layer();
+    ASSERT_TRUE(layer.isSelfPaintingLayer());
+    EXPECT_TRUE(layer.needsPaintPhaseDescendantOutlines());
+    EXPECT_TRUE(layer.needsPaintPhaseFloat());
+    EXPECT_TRUE(layer.needsPaintPhaseDescendantBlockBackgrounds());
+
+    PaintLayer& htmlLayer = *toLayoutBlock(document().documentElement()->layoutObject())->layer();
+    EXPECT_FALSE(htmlLayer.needsPaintPhaseDescendantOutlines());
+    EXPECT_FALSE(htmlLayer.needsPaintPhaseFloat());
+    EXPECT_FALSE(htmlLayer.needsPaintPhaseDescendantBlockBackgrounds());
+
+    toHTMLElement(layerDiv.node())->setAttribute(HTMLNames::styleAttr, "opacity: 1");
+    document().view()->updateAllLifecyclePhases();
+
+    EXPECT_FALSE(layerDiv.hasLayer());
+    EXPECT_TRUE(htmlLayer.needsPaintPhaseDescendantOutlines());
+    EXPECT_TRUE(htmlLayer.needsPaintPhaseFloat());
+    EXPECT_TRUE(htmlLayer.needsPaintPhaseDescendantBlockBackgrounds());
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
index feba660..ba2878b 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
@@ -1080,8 +1080,7 @@
             m_scrollCorner = LayoutScrollbarPart::createAnonymous(&box().document());
             m_scrollCorner->setDangerousOneWayParent(&box());
         }
-        m_scrollCorner->adjustStyleBeforeSet(corner.get());
-        m_scrollCorner->setStyle(corner.release());
+        m_scrollCorner->setStyleWithWritingModeOfParent(corner.release());
     } else if (m_scrollCorner) {
         m_scrollCorner->destroy();
         m_scrollCorner = nullptr;
@@ -1209,8 +1208,7 @@
             m_resizer = LayoutScrollbarPart::createAnonymous(&box().document());
             m_resizer->setDangerousOneWayParent(&box());
         }
-        m_resizer->adjustStyleBeforeSet(resizer.get());
-        m_resizer->setStyle(resizer.release());
+        m_resizer->setStyleWithWritingModeOfParent(resizer.release());
     } else if (m_resizer) {
         m_resizer->destroy();
         m_resizer = nullptr;
diff --git a/third_party/WebKit/Source/core/paint/TextPainterTest.cpp b/third_party/WebKit/Source/core/paint/TextPainterTest.cpp
index 1321af8..0c11eb4 100644
--- a/third_party/WebKit/Source/core/paint/TextPainterTest.cpp
+++ b/third_party/WebKit/Source/core/paint/TextPainterTest.cpp
@@ -84,7 +84,7 @@
     EXPECT_EQ(1, textStyle.shadow->shadows()[0].x());
     EXPECT_EQ(2, textStyle.shadow->shadows()[0].y());
     EXPECT_EQ(3, textStyle.shadow->shadows()[0].blur());
-    EXPECT_EQ(Color(255, 255, 0), textStyle.shadow->shadows()[0].color().color());
+    EXPECT_EQ(Color(255, 255, 0), textStyle.shadow->shadows()[0].color().getColor());
 }
 
 TEST_F(TextPainterTest, TextPaintingStyle_UsesTextAsClip)
diff --git a/third_party/WebKit/Source/core/paint/ThemePainter.cpp b/third_party/WebKit/Source/core/paint/ThemePainter.cpp
index b965883..51b1d78 100644
--- a/third_party/WebKit/Source/core/paint/ThemePainter.cpp
+++ b/third_party/WebKit/Source/core/paint/ThemePainter.cpp
@@ -35,15 +35,12 @@
 #include "core/paint/MediaControlsPainter.h"
 #include "core/paint/PaintInfo.h"
 #include "core/style/ComputedStyle.h"
+#include "platform/Theme.h"
 #include "platform/graphics/GraphicsContextStateSaver.h"
 #include "public/platform/Platform.h"
 #include "public/platform/WebFallbackThemeEngine.h"
 #include "public/platform/WebRect.h"
 
-#if USE(NEW_THEME)
-#include "platform/Theme.h"
-#endif
-
 // The methods in this file are shared by all themes on every platform.
 
 namespace blink {
@@ -60,6 +57,11 @@
     return WebFallbackThemeEngine::StateNormal;
 }
 
+ThemePainter::ThemePainter(Theme* platformTheme)
+    : m_platformTheme(platformTheme)
+{
+}
+
 bool ThemePainter::paint(const LayoutObject& o, const PaintInfo& paintInfo, const IntRect&r)
 {
     ControlPart part = o.styleRef().appearance();
@@ -67,24 +69,23 @@
     if (LayoutTheme::theme().shouldUseFallbackTheme(o.styleRef()))
         return paintUsingFallbackTheme(o, paintInfo, r);
 
-#if USE(NEW_THEME)
-    switch (part) {
-    case CheckboxPart:
-    case RadioPart:
-    case PushButtonPart:
-    case SquareButtonPart:
-    case ButtonPart:
-    case InnerSpinButtonPart:
-        platformTheme()->paint(part, LayoutTheme::controlStatesForLayoutObject(o), const_cast<GraphicsContext&>(paintInfo.context), r, o.styleRef().effectiveZoom(), o.view()->frameView());
-        return false;
-    default:
-        break;
+    if (m_platformTheme) {
+        switch (part) {
+        case CheckboxPart:
+        case RadioPart:
+        case PushButtonPart:
+        case SquareButtonPart:
+        case ButtonPart:
+        case InnerSpinButtonPart:
+            m_platformTheme->paint(part, LayoutTheme::controlStatesForLayoutObject(o), const_cast<GraphicsContext&>(paintInfo.context), r, o.styleRef().effectiveZoom(), o.view()->frameView());
+            return false;
+        default:
+            break;
+        }
     }
-#endif
 
     // Call the appropriate paint method based off the appearance value.
     switch (part) {
-#if !USE(NEW_THEME)
     case CheckboxPart:
         return paintCheckbox(o, paintInfo, r);
     case RadioPart:
@@ -95,7 +96,6 @@
         return paintButton(o, paintInfo, r);
     case InnerSpinButtonPart:
         return paintInnerSpinButton(o, paintInfo, r);
-#endif
     case MenulistPart:
         return paintMenuList(o, paintInfo, r);
     case MeterPart:
diff --git a/third_party/WebKit/Source/core/paint/ThemePainter.h b/third_party/WebKit/Source/core/paint/ThemePainter.h
index 456392d..45f6b24 100644
--- a/third_party/WebKit/Source/core/paint/ThemePainter.h
+++ b/third_party/WebKit/Source/core/paint/ThemePainter.h
@@ -30,12 +30,15 @@
 
 class IntRect;
 class LayoutObject;
+class Theme;
 
 struct PaintInfo;
 
 class ThemePainter {
     DISALLOW_NEW();
 public:
+    explicit ThemePainter(Theme*);
+
     // This method is called to paint the widget as a background of the LayoutObject.  A widget's foreground, e.g., the
     // text of a button, is always rendered by the engine itself.  The boolean return value indicates
     // whether the CSS border/background should also be painted.
@@ -47,13 +50,10 @@
     void paintSliderTicks(const LayoutObject&, const PaintInfo&, const IntRect&);
 
 protected:
-#if !USE(NEW_THEME)
     virtual bool paintCheckbox(const LayoutObject&, const PaintInfo&, const IntRect&) { return true; }
     virtual bool paintRadio(const LayoutObject&, const PaintInfo&, const IntRect&) { return true; }
     virtual bool paintButton(const LayoutObject&, const PaintInfo&, const IntRect&) { return true; }
     virtual bool paintInnerSpinButton(const LayoutObject&, const PaintInfo&, const IntRect&) { return true; }
-#endif
-
     virtual bool paintTextField(const LayoutObject&, const PaintInfo&, const IntRect&) { return true; }
     virtual bool paintTextArea(const LayoutObject&, const PaintInfo&, const IntRect&) { return true; }
     virtual bool paintMenuList(const LayoutObject&, const PaintInfo&, const IntRect&) { return true; }
@@ -70,6 +70,9 @@
     bool paintUsingFallbackTheme(const LayoutObject&, const PaintInfo&, const IntRect&);
     bool paintCheckboxUsingFallbackTheme(const LayoutObject&, const PaintInfo&, const IntRect&);
     bool paintRadioUsingFallbackTheme(const LayoutObject&, const PaintInfo&, const IntRect&);
+
+private:
+    Theme* m_platformTheme; // The platform-specific theme.
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/ThemePainterDefault.cpp b/third_party/WebKit/Source/core/paint/ThemePainterDefault.cpp
index e91538e..7191690b 100644
--- a/third_party/WebKit/Source/core/paint/ThemePainterDefault.cpp
+++ b/third_party/WebKit/Source/core/paint/ThemePainterDefault.cpp
@@ -133,6 +133,11 @@
 
 } // namespace
 
+ThemePainterDefault::ThemePainterDefault()
+    : ThemePainter(nullptr)
+{
+}
+
 bool ThemePainterDefault::paintCheckbox(const LayoutObject& o, const PaintInfo& i, const IntRect& rect)
 {
     WebThemeEngine::ExtraParams extraParams;
diff --git a/third_party/WebKit/Source/core/paint/ThemePainterDefault.h b/third_party/WebKit/Source/core/paint/ThemePainterDefault.h
index d0c596b..84802657 100644
--- a/third_party/WebKit/Source/core/paint/ThemePainterDefault.h
+++ b/third_party/WebKit/Source/core/paint/ThemePainterDefault.h
@@ -37,6 +37,9 @@
 class LayoutBox;
 
 class ThemePainterDefault final : public ThemePainter {
+public:
+    ThemePainterDefault();
+
 private:
     bool paintCheckbox(const LayoutObject&, const PaintInfo&, const IntRect&) override;
     bool paintRadio(const LayoutObject&, const PaintInfo&, const IntRect&) override;
diff --git a/third_party/WebKit/Source/core/paint/ThemePainterMac.h b/third_party/WebKit/Source/core/paint/ThemePainterMac.h
index 21e07fa..aaac29f 100644
--- a/third_party/WebKit/Source/core/paint/ThemePainterMac.h
+++ b/third_party/WebKit/Source/core/paint/ThemePainterMac.h
@@ -32,7 +32,7 @@
 
 class ThemePainterMac final : public ThemePainter {
 public:
-    ThemePainterMac(LayoutThemeMac& layoutTheme) : m_layoutTheme(layoutTheme) { }
+    ThemePainterMac(LayoutThemeMac&, Theme*);
 
 private:
     bool paintCapsLockIndicator(const LayoutObject&, const PaintInfo&, const IntRect&) override;
diff --git a/third_party/WebKit/Source/core/paint/ThemePainterMac.mm b/third_party/WebKit/Source/core/paint/ThemePainterMac.mm
index 8c9157c..7424cb6 100644
--- a/third_party/WebKit/Source/core/paint/ThemePainterMac.mm
+++ b/third_party/WebKit/Source/core/paint/ThemePainterMac.mm
@@ -50,6 +50,12 @@
 
 namespace blink {
 
+ThemePainterMac::ThemePainterMac(LayoutThemeMac& layoutTheme, Theme* platformTheme)
+    : ThemePainter(platformTheme)
+    , m_layoutTheme(layoutTheme)
+{
+}
+
 bool ThemePainterMac::paintTextField(const LayoutObject& o, const PaintInfo& paintInfo, const IntRect& r)
 {
     LocalCurrentGraphicsContext localContext(paintInfo.context, &paintInfo.cullRect().m_rect, r);
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.cpp b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
index 42d731c..ed5d4b0 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.cpp
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
@@ -83,6 +83,11 @@
     return adoptRef(new ComputedStyle(InitialStyle));
 }
 
+void ComputedStyle::invalidateInitialStyle()
+{
+    initialStyle()->setTapHighlightColor(initialTapHighlightColor());
+}
+
 PassRefPtr<ComputedStyle> ComputedStyle::createAnonymousStyleWithDisplay(const ComputedStyle& parentStyle, EDisplay display)
 {
     RefPtr<ComputedStyle> newStyle = ComputedStyle::create();
@@ -1499,7 +1504,7 @@
     if (textStrokeWidth()) {
         // Prefer stroke color if possible, but not if it's fully transparent.
         StyleColor textStrokeStyleColor = visitedLink ? visitedLinkTextStrokeColor() : textStrokeColor();
-        if (!textStrokeStyleColor.isCurrentColor() && textStrokeStyleColor.color().alpha())
+        if (!textStrokeStyleColor.isCurrentColor() && textStrokeStyleColor.getColor().alpha())
             return textStrokeStyleColor;
     }
 
@@ -1569,7 +1574,7 @@
     }
 
     if (!result.isCurrentColor())
-        return result.color();
+        return result.getColor();
 
     // FIXME: Treating styled borders with initial color differently causes problems
     // See crbug.com/316559, crbug.com/276231
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h
index b666a15f..142975a 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -369,6 +369,7 @@
     static PassRefPtr<ComputedStyle> create();
     static PassRefPtr<ComputedStyle> createAnonymousStyleWithDisplay(const ComputedStyle& parentStyle, EDisplay);
     static PassRefPtr<ComputedStyle> clone(const ComputedStyle&);
+    static void invalidateInitialStyle();
 
     // Computes how the style change should be propagated down the tree.
     static StyleRecalcChange stylePropagationDiff(const ComputedStyle* oldStyle, const ComputedStyle* newStyle);
diff --git a/third_party/WebKit/Source/core/style/StylePath.cpp b/third_party/WebKit/Source/core/style/StylePath.cpp
index 2f67b68b..e5ad7168 100644
--- a/third_party/WebKit/Source/core/style/StylePath.cpp
+++ b/third_party/WebKit/Source/core/style/StylePath.cpp
@@ -11,7 +11,7 @@
 
 namespace blink {
 
-StylePath::StylePath(PassRefPtr<SVGPathByteStream> pathByteStream)
+StylePath::StylePath(PassOwnPtr<SVGPathByteStream> pathByteStream)
     : m_byteStream(pathByteStream)
     , m_pathLength(std::numeric_limits<float>::quiet_NaN())
 {
@@ -22,7 +22,7 @@
 {
 }
 
-PassRefPtr<StylePath> StylePath::create(PassRefPtr<SVGPathByteStream> pathByteStream)
+PassRefPtr<StylePath> StylePath::create(PassOwnPtr<SVGPathByteStream> pathByteStream)
 {
     return adoptRef(new StylePath(pathByteStream));
 }
@@ -61,7 +61,7 @@
 
 PassRefPtrWillBeRawPtr<CSSValue> StylePath::computedCSSValue() const
 {
-    return CSSPathValue::create(m_byteStream, const_cast<StylePath*>(this));
+    return CSSPathValue::create(const_cast<StylePath*>(this));
 }
 
 bool StylePath::equals(const StylePath& other) const
diff --git a/third_party/WebKit/Source/core/style/StylePath.h b/third_party/WebKit/Source/core/style/StylePath.h
index 76d94412..a7ef77f 100644
--- a/third_party/WebKit/Source/core/style/StylePath.h
+++ b/third_party/WebKit/Source/core/style/StylePath.h
@@ -19,7 +19,7 @@
 
 class StylePath : public RefCounted<StylePath> {
 public:
-    static PassRefPtr<StylePath> create(PassRefPtr<SVGPathByteStream>);
+    static PassRefPtr<StylePath> create(PassOwnPtr<SVGPathByteStream>);
     ~StylePath();
 
     static StylePath* emptyPath();
@@ -35,9 +35,9 @@
     bool equals(const StylePath&) const;
 
 private:
-    explicit StylePath(PassRefPtr<SVGPathByteStream>);
+    explicit StylePath(PassOwnPtr<SVGPathByteStream>);
 
-    RefPtr<SVGPathByteStream> m_byteStream;
+    OwnPtr<SVGPathByteStream> m_byteStream;
     mutable OwnPtr<Path> m_path;
     mutable float m_pathLength;
 };
diff --git a/third_party/WebKit/Source/core/svg/SVGAnimatedColor.cpp b/third_party/WebKit/Source/core/svg/SVGAnimatedColor.cpp
index 433a8958..9e24cb8a 100644
--- a/third_party/WebKit/Source/core/svg/SVGAnimatedColor.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGAnimatedColor.cpp
@@ -37,7 +37,7 @@
 
 String SVGColorProperty::valueAsString() const
 {
-    return m_styleColor.isCurrentColor() ? "currentColor" : m_styleColor.color().serializedAsCSSComponentValue();
+    return m_styleColor.isCurrentColor() ? "currentColor" : m_styleColor.getColor().serializedAsCSSComponentValue();
 }
 
 PassRefPtrWillBeRawPtr<SVGPropertyBase> SVGColorProperty::cloneForAnimation(const String&) const
diff --git a/third_party/WebKit/Source/core/svg/SVGElement.idl b/third_party/WebKit/Source/core/svg/SVGElement.idl
index 4707f937..d8faebb 100644
--- a/third_party/WebKit/Source/core/svg/SVGElement.idl
+++ b/third_party/WebKit/Source/core/svg/SVGElement.idl
@@ -33,13 +33,6 @@
     [CustomElementCallbacks] attribute long tabIndex;
     void focus();
     void blur();
-
-    // TODO(tanay.c): SVGElement.offset* are non-standard. crbug.com/463116
-    [DeprecateAs=V8SVGElement_OffsetParent_AttributeGetter, PerWorldBindings] readonly attribute Element? offsetParent;
-    [DeprecateAs=V8SVGElement_OffsetTop_AttributeGetter] readonly attribute long offsetTop;
-    [DeprecateAs=V8SVGElement_OffsetLeft_AttributeGetter] readonly attribute long offsetLeft;
-    [DeprecateAs=V8SVGElement_OffsetWidth_AttributeGetter] readonly attribute long offsetWidth;
-    [DeprecateAs=V8SVGElement_OffsetHeight_AttributeGetter] readonly attribute long offsetHeight;
 };
 
 SVGElement implements GlobalEventHandlers;
diff --git a/third_party/WebKit/Source/core/svg/SVGPath.cpp b/third_party/WebKit/Source/core/svg/SVGPath.cpp
index 37547ed..43aa508 100644
--- a/third_party/WebKit/Source/core/svg/SVGPath.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGPath.cpp
@@ -35,9 +35,9 @@
 
 namespace {
 
-PassRefPtr<SVGPathByteStream> blendPathByteStreams(const SVGPathByteStream& fromStream, const SVGPathByteStream& toStream, float progress)
+PassOwnPtr<SVGPathByteStream> blendPathByteStreams(const SVGPathByteStream& fromStream, const SVGPathByteStream& toStream, float progress)
 {
-    RefPtr<SVGPathByteStream> resultStream = SVGPathByteStream::create();
+    OwnPtr<SVGPathByteStream> resultStream = SVGPathByteStream::create();
     SVGPathByteStreamBuilder builder(*resultStream);
     SVGPathByteStreamSource fromSource(fromStream);
     SVGPathByteStreamSource toSource(toStream);
@@ -46,9 +46,9 @@
     return resultStream.release();
 }
 
-PassRefPtr<SVGPathByteStream> addPathByteStreams(const SVGPathByteStream& fromStream, const SVGPathByteStream& byStream, unsigned repeatCount = 1)
+PassOwnPtr<SVGPathByteStream> addPathByteStreams(const SVGPathByteStream& fromStream, const SVGPathByteStream& byStream, unsigned repeatCount = 1)
 {
-    RefPtr<SVGPathByteStream> resultStream = SVGPathByteStream::create();
+    OwnPtr<SVGPathByteStream> resultStream = SVGPathByteStream::create();
     SVGPathByteStreamBuilder builder(*resultStream);
     SVGPathByteStreamSource fromSource(fromStream);
     SVGPathByteStreamSource bySource(byStream);
@@ -57,7 +57,7 @@
     return resultStream.release();
 }
 
-PassRefPtr<SVGPathByteStream> conditionallyAddPathByteStreams(PassRefPtr<SVGPathByteStream> fromStream, const SVGPathByteStream& byStream, unsigned repeatCount = 1)
+PassOwnPtr<SVGPathByteStream> conditionallyAddPathByteStreams(PassOwnPtr<SVGPathByteStream> fromStream, const SVGPathByteStream& byStream, unsigned repeatCount = 1)
 {
     if (fromStream->isEmpty() || byStream.isEmpty())
         return fromStream;
@@ -95,7 +95,7 @@
 
 SVGParsingError SVGPath::setValueAsString(const String& string)
 {
-    RefPtr<SVGPathByteStream> byteStream = SVGPathByteStream::create();
+    OwnPtr<SVGPathByteStream> byteStream = SVGPathByteStream::create();
     SVGParsingError parseStatus = buildByteStreamFromString(string, *byteStream);
     m_pathValue = CSSPathValue::create(byteStream.release());
     return parseStatus;
@@ -103,7 +103,9 @@
 
 PassRefPtrWillBeRawPtr<SVGPropertyBase> SVGPath::cloneForAnimation(const String& value) const
 {
-    return SVGPath::create(CSSPathValue::create(value));
+    OwnPtr<SVGPathByteStream> byteStream = SVGPathByteStream::create();
+    buildByteStreamFromString(value, *byteStream);
+    return SVGPath::create(CSSPathValue::create(byteStream.release()));
 }
 
 void SVGPath::add(PassRefPtrWillBeRawPtr<SVGPropertyBase> other, SVGElement*)
@@ -122,17 +124,17 @@
     ASSERT(animationElement);
     bool isToAnimation = animationElement->animationMode() == ToAnimation;
 
-    const RefPtrWillBeRawPtr<SVGPath> to = toSVGPath(toValue);
-    const SVGPathByteStream& toStream = to->byteStream();
+    const SVGPath& to = toSVGPath(*toValue);
+    const SVGPathByteStream& toStream = to.byteStream();
 
     // If no 'to' value is given, nothing to animate.
     if (!toStream.size())
         return;
 
-    const RefPtrWillBeRawPtr<SVGPath> from = toSVGPath(fromValue);
-    const SVGPathByteStream* fromStream = &from->byteStream();
+    const SVGPath& from = toSVGPath(*fromValue);
+    const SVGPathByteStream* fromStream = &from.byteStream();
 
-    RefPtr<SVGPathByteStream> copy;
+    OwnPtr<SVGPathByteStream> copy;
     if (isToAnimation) {
         copy = byteStream().clone();
         fromStream = copy.get();
@@ -142,16 +144,16 @@
     if (fromStream->size() != toStream.size() && fromStream->size()) {
         if (percentage < 0.5) {
             if (!isToAnimation) {
-                m_pathValue = from->pathValue();
+                m_pathValue = from.pathValue();
                 return;
             }
         } else {
-            m_pathValue = to->pathValue();
+            m_pathValue = to.pathValue();
             return;
         }
     }
 
-    RefPtr<SVGPathByteStream> newStream = blendPathByteStreams(*fromStream, toStream, percentage);
+    OwnPtr<SVGPathByteStream> newStream = blendPathByteStreams(*fromStream, toStream, percentage);
 
     // Handle additive='sum'.
     if (animationElement->isAdditive() && !isToAnimation)
diff --git a/third_party/WebKit/Source/core/svg/SVGPathByteStream.h b/third_party/WebKit/Source/core/svg/SVGPathByteStream.h
index 0442474..31ac395 100644
--- a/third_party/WebKit/Source/core/svg/SVGPathByteStream.h
+++ b/third_party/WebKit/Source/core/svg/SVGPathByteStream.h
@@ -21,8 +21,7 @@
 #define SVGPathByteStream_h
 
 #include "wtf/Noncopyable.h"
-#include "wtf/PassRefPtr.h"
-#include "wtf/RefCounted.h"
+#include "wtf/PassOwnPtr.h"
 #include "wtf/Vector.h"
 
 namespace blink {
@@ -33,17 +32,17 @@
     unsigned char bytes[sizeof(DataType)];
 };
 
-class SVGPathByteStream : public RefCounted<SVGPathByteStream> {
+class SVGPathByteStream {
     USING_FAST_MALLOC(SVGPathByteStream);
 public:
-    static PassRefPtr<SVGPathByteStream> create()
+    static PassOwnPtr<SVGPathByteStream> create()
     {
-        return adoptRef(new SVGPathByteStream);
+        return adoptPtr(new SVGPathByteStream);
     }
 
-    PassRefPtr<SVGPathByteStream> clone() const
+    PassOwnPtr<SVGPathByteStream> clone() const
     {
-        return adoptRef(new SVGPathByteStream(m_data));
+        return adoptPtr(new SVGPathByteStream(m_data));
     }
 
     typedef Vector<unsigned char> Data;
diff --git a/third_party/WebKit/Source/core/svg/SVGPathElement.cpp b/third_party/WebKit/Source/core/svg/SVGPathElement.cpp
index 28330190..380cedad 100644
--- a/third_party/WebKit/Source/core/svg/SVGPathElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGPathElement.cpp
@@ -72,7 +72,7 @@
 {
     if (LayoutObject* layoutObject = this->layoutObject())
         return layoutObject->styleRef().svgStyle().d();
-    return m_path->currentValue()->pathValue()->cachedPath();
+    return m_path->currentValue()->pathValue()->stylePath();
 }
 
 float SVGPathElement::pathLengthScaleFactor() const
diff --git a/third_party/WebKit/Source/core/testing/Internals.cpp b/third_party/WebKit/Source/core/testing/Internals.cpp
index b6443831..61c65d97 100644
--- a/third_party/WebKit/Source/core/testing/Internals.cpp
+++ b/third_party/WebKit/Source/core/testing/Internals.cpp
@@ -310,7 +310,7 @@
     }
 
     unsigned beforeCount = document->styleEngine().styleForElementCount();
-    document->updateLayoutTreeIfNeeded();
+    document->updateLayoutTree();
     return document->styleEngine().styleForElementCount() - beforeCount;
 }
 
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
index df55400..e2b281d 100644
--- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
@@ -75,7 +75,7 @@
     : m_url(url)
     , m_userAgent(userAgent)
     , m_v8CacheOptions(V8CacheOptionsDefault)
-    , m_script(WorkerOrWorkletScriptController::create(this, thread->isolate()))
+    , m_scriptController(WorkerOrWorkletScriptController::create(this, thread->isolate()))
     , m_thread(thread)
     , m_workerInspectorController(adoptRefWillBeNoop(new WorkerInspectorController(this)))
     , m_closing(false)
@@ -98,7 +98,7 @@
 
 WorkerGlobalScope::~WorkerGlobalScope()
 {
-    ASSERT(!m_script);
+    ASSERT(!m_scriptController);
     ASSERT(!m_workerInspectorController);
 }
 
@@ -145,7 +145,7 @@
 
 void WorkerGlobalScope::disableEval(const String& errorMessage)
 {
-    m_script->disableEval(errorMessage);
+    m_scriptController->disableEval(errorMessage);
 }
 
 DOMTimerCoordinator* WorkerGlobalScope::timers()
@@ -187,9 +187,9 @@
 
 void WorkerGlobalScope::clearScript()
 {
-    ASSERT(m_script);
-    m_script->dispose();
-    m_script.clear();
+    ASSERT(m_scriptController);
+    m_scriptController->dispose();
+    m_scriptController.clear();
 }
 
 void WorkerGlobalScope::clearInspector()
@@ -271,9 +271,9 @@
         RefPtrWillBeRawPtr<ErrorEvent> errorEvent = nullptr;
         OwnPtr<Vector<char>> cachedMetaData(scriptLoader->releaseCachedMetadata());
         OwnPtrWillBeRawPtr<CachedMetadataHandler> handler(createWorkerScriptCachedMetadataHandler(completeURL, cachedMetaData.get()));
-        m_script->evaluate(ScriptSourceCode(scriptLoader->script(), scriptLoader->responseURL()), &errorEvent, handler.get(), m_v8CacheOptions);
+        m_scriptController->evaluate(ScriptSourceCode(scriptLoader->script(), scriptLoader->responseURL()), &errorEvent, handler.get(), m_v8CacheOptions);
         if (errorEvent) {
-            m_script->rethrowExceptionFromImportedScript(errorEvent.release(), exceptionState);
+            m_scriptController->rethrowExceptionFromImportedScript(errorEvent.release(), exceptionState);
             return;
         }
     }
@@ -320,7 +320,7 @@
 
 bool WorkerGlobalScope::isJSExecutionForbidden() const
 {
-    return m_script->isExecutionForbidden();
+    return m_scriptController->isExecutionForbidden();
 }
 
 WorkerEventQueue* WorkerGlobalScope::eventQueue() const
@@ -381,7 +381,10 @@
     // |isSecureContext| check here, we can check the responsible
     // document for a privileged context at worker creation time, pass
     // it in via WorkerThreadStartupData, and check it here.
-    return securityOrigin()->isPotentiallyTrustworthy(errorMessage);
+    if (securityOrigin()->isPotentiallyTrustworthy())
+        return true;
+    errorMessage = securityOrigin()->isPotentiallyTrustworthyErrorMessage();
+    return false;
 }
 
 void WorkerGlobalScope::removeURLFromMemoryCache(const KURL& url)
@@ -414,7 +417,7 @@
     visitor->trace(m_console);
     visitor->trace(m_location);
     visitor->trace(m_navigator);
-    visitor->trace(m_script);
+    visitor->trace(m_scriptController);
     visitor->trace(m_workerInspectorController);
     visitor->trace(m_eventQueue);
     visitor->trace(m_workerClients);
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
index 54fd8e5..e5a2dba 100644
--- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
+++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
@@ -88,7 +88,7 @@
     String userAgent() const final;
     void disableEval(const String& errorMessage) final;
 
-    WorkerOrWorkletScriptController* script() final { return m_script.get(); }
+    WorkerOrWorkletScriptController* scriptController() final { return m_scriptController.get(); }
 
     virtual void didEvaluateWorkerScript();
     void dispose();
@@ -191,7 +191,7 @@
 
     mutable UseCounter::CountBits m_deprecationWarningBits;
 
-    OwnPtrWillBeMember<WorkerOrWorkletScriptController> m_script;
+    OwnPtrWillBeMember<WorkerOrWorkletScriptController> m_scriptController;
     WorkerThread* m_thread;
 
     RefPtrWillBeMember<WorkerInspectorController> m_workerInspectorController;
diff --git a/third_party/WebKit/Source/core/workers/WorkerOrWorkletGlobalScope.h b/third_party/WebKit/Source/core/workers/WorkerOrWorkletGlobalScope.h
index a418dbf..3c369eb 100644
--- a/third_party/WebKit/Source/core/workers/WorkerOrWorkletGlobalScope.h
+++ b/third_party/WebKit/Source/core/workers/WorkerOrWorkletGlobalScope.h
@@ -16,7 +16,7 @@
 class CORE_EXPORT WorkerOrWorkletGlobalScope : public ExecutionContext {
 public:
     virtual ScriptWrappable* scriptWrappable() const = 0;
-    virtual WorkerOrWorkletScriptController* script() = 0;
+    virtual WorkerOrWorkletScriptController* scriptController() = 0;
 };
 
 DEFINE_TYPE_CASTS(WorkerOrWorkletGlobalScope, ExecutionContext, context, (context->isWorkerGlobalScope() || context->isWorkletGlobalScope()), (context.isWorkerGlobalScope() || context.isWorkletGlobalScope()));
diff --git a/third_party/WebKit/Source/core/workers/WorkerThread.cpp b/third_party/WebKit/Source/core/workers/WorkerThread.cpp
index 238b3ddd..7531f85 100644
--- a/third_party/WebKit/Source/core/workers/WorkerThread.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerThread.cpp
@@ -71,7 +71,7 @@
     {
         Microtask::performCheckpoint(m_workerThread->isolate());
         if (WorkerGlobalScope* globalScope = m_workerThread->workerGlobalScope()) {
-            if (WorkerOrWorkletScriptController* scriptController = globalScope->script())
+            if (WorkerOrWorkletScriptController* scriptController = globalScope->scriptController())
                 scriptController->rejectedPromises()->processQueue();
             if (globalScope->isClosing()) {
                 m_workerThread->workerReportingProxy().workerGlobalScopeClosed();
@@ -283,18 +283,18 @@
         // Notify proxy that a new WorkerGlobalScope has been created and started.
         m_workerReportingProxy.workerGlobalScopeStarted(m_workerGlobalScope.get());
 
-        WorkerOrWorkletScriptController* script = m_workerGlobalScope->script();
-        if (!script->isExecutionForbidden())
-            script->initializeContextIfNeeded();
+        WorkerOrWorkletScriptController* scriptController = m_workerGlobalScope->scriptController();
+        if (!scriptController->isExecutionForbidden())
+            scriptController->initializeContextIfNeeded();
     }
     m_workerGlobalScope->workerInspectorController()->workerContextInitialized(startMode == PauseWorkerGlobalScopeOnStart);
 
-    if (m_workerGlobalScope->script()->isContextInitialized()) {
+    if (m_workerGlobalScope->scriptController()->isContextInitialized()) {
         m_workerReportingProxy.didInitializeWorkerContext();
     }
 
     OwnPtrWillBeRawPtr<CachedMetadataHandler> handler(workerGlobalScope()->createWorkerScriptCachedMetadataHandler(scriptURL, cachedMetaData.get()));
-    bool success = m_workerGlobalScope->script()->evaluate(ScriptSourceCode(sourceCode, scriptURL), nullptr, handler.get(), v8CacheOptions);
+    bool success = m_workerGlobalScope->scriptController()->evaluate(ScriptSourceCode(sourceCode, scriptURL), nullptr, handler.get(), v8CacheOptions);
     m_workerGlobalScope->didEvaluateWorkerScript();
     m_workerReportingProxy.didEvaluateWorkerScript(success);
 
@@ -401,7 +401,7 @@
         return;
 
     // Ensure that tasks are being handled by thread event loop. If script execution weren't forbidden, a while(1) loop in JS could keep the thread alive forever.
-    m_workerGlobalScope->script()->willScheduleExecutionTermination();
+    m_workerGlobalScope->scriptController()->willScheduleExecutionTermination();
     terminateV8Execution();
 
     InspectorInstrumentation::didKillAllExecutionContextTasks(m_workerGlobalScope.get());
diff --git a/third_party/WebKit/Source/core/xml/parser/XMLErrors.cpp b/third_party/WebKit/Source/core/xml/parser/XMLErrors.cpp
index 096cdcc..a8253df 100644
--- a/third_party/WebKit/Source/core/xml/parser/XMLErrors.cpp
+++ b/third_party/WebKit/Source/core/xml/parser/XMLErrors.cpp
@@ -167,7 +167,7 @@
         documentElement->parserAppendChild(reportElement);
 
     // FIXME: Why do we need to call this manually?
-    m_document->updateLayoutTreeIfNeeded();
+    m_document->updateLayoutTree();
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/devtools/Inspector-1.1.json b/third_party/WebKit/Source/devtools/Inspector-1.1.json
index 5a5a3ed7..55afa73 100644
--- a/third_party/WebKit/Source/devtools/Inspector-1.1.json
+++ b/third_party/WebKit/Source/devtools/Inspector-1.1.json
@@ -1330,7 +1330,7 @@
                 "description": "Database with an array of object stores.",
                 "properties": [
                     { "name": "name", "type": "string", "description": "Database name." },
-                    { "name": "intVersion", "type": "integer", "description": "Database version." },
+                    { "name": "version", "type": "integer", "description": "Database version." },
                     { "name": "objectStores", "type": "array", "items": { "$ref": "ObjectStore" }, "description": "Object stores in this database." }
                 ]
             },
diff --git a/third_party/WebKit/Source/devtools/devtools.gypi b/third_party/WebKit/Source/devtools/devtools.gypi
index a6b29ca..c5c315c 100644
--- a/third_party/WebKit/Source/devtools/devtools.gypi
+++ b/third_party/WebKit/Source/devtools/devtools.gypi
@@ -86,6 +86,7 @@
             'front_end/components/customPreviewSection.css',
             'front_end/components/domUtils.css',
             'front_end/components/inspectorViewTabbedPane.css',
+            'front_end/components/networkConditionsSettingsTab.css',
             'front_end/components/objectPropertiesSection.css',
             'front_end/components/objectValue.css',
             'front_end/components/CustomPreviewSection.js',
@@ -101,6 +102,7 @@
             'front_end/components/InspectorView.js',
             'front_end/components/BreakpointsSidebarPaneBase.js',
             'front_end/components/Linkifier.js',
+            'front_end/components/NetworkConditionsSelector.js',
             'front_end/components/ObjectPopoverHelper.js',
             'front_end/components/ObjectPropertiesSection.js',
             'front_end/components/RemoteObjectPreviewFormatter.js',
@@ -119,6 +121,7 @@
         'devtools_sass_js_files': [
             'front_end/sass/ASTService.js',
             'front_end/sass/ASTSourceMap.js',
+            'front_end/sass/SASSProcessor.js',
             'front_end/sass/SASSSupport.js',
         ],
         'devtools_screencast_js_files': [
@@ -501,7 +504,6 @@
         'devtools_network_js_files': [
             'front_end/network/blockedURLsPane.css',
             'front_end/network/eventSourceMessagesView.css',
-            'front_end/network/networkConditionsSettingsTab.css',
             'front_end/network/networkConfigView.css',
             'front_end/network/networkLogView.css',
             'front_end/network/networkPanel.css',
@@ -514,7 +516,6 @@
             'front_end/network/FilterSuggestionBuilder.js',
             'front_end/network/HARWriter.js',
             'front_end/network/JSONView.js',
-            'front_end/network/NetworkConditionsSelector.js',
             'front_end/network/NetworkConfigView.js',
             'front_end/network/NetworkDataGridNode.js',
             'front_end/network/NetworkItemView.js',
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes b/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes
index aa594ff..25464fd 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes
+++ b/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes
@@ -1,7 +1,7 @@
 {
-    "breakpointConditional.svg": "4cf90210b2af2ed84db2f60b07bcde28",
     "errorWave.svg": "e183fa242a22ed4784a92f6becbc2c45",
+    "breakpoint.svg": "69cd92d807259c022791112809b97799",
     "settingsListRemove.svg": "ce9e7c5c5cdaef28e6ee51d9478d5485",
-    "toolbarButtonGlyphs.svg": "9cb447c4c5e8e65ae5c9a32983a6e515",
-    "breakpoint.svg": "69cd92d807259c022791112809b97799"
+    "breakpointConditional.svg": "4cf90210b2af2ed84db2f60b07bcde28",
+    "toolbarButtonGlyphs.svg": "fcf3159499e07a580dc9bd827d4f627f"
 }
\ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes b/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes
index aa594ff..25464fd 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes
+++ b/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes
@@ -1,7 +1,7 @@
 {
-    "breakpointConditional.svg": "4cf90210b2af2ed84db2f60b07bcde28",
     "errorWave.svg": "e183fa242a22ed4784a92f6becbc2c45",
+    "breakpoint.svg": "69cd92d807259c022791112809b97799",
     "settingsListRemove.svg": "ce9e7c5c5cdaef28e6ee51d9478d5485",
-    "toolbarButtonGlyphs.svg": "9cb447c4c5e8e65ae5c9a32983a6e515",
-    "breakpoint.svg": "69cd92d807259c022791112809b97799"
+    "breakpointConditional.svg": "4cf90210b2af2ed84db2f60b07bcde28",
+    "toolbarButtonGlyphs.svg": "fcf3159499e07a580dc9bd827d4f627f"
 }
\ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg b/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg
index 7046181..779809e 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg
+++ b/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg
@@ -15,15 +15,15 @@
    xml:space="preserve"
    id="svg3395"
    inkscape:version="0.48.4 r9939"
-   sodipodi:docname="out2.svg"><metadata
+   sodipodi:docname="toolbarButtonGlyphs.svg"><metadata
      id="metadata3773"><rdf:RDF><cc:Work
          rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><sodipodi:namedview
      showgrid="true"
      id="namedview3397"
-     inkscape:zoom="4.7448473"
-     inkscape:cx="225.17445"
-     inkscape:cy="59.825604"
+     inkscape:zoom="9.4896946"
+     inkscape:cx="52.098429"
+     inkscape:cy="52.790212"
      inkscape:window-width="2560"
      inkscape:window-height="1547"
      inkscape:window-x="0"
@@ -1051,7 +1051,7 @@
      style="fill:none;stroke:none"
      id="Page-1-0"
      sketch:type="MSPage"
-     transform="matrix(1.4,0,0,1.4,9,126)"><g
+     transform="matrix(1.1,0,0,1.1,10,127)"><g
        style="fill:#000000"
        id="Forward-Right"
        sketch:type="MSLayerGroup"
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png
index d3c07876..c19a2bf2 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png
index 5c92936..0a8df07 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/common/TextRange.js b/third_party/WebKit/Source/devtools/front_end/common/TextRange.js
index e9d4e9a..43f21c1 100644
--- a/third_party/WebKit/Source/devtools/front_end/common/TextRange.js
+++ b/third_party/WebKit/Source/devtools/front_end/common/TextRange.js
@@ -316,18 +316,42 @@
     this.length = length;
 }
 
+WebInspector.SourceRange.prototype = {
+    /**
+     * @param {string} text
+     * @return {!WebInspector.TextRange}
+     */
+    toTextRange: function(text)
+    {
+        var p1 = fromOffset(text, this.offset);
+        var p2 = fromOffset(text, this.offset + this.length);
+        return new WebInspector.TextRange(p1.lineNumber, p1.columnNumber, p2.lineNumber, p2.columnNumber);
+
+        /**
+         * @param {string} text
+         * @param {number} offset
+         * @return {!{lineNumber: number, columnNumber: number}}
+         */
+        function fromOffset(text, offset)
+        {
+            var lineEndings = text.lineEndings();
+            var lineNumber = lineEndings.lowerBound(offset);
+            var columnNumber = lineNumber === 0 ? offset : offset - lineEndings[lineNumber - 1] - 1;
+            return {lineNumber: lineNumber, columnNumber: columnNumber};
+        }
+    }
+}
+
 /**
  * @constructor
  * @param {string} sourceURL
  * @param {!WebInspector.TextRange} oldRange
- * @param {string} oldText
  * @param {string} newText
  */
-WebInspector.SourceEdit = function(sourceURL, oldRange, oldText, newText)
+WebInspector.SourceEdit = function(sourceURL, oldRange, newText)
 {
     this.sourceURL = sourceURL;
     this.oldRange = oldRange;
-    this.oldText = oldText;
     this.newText = newText;
 }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkConditionsSelector.js b/third_party/WebKit/Source/devtools/front_end/components/NetworkConditionsSelector.js
similarity index 62%
rename from third_party/WebKit/Source/devtools/front_end/network/NetworkConditionsSelector.js
rename to third_party/WebKit/Source/devtools/front_end/components/NetworkConditionsSelector.js
index b2796da..80e8532 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/NetworkConditionsSelector.js
+++ b/third_party/WebKit/Source/devtools/front_end/components/NetworkConditionsSelector.js
@@ -4,12 +4,13 @@
 
 /**
  * @constructor
- * @param {!HTMLSelectElement} selectElement
+ * @param {function(!Array<!WebInspector.NetworkConditionsProfileGroup>):!Array<!{conditions: ?WebInspector.NetworkManager.Conditions}>} populateCallback
+ * @param {function(number)} selectCallback
  */
-WebInspector.NetworkConditionsSelector = function(selectElement)
+WebInspector.NetworkConditionsSelector = function(populateCallback, selectCallback)
 {
-    this._selectElement = selectElement;
-    this._selectElement.addEventListener("change", this._optionSelected.bind(this), false);
+    this._populateCallback = populateCallback;
+    this._selectCallback = selectCallback;
     this._customSetting = WebInspector.moduleSetting("networkConditionsCustomProfiles");
     this._customSetting.addChangeListener(this._populateOptions, this);
     this._manager = WebInspector.multitargetNetworkManager;
@@ -20,11 +21,14 @@
 /** @typedef {!{title: string, value: !WebInspector.NetworkManager.Conditions}} */
 WebInspector.NetworkConditionsProfile;
 
+/** @typedef {!{title: string, items: !Array<!WebInspector.NetworkConditionsProfile>}} */
+WebInspector.NetworkConditionsProfileGroup;
+
 /**
  * @param {number} throughput
  * @return {string}
  */
-WebInspector.NetworkConditionsSelector.throughputText = function(throughput)
+WebInspector.NetworkConditionsSelector._throughputText = function(throughput)
 {
     if (throughput < 0)
         return "";
@@ -52,76 +56,172 @@
 /** @type {!WebInspector.NetworkConditionsProfile} */
 WebInspector.NetworkConditionsSelector._disabledPreset = {title: "No throttling", value: {download: -1, upload: -1, latency: 0}};
 
+/**
+ * @param {!WebInspector.NetworkConditionsProfile} preset
+ * @return {!{text: string, title: string}}
+ */
+WebInspector.NetworkConditionsSelector._profileTitle = function(preset)
+{
+    var downloadInKbps = preset.value.download / (1024 / 8);
+    var uploadInKbps = preset.value.upload / (1024 / 8);
+    var isThrottling = (downloadInKbps >= 0) || (uploadInKbps >= 0) || (preset.value.latency > 0);
+    var presetTitle = WebInspector.UIString(preset.title);
+    if (!isThrottling)
+        return {text: presetTitle, title: presetTitle};
+
+    var downloadText = WebInspector.NetworkConditionsSelector._throughputText(preset.value.download);
+    var uploadText = WebInspector.NetworkConditionsSelector._throughputText(preset.value.upload);
+    var title = WebInspector.UIString("%s (%s\u2b07 %s\u2b06 %dms RTT)", presetTitle, downloadText, uploadText, preset.value.latency);
+    return {text: title, title: WebInspector.UIString("Maximum download throughput: %s.\r\nMaximum upload throughput: %s.\r\nMinimum round-trip time: %dms.", downloadText, uploadText, preset.value.latency)};
+}
+
 WebInspector.NetworkConditionsSelector.prototype = {
     _populateOptions: function()
     {
-        this._selectElement.removeChildren();
+        var customGroup = {title: WebInspector.UIString("Custom"), items: this._customSetting.get()};
+        var presetsGroup = {title: WebInspector.UIString("Presets"), items: WebInspector.NetworkConditionsSelector._networkConditionsPresets};
+        var disabledGroup = {title: WebInspector.UIString("Disabled"), items: [WebInspector.NetworkConditionsSelector._disabledPreset]};
+        this._options = this._populateCallback([customGroup, presetsGroup, disabledGroup]);
+        this._conditionsChanged();
+    },
 
-        var customGroup = this._addGroup(this._customSetting.get(), WebInspector.UIString("Custom"));
-        customGroup.insertBefore(new Option(WebInspector.UIString("Add\u2026"), WebInspector.UIString("Add\u2026")), customGroup.firstChild);
-
-        this._addGroup(WebInspector.NetworkConditionsSelector._networkConditionsPresets, WebInspector.UIString("Presets"));
-        this._addGroup([WebInspector.NetworkConditionsSelector._disabledPreset], WebInspector.UIString("Disabled"));
-
+    revealAndUpdate: function()
+    {
+        WebInspector.Revealer.reveal(this._customSetting);
         this._conditionsChanged();
     },
 
     /**
-     * @param {!Array.<!WebInspector.NetworkConditionsProfile>} presets
-     * @param {string} groupName
-     * @return {!Element}
+     * @param {!WebInspector.NetworkManager.Conditions} conditions
      */
-    _addGroup: function(presets, groupName)
+    optionSelected: function(conditions)
     {
-        var groupElement = this._selectElement.createChild("optgroup");
-        groupElement.label = groupName;
-        for (var i = 0; i < presets.length; ++i) {
-            var preset = presets[i];
-            var downloadInKbps = preset.value.download / (1024 / 8);
-            var uploadInKbps = preset.value.upload / (1024 / 8);
-            var isThrottling = (downloadInKbps >= 0) || (uploadInKbps >= 0) || (preset.value.latency > 0);
-            var option;
-            var presetTitle = WebInspector.UIString(preset.title);
-            if (!isThrottling) {
-                option = new Option(presetTitle, presetTitle);
-            } else {
-                var downloadText = WebInspector.NetworkConditionsSelector.throughputText(preset.value.download);
-                var uploadText = WebInspector.NetworkConditionsSelector.throughputText(preset.value.upload);
-                var title = WebInspector.UIString("%s (%s\u2b07 %s\u2b06 %dms RTT)", presetTitle, downloadText, uploadText, preset.value.latency);
-                option = new Option(title, presetTitle);
-                option.title = WebInspector.UIString("Maximum download throughput: %s.\r\nMaximum upload throughput: %s.\r\nMinimum round-trip time: %dms.", downloadText, uploadText, preset.value.latency);
-            }
-            option.conditions = preset.value;
-            groupElement.appendChild(option);
-        }
-        return groupElement;
-    },
-
-    _optionSelected: function()
-    {
-        if (this._selectElement.selectedIndex === 0) {
-            WebInspector.Revealer.reveal(this._customSetting);
-            this._conditionsChanged();
-            return;
-        }
-
-        this._manager.removeEventListener(WebInspector.MultitargetNetworkManager.Events.ConditionsChanged, this._conditionsChanged, this);
-        this._manager.setNetworkConditions(this._selectElement.options[this._selectElement.selectedIndex].conditions);
-        this._manager.addEventListener(WebInspector.MultitargetNetworkManager.Events.ConditionsChanged, this._conditionsChanged, this);
+        this._manager.setNetworkConditions(conditions);
     },
 
     _conditionsChanged: function()
     {
         var value = this._manager.networkConditions();
-        var options = this._selectElement.options;
-        for (var index = 1; index < options.length; ++index) {
-            var option = options[index];
+        for (var index = 0; index < this._options.length; ++index) {
+            var option = this._options[index];
+            if (!option.conditions)
+                continue;
             if (option.conditions.download === value.download && option.conditions.upload === value.upload && option.conditions.latency === value.latency)
-                this._selectElement.selectedIndex = index;
+                this._selectCallback(index);
         }
     }
 }
 
+/**
+ * @param {!HTMLSelectElement} selectElement
+ */
+WebInspector.NetworkConditionsSelector.decorateSelect = function(selectElement)
+{
+    var options = [];
+    var selector = new WebInspector.NetworkConditionsSelector(populate, select);
+    selectElement.addEventListener("change", optionSelected, false);
+
+    /**
+     * @param {!Array.<!WebInspector.NetworkConditionsProfileGroup>} groups
+     * @return {!Array<!{conditions: ?WebInspector.NetworkManager.Conditions}>}
+     */
+    function populate(groups)
+    {
+        selectElement.removeChildren();
+        options = [];
+        for (var i = 0; i < groups.length; ++i) {
+            var group = groups[i];
+            var groupElement = selectElement.createChild("optgroup");
+            groupElement.label = group.title;
+            if (!i) {
+                groupElement.appendChild(new Option(WebInspector.UIString("Add\u2026"), WebInspector.UIString("Add\u2026")));
+                options.push({conditions: null});
+            }
+            for (var preset of group.items) {
+                var title = WebInspector.NetworkConditionsSelector._profileTitle(preset);
+                var option = new Option(title.text, title.text);
+                option.title = title.title;
+                groupElement.appendChild(option);
+                options.push({conditions: preset.value});
+            }
+        }
+        return options;
+    }
+
+    function optionSelected()
+    {
+        if (selectElement.selectedIndex === 0)
+            selector.revealAndUpdate();
+        else
+            selector.optionSelected(options[selectElement.selectedIndex].conditions);
+    }
+
+    /**
+     * @param {number} index
+     */
+    function select(index)
+    {
+        if (selectElement.selectedIndex !== index)
+            selectElement.selectedIndex = index;
+    }
+}
+
+/**
+ * @return {!WebInspector.ToolbarMenuButton}
+ */
+WebInspector.NetworkConditionsSelector.createToolbarMenuButton = function()
+{
+    var button = new WebInspector.ToolbarMenuButton(appendItems);
+    button.setGlyph("");
+    button.turnIntoSelect();
+
+    /** @type {!Array<!{separator: boolean, text: string, title: string, conditions: !WebInspector.NetworkManager.Conditions}>} */
+    var items = [];
+    var selectedIndex = -1;
+    var selector = new WebInspector.NetworkConditionsSelector(populate, select);
+    return button;
+
+    /**
+     * @param {!WebInspector.ContextMenu} contextMenu
+     */
+    function appendItems(contextMenu)
+    {
+        for (var index = 0; index < items.length; ++index) {
+            var item = items[index];
+            if (item.separator)
+                contextMenu.appendSeparator();
+            else
+                contextMenu.appendCheckboxItem(item.title, selector.optionSelected.bind(selector, item.conditions), selectedIndex === index);
+        }
+        contextMenu.appendItem(WebInspector.UIString("Edit\u2026"), selector.revealAndUpdate.bind(selector));
+    }
+
+    /**
+     * @param {!Array.<!WebInspector.NetworkConditionsProfileGroup>} groups
+     * @return {!Array<!{conditions: !WebInspector.NetworkManager.Conditions}>}
+     */
+    function populate(groups)
+    {
+        items = [];
+        for (var group of groups) {
+            for (var preset of group.items) {
+                var title = WebInspector.NetworkConditionsSelector._profileTitle(preset);
+                items.push({separator: false, text: preset.title, title: title.text, conditions: preset.value});
+            }
+            items.push({separator: true, text: "", title: "", conditions: null});
+        }
+        return /** @type {!Array<!{conditions: !WebInspector.NetworkManager.Conditions}>} */ (items);
+    }
+
+    /**
+     * @param {number} index
+     */
+    function select(index)
+    {
+        selectedIndex = index;
+        button.setText(items[index].text);
+    }
+}
 
 /**
  * @constructor
@@ -131,7 +231,7 @@
 WebInspector.NetworkConditionsSettingsTab = function()
 {
     WebInspector.VBox.call(this, true);
-    this.registerRequiredCSS("network/networkConditionsSettingsTab.css");
+    this.registerRequiredCSS("components/networkConditionsSettingsTab.css");
 
     this.contentElement.createChild("div", "header").textContent = WebInspector.UIString("Network Throttling Profiles");
 
@@ -140,7 +240,7 @@
 
     this._list = new WebInspector.ListWidget(this);
     this._list.element.classList.add("conditions-list");
-    this._list.registerRequiredCSS("network/networkConditionsSettingsTab.css");
+    this._list.registerRequiredCSS("components/networkConditionsSettingsTab.css");
     this._list.show(this.contentElement);
 
     this._customSetting = WebInspector.moduleSetting("networkConditionsCustomProfiles");
@@ -192,9 +292,9 @@
         titleText.textContent = conditions.title;
         titleText.title = conditions.title;
         element.createChild("div", "conditions-list-separator");
-        element.createChild("div", "conditions-list-text").textContent = WebInspector.NetworkConditionsSelector.throughputText(conditions.value.download);
+        element.createChild("div", "conditions-list-text").textContent = WebInspector.NetworkConditionsSelector._throughputText(conditions.value.download);
         element.createChild("div", "conditions-list-separator");
-        element.createChild("div", "conditions-list-text").textContent = WebInspector.NetworkConditionsSelector.throughputText(conditions.value.upload);
+        element.createChild("div", "conditions-list-text").textContent = WebInspector.NetworkConditionsSelector._throughputText(conditions.value.upload);
         element.createChild("div", "conditions-list-separator");
         element.createChild("div", "conditions-list-text").textContent = WebInspector.UIString("%dms", conditions.value.latency);
         return element;
diff --git a/third_party/WebKit/Source/devtools/front_end/components/module.json b/third_party/WebKit/Source/devtools/front_end/components/module.json
index 8310cd7..8fb44c6 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/components/module.json
@@ -14,6 +14,22 @@
             "marker": "breakpoint-marker",
             "title": "DOM Breakpoint",
             "color": "rgb(105, 140, 254)"
+        },
+        {
+            "type": "setting",
+            "settingName": "networkConditionsCustomProfiles",
+            "settingType": "array",
+            "defaultValue": []
+        },
+        {
+            "type": "settings-view",
+            "name": "network-conditions",
+            "title": "Throttling",
+            "order": "35",
+            "className": "WebInspector.NetworkConditionsSettingsTab",
+            "settings": [
+                "networkConditionsCustomProfiles"
+            ]
         }
     ],
     "dependencies": [
@@ -35,6 +51,7 @@
         "HandlerRegistry.js",
         "InspectorView.js",
         "Linkifier.js",
+        "NetworkConditionsSelector.js",
         "ObjectPopoverHelper.js",
         "ObjectPropertiesSection.js",
         "RemoteObjectPreviewFormatter.js",
@@ -49,6 +66,7 @@
         "eventListenersView.css",
         "domUtils.css",
         "inspectorViewTabbedPane.css",
+        "networkConditionsSettingsTab.css",
         "objectPropertiesSection.css",
         "objectValue.css"
     ]
diff --git a/third_party/WebKit/Source/devtools/front_end/network/networkConditionsSettingsTab.css b/third_party/WebKit/Source/devtools/front_end/components/networkConditionsSettingsTab.css
similarity index 100%
rename from third_party/WebKit/Source/devtools/front_end/network/networkConditionsSettingsTab.css
rename to third_party/WebKit/Source/devtools/front_end/components/networkConditionsSettingsTab.css
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/computedStyleSidebarPane.css b/third_party/WebKit/Source/devtools/front_end/elements/computedStyleSidebarPane.css
index 84a06ad..d453c83 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/computedStyleSidebarPane.css
+++ b/third_party/WebKit/Source/devtools/front_end/elements/computedStyleSidebarPane.css
@@ -38,7 +38,6 @@
     position: absolute;
     top: -6px;
     left: -27px;
-    transform: scale(0.8);
 }
 
 .goto-source-icon:hover {
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeToolbar.js b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeToolbar.js
index b3ed9a7bd..8f53f3ae 100644
--- a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeToolbar.js
+++ b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeToolbar.js
@@ -20,6 +20,9 @@
     this._showUserAgentTypeSetting = WebInspector.settings.createSetting("emulation.showUserAgentType", false);
     this._showUserAgentTypeSetting.addChangeListener(this._updateUserAgentTypeVisibility, this);
 
+    this._showNetworkConditionsSetting = WebInspector.settings.createSetting("emulation.showNetworkConditions", false);
+    this._showNetworkConditionsSetting.addChangeListener(this._updateNetworkConditionsVisibility, this);
+
     /** @type {!Map<!WebInspector.EmulatedDevice, !WebInspector.EmulatedDevice.Mode>} */
     this._lastMode = new Map();
 
@@ -136,13 +139,7 @@
         this._scaleItem.setGlyph("");
         this._scaleItem.turnIntoSelect();
         toolbar.appendToolbarItem(this._scaleItem);
-    },
 
-    /**
-     * @param {!WebInspector.Toolbar} toolbar
-     */
-    _fillModeToolbar: function(toolbar)
-    {
         toolbar.appendToolbarItem(this._wrapToolbarItem(createElementWithClass("div", "device-mode-empty-toolbar-element")));
         this._deviceScaleItem = new WebInspector.ToolbarMenuButton(this._appendDeviceScaleMenuItems.bind(this));
         this._deviceScaleItem.setVisible(this._showDeviceScaleFactorSetting.get());
@@ -160,7 +157,13 @@
         this._uaItem.turnIntoSelect();
         this._uaItem.element.style.padding = "0 5px";
         toolbar.appendToolbarItem(this._uaItem);
+    },
 
+    /**
+     * @param {!WebInspector.Toolbar} toolbar
+     */
+    _fillModeToolbar: function(toolbar)
+    {
         toolbar.appendToolbarItem(this._wrapToolbarItem(createElementWithClass("div", "device-mode-empty-toolbar-element")));
         this._modeButton = new WebInspector.ToolbarButton("", "rotate-screen-toolbar-item");
         this._modeButton.addEventListener("click", this._modeMenuClicked, this);
@@ -172,6 +175,13 @@
      */
     _fillOptionsToolbar: function(toolbar)
     {
+        this._networkConditionsItem = WebInspector.NetworkConditionsSelector.createToolbarMenuButton();
+        this._networkConditionsItem.setVisible(this._showNetworkConditionsSetting.get());
+        this._networkConditionsItem.setTitle(WebInspector.UIString("Network throttling"));
+        this._networkConditionsItem.element.style.padding = "0 5px";
+        this._networkConditionsItem.element.style.maxWidth = "140px";
+        toolbar.appendToolbarItem(this._networkConditionsItem);
+
         var moreOptionsButton = new WebInspector.ToolbarMenuButton(this._appendOptionsMenuItems.bind(this));
         moreOptionsButton.setTitle(WebInspector.UIString("More options"));
         toolbar.appendToolbarItem(moreOptionsButton);
@@ -257,10 +267,10 @@
     {
         contextMenu.appendCheckboxItem(WebInspector.UIString("Show device pixel ratio"), this._toggleDeviceScaleFactor.bind(this), this._showDeviceScaleFactorSetting.get(), this._model.type() === WebInspector.DeviceModeModel.Type.None);
         contextMenu.appendCheckboxItem(WebInspector.UIString("Show device type"), this._toggleUserAgentType.bind(this), this._showUserAgentTypeSetting.get(), this._model.type() === WebInspector.DeviceModeModel.Type.None);
+        contextMenu.appendCheckboxItem(WebInspector.UIString("Show throttling"), this._toggleNetworkConditions.bind(this), this._showNetworkConditionsSetting.get(), this._model.type() === WebInspector.DeviceModeModel.Type.None);
         contextMenu.appendCheckboxItem(WebInspector.UIString("Show media queries"), this._toggleMediaInspector.bind(this), this._showMediaInspectorSetting.get(), this._model.type() === WebInspector.DeviceModeModel.Type.None);
         contextMenu.appendCheckboxItem(WebInspector.UIString("Show rulers"), this._toggleRulers.bind(this), this._showRulersSetting.get(), this._model.type() === WebInspector.DeviceModeModel.Type.None);
         contextMenu.appendSeparator();
-        contextMenu.appendItem(WebInspector.UIString("Configure network\u2026"), this._openNetworkConfig.bind(this), false);
         contextMenu.appendItemsAtLocation("deviceModeMenu");
         contextMenu.appendSeparator();
         contextMenu.appendItem(WebInspector.UIString("Reset to defaults"), this._reset.bind(this));
@@ -286,11 +296,9 @@
         this._showRulersSetting.set(!this._showRulersSetting.get());
     },
 
-    _openNetworkConfig: function()
+    _toggleNetworkConditions: function()
     {
-        InspectorFrontendHost.bringToFront();
-        // TODO(dgozman): make it explicit.
-        WebInspector.actionRegistry.action("network.show-config").execute();
+        this._showNetworkConditionsSetting.set(!this._showNetworkConditionsSetting.get());
     },
 
     _reset: function()
@@ -299,6 +307,7 @@
         this._showUserAgentTypeSetting.set(false);
         this._showMediaInspectorSetting.set(false);
         this._showRulersSetting.set(false);
+        this._showNetworkConditionsSetting.set(false);
         this._model.reset();
     },
 
@@ -414,6 +423,11 @@
         this._uaItem.setVisible(this._showUserAgentTypeSetting.get());
     },
 
+    _updateNetworkConditionsVisibility: function()
+    {
+        this._networkConditionsItem.setVisible(this._showNetworkConditionsSetting.get());
+    },
+
     /**
      * @param {!WebInspector.Event} event
      */
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/sensors.css b/third_party/WebKit/Source/devtools/front_end/emulation/sensors.css
index 919e277..ea99a95 100644
--- a/third_party/WebKit/Source/devtools/front_end/emulation/sensors.css
+++ b/third_party/WebKit/Source/devtools/front_end/emulation/sensors.css
@@ -17,7 +17,7 @@
     width: 80px;
 }
 
-.sensors-view input[type=text]:enabled:focus,
+.sensors-view input[type=text]:not(.error-input):enabled:focus,
 .sensors-view select:enabled:focus {
     border-color: rgb(77, 144, 254);
     outline: none;
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkConfigView.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkConfigView.js
index 7042f1b..e44fa6d 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/NetworkConfigView.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkConfigView.js
@@ -41,7 +41,7 @@
     _createNetworkThrottlingSection: function()
     {
         var section = this._createSection(WebInspector.UIString("Network throttling"), "network-config-throttling");
-        new WebInspector.NetworkConditionsSelector(/** @type {!HTMLSelectElement} */(section.createChild("select", "chrome-select")));
+        WebInspector.NetworkConditionsSelector.decorateSelect(/** @type {!HTMLSelectElement} */(section.createChild("select", "chrome-select")));
     },
 
     _createUserAgentSection: function()
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkPanel.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkPanel.js
index 34e66c14..79e97141 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/NetworkPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkPanel.js
@@ -177,7 +177,7 @@
     {
         var toolbarItem = new WebInspector.ToolbarComboBox(null);
         toolbarItem.setMaxWidth(140);
-        new WebInspector.NetworkConditionsSelector(toolbarItem.selectElement());
+        WebInspector.NetworkConditionsSelector.decorateSelect(toolbarItem.selectElement());
         return toolbarItem;
     },
 
diff --git a/third_party/WebKit/Source/devtools/front_end/network/module.json b/third_party/WebKit/Source/devtools/front_end/network/module.json
index cb648194..f7db8b4e 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/network/module.json
@@ -86,22 +86,6 @@
             "persistence": "closeable",
             "order": 40,
             "className": "WebInspector.NetworkConfigView"
-        },
-        {
-            "type": "setting",
-            "settingName": "networkConditionsCustomProfiles",
-            "settingType": "array",
-            "defaultValue": []
-        },
-        {
-            "type": "settings-view",
-            "name": "network-conditions",
-            "title": "Throttling",
-            "order": "35",
-            "className": "WebInspector.NetworkConditionsSettingsTab",
-            "settings": [
-                "networkConditionsCustomProfiles"
-            ]
         }
     ],
     "dependencies": [
@@ -117,7 +101,6 @@
         "HARWriter.js",
         "JSONView.js",
         "RequestView.js",
-        "NetworkConditionsSelector.js",
         "NetworkConfigView.js",
         "NetworkDataGridNode.js",
         "NetworkItemView.js",
@@ -137,7 +120,6 @@
     "resources": [
         "blockedURLsPane.css",
         "eventSourceMessagesView.css",
-        "networkConditionsSettingsTab.css",
         "networkConfigView.css",
         "networkLogView.css",
         "networkPanel.css",
diff --git a/third_party/WebKit/Source/devtools/front_end/platform/utilities.js b/third_party/WebKit/Source/devtools/front_end/platform/utilities.js
index d46addb..699bc73 100644
--- a/third_party/WebKit/Source/devtools/front_end/platform/utilities.js
+++ b/third_party/WebKit/Source/devtools/front_end/platform/utilities.js
@@ -1273,6 +1273,16 @@
 }
 
 /**
+ * @param {!Iterable<T>} iterable
+ * @template T
+ */
+Set.prototype.addAll = function(iterable)
+{
+    for (var e of iterable)
+        this.add(e);
+}
+
+/**
  * @return {T}
  * @template T
  */
@@ -1540,3 +1550,112 @@
         return defaultValue;
     });
 }
+
+/**
+ * @constructor
+ * @param {(function(!Segment, !Segment): ?Segment)=} mergeCallback
+ */
+function SegmentedRange(mergeCallback)
+{
+    /** @type {!Array<!Segment>} */
+    this._segments = [];
+    this._mergeCallback = mergeCallback;
+}
+
+/**
+ * @constructor
+ * @param {number} begin
+ * @param {number} end
+ * @param {*} data
+ */
+function Segment(begin, end, data)
+{
+    if (begin > end)
+        console.assert(false, "Invalid segment");
+    this.begin = begin;
+    this.end = end;
+    this.data = data;
+}
+
+Segment.prototype = {
+    /**
+     * @param {!Segment} that
+     * @return {boolean}
+     */
+    intersects: function(that)
+    {
+        return this.begin < that.end && that.begin < this.end;
+    }
+};
+
+SegmentedRange.prototype = {
+    /**
+     * @param {!Segment} newSegment
+     */
+    append: function(newSegment)
+    {
+        // 1. Find the proper insertion point for new segment
+        var startIndex = this._segments.lowerBound(newSegment, (a, b) => a.begin - b.begin);
+        var endIndex = startIndex;
+        var merged = null;
+        if (startIndex > 0) {
+            // 2. Try mering the preceding segment
+            var precedingSegment = this._segments[startIndex - 1];
+            merged = this._tryMerge(precedingSegment, newSegment);
+            if (merged) {
+                --startIndex;
+                newSegment = merged;
+            } else if (this._segments[startIndex - 1].end >= newSegment.begin) {
+                // 2a. If merge failed and segments overlap, adjust preceding segment.
+                // If an old segment entirely contains new one, split it in two.
+                if (newSegment.end < precedingSegment.end)
+                    this._segments.splice(startIndex, 0, new Segment(newSegment.end, precedingSegment.end, precedingSegment.data));
+                precedingSegment.end = newSegment.begin;
+            }
+        }
+        // 3. Consume all segments that are entirely covered by the new one.
+        while (endIndex < this._segments.length && this._segments[endIndex].end <= newSegment.end)
+            ++endIndex;
+        // 4. Merge or adjust the succeeding segment if it overlaps.
+        if (endIndex < this._segments.length) {
+            merged = this._tryMerge(newSegment, this._segments[endIndex]);
+            if (merged) {
+                endIndex++;
+                newSegment = merged;
+            } else if (newSegment.intersects(this._segments[endIndex]))
+                this._segments[endIndex].begin = newSegment.end;
+        }
+        this._segments.splice(startIndex, endIndex - startIndex, newSegment);
+    },
+
+    /**
+     * @param {!SegmentedRange} that
+     */
+    appendRange: function(that)
+    {
+        that.segments().forEach(segment => this.append(segment));
+    },
+
+    /**
+     * @return {!Array<!Segment>}
+     */
+    segments: function()
+    {
+        return this._segments;
+    },
+
+    /**
+     * @param {!Segment} first
+     * @param {!Segment} second
+     * @return {?Segment}
+     */
+    _tryMerge: function(first, second)
+    {
+        var merged = this._mergeCallback && this._mergeCallback(first, second);
+        if (!merged)
+            return null;
+        merged.begin = first.begin;
+        merged.end = Math.max(first.end, second.end);
+        return merged;
+    }
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBModel.js b/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBModel.js
index c739ab8..c3853060 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBModel.js
@@ -330,7 +330,7 @@
 
             if (!this._databaseNamesBySecurityOrigin[databaseId.securityOrigin])
                 return;
-            var databaseModel = new WebInspector.IndexedDBModel.Database(databaseId, databaseWithObjectStores.intVersion);
+            var databaseModel = new WebInspector.IndexedDBModel.Database(databaseId, databaseWithObjectStores.version);
             this._databases.set(databaseId, databaseModel);
             for (var i = 0; i < databaseWithObjectStores.objectStores.length; ++i) {
                 var objectStore = databaseWithObjectStores.objectStores[i];
@@ -459,12 +459,12 @@
 /**
  * @constructor
  * @param {!WebInspector.IndexedDBModel.DatabaseId} databaseId
- * @param {number} intVersion
+ * @param {number} version
  */
-WebInspector.IndexedDBModel.Database = function(databaseId, intVersion)
+WebInspector.IndexedDBModel.Database = function(databaseId, version)
 {
     this.databaseId = databaseId;
-    this.intVersion = intVersion;
+    this.version = version;
     this.objectStores = {};
 }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBViews.js b/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBViews.js
index c607d8a..7ae1cc8 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBViews.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBViews.js
@@ -54,13 +54,9 @@
     this._nameTreeElement.selectable = false;
     this._headersTreeOutline.appendChild(this._nameTreeElement);
 
-    this._intVersionTreeElement = new TreeElement();
-    this._intVersionTreeElement.selectable = false;
-    this._headersTreeOutline.appendChild(this._intVersionTreeElement);
-
-    this._stringVersionTreeElement = new TreeElement();
-    this._stringVersionTreeElement.selectable = false;
-    this._headersTreeOutline.appendChild(this._stringVersionTreeElement);
+    this._versionTreeElement = new TreeElement();
+    this._versionTreeElement.selectable = false;
+    this._headersTreeOutline.appendChild(this._versionTreeElement);
 
     this.update(database);
 }
@@ -91,8 +87,7 @@
     {
         this._securityOriginTreeElement.title = this._formatHeader(WebInspector.UIString("Security origin"), this._database.databaseId.securityOrigin);
         this._nameTreeElement.title = this._formatHeader(WebInspector.UIString("Name"), this._database.databaseId.name);
-        this._stringVersionTreeElement.title = this._formatHeader(WebInspector.UIString("String Version"), this._database.version);
-        this._intVersionTreeElement.title = this._formatHeader(WebInspector.UIString("Integer Version"), this._database.intVersion);
+        this._versionTreeElement.title = this._formatHeader(WebInspector.UIString("Version"), this._database.version);
     },
 
     /**
diff --git a/third_party/WebKit/Source/devtools/front_end/sass/ASTSourceMap.js b/third_party/WebKit/Source/devtools/front_end/sass/ASTSourceMap.js
index 787cb2e..989c303 100644
--- a/third_party/WebKit/Source/devtools/front_end/sass/ASTSourceMap.js
+++ b/third_party/WebKit/Source/devtools/front_end/sass/ASTSourceMap.js
@@ -4,13 +4,14 @@
 
 /**
  * @constructor
- * @param {!WebInspector.SASSSupport.AST} cssAST
- * @param {!Map<string, !WebInspector.SASSSupport.AST>} sassModels
+ * @param {string} cssURL
+ * @param {!Map<string, !WebInspector.SASSSupport.AST>} models
  */
-WebInspector.ASTSourceMap = function(cssAST, sassModels)
+WebInspector.ASTSourceMap = function(cssURL, models)
 {
-    this._cssAST = cssAST;
-    this._sassModels = sassModels;
+    this._cssURL = cssURL;
+    /** @type {!Map<string, !WebInspector.SASSSupport.AST>} */
+    this._models = models;
     /** @type {!Map<!WebInspector.SASSSupport.TextNode, !WebInspector.SASSSupport.TextNode>} */
     this._cssToSass = new Map();
     /** @type {!Multimap<!WebInspector.SASSSupport.TextNode, !WebInspector.SASSSupport.TextNode>} */
@@ -30,23 +31,24 @@
         return Promise.resolve(/** @type {?WebInspector.ASTSourceMap} */(null));
     var header = cssModel.styleSheetHeaderForId(headerIds[0]);
 
-    var sassModels = new Map();
-    var cssAST = null;
+    /** @type {!Map<string, !WebInspector.SASSSupport.AST>} */
+    var models = new Map();
     var promises = [];
     for (var url of sourceMap.sources()) {
         var contentProvider = sourceMap.sourceContentProvider(url, WebInspector.resourceTypes.SourceMapStyleSheet);
         var sassPromise = contentProvider.requestContent()
             .then(onSCSSText.bind(null, url))
-            .then(ast => sassModels.set(ast.document.url, ast));
+            .then(ast => models.set(ast.document.url, ast));
         promises.push(sassPromise);
     }
+    var cssURL = sourceMap.compiledURL();
     var cssPromise = header.requestContent()
-        .then(text => astService.parseCSS(sourceMap.compiledURL(), text || ""))
-        .then(ast => cssAST = ast);
+        .then(text => astService.parseCSS(cssURL, text || ""))
+        .then(ast => models.set(ast.document.url, ast));
     promises.push(cssPromise);
 
     return Promise.all(promises)
-        .then(() => onParsed(cssAST, sassModels, sourceMap))
+        .then(() => onParsed(cssURL, models, sourceMap))
         .catchException(/** @type {?WebInspector.ASTSourceMap} */(null));
 
     /**
@@ -60,44 +62,53 @@
     }
 
     /**
-     * @param {!WebInspector.SASSSupport.AST} cssAST
-     * @param {!Map<string, !WebInspector.SASSSupport.AST>} sassModels
+     * @param {string} cssURL
+     * @param {!Map<string, !WebInspector.SASSSupport.AST>} models
      * @param {!WebInspector.SourceMap} sourceMap
+     * @return {!WebInspector.ASTSourceMap}
      */
-    function onParsed(cssAST, sassModels, sourceMap)
+    function onParsed(cssURL, models, sourceMap)
     {
-        var mapping = new WebInspector.ASTSourceMap(cssAST, sassModels);
+        var map = new WebInspector.ASTSourceMap(cssURL, models);
         //FIXME: this works O(N^2).
-        cssAST.visit(map);
-        return mapping;
+        map.cssAST().visit(onNode);
+        return map;
 
         /**
          * @param {!WebInspector.SASSSupport.Node} cssNode
          */
-        function map(cssNode)
+        function onNode(cssNode)
         {
             if (!(cssNode instanceof WebInspector.SASSSupport.TextNode))
                 return;
             var entry = sourceMap.findEntry(cssNode.range.endLine, cssNode.range.endColumn);
             if (!entry || !entry.sourceURL || typeof entry.sourceLineNumber === "undefined" || typeof entry.sourceColumnNumber === "undefined")
                 return;
-            var sassAST = sassModels.get(entry.sourceURL);
+            var sassAST = models.get(entry.sourceURL);
             if (!sassAST)
                 return;
             var sassNode = sassAST.findNodeForPosition(entry.sourceLineNumber, entry.sourceColumnNumber);
             if (sassNode)
-                mapping.mapCssToSass(cssNode, sassNode);
+                map.mapCssToSass(cssNode, sassNode);
         }
     }
 }
 
 WebInspector.ASTSourceMap.prototype = {
     /**
+     * @return {string}
+     */
+    cssURL: function()
+    {
+        return this._cssURL;
+    },
+
+    /**
      * @return {!WebInspector.SASSSupport.AST}
      */
     cssAST: function()
     {
-        return this._cssAST;
+        return /** @type {!WebInspector.SASSSupport.AST} */(this._models.get(this._cssURL));
     },
 
     /**
@@ -105,7 +116,26 @@
      */
     sassModels: function()
     {
-        return this._sassModels;
+        var sassModels = new Map(this._models);
+        sassModels.delete(this._cssURL);
+        return sassModels;
+    },
+
+    /**
+     * @return {!Map<string, !WebInspector.SASSSupport.AST>}
+     */
+    models: function()
+    {
+        return new Map(this._models);
+    },
+
+    /**
+     * @param {string} url
+     * @return {?WebInspector.SASSSupport.AST}
+     */
+    modelForURL: function(url)
+    {
+        return this._models.get(url) || null;
     },
 
     /**
@@ -167,41 +197,33 @@
     },
 
     /**
-     * @param {!WebInspector.SASSSupport.ASTDiff} cssDiff
-     * @return {!WebInspector.ASTSourceMap}
+     * @param {!Array<!WebInspector.SASSSupport.AST>} updated
+     * @param {!Map<!WebInspector.SASSSupport.Node, !WebInspector.SASSSupport.Node>=} outNodeMapping
+     * @return {?WebInspector.ASTSourceMap}
      */
-    rebaseForCSSDiff: function(cssDiff)
+    rebase: function(updated, outNodeMapping)
     {
-        var newMapping = new WebInspector.ASTSourceMap(cssDiff.newAST, this._sassModels);
-        var cssNodes = this._cssToSass.keysArray();
-        for (var i = 0; i < cssNodes.length; ++i) {
-            var cssNode = cssNodes[i];
-            var sassNode = this._cssToSass.get(cssNode);
-            var mappedNode = cssDiff.mapping.get(cssNode);
-            if (mappedNode && sassNode)
-                newMapping.mapCssToSass(mappedNode, sassNode);
-        }
-        return newMapping;
-    },
+        outNodeMapping = outNodeMapping || new Map();
+        outNodeMapping.clear();
 
-    /**
-     * @param {!WebInspector.SASSSupport.ASTDiff} sassDiff
-     * @return {!WebInspector.ASTSourceMap}
-     */
-    rebaseForSASSDiff: function(sassDiff)
-    {
-        var sassModels = new Map(this._sassModels);
-        sassModels.set(sassDiff.url, sassDiff.newAST);
-        var newMapping = new WebInspector.ASTSourceMap(this._cssAST, sassModels);
+        var models = new Map(this._models);
+        for (var newAST of updated) {
+            var oldAST = models.get(newAST.document.url);
+            if (!oldAST.match(newAST, outNodeMapping))
+                return null;
+            models.set(newAST.document.url, newAST);
+        }
+
+        var newMap = new WebInspector.ASTSourceMap(this._cssURL, models);
         var cssNodes = this._cssToSass.keysArray();
         for (var i = 0; i < cssNodes.length; ++i) {
             var cssNode = cssNodes[i];
-            var sassNode = this._cssToSass.get(cssNode);
-            var mappedNode = sassNode.document.url === sassDiff.url ? sassDiff.mapping.get(sassNode) : sassNode;
-            if (mappedNode)
-                newMapping.mapCssToSass(cssNode, mappedNode);
+            var sassNode = /** @type {!WebInspector.SASSSupport.TextNode} */(this._cssToSass.get(cssNode));
+            var mappedCSSNode = /** @type {!WebInspector.SASSSupport.TextNode} */(outNodeMapping.get(cssNode) || cssNode);
+            var mappedSASSNode = /** @type {!WebInspector.SASSSupport.TextNode} */(outNodeMapping.get(sassNode) || sassNode);
+            newMap.mapCssToSass(mappedCSSNode, mappedSASSNode);
         }
-        return newMapping;
+        return newMap;
     },
 
     /**
diff --git a/third_party/WebKit/Source/devtools/front_end/sass/SASSProcessor.js b/third_party/WebKit/Source/devtools/front_end/sass/SASSProcessor.js
new file mode 100644
index 0000000..ed9d31861
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/sass/SASSProcessor.js
@@ -0,0 +1,287 @@
+// Copyright 2016 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.
+
+/**
+ * @constructor
+ * @param {!WebInspector.ASTService} astService
+ * @param {!WebInspector.ASTSourceMap} map
+ * @param {!Array<!WebInspector.SASSProcessor.EditOperation>} editOperations
+ */
+WebInspector.SASSProcessor = function(astService, map, editOperations)
+{
+    this._astService = astService;
+    this._map = map;
+    this._editOperations = editOperations;
+}
+
+WebInspector.SASSProcessor.prototype = {
+    /**
+     * @return {!Promise<?WebInspector.SASSProcessor.Result>}
+     */
+    _mutate: function()
+    {
+        /** @type {!Set<!WebInspector.SASSSupport.Rule>} */
+        var changedCSSRules = new Set();
+        for (var editOperation of this._editOperations) {
+            var rules = editOperation.perform();
+            changedCSSRules.addAll(rules);
+        }
+
+        // Reparse new texts, make sure changes result in anticipated AST trees.
+        var promises = [];
+        for (var ast of this._map.models().values()) {
+            if (!ast.document.hasChanged())
+                continue;
+            var promise;
+            if (ast.document.url === this._map.cssURL())
+                promise = this._astService.parseCSS(ast.document.url, ast.document.newText());
+            else
+                promise = this._astService.parseSCSS(ast.document.url, ast.document.newText());
+            promises.push(promise);
+        }
+
+        return Promise.all(promises)
+            .then(this._onFinished.bind(this, changedCSSRules));
+    },
+
+    /**
+     * @param {!Set<!WebInspector.SASSSupport.Rule>} changedCSSRules
+     * @param {!Array<!WebInspector.SASSSupport.AST>} changedModels
+     * @return {?WebInspector.SASSProcessor.Result}
+     */
+    _onFinished: function(changedCSSRules, changedModels)
+    {
+        var nodeMapping = new Map();
+        var map = this._map.rebase(changedModels, nodeMapping);
+        if (!map)
+            return null;
+
+        var cssEdits = [];
+        for (var rule of changedCSSRules) {
+            var oldRange = rule.styleRange;
+            var newRule = nodeMapping.get(rule);
+            var newText = newRule.styleRange.extract(newRule.document.text);
+            cssEdits.push(new WebInspector.SourceEdit(newRule.document.url, oldRange, newText));
+        }
+
+        /** @type {!Map<string, string>} */
+        var newSASSSources = new Map();
+        for (var model of changedModels) {
+            if (model.document.url === map.cssURL())
+                continue;
+            newSASSSources.set(model.document.url, model.document.text);
+        }
+        return new WebInspector.SASSProcessor.Result(map, cssEdits, newSASSSources);
+    }
+}
+
+/**
+ * @constructor
+ * @param {!WebInspector.ASTSourceMap} map
+ * @param {!Array<!WebInspector.SourceEdit>} cssEdits
+ * @param {!Map<string, string>} newSASSSources
+ */
+WebInspector.SASSProcessor.Result = function(map, cssEdits, newSASSSources)
+{
+    this.map = map;
+    this.cssEdits = cssEdits;
+    this.newSASSSources = newSASSSources;
+}
+
+/**
+ * @param {!WebInspector.ASTService} astService
+ * @param {!WebInspector.ASTSourceMap} map
+ * @param {!Array<!WebInspector.TextRange>} ranges
+ * @param {!Array<string>} newTexts
+ * @return {!Promise<?WebInspector.SASSProcessor.Result>}
+ */
+WebInspector.SASSProcessor.processCSSEdits = function(astService, map, ranges, newTexts)
+{
+    console.assert(ranges.length === newTexts.length);
+    var cssURL = map.cssURL();
+    var cssText = map.cssAST().document.text;
+    for (var i = 0; i < ranges.length; ++i) {
+        var range = ranges[i];
+        var edit = new WebInspector.SourceEdit(cssURL, range, newTexts[i]);
+        cssText = edit.applyToText(cssText);
+    }
+    return astService.parseCSS(cssURL, cssText)
+        .then(onCSSParsed);
+
+    /**
+     * @param {!WebInspector.SASSSupport.AST} newCSSAST
+     * @return {!Promise<?WebInspector.SASSProcessor.Result>}
+     */
+    function onCSSParsed(newCSSAST)
+    {
+        //TODO(lushnikov): only diff changed styles.
+        var cssDiff = WebInspector.SASSSupport.diffModels(map.cssAST(), newCSSAST);
+        var edits = WebInspector.SASSProcessor._editsFromCSSDiff(cssDiff, map);
+
+        // Determine AST trees which will change and clone them.
+        var changedURLs = new Set(edits.map(edit => edit.sassURL));
+        changedURLs.add(map.cssURL());
+        var clonedModels = [];
+        for (var url of changedURLs)
+            clonedModels.push(map.modelForURL(url).clone());
+
+        // Rebase map and edits onto a cloned AST trees.
+        var nodeMapping = new Map();
+        var rebasedMap = /** @type {!WebInspector.ASTSourceMap} */(map.rebase(clonedModels, nodeMapping));
+        console.assert(rebasedMap);
+        var rebasedEdits = edits.map(edit => edit.rebase(rebasedMap, nodeMapping));
+
+        return new WebInspector.SASSProcessor(astService, rebasedMap, rebasedEdits)._mutate();
+    }
+}
+
+/**
+ * @param {!WebInspector.SASSSupport.ASTDiff} cssDiff
+ * @param {!WebInspector.ASTSourceMap} map
+ * @return {!Array<!WebInspector.SASSProcessor.EditOperation>}
+ */
+WebInspector.SASSProcessor._editsFromCSSDiff = function(cssDiff, map)
+{
+    var T = WebInspector.SASSSupport.PropertyChangeType;
+    var operations = [];
+    for (var i = 0; i < cssDiff.changes.length; ++i) {
+        var change = cssDiff.changes[i];
+        var operation = null;
+        if (change.type === T.ValueChanged || change.type === T.NameChanged)
+            operation = WebInspector.SASSProcessor.SetTextOperation.fromCSSChange(change, map);
+        if (!operation) {
+            WebInspector.console.error("Operation ignored: " + change.type);
+            continue;
+        }
+
+        var merged = false;
+        for (var j = 0; !merged && j < operations.length; ++j)
+            merged = operations[j].merge(operation);
+        if (!merged)
+            operations.push(operation);
+    }
+    return operations;
+}
+
+/**
+ * @constructor
+ * @param {!WebInspector.ASTSourceMap} map
+ * @param {string} sassURL
+ */
+WebInspector.SASSProcessor.EditOperation = function(map, sassURL)
+{
+    this.map = map;
+    this.sassURL = sassURL;
+}
+
+WebInspector.SASSProcessor.EditOperation.prototype = {
+    /**
+     * @param {!WebInspector.SASSProcessor.EditOperation} other
+     * @return {boolean}
+     */
+    merge: function(other)
+    {
+        return false;
+    },
+
+    /**
+     * @return {!Array<!WebInspector.SASSSupport.Rule>}
+     */
+    perform: function()
+    {
+        return [];
+    },
+
+    /**
+     * @param {!WebInspector.ASTSourceMap} newMap
+     * @param {!Map<!WebInspector.SASSSupport.Node, !WebInspector.SASSSupport.Node>} nodeMapping
+     * @return {!WebInspector.SASSProcessor.EditOperation}
+     */
+    rebase: function(newMap, nodeMapping)
+    {
+        return this;
+    },
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.SASSProcessor.EditOperation}
+ * @param {!WebInspector.ASTSourceMap} map
+ * @param {!WebInspector.SASSSupport.TextNode} sassNode
+ * @param {string} newText
+ */
+WebInspector.SASSProcessor.SetTextOperation = function(map, sassNode, newText)
+{
+    WebInspector.SASSProcessor.EditOperation.call(this, map, sassNode.document.url);
+    this._sassNode = sassNode;
+    this._newText = newText;
+}
+
+/**
+ * @param {!WebInspector.SASSSupport.PropertyChange} change
+ * @param {!WebInspector.ASTSourceMap} map
+ * @return {?WebInspector.SASSProcessor.SetTextOperation}
+ */
+WebInspector.SASSProcessor.SetTextOperation.fromCSSChange = function(change, map)
+{
+    var oldProperty = /** @type {!WebInspector.SASSSupport.Property} */(change.oldProperty());
+    var newProperty = /** @type {!WebInspector.SASSSupport.Property} */(change.newProperty());
+    console.assert(oldProperty && newProperty, "SetTextOperation must have both oldProperty and newProperty");
+    var newValue = null;
+    var sassNode = null;
+    if (change.type === WebInspector.SASSSupport.PropertyChangeType.NameChanged) {
+        newValue = newProperty.name.text;
+        sassNode = map.toSASSNode(oldProperty.name);
+    } else {
+        newValue = newProperty.value.text;
+        sassNode = map.toSASSNode(oldProperty.value);
+    }
+    if (!sassNode)
+        return null;
+    return new WebInspector.SASSProcessor.SetTextOperation(map, sassNode, newValue);
+}
+
+WebInspector.SASSProcessor.SetTextOperation.prototype = {
+    /**
+     * @override
+     * @param {!WebInspector.SASSProcessor.EditOperation} other
+     * @return {boolean}
+     */
+    merge: function(other)
+    {
+        if (!(other instanceof WebInspector.SASSProcessor.SetTextOperation))
+            return false;
+        return this._sassNode === other._sassNode;
+    },
+
+    /**
+     * @override
+     * @return {!Array<!WebInspector.SASSSupport.Rule>}
+     */
+    perform: function()
+    {
+        this._sassNode.setText(this._newText);
+        var nodes = this.map.toCSSNodes(this._sassNode);
+        for (var node of nodes)
+            node.setText(this._newText);
+
+        var cssRules = nodes.map(textNode => textNode.parent.parent);
+        return cssRules;
+    },
+
+    /**
+     * @override
+     * @param {!WebInspector.ASTSourceMap} newMap
+     * @param {!Map<!WebInspector.SASSSupport.Node, !WebInspector.SASSSupport.Node>} nodeMapping
+     * @return {!WebInspector.SASSProcessor.SetTextOperation}
+     */
+    rebase: function(newMap, nodeMapping)
+    {
+        var sassNode = /** @type {?WebInspector.SASSSupport.TextNode} */(nodeMapping.get(this._sassNode)) || this._sassNode;
+        return new WebInspector.SASSProcessor.SetTextOperation(newMap, sassNode, this._newText);
+    },
+
+    __proto__: WebInspector.SASSProcessor.EditOperation.prototype
+}
+
diff --git a/third_party/WebKit/Source/devtools/front_end/sass/SASSSupport.js b/third_party/WebKit/Source/devtools/front_end/sass/SASSSupport.js
index d6744a5..bb387c2e 100644
--- a/third_party/WebKit/Source/devtools/front_end/sass/SASSSupport.js
+++ b/third_party/WebKit/Source/devtools/front_end/sass/SASSSupport.js
@@ -256,6 +256,14 @@
     },
 
     /**
+     * @return {boolean}
+     */
+    hasChanged: function()
+    {
+        return !!this.edits.length;
+    },
+
+    /**
      * @return {string}
      */
     newText: function()
@@ -314,7 +322,7 @@
         if (this.text === newText)
             return;
         this.text = newText;
-        this.document.edits.push(new WebInspector.SourceEdit(this.document.url, this.range, this.text, newText));
+        this.document.edits.push(new WebInspector.SourceEdit(this.document.url, this.range, newText));
     },
 
     /**
@@ -326,6 +334,20 @@
         return new WebInspector.SASSSupport.TextNode(document, this.text, this.range.clone());
     },
 
+    /**
+     * @param {!WebInspector.SASSSupport.TextNode} other
+     * @param {!Map<!WebInspector.SASSSupport.Node, !WebInspector.SASSSupport.Node>=} outNodeMapping
+     * @return {boolean}
+     */
+    match: function(other, outNodeMapping)
+    {
+        if (this.text.trim() !== other.text.trim())
+            return false;
+        if (outNodeMapping)
+            outNodeMapping.set(this, other);
+        return true;
+    },
+
     __proto__: WebInspector.SASSSupport.Node.prototype
 }
 
@@ -370,6 +392,20 @@
     },
 
     /**
+     * @param {!WebInspector.SASSSupport.Property} other
+     * @param {!Map<!WebInspector.SASSSupport.Node, !WebInspector.SASSSupport.Node>=} outNodeMapping
+     * @return {boolean}
+     */
+    match: function(other, outNodeMapping)
+    {
+        if (this.disabled !== other.disabled)
+            return false;
+        if (outNodeMapping)
+            outNodeMapping.set(this, other);
+        return this.name.match(other.name, outNodeMapping) && this.value.match(other.value, outNodeMapping);
+    },
+
+    /**
      * @param {boolean} disabled
      */
     setDisabled: function(disabled)
@@ -379,17 +415,17 @@
         this.disabled = disabled;
         if (disabled) {
             var oldRange1 = WebInspector.TextRange.createFromLocation(this.range.startLine, this.range.startColumn);
-            var edit1 = new WebInspector.SourceEdit(this.document.url, oldRange1, "", "/* ");
+            var edit1 = new WebInspector.SourceEdit(this.document.url, oldRange1, "/* ");
             var oldRange2 = WebInspector.TextRange.createFromLocation(this.range.endLine, this.range.endColumn);
-            var edit2 = new WebInspector.SourceEdit(this.document.url, oldRange2, "", " */");
+            var edit2 = new WebInspector.SourceEdit(this.document.url, oldRange2, " */");
             this.document.edits.push(edit1, edit2);
             return;
         }
         var oldRange1 = new WebInspector.TextRange(this.range.startLine, this.range.startColumn, this.range.startLine, this.name.range.startColumn);
         var text = this.document.text;
-        var edit1 = new WebInspector.SourceEdit(this.document.url, oldRange1, oldRange1.extract(text), "");
+        var edit1 = new WebInspector.SourceEdit(this.document.url, oldRange1, "");
         var oldRange2 = new WebInspector.TextRange(this.range.endLine, this.range.endColumn - 2, this.range.endLine, this.range.endColumn);
-        var edit2 = new WebInspector.SourceEdit(this.document.url, oldRange2, "*/", "");
+        var edit2 = new WebInspector.SourceEdit(this.document.url, oldRange2, "");
         this.document.edits.push(edit1, edit2);
     },
 
@@ -407,7 +443,7 @@
             oldRange = lineRange;
         else
             oldRange = this.range;
-        this.document.edits.push(new WebInspector.SourceEdit(this.document.url, oldRange, oldRange.extract(this.document.text), ""));
+        this.document.edits.push(new WebInspector.SourceEdit(this.document.url, oldRange, ""));
     },
 
     __proto__: WebInspector.SASSSupport.Node.prototype
@@ -456,12 +492,31 @@
             this.properties[i].visit(callback);
     },
 
+    /**
+     * @param {!WebInspector.SASSSupport.Rule} other
+     * @param {!Map<!WebInspector.SASSSupport.Node, !WebInspector.SASSSupport.Node>=} outNodeMapping
+     * @return {boolean}
+     */
+    match: function(other, outNodeMapping)
+    {
+        if (this.selector !== other.selector)
+            return false;
+        if (this.properties.length !== other.properties.length)
+            return false;
+        if (outNodeMapping)
+            outNodeMapping.set(this, other);
+        var result = true;
+        for (var i = 0; result && i < this.properties.length; ++i)
+            result = result && this.properties[i].match(other.properties[i], outNodeMapping);
+        return result;
+    },
+
     _addTrailingSemicolon: function()
     {
         if (this._hasTrailingSemicolon || !this.properties)
             return;
         this._hasTrailingSemicolon = true;
-        this.document.edits.push(new WebInspector.SourceEdit(this.document.url, this.properties.peekLast().range.collapseToEnd(), "", ";"))
+        this.document.edits.push(new WebInspector.SourceEdit(this.document.url, this.properties.peekLast().range.collapseToEnd(), ";"))
     },
 
     /**
@@ -521,7 +576,7 @@
         } else {
             newText = String.sprintf("\n%s%s%s: %s;%s", indent, leftComment, nameText, valueText, rightComment);
         }
-        return new WebInspector.SourceEdit(this.document.url, oldRange, "", newText);
+        return new WebInspector.SourceEdit(this.document.url, oldRange, newText);
     },
 
     __proto__: WebInspector.SASSSupport.Node.prototype
@@ -555,6 +610,25 @@
     },
 
     /**
+     * @param {!WebInspector.SASSSupport.AST} other
+     * @param {!Map<!WebInspector.SASSSupport.Node, !WebInspector.SASSSupport.Node>=} outNodeMapping
+     * @return {boolean}
+     */
+    match: function(other, outNodeMapping)
+    {
+        if (other.document.url !== this.document.url)
+            return false;
+        if (other.rules.length !== this.rules.length)
+            return false;
+        if (outNodeMapping)
+            outNodeMapping.set(this, other);
+        var result = true;
+        for (var i = 0; result && i < this.rules.length; ++i)
+            result = result && this.rules[i].match(other.rules[i], outNodeMapping);
+        return result;
+    },
+
+    /**
      * @param {function(!WebInspector.SASSSupport.Node)} callback
      */
     visit: function(callback)
@@ -616,6 +690,24 @@
     this.newPropertyIndex = newPropertyIndex;
 }
 
+WebInspector.SASSSupport.PropertyChange.prototype = {
+    /**
+     * @return {?WebInspector.SASSSupport.Property}
+     */
+    oldProperty: function()
+    {
+        return this.oldRule.properties[this.oldPropertyIndex] || null;
+    },
+
+    /**
+     * @return {?WebInspector.SASSSupport.Property}
+     */
+    newProperty: function()
+    {
+        return this.newRule.properties[this.newPropertyIndex] || null;
+    }
+}
+
 /**
  * @constructor
  * @param {string} url
diff --git a/third_party/WebKit/Source/devtools/front_end/sass/module.json b/third_party/WebKit/Source/devtools/front_end/sass/module.json
index 2c9da98..317d348f 100644
--- a/third_party/WebKit/Source/devtools/front_end/sass/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/sass/module.json
@@ -3,6 +3,7 @@
     "scripts": [
         "SASSSupport.js",
         "ASTService.js",
+        "SASSProcessor.js",
         "ASTSourceMap.js"
     ]
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleModel.js
index cc46da3..3707481 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleModel.js
@@ -1601,7 +1601,7 @@
         {
             if (!insideProperty) {
                 var disabledProperty = tokenType && tokenType.includes("css-comment") && isDisabledProperty(token);
-                var isPropertyStart = tokenType && (tokenType.includes("css-meta") || tokenType.includes("css-property") || tokenType.includes("css-variable-2"));
+                var isPropertyStart = tokenType && (tokenType.includes("css-string") || tokenType.includes("css-meta") || tokenType.includes("css-property") || tokenType.includes("css-variable-2"));
                 if (disabledProperty) {
                     result = result.trimRight() + indentation + token;
                 } else if (isPropertyStart) {
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/DOMModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/DOMModel.js
index 981e353..ba8394e 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/DOMModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/DOMModel.js
@@ -1807,7 +1807,8 @@
     _buildHighlightConfig: function(mode)
     {
         mode = mode || "all";
-        var highlightConfig = { showInfo: mode === "all", showRulers: WebInspector.moduleSetting("showMetricsRulers").get(), showExtensionLines: true };
+        var showRulers = WebInspector.moduleSetting("showMetricsRulers").get();
+        var highlightConfig = { showInfo: mode === "all", showRulers: showRulers, showExtensionLines: showRulers };
         if (mode === "all" || mode === "content")
             highlightConfig.contentColor = WebInspector.Color.PageHighlight.Content.toProtocolRGBA();
 
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js
index 245e93b..ebbec5604 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js
@@ -818,7 +818,7 @@
     },
 
     /**
-     * @param {!WebInspector.Segment} segment
+     * @param {!Segment} segment
      */
     _appendSegment: function(segment)
     {
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineIRModel.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineIRModel.js
index 03483d9..ffaf571 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineIRModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineIRModel.js
@@ -82,7 +82,7 @@
         var animations = asyncEventsByGroup.get(groups.animation);
         if (animations)
             this._processAnimations(animations);
-        var range = new WebInspector.SegmentedRange();
+        var range = new SegmentedRange();
         range.appendRange(this._drags); // Drags take lower precedence than animation, as we can't detect them reliably.
         range.appendRange(this._cssAnimations);
         range.appendRange(this._scrolls);
@@ -129,7 +129,7 @@
                 // FIXME: also process renderer fling events.
                 if (!flingStart)
                     break;
-                this._scrolls.append(new WebInspector.Segment(flingStart.startTime, event.endTime, phases.Fling));
+                this._scrolls.append(new Segment(flingStart.startTime, event.endTime, phases.Fling));
                 flingStart = null;
                 break;
 
@@ -168,7 +168,7 @@
                     this._drags.append(this._segmentForEvent(event, phases.Drag));
                 } else if (touchStart) {
                     firstTouchMove = event;
-                    this._responses.append(new WebInspector.Segment(touchStart.startTime, event.endTime, phases.Response));
+                    this._responses.append(new Segment(touchStart.startTime, event.endTime, phases.Response));
                 }
                 break;
 
@@ -199,7 +199,7 @@
             case eventTypes.MouseWheel:
                 // Do not consider first MouseWheel as trace viewer's implementation does -- in case of MouseWheel it's not really special.
                 if (mouseWheel && canMerge(thresholdsMs.mouse, mouseWheel, event))
-                    this._scrolls.append(new WebInspector.Segment(mouseWheel.endTime, event.startTime, phases.Scroll));
+                    this._scrolls.append(new Segment(mouseWheel.endTime, event.startTime, phases.Scroll));
                 this._scrolls.append(this._segmentForEvent(event, phases.Scroll));
                 mouseWheel = event;
                 break;
@@ -230,15 +230,15 @@
     /**
      * @param {!WebInspector.TracingModel.AsyncEvent} event
      * @param {!WebInspector.TimelineIRModel.Phases} phase
-     * @return {!WebInspector.Segment}
+     * @return {!Segment}
      */
     _segmentForEvent: function(event, phase)
     {
-        return new WebInspector.Segment(event.startTime, event.endTime, phase);
+        return new Segment(event.startTime, event.endTime, phase);
     },
 
     /**
-     * @return {!Array<!WebInspector.Segment>}
+     * @return {!Array<!Segment>}
      */
     interactionRecords: function()
     {
@@ -250,15 +250,15 @@
         var thresholdsMs = WebInspector.TimelineIRModel._mergeThresholdsMs;
 
         this._segments = [];
-        this._drags = new WebInspector.SegmentedRange(merge.bind(null, thresholdsMs.mouse));
-        this._cssAnimations = new WebInspector.SegmentedRange(merge.bind(null, thresholdsMs.animation));
-        this._responses = new WebInspector.SegmentedRange(merge.bind(null, 0));
-        this._scrolls = new WebInspector.SegmentedRange(merge.bind(null, thresholdsMs.animation));
+        this._drags = new SegmentedRange(merge.bind(null, thresholdsMs.mouse));
+        this._cssAnimations = new SegmentedRange(merge.bind(null, thresholdsMs.animation));
+        this._responses = new SegmentedRange(merge.bind(null, 0));
+        this._scrolls = new SegmentedRange(merge.bind(null, thresholdsMs.animation));
 
         /**
          * @param {number} threshold
-         * @param {!WebInspector.Segment} first
-         * @param {!WebInspector.Segment} second
+         * @param {!Segment} first
+         * @param {!Segment} second
          */
         function merge(threshold, first, second)
         {
@@ -283,111 +283,3 @@
     }
 };
 
-/**
- * @constructor
- * @param {(function(!WebInspector.Segment, !WebInspector.Segment): ?WebInspector.Segment)=} mergeCallback
- */
-WebInspector.SegmentedRange = function(mergeCallback)
-{
-    /** @type {!Array<!WebInspector.Segment>} */
-    this._segments = [];
-    this._mergeCallback = mergeCallback;
-}
-
-/**
- * @constructor
- * @param {number} begin
- * @param {number} end
- * @param {*} data
- */
-WebInspector.Segment = function(begin, end, data)
-{
-    if (begin > end)
-        console.assert(false, "Invalid segment");
-    this.begin = begin;
-    this.end = end;
-    this.data = data;
-}
-
-WebInspector.Segment.prototype = {
-    /**
-     * @param {!WebInspector.Segment} that
-     * @return {boolean}
-     */
-    intersects: function(that)
-    {
-        return this.begin < that.end && that.begin < this.end;
-    }
-};
-
-WebInspector.SegmentedRange.prototype = {
-    /**
-     * @param {!WebInspector.Segment} newSegment
-     */
-    append: function(newSegment)
-    {
-        // 1. Find the proper insertion point for new segment
-        var startIndex = this._segments.lowerBound(newSegment, (a, b) => a.begin - b.begin);
-        var endIndex = startIndex;
-        var merged = null;
-        if (startIndex > 0) {
-            // 2. Try mering the preceding segment
-            var precedingSegment = this._segments[startIndex - 1];
-            merged = this._tryMerge(precedingSegment, newSegment);
-            if (merged) {
-                --startIndex;
-                newSegment = merged;
-            } else if (this._segments[startIndex - 1].end >= newSegment.begin) {
-                // 2a. If merge failed and segments overlap, adjust preceding segment.
-                // If an old segment entirely contains new one, split it in two.
-                if (newSegment.end < precedingSegment.end)
-                    this._segments.splice(startIndex, 0, new WebInspector.Segment(newSegment.end, precedingSegment.end, precedingSegment.data));
-                precedingSegment.end = newSegment.begin;
-            }
-        }
-        // 3. Consume all segments that are entirely covered by the new one.
-        while (endIndex < this._segments.length && this._segments[endIndex].end <= newSegment.end)
-            ++endIndex;
-        // 4. Merge or adjust the succeeding segment if it overlaps.
-        if (endIndex < this._segments.length) {
-            merged = this._tryMerge(newSegment, this._segments[endIndex]);
-            if (merged) {
-                endIndex++;
-                newSegment = merged;
-            } else if (newSegment.intersects(this._segments[endIndex]))
-                this._segments[endIndex].begin = newSegment.end;
-        }
-        this._segments.splice(startIndex, endIndex - startIndex, newSegment);
-    },
-
-    /**
-     * @param {!WebInspector.SegmentedRange} that
-     */
-    appendRange: function(that)
-    {
-        that.segments().forEach(segment => this.append(segment));
-    },
-
-    /**
-     * @return {!Array<!WebInspector.Segment>}
-     */
-    segments: function()
-    {
-        return this._segments;
-    },
-
-    /**
-     * @param {!WebInspector.Segment} first
-     * @param {!WebInspector.Segment} second
-     * @return {?WebInspector.Segment}
-     */
-    _tryMerge: function(first, second)
-    {
-        var merged = this._mergeCallback && this._mergeCallback(first, second);
-        if (!merged)
-            return null;
-        merged.begin = first.begin;
-        merged.end = Math.max(first.end, second.end);
-        return merged;
-    }
-}
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js b/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js
index 25c8230d..bdc958f 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js
@@ -639,6 +639,11 @@
      */
     _mouseDown: function(event)
     {
+        if (event.buttons !== 1) {
+            WebInspector.ToolbarButton.prototype._mouseDown.call(this, event);
+            return;
+        }
+
         var contextMenu = new WebInspector.ContextMenu(event,
             this._useSoftMenu,
             this.element.totalOffsetLeft(),
diff --git a/third_party/WebKit/Source/devtools/protocol.json b/third_party/WebKit/Source/devtools/protocol.json
index bd0b1a5..ca29d208 100644
--- a/third_party/WebKit/Source/devtools/protocol.json
+++ b/third_party/WebKit/Source/devtools/protocol.json
@@ -1809,7 +1809,7 @@
                 "description": "Database with an array of object stores.",
                 "properties": [
                     { "name": "name", "type": "string", "description": "Database name." },
-                    { "name": "intVersion", "type": "integer", "description": "Database version." },
+                    { "name": "version", "type": "integer", "description": "Database version." },
                     { "name": "objectStores", "type": "array", "items": { "$ref": "ObjectStore" }, "description": "Object stores in this database." }
                 ]
             },
diff --git a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
index b77dd508..63ffc61 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXLayoutObject.cpp
@@ -578,7 +578,7 @@
     if (controlObject && controlObject->isCheckboxOrRadio() && controlObject->nameFromLabelElement()) {
         if (ignoredReasons) {
             HTMLLabelElement* label = labelElementContainer();
-            if (label && !label->isSameNode(node())) {
+            if (label && label != node()) {
                 AXObject* labelAXObject = axObjectCache().getOrCreate(label);
                 ignoredReasons->append(IgnoredReason(AXLabelContainer, labelAXObject));
             }
@@ -704,15 +704,6 @@
         return true;
     }
 
-    if (m_layoutObject->isLayoutBlockFlow() && m_layoutObject->childrenInline() && !canSetFocusAttribute()) {
-        if (toLayoutBlockFlow(m_layoutObject)->firstLineBox() || mouseButtonListener())
-            return false;
-
-        if (ignoredReasons)
-            ignoredReasons->append(IgnoredReason(AXUninteresting));
-        return true;
-    }
-
     // ignore images seemingly used as spacers
     if (isImage()) {
         // If the image can take focus, it should not be ignored, lest the user not be able to interact with something important.
@@ -793,6 +784,23 @@
     if (isScrollableContainer())
         return false;
 
+    // Ignore layout objects that are block flows with inline children. These
+    // are usually dummy layout objects that pad out the tree, but there are
+    // some exceptions below.
+    if (m_layoutObject->isLayoutBlockFlow() && m_layoutObject->childrenInline() && !canSetFocusAttribute()) {
+        // If the layout object has any plain text in it, that text will be
+        // inside a LineBox, so the layout object will have a first LineBox.
+        bool hasAnyText = !!toLayoutBlockFlow(m_layoutObject)->firstLineBox();
+
+        // Always include interesting-looking objects.
+        if (hasAnyText || mouseButtonListener())
+            return false;
+
+        if (ignoredReasons)
+            ignoredReasons->append(IgnoredReason(AXUninteresting));
+        return true;
+    }
+
     // By default, objects should be ignored so that the AX hierarchy is not
     // filled with unnecessary items.
     if (ignoredReasons)
diff --git a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
index 42938a9..de3a9d9 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
@@ -176,7 +176,7 @@
     if (controlObject && controlObject->isCheckboxOrRadio() && controlObject->nameFromLabelElement()) {
         if (ignoredReasons) {
             HTMLLabelElement* label = labelElementContainer();
-            if (label && !label->isSameNode(node())) {
+            if (label && label != node()) {
                 AXObject* labelAXObject = axObjectCache().getOrCreate(label);
                 ignoredReasons->append(IgnoredReason(AXLabelContainer, labelAXObject));
             }
@@ -519,7 +519,7 @@
     if (node()->isElementNode()) {
         Element* element = toElement(node());
         if (element->isInCanvasSubtree()) {
-            document()->updateLayoutTreeForNodeIfNeeded(element);
+            document()->updateLayoutTreeForNode(element);
             if (element->isFocusable())
                 return GroupRole;
         }
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothError.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothError.cpp
index 991d2719..c540bdb 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothError.cpp
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothError.cpp
@@ -61,6 +61,7 @@
 
         // SecurityErrors:
         MAP_ERROR(GATTNotAuthorized, SecurityError, "GATT operation not authorized.");
+        MAP_ERROR(BlacklistedCharacteristicUUID, SecurityError, "getCharacteristic(s) called with blacklisted UUID. https://goo.gl/4NeimX");
         MAP_ERROR(NotAllowedToAccessService, SecurityError, "Origin is not allowed to access the service. Remember to add the service to a filter or to optionalServices in requestDevice().");
         MAP_ERROR(RequestDeviceWithBlacklistedUUID, SecurityError, "requestDevice() called with a filter containing a blacklisted UUID. https://goo.gl/4NeimX");
         MAP_ERROR(RequestDeviceWithUniqueOrigin, SecurityError, "requestDevice() called from sandboxed or otherwise unique origin.");
diff --git a/third_party/WebKit/Source/modules/cachestorage/InspectorCacheStorageAgent.cpp b/third_party/WebKit/Source/modules/cachestorage/InspectorCacheStorageAgent.cpp
index 06775fa..574ab29 100644
--- a/third_party/WebKit/Source/modules/cachestorage/InspectorCacheStorageAgent.cpp
+++ b/third_party/WebKit/Source/modules/cachestorage/InspectorCacheStorageAgent.cpp
@@ -71,8 +71,10 @@
     RefPtr<SecurityOrigin> secOrigin = SecurityOrigin::createFromString(securityOrigin);
 
     // Cache Storage API is restricted to trustworthy origins.
-    if (!secOrigin->isPotentiallyTrustworthy(*errorString))
+    if (!secOrigin->isPotentiallyTrustworthy()) {
+        *errorString = secOrigin->isPotentiallyTrustworthyErrorMessage();
         return nullptr;
+    }
 
     String identifier = createDatabaseIdentifierFromSecurityOrigin(secOrigin.get());
     OwnPtr<WebServiceWorkerCacheStorage> cache = adoptPtr(Platform::current()->cacheStorage(identifier));
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
index fdcfd12a..69aca02 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
@@ -1726,7 +1726,7 @@
     if (!canvas()->document().frame())
         return;
 
-    canvas()->document().updateLayoutTreeForNodeIfNeeded(canvas());
+    canvas()->document().updateLayoutTreeForNode(canvas());
 
     // The following early exit is dependent on the cache not being empty
     // because an empty cache may indicate that a style change has occured
@@ -1873,7 +1873,7 @@
 String CanvasRenderingContext2D::direction() const
 {
     if (state().direction() == CanvasRenderingContext2DState::DirectionInherit)
-        canvas()->document().updateLayoutTreeForNodeIfNeeded(canvas());
+        canvas()->document().updateLayoutTreeForNode(canvas());
     return toTextDirection(state().direction(), canvas()) == RTL ? rtl : ltr;
 }
 
@@ -1923,7 +1923,7 @@
     if (!canvas()->document().frame())
         return metrics;
 
-    canvas()->document().updateLayoutTreeForNodeIfNeeded(canvas());
+    canvas()->document().updateLayoutTreeForNode(canvas());
     const Font& font = accessFont();
 
     TextDirection direction;
@@ -1971,7 +1971,7 @@
     // accessFont needs the style to be up to date, but updating style can cause script to run,
     // (e.g. due to autofocus) which can free the canvas (set size to 0, for example), so update
     // style before grabbing the drawingCanvas.
-    canvas()->document().updateLayoutTreeForNodeIfNeeded(canvas());
+    canvas()->document().updateLayoutTreeForNode(canvas());
 
     SkCanvas* c = drawingCanvas();
     if (!c)
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DAPITest.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DAPITest.cpp
index c602b90..ef9e97f 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DAPITest.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DAPITest.cpp
@@ -288,7 +288,7 @@
     HTMLCanvasElement* canvas = toHTMLCanvasElement(document().getElementById("canvas"));
     CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(canvas->renderingContext());
 
-    document().updateLayoutTreeForNodeIfNeeded(canvas);
+    document().updateLayoutTreeForNode(canvas);
 
     context->beginPath();
     context->rect(10, 10, 40, 40);
diff --git a/third_party/WebKit/Source/modules/canvas2d/EventHitRegion.cpp b/third_party/WebKit/Source/modules/canvas2d/EventHitRegion.cpp
index 07651b8..18d97016 100644
--- a/third_party/WebKit/Source/modules/canvas2d/EventHitRegion.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/EventHitRegion.cpp
@@ -20,7 +20,7 @@
         return String();
 
     Document& document = canvas.document();
-    document.updateLayoutTreeForNodeIfNeeded(&canvas);
+    document.updateLayoutTreeForNode(&canvas);
 
     // Adjust offsetLocation to be relative to the canvas's position.
     LayoutBox* box = canvas.layoutBox();
diff --git a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThreadTest.cpp b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThreadTest.cpp
index 0cb2c41..2154ae7 100644
--- a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThreadTest.cpp
+++ b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThreadTest.cpp
@@ -181,7 +181,7 @@
 private:
     void executeScriptInWorker(WorkerThread* worker, WaitableEvent* waitEvent)
     {
-        WorkerOrWorkletScriptController* scriptController = worker->workerGlobalScope()->script();
+        WorkerOrWorkletScriptController* scriptController = worker->workerGlobalScope()->scriptController();
         bool evaluateResult = scriptController->evaluate(ScriptSourceCode("var counter = 0; ++counter;"));
         ASSERT_UNUSED(evaluateResult, evaluateResult);
         waitEvent->signal();
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.cpp
index b67f4d0..6c10af9 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.cpp
@@ -373,7 +373,7 @@
         return;
     }
 
-    Nullable<unsigned long long> newVersionNullable = (newVersion == IDBDatabaseMetadata::NoIntVersion) ? Nullable<unsigned long long>() : Nullable<unsigned long long>(newVersion);
+    Nullable<unsigned long long> newVersionNullable = (newVersion == IDBDatabaseMetadata::NoVersion) ? Nullable<unsigned long long>() : Nullable<unsigned long long>(newVersion);
     enqueueEvent(IDBVersionChangeEvent::create(EventTypeNames::versionchange, oldVersion, newVersionNullable));
 }
 
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.h b/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.h
index 9f040d5..772ff4f 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.h
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBDatabase.h
@@ -72,7 +72,7 @@
 
     // Implement the IDL
     const String& name() const { return m_metadata.name; }
-    unsigned long long version() const { return m_metadata.intVersion; }
+    unsigned long long version() const { return m_metadata.version; }
     PassRefPtrWillBeRawPtr<DOMStringList> objectStoreNames() const;
 
     IDBObjectStore* createObjectStore(const String& name, const IDBObjectStoreParameters& options, ExceptionState& exceptionState) { return createObjectStore(name, IDBKeyPath(options.keyPath()), options.autoIncrement(), exceptionState); }
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBFactory.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBFactory.cpp
index b1976633..eebcf63c 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBFactory.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBFactory.cpp
@@ -104,7 +104,7 @@
 IDBOpenDBRequest* IDBFactory::openInternal(ScriptState* scriptState, const String& name, int64_t version, ExceptionState& exceptionState)
 {
     IDBDatabase::recordApiCallsHistogram(IDBOpenCall);
-    ASSERT(version >= 1 || version == IDBDatabaseMetadata::NoIntVersion);
+    ASSERT(version >= 1 || version == IDBDatabaseMetadata::NoVersion);
     if (!isContextValid(scriptState->executionContext()))
         return nullptr;
     if (!scriptState->executionContext()->securityOrigin()->canAccessDatabase()) {
@@ -128,7 +128,7 @@
 IDBOpenDBRequest* IDBFactory::open(ScriptState* scriptState, const String& name, ExceptionState& exceptionState)
 {
     IDB_TRACE("IDBFactory::open");
-    return openInternal(scriptState, name, IDBDatabaseMetadata::NoIntVersion, exceptionState);
+    return openInternal(scriptState, name, IDBDatabaseMetadata::NoVersion, exceptionState);
 }
 
 IDBOpenDBRequest* IDBFactory::deleteDatabase(ScriptState* scriptState, const String& name, ExceptionState& exceptionState)
@@ -142,7 +142,7 @@
         return nullptr;
     }
 
-    IDBOpenDBRequest* request = IDBOpenDBRequest::create(scriptState, nullptr, 0, IDBDatabaseMetadata::DefaultIntVersion);
+    IDBOpenDBRequest* request = IDBOpenDBRequest::create(scriptState, nullptr, 0, IDBDatabaseMetadata::DefaultVersion);
 
     if (!m_permissionClient->allowIndexedDB(scriptState->executionContext(), name)) {
         request->onError(DOMException::create(UnknownError, permissionDeniedErrorMessage));
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBMetadata.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBMetadata.cpp
index 1a31bb7..e2b28eae 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBMetadata.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBMetadata.cpp
@@ -11,7 +11,7 @@
 IDBDatabaseMetadata::IDBDatabaseMetadata(const WebIDBMetadata& webMetadata)
     : name(webMetadata.name)
     , id(webMetadata.id)
-    , intVersion(webMetadata.intVersion)
+    , version(webMetadata.version)
     , maxObjectStoreId(webMetadata.maxObjectStoreId)
 {
     for (size_t i = 0; i < webMetadata.objectStores.size(); ++i) {
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBMetadata.h b/third_party/WebKit/Source/modules/indexeddb/IDBMetadata.h
index 09cf49e..e293d3a 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBMetadata.h
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBMetadata.h
@@ -83,21 +83,21 @@
     DISALLOW_NEW();
     // FIXME: These can probably be collapsed into 0.
     enum {
-        NoIntVersion = -1,
-        DefaultIntVersion = 0
+        NoVersion = -1,
+        DefaultVersion = 0
     };
 
     typedef HashMap<int64_t, IDBObjectStoreMetadata> ObjectStoreMap;
 
     IDBDatabaseMetadata()
-        : intVersion(NoIntVersion)
+        : version(NoVersion)
     {
     }
 
-    IDBDatabaseMetadata(const String& name, int64_t id, int64_t intVersion, int64_t maxObjectStoreId)
+    IDBDatabaseMetadata(const String& name, int64_t id, int64_t version, int64_t maxObjectStoreId)
         : name(name)
         , id(id)
-        , intVersion(intVersion)
+        , version(version)
         , maxObjectStoreId(maxObjectStoreId)
     {
     }
@@ -106,7 +106,7 @@
 
     String name;
     int64_t id;
-    int64_t intVersion;
+    int64_t version;
     int64_t maxObjectStoreId;
 
     ObjectStoreMap objectStores;
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBOpenDBRequest.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBOpenDBRequest.cpp
index 6cfdb3b..788ab7db 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBOpenDBRequest.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBOpenDBRequest.cpp
@@ -74,7 +74,7 @@
     IDB_TRACE("IDBOpenDBRequest::onBlocked()");
     if (!shouldEnqueueEvent())
         return;
-    Nullable<unsigned long long> newVersionNullable = (m_version == IDBDatabaseMetadata::DefaultIntVersion) ? Nullable<unsigned long long>() : Nullable<unsigned long long>(m_version);
+    Nullable<unsigned long long> newVersionNullable = (m_version == IDBDatabaseMetadata::DefaultVersion) ? Nullable<unsigned long long>() : Nullable<unsigned long long>(m_version);
     enqueueEvent(IDBVersionChangeEvent::create(EventTypeNames::blocked, oldVersion, newVersionNullable));
 }
 
@@ -95,17 +95,17 @@
     IDBDatabase* idbDatabase = IDBDatabase::create(executionContext(), backend, m_databaseCallbacks.release());
     idbDatabase->setMetadata(metadata);
 
-    if (oldVersion == IDBDatabaseMetadata::NoIntVersion) {
-        // This database hasn't had an integer version before.
-        oldVersion = IDBDatabaseMetadata::DefaultIntVersion;
+    if (oldVersion == IDBDatabaseMetadata::NoVersion) {
+        // This database hasn't had a version before.
+        oldVersion = IDBDatabaseMetadata::DefaultVersion;
     }
     IDBDatabaseMetadata oldMetadata(metadata);
-    oldMetadata.intVersion = oldVersion;
+    oldMetadata.version = oldVersion;
 
     m_transaction = IDBTransaction::create(scriptState(), m_transactionId, idbDatabase, this, oldMetadata);
     setResult(IDBAny::create(idbDatabase));
 
-    if (m_version == IDBDatabaseMetadata::NoIntVersion)
+    if (m_version == IDBDatabaseMetadata::NoVersion)
         m_version = 1;
     enqueueEvent(IDBVersionChangeEvent::create(EventTypeNames::upgradeneeded, oldVersion, m_version, dataLoss, dataLossMessage));
 }
@@ -144,9 +144,9 @@
     IDB_TRACE("IDBOpenDBRequest::onSuccess()");
     if (!shouldEnqueueEvent())
         return;
-    if (oldVersion == IDBDatabaseMetadata::NoIntVersion) {
+    if (oldVersion == IDBDatabaseMetadata::NoVersion) {
         // This database hasn't had an integer version before.
-        oldVersion = IDBDatabaseMetadata::DefaultIntVersion;
+        oldVersion = IDBDatabaseMetadata::DefaultVersion;
     }
     setResult(IDBAny::createUndefined());
     enqueueEvent(IDBVersionChangeEvent::create(EventTypeNames::success, oldVersion, Nullable<unsigned long long>()));
diff --git a/third_party/WebKit/Source/modules/indexeddb/InspectorIndexedDBAgent.cpp b/third_party/WebKit/Source/modules/indexeddb/InspectorIndexedDBAgent.cpp
index c2b3db1..2edb8a0e 100644
--- a/third_party/WebKit/Source/modules/indexeddb/InspectorIndexedDBAgent.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/InspectorIndexedDBAgent.cpp
@@ -341,7 +341,7 @@
         }
         OwnPtr<DatabaseWithObjectStores> result = DatabaseWithObjectStores::create()
             .setName(databaseMetadata.name)
-            .setIntVersion(databaseMetadata.intVersion)
+            .setVersion(databaseMetadata.version)
             .setObjectStores(objectStores.release()).build();
 
         m_requestCallback->sendSuccess(result.release());
diff --git a/third_party/WebKit/Source/modules/quota/DeprecatedStorageInfo.cpp b/third_party/WebKit/Source/modules/quota/DeprecatedStorageInfo.cpp
index 1c432fb..9e4dcec26 100644
--- a/third_party/WebKit/Source/modules/quota/DeprecatedStorageInfo.cpp
+++ b/third_party/WebKit/Source/modules/quota/DeprecatedStorageInfo.cpp
@@ -50,7 +50,7 @@
     DeprecatedStorageQuota* storageQuota = getStorageQuota(storageType);
     if (!storageQuota) {
         // Unknown storage type is requested.
-        executionContext->postTask(BLINK_FROM_HERE, StorageErrorCallback::CallbackTask::create(errorCallback, NotSupportedError));
+        executionContext->postTask(BLINK_FROM_HERE, StorageErrorCallback::createSameThreadTask(errorCallback, NotSupportedError));
         return;
     }
     storageQuota->queryUsageAndQuota(executionContext, successCallback, errorCallback);
@@ -62,7 +62,7 @@
     DeprecatedStorageQuota* storageQuota = getStorageQuota(storageType);
     if (!storageQuota) {
         // Unknown storage type is requested.
-        executionContext->postTask(BLINK_FROM_HERE, StorageErrorCallback::CallbackTask::create(errorCallback, NotSupportedError));
+        executionContext->postTask(BLINK_FROM_HERE, StorageErrorCallback::createSameThreadTask(errorCallback, NotSupportedError));
         return;
     }
     storageQuota->requestQuota(executionContext, newQuotaInBytes, successCallback, errorCallback);
diff --git a/third_party/WebKit/Source/modules/quota/DeprecatedStorageQuota.cpp b/third_party/WebKit/Source/modules/quota/DeprecatedStorageQuota.cpp
index 721d22f..7756a73 100644
--- a/third_party/WebKit/Source/modules/quota/DeprecatedStorageQuota.cpp
+++ b/third_party/WebKit/Source/modules/quota/DeprecatedStorageQuota.cpp
@@ -58,13 +58,13 @@
     WebStorageQuotaType storageType = static_cast<WebStorageQuotaType>(m_type);
     if (storageType != WebStorageQuotaTypeTemporary && storageType != WebStorageQuotaTypePersistent) {
         // Unknown storage type is requested.
-        executionContext->postTask(BLINK_FROM_HERE, StorageErrorCallback::CallbackTask::create(errorCallback, NotSupportedError));
+        executionContext->postTask(BLINK_FROM_HERE, StorageErrorCallback::createSameThreadTask(errorCallback, NotSupportedError));
         return;
     }
 
     SecurityOrigin* securityOrigin = executionContext->securityOrigin();
     if (securityOrigin->isUnique()) {
-        executionContext->postTask(BLINK_FROM_HERE, StorageErrorCallback::CallbackTask::create(errorCallback, NotSupportedError));
+        executionContext->postTask(BLINK_FROM_HERE, StorageErrorCallback::createSameThreadTask(errorCallback, NotSupportedError));
         return;
     }
 
@@ -80,13 +80,13 @@
     WebStorageQuotaType storageType = static_cast<WebStorageQuotaType>(m_type);
     if (storageType != WebStorageQuotaTypeTemporary && storageType != WebStorageQuotaTypePersistent) {
         // Unknown storage type is requested.
-        executionContext->postTask(BLINK_FROM_HERE, StorageErrorCallback::CallbackTask::create(errorCallback, NotSupportedError));
+        executionContext->postTask(BLINK_FROM_HERE, StorageErrorCallback::createSameThreadTask(errorCallback, NotSupportedError));
         return;
     }
 
     StorageQuotaClient* client = StorageQuotaClient::from(executionContext);
     if (!client) {
-        executionContext->postTask(BLINK_FROM_HERE, StorageErrorCallback::CallbackTask::create(errorCallback, NotSupportedError));
+        executionContext->postTask(BLINK_FROM_HERE, StorageErrorCallback::createSameThreadTask(errorCallback, NotSupportedError));
         return;
     }
 
diff --git a/third_party/WebKit/Source/modules/quota/StorageErrorCallback.cpp b/third_party/WebKit/Source/modules/quota/StorageErrorCallback.cpp
index e73bc46f..00551790 100644
--- a/third_party/WebKit/Source/modules/quota/StorageErrorCallback.cpp
+++ b/third_party/WebKit/Source/modules/quota/StorageErrorCallback.cpp
@@ -34,17 +34,16 @@
 
 namespace blink {
 
-StorageErrorCallback::CallbackTask::CallbackTask(StorageErrorCallback* callback, ExceptionCode ec)
-    : m_callback(callback)
-    , m_ec(ec)
+PassOwnPtr<ExecutionContextTask> StorageErrorCallback::createSameThreadTask(StorageErrorCallback* callback, ExceptionCode ec)
 {
+    return blink::createSameThreadTask(&StorageErrorCallback::run, callback, ec);
 }
 
-void StorageErrorCallback::CallbackTask::performTask(ExecutionContext*)
+void StorageErrorCallback::run(StorageErrorCallback* callback, ExceptionCode ec)
 {
-    if (!m_callback)
+    if (!callback)
         return;
-    m_callback->handleEvent(DOMError::create(m_ec));
+    callback->handleEvent(DOMError::create(ec));
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/quota/StorageErrorCallback.h b/third_party/WebKit/Source/modules/quota/StorageErrorCallback.h
index 2700efe..d75c6a4 100644
--- a/third_party/WebKit/Source/modules/quota/StorageErrorCallback.h
+++ b/third_party/WebKit/Source/modules/quota/StorageErrorCallback.h
@@ -49,21 +49,10 @@
     DEFINE_INLINE_VIRTUAL_TRACE() { }
     virtual void handleEvent(DOMError*) = 0;
 
-    class MODULES_EXPORT CallbackTask final : public ExecutionContextTask {
-    public:
-        static PassOwnPtr<CallbackTask> create(StorageErrorCallback* callback, ExceptionCode ec)
-        {
-            return adoptPtr(new CallbackTask(callback, ec));
-        }
+    MODULES_EXPORT static PassOwnPtr<ExecutionContextTask> createSameThreadTask(StorageErrorCallback*, ExceptionCode);
 
-        void performTask(ExecutionContext*) override;
-
-    private:
-        CallbackTask(StorageErrorCallback*, ExceptionCode);
-
-        Persistent<StorageErrorCallback> m_callback;
-        ExceptionCode m_ec;
-    };
+private:
+    static void run(StorageErrorCallback*, ExceptionCode);
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/webaudio/WindowWebAudio.idl b/third_party/WebKit/Source/modules/webaudio/WindowWebAudio.idl
index b2ac6d9..0a5bb07 100644
--- a/third_party/WebKit/Source/modules/webaudio/WindowWebAudio.idl
+++ b/third_party/WebKit/Source/modules/webaudio/WindowWebAudio.idl
@@ -5,8 +5,8 @@
 [
     ImplementedAs=DOMWindowWebAudio,
 ] partial interface Window {
-    [MeasureAs=AudioContext, RuntimeEnabled=WebAudio] attribute AudioContextConstructor AudioContext;
-    [MeasureAs=OfflineAudioContext, RuntimeEnabled=WebAudio] attribute OfflineAudioContextConstructor OfflineAudioContext;
-    [DeprecateAs=PrefixedAudioContext, RuntimeEnabled=WebAudio] attribute AudioContextConstructor webkitAudioContext;
-    [DeprecateAs=PrefixedOfflineAudioContext, RuntimeEnabled=WebAudio] attribute OfflineAudioContextConstructor webkitOfflineAudioContext;
+    [MeasureAs=AudioContext] attribute AudioContextConstructor AudioContext;
+    [MeasureAs=OfflineAudioContext] attribute OfflineAudioContextConstructor OfflineAudioContext;
+    [DeprecateAs=PrefixedAudioContext] attribute AudioContextConstructor webkitAudioContext;
+    [DeprecateAs=PrefixedOfflineAudioContext] attribute OfflineAudioContextConstructor webkitOfflineAudioContext;
 };
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
index 6155dc0..22ad5e4 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
@@ -840,6 +840,50 @@
     return true;
 }
 
+void WebGL2RenderingContextBase::texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLintptr offset)
+{
+    if (isContextLost())
+        return;
+    if (!validateTexture2DBinding("texImage2D", target))
+        return;
+    if (!validateTexFunc("texImage2D", TexImage, SourceUnpackBuffer, target, level, internalformat, width, height, 1, border, format, type, 0, 0, 0))
+        return;
+    if (!validateValueFitNonNegInt32("texImage2D", "offset", offset))
+        return;
+
+    webContext()->texImage2D(target, level, convertTexInternalFormat(internalformat, type), width, height, border, format, type, reinterpret_cast<const void *>(offset));
+}
+
+void WebGL2RenderingContextBase::texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, DOMArrayBufferView* data)
+{
+    WebGLRenderingContextBase::texImage2D(target, level, internalformat, width, height, border, format, type, data);
+}
+
+void WebGL2RenderingContextBase::texImage2D(GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, ImageData* imageData)
+{
+    WebGLRenderingContextBase::texImage2D(target, level, internalformat, format, type, imageData);
+}
+
+void WebGL2RenderingContextBase::texImage2D(GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, HTMLImageElement* image, ExceptionState& exceptionState)
+{
+    WebGLRenderingContextBase::texImage2D(target, level, internalformat, format, type, image, exceptionState);
+}
+
+void WebGL2RenderingContextBase::texImage2D(GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, HTMLCanvasElement* canvas, ExceptionState& exceptionState)
+{
+    WebGLRenderingContextBase::texImage2D(target, level, internalformat, format, type, canvas, exceptionState);
+}
+
+void WebGL2RenderingContextBase::texImage2D(GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, HTMLVideoElement* video, ExceptionState& exceptionState)
+{
+    WebGLRenderingContextBase::texImage2D(target, level, internalformat, format, type, video, exceptionState);
+}
+
+void WebGL2RenderingContextBase::texImage2D(GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, PassRefPtrWillBeRawPtr<ImageBitmap> imageBitMap, ExceptionState& exceptionState)
+{
+    WebGLRenderingContextBase::texImage2D(target, level, internalformat, format, type, imageBitMap, exceptionState);
+}
+
 void WebGL2RenderingContextBase::texStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
 {
     if (isContextLost() || !validateTexStorage("texStorage2D", target, levels, internalformat, width, height, 1, TexStorageType2D))
@@ -878,6 +922,20 @@
     webContext()->texImage3D(target, level, convertTexInternalFormat(internalformat, type), width, height, depth, border, format, type, data);
 }
 
+void WebGL2RenderingContextBase::texImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, GLintptr offset)
+{
+    if (isContextLost())
+        return;
+    if (!validateTexture3DBinding("texImage3D", target))
+        return;
+    if (!validateTexFunc("texImage3D", TexImage, SourceUnpackBuffer, target, level, internalformat, width, height, depth, border, format, type, 0, 0, 0))
+        return;
+    if (!validateValueFitNonNegInt32("texImage3D", "offset", offset))
+        return;
+
+    webContext()->texImage3D(target, level, convertTexInternalFormat(internalformat, type), width, height, depth, border, format, type, reinterpret_cast<const void *>(offset));
+}
+
 void WebGL2RenderingContextBase::texSubImage3DImpl(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLenum format, GLenum type, Image* image, WebGLImageConversion::ImageHtmlDomSource domSource, bool flipY, bool premultiplyAlpha)
 {
     // All calling functions check isContextLost, so a duplicate check is not needed here.
@@ -1036,10 +1094,25 @@
         return;
     if (!validateTexFunc("texSubImage3D", TexSubImage, SourceImageBitmap, target, level, 0, bitmap->width(), bitmap->height(), 1, 0, format, type, xoffset, yoffset, zoffset))
         return;
-
-    StaticBitmapImage* imageForRender = bitmap->bitmapImage();
-    ASSERT(imageForRender);
-    texSubImage3DImpl(target, level, xoffset, yoffset, zoffset, format, type, imageForRender, WebGLImageConversion::HtmlDomImage, m_unpackFlipY, m_unpackPremultiplyAlpha);
+    if (type == GL_UNSIGNED_INT_10F_11F_11F_REV) {
+        // The UNSIGNED_INT_10F_11F_11F_REV type pack/unpack isn't implemented.
+        type = GL_FLOAT;
+    }
+    OwnPtr<uint8_t[]> pixelData = bitmap->copyBitmapData(PremultiplyAlpha);
+    Vector<uint8_t> data;
+    bool needConversion = true;
+    if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
+        needConversion = false;
+    } else {
+        // In the case of ImageBitmap, we do not need to apply flipY or premultiplyAlpha.
+        if (!WebGLImageConversion::extractImageData(pixelData.get(), bitmap->size(), format, type, false, false, data)) {
+            synthesizeGLError(GL_INVALID_VALUE, "texSubImage3D", "bad image data");
+            return;
+        }
+    }
+    resetUnpackParameters();
+    webContext()->texSubImage3D(target, level, xoffset, yoffset, zoffset, bitmap->width(), bitmap->height(), 1, format, type, needConversion ? data.data() : pixelData.get());
+    restoreUnpackParameters();
 }
 
 void WebGL2RenderingContextBase::copyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height)
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h
index 430cb14..8f798ed6 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h
@@ -44,9 +44,27 @@
     void renderbufferStorageMultisample(GLenum, GLsizei, GLenum, GLsizei, GLsizei);
 
     /* Texture objects */
+    void texImage2D(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, GLintptr);
+    // Have to re-declair/re-define the following texImage2D functions from base class.
+    // This is because the above texImage2D() hides the name from base class.
+    void texImage2D(GLenum target, GLint level, GLint internalformat,
+        GLsizei width, GLsizei height, GLint border,
+        GLenum format, GLenum type, DOMArrayBufferView*);
+    void texImage2D(GLenum target, GLint level, GLint internalformat,
+        GLenum format, GLenum type, ImageData*);
+    void texImage2D(GLenum target, GLint level, GLint internalformat,
+        GLenum format, GLenum type, HTMLImageElement*, ExceptionState&);
+    void texImage2D(GLenum target, GLint level, GLint internalformat,
+        GLenum format, GLenum type, HTMLCanvasElement*, ExceptionState&);
+    void texImage2D(GLenum target, GLint level, GLint internalformat,
+        GLenum format, GLenum type, HTMLVideoElement*, ExceptionState&);
+    void texImage2D(GLenum target, GLint level, GLint internalformat,
+        GLenum format, GLenum type, PassRefPtrWillBeRawPtr<ImageBitmap>, ExceptionState&);
+
     void texStorage2D(GLenum, GLsizei, GLenum, GLsizei, GLsizei);
     void texStorage3D(GLenum, GLsizei, GLenum, GLsizei, GLsizei, GLsizei);
     void texImage3D(GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, DOMArrayBufferView*);
+    void texImage3D(GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, GLintptr);
     void texSubImage3D(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, DOMArrayBufferView*);
     void texSubImage3D(GLenum, GLint, GLint, GLint, GLint, GLenum, GLenum, ImageData*);
     void texSubImage3D(GLenum, GLint, GLint, GLint, GLint, GLenum, GLenum, HTMLImageElement*, ExceptionState&);
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.idl b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.idl
index 66f04fcc..cb2eaf0 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.idl
+++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.idl
@@ -318,9 +318,11 @@
     void renderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
 
     /* Texture objects */
+    void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLintptr offset);
     void texStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
     void texStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
     void texImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, ArrayBufferView? pixels);
+    void texImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, GLintptr offset);
     void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, ArrayBufferView? pixels);
     void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLenum format, GLenum type, ImageData? data);
     [RaisesException] void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLenum format, GLenum type, HTMLImageElement? image);
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
index b6ccb5d..abb24db 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -4184,9 +4184,25 @@
         return;
     if (!validateTexFunc("texImage2D", TexImage, SourceImageBitmap, target, level, internalformat, bitmap->width(), bitmap->height(), 1, 0, format, type, 0, 0, 0))
         return;
-    StaticBitmapImage* imageForRender = bitmap->bitmapImage();
-    ASSERT(imageForRender);
-    texImage2DImpl(target, level, internalformat, format, type, imageForRender, WebGLImageConversion::HtmlDomImage, m_unpackFlipY, m_unpackPremultiplyAlpha);
+    OwnPtr<uint8_t[]> pixelData = bitmap->copyBitmapData(PremultiplyAlpha);
+    Vector<uint8_t> data;
+    bool needConversion = true;
+    if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
+        needConversion = false;
+    } else {
+        if (type == GL_UNSIGNED_INT_10F_11F_11F_REV) {
+            // The UNSIGNED_INT_10F_11F_11F_REV type pack/unpack isn't implemented.
+            type = GL_FLOAT;
+        }
+        // In the case of ImageBitmap, we do not need to apply flipY or premultiplyAlpha.
+        if (!WebGLImageConversion::extractImageData(pixelData.get(), bitmap->size(), format, type, false, false, data)) {
+            synthesizeGLError(GL_INVALID_VALUE, "texImage2D", "bad image data");
+            return;
+        }
+    }
+    resetUnpackParameters();
+    texImage2DBase(target, level, internalformat, bitmap->width(), bitmap->height(), 0, format, type, needConversion ? data.data() : pixelData.get());
+    restoreUnpackParameters();
 }
 
 void WebGLRenderingContextBase::texParameter(GLenum target, GLenum pname, GLfloat paramf, GLint parami, bool isFloat)
@@ -4433,9 +4449,25 @@
         return;
     if (!validateTexFunc("texSubImage2D", TexSubImage, SourceImageBitmap, target, level, 0, bitmap->width(), bitmap->height(), 1, 0, format, type, 0, 0, 0))
         return;
-    StaticBitmapImage* imageForRender = bitmap->bitmapImage();
-    ASSERT(imageForRender);
-    texSubImage2DImpl(target, level, xoffset, yoffset, format, type, imageForRender, WebGLImageConversion::HtmlDomImage, m_unpackFlipY, m_unpackPremultiplyAlpha);
+    if (type == GL_UNSIGNED_INT_10F_11F_11F_REV) {
+        // The UNSIGNED_INT_10F_11F_11F_REV type pack/unpack isn't implemented.
+        type = GL_FLOAT;
+    }
+    OwnPtr<uint8_t[]> pixelData = bitmap->copyBitmapData(PremultiplyAlpha);
+    Vector<uint8_t> data;
+    bool needConversion = true;
+    if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
+        needConversion = false;
+    } else {
+        // In the case of ImageBitmap, we do not need to apply flipY or premultiplyAlpha.
+        if (!WebGLImageConversion::extractImageData(pixelData.get(), bitmap->size(), format, type, false, false, data)) {
+            synthesizeGLError(GL_INVALID_VALUE, "texSubImage2D", "bad image data");
+            return;
+        }
+    }
+    resetUnpackParameters();
+    webContext()->texSubImage2D(target, level, xoffset, yoffset, bitmap->width(), bitmap->height(), format, type, needConversion ? data.data() : pixelData.get());
+    restoreUnpackParameters();
 }
 
 void WebGLRenderingContextBase::uniform1f(const WebGLUniformLocation* location, GLfloat x)
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
index f341d6b..8c09cb38 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
@@ -874,6 +874,7 @@
         SourceHTMLCanvasElement,
         SourceHTMLVideoElement,
         SourceImageBitmap,
+        SourceUnpackBuffer,
     };
 
     // Helper function for tex{Sub}Image{2|3}D to check if the input format/type/level/target/width/height/depth/border/xoffset/yoffset/zoffset are valid.
diff --git a/third_party/WebKit/Source/modules/websockets/InspectorWebSocketEvents.cpp b/third_party/WebKit/Source/modules/websockets/InspectorWebSocketEvents.cpp
index f9ef20a..65729140 100644
--- a/third_party/WebKit/Source/modules/websockets/InspectorWebSocketEvents.cpp
+++ b/third_party/WebKit/Source/modules/websockets/InspectorWebSocketEvents.cpp
@@ -9,9 +9,9 @@
 
 namespace blink {
 
-PassRefPtr<TracedValue> InspectorWebSocketCreateEvent::data(Document* document, unsigned long identifier, const KURL& url, const String& protocol)
+PassOwnPtr<TracedValue> InspectorWebSocketCreateEvent::data(Document* document, unsigned long identifier, const KURL& url, const String& protocol)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setInteger("identifier", identifier);
     value->setString("url", url.string());
     value->setString("frame", toHexString(document->frame()));
@@ -21,9 +21,9 @@
     return value.release();
 }
 
-PassRefPtr<TracedValue> InspectorWebSocketEvent::data(Document* document, unsigned long identifier)
+PassOwnPtr<TracedValue> InspectorWebSocketEvent::data(Document* document, unsigned long identifier)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setInteger("identifier", identifier);
     value->setString("frame", toHexString(document->frame()));
     setCallStack(value.get());
diff --git a/third_party/WebKit/Source/modules/websockets/InspectorWebSocketEvents.h b/third_party/WebKit/Source/modules/websockets/InspectorWebSocketEvents.h
index 94c10bd..418f0e66 100644
--- a/third_party/WebKit/Source/modules/websockets/InspectorWebSocketEvents.h
+++ b/third_party/WebKit/Source/modules/websockets/InspectorWebSocketEvents.h
@@ -20,13 +20,13 @@
 class InspectorWebSocketCreateEvent {
     STATIC_ONLY(InspectorWebSocketCreateEvent);
 public:
-    static PassRefPtr<TracedValue> data(Document*, unsigned long identifier, const KURL&, const String& protocol);
+    static PassOwnPtr<TracedValue> data(Document*, unsigned long identifier, const KURL&, const String& protocol);
 };
 
 class InspectorWebSocketEvent {
     STATIC_ONLY(InspectorWebSocketEvent);
 public:
-    static PassRefPtr<TracedValue> data(Document*, unsigned long identifier);
+    static PassOwnPtr<TracedValue> data(Document*, unsigned long identifier);
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/worklet/Worklet.cpp b/third_party/WebKit/Source/modules/worklet/Worklet.cpp
index bbab7dc..4218b58 100644
--- a/third_party/WebKit/Source/modules/worklet/Worklet.cpp
+++ b/third_party/WebKit/Source/modules/worklet/Worklet.cpp
@@ -69,7 +69,7 @@
         // TODO(ikilpatrick): Worklets don't have the same error behaviour
         // as workers, etc. For a SyntaxError we should reject, however if
         // the script throws a normal error, resolve. For now just resolve.
-        m_workletGlobalScope->script()->evaluate(ScriptSourceCode(scriptLoader->script(), scriptLoader->url()));
+        m_workletGlobalScope->scriptController()->evaluate(ScriptSourceCode(scriptLoader->script(), scriptLoader->url()));
         resolver->resolve();
     }
 
@@ -84,7 +84,7 @@
 
 void Worklet::stop()
 {
-    m_workletGlobalScope->script()->willScheduleExecutionTermination();
+    m_workletGlobalScope->scriptController()->willScheduleExecutionTermination();
 
     for (auto scriptLoader : m_scriptLoaders) {
         scriptLoader->cancel();
diff --git a/third_party/WebKit/Source/modules/worklet/WorkletGlobalScope.cpp b/third_party/WebKit/Source/modules/worklet/WorkletGlobalScope.cpp
index 9be0628..d2b4b20 100644
--- a/third_party/WebKit/Source/modules/worklet/WorkletGlobalScope.cpp
+++ b/third_party/WebKit/Source/modules/worklet/WorkletGlobalScope.cpp
@@ -12,14 +12,14 @@
 PassRefPtrWillBeRawPtr<WorkletGlobalScope> WorkletGlobalScope::create(const KURL& url, const String& userAgent, PassRefPtr<SecurityOrigin> securityOrigin, v8::Isolate* isolate)
 {
     RefPtrWillBeRawPtr<WorkletGlobalScope> workletGlobalScope = adoptRefWillBeNoop(new WorkletGlobalScope(url, userAgent, securityOrigin, isolate));
-    workletGlobalScope->script()->initializeContextIfNeeded();
+    workletGlobalScope->scriptController()->initializeContextIfNeeded();
     return workletGlobalScope.release();
 }
 
 WorkletGlobalScope::WorkletGlobalScope(const KURL& url, const String& userAgent, PassRefPtr<SecurityOrigin> securityOrigin, v8::Isolate* isolate)
     : m_url(url)
     , m_userAgent(userAgent)
-    , m_script(WorkerOrWorkletScriptController::create(this, isolate))
+    , m_scriptController(WorkerOrWorkletScriptController::create(this, isolate))
 {
     setSecurityOrigin(securityOrigin);
 }
@@ -44,7 +44,7 @@
 
 void WorkletGlobalScope::disableEval(const String& errorMessage)
 {
-    m_script->disableEval(errorMessage);
+    m_scriptController->disableEval(errorMessage);
 }
 
 bool WorkletGlobalScope::isSecureContext(String& errorMessage, const SecureContextCheck privilegeContextCheck) const
@@ -52,7 +52,10 @@
     // Until there are APIs that are available in worklets and that
     // require a privileged context test that checks ancestors, just do
     // a simple check here.
-    return securityOrigin()->isPotentiallyTrustworthy(errorMessage);
+    if (securityOrigin()->isPotentiallyTrustworthy())
+        return true;
+    errorMessage = securityOrigin()->isPotentiallyTrustworthyErrorMessage();
+    return false;
 }
 
 KURL WorkletGlobalScope::virtualCompleteURL(const String& url) const
@@ -68,7 +71,7 @@
 
 DEFINE_TRACE(WorkletGlobalScope)
 {
-    visitor->trace(m_script);
+    visitor->trace(m_scriptController);
     ExecutionContext::trace(visitor);
     SecurityContext::trace(visitor);
 }
diff --git a/third_party/WebKit/Source/modules/worklet/WorkletGlobalScope.h b/third_party/WebKit/Source/modules/worklet/WorkletGlobalScope.h
index a9498de7..007f9e1 100644
--- a/third_party/WebKit/Source/modules/worklet/WorkletGlobalScope.h
+++ b/third_party/WebKit/Source/modules/worklet/WorkletGlobalScope.h
@@ -38,7 +38,7 @@
 
     // WorkerOrWorkletGlobalScope
     ScriptWrappable* scriptWrappable() const final { return const_cast<WorkletGlobalScope*>(this); }
-    WorkerOrWorkletScriptController* script() final { return m_script.get(); }
+    WorkerOrWorkletScriptController* scriptController() final { return m_scriptController.get(); }
 
     // ScriptWrappable
     v8::Local<v8::Object> wrap(v8::Isolate*, v8::Local<v8::Object> creationContext) final;
@@ -84,7 +84,7 @@
 
     KURL m_url;
     String m_userAgent;
-    OwnPtrWillBeMember<WorkerOrWorkletScriptController> m_script;
+    OwnPtrWillBeMember<WorkerOrWorkletScriptController> m_scriptController;
 };
 
 DEFINE_TYPE_CASTS(WorkletGlobalScope, ExecutionContext, context, context->isWorkletGlobalScope(), context.isWorkletGlobalScope());
diff --git a/third_party/WebKit/Source/platform/EventTracer.cpp b/third_party/WebKit/Source/platform/EventTracer.cpp
index e936687..e7cd5fd 100644
--- a/third_party/WebKit/Source/platform/EventTracer.cpp
+++ b/third_party/WebKit/Source/platform/EventTracer.cpp
@@ -72,8 +72,8 @@
     const char* name, const char* scope, unsigned long long id, unsigned long long bindId, double timestamp,
     int numArgs, const char* argNames[], const unsigned char argTypes[],
     const unsigned long long argValues[],
-    PassRefPtr<TracedValue> tracedValue1,
-    PassRefPtr<TracedValue> tracedValue2,
+    PassOwnPtr<TracedValue> tracedValue1,
+    PassOwnPtr<TracedValue> tracedValue2,
     unsigned flags)
 {
     scoped_refptr<base::trace_event::ConvertableToTraceFormat> convertables[2];
diff --git a/third_party/WebKit/Source/platform/EventTracer.h b/third_party/WebKit/Source/platform/EventTracer.h
index 18a72f5..ec4dcdc0 100644
--- a/third_party/WebKit/Source/platform/EventTracer.h
+++ b/third_party/WebKit/Source/platform/EventTracer.h
@@ -34,8 +34,8 @@
 #include "base/memory/ref_counted.h"
 #include "platform/PlatformExport.h"
 #include "wtf/Allocator.h"
+#include "wtf/PassOwnPtr.h"
 #include "wtf/RefCounted.h"
-#include "wtf/RefPtr.h"
 #include "wtf/text/WTFString.h"
 
 #include <stdint.h>
@@ -79,8 +79,8 @@
         const char* argNames[],
         const unsigned char argTypes[],
         const unsigned long long argValues[],
-        PassRefPtr<TracedValue>,
-        PassRefPtr<TracedValue>,
+        PassOwnPtr<TracedValue>,
+        PassOwnPtr<TracedValue>,
         unsigned flags);
     static TraceEvent::TraceEventHandle addTraceEvent(char phase,
         const unsigned char* categoryEnabledFlag,
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
index 0b5a809d..6e3dd5b 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
@@ -37,7 +37,7 @@
 // Unified Chrome Compositor and Blink Animations engine (Project Heaviside). crbug.com/394772
 CompositorAnimationTimelines
 ContextMenu status=experimental
-CredentialManager status=test
+CredentialManager status=stable
 CSS3Text status=experimental
 CSS3TextDecorations status=experimental
 CSSAdditiveAnimations status=experimental, depends_on=StackedCSSPropertyAnimations
@@ -86,7 +86,7 @@
 FileAPIBlobClose status=experimental
 FileSystem status=stable
 ForeignFetch status=experimental
-FormDataNewMethods status=experimental
+FormDataNewMethods status=stable
 FullscreenUnprefixed status=test
 FrameTimingSupport status=experimental
 Geofencing status=experimental
@@ -98,6 +98,7 @@
 ImageOrientation status=test
 ImageRenderingPixelated status=stable
 IndexedDBExperimental status=experimental
+InertTopControls status=experimental
 InputDeviceCapabilities status=stable
 InputEvent status=experimental
 InputModeAttribute status=experimental
@@ -122,6 +123,7 @@
 MediaSourceExperimental depends_on=MediaSource, status=experimental
 MediaStreamSpeech status=experimental
 MemoryInfoInWorkers status=experimental
+MobileLayoutTheme
 NavigatorConnect status=experimental
 NavigatorContentUtils
 WebNFC status=experimental
@@ -130,7 +132,7 @@
 NewMediaPlaybackUi
 NotificationConstructor status=stable
 NotificationExperimental status=test
-NotificationActionIcons status=test
+NotificationActionIcons status=stable
 Notifications status=stable
 OrientationEvent
 // For simulating Android's overlay fullscreen video in layout tests on Linux.
@@ -203,7 +205,6 @@
 UserSelectAll status=experimental
 WebAnimationsAPI status=experimental
 WebAnimationsSVG status=experimental
-WebAudio status=stable
 WebBluetooth origin_trial_feature_name=WebBluetooth
 WebGLDraftExtensions status=experimental
 WebGLImageChromium
diff --git a/third_party/WebKit/Source/platform/Timer.cpp b/third_party/WebKit/Source/platform/Timer.cpp
index 4dbaea66..9e688dd 100644
--- a/third_party/WebKit/Source/platform/Timer.cpp
+++ b/third_party/WebKit/Source/platform/Timer.cpp
@@ -65,7 +65,7 @@
 
     m_location = caller;
     m_repeatInterval = repeatInterval;
-    setNextFireTime(monotonicallyIncreasingTime(), nextFireInterval);
+    setNextFireTime(timerMonotonicallyIncreasingTime(), nextFireInterval);
 }
 
 void TimerBase::stop()
@@ -82,13 +82,13 @@
 double TimerBase::nextFireInterval() const
 {
     ASSERT(isActive());
-    double current = monotonicallyIncreasingTime();
+    double current = timerMonotonicallyIncreasingTime();
     if (m_nextFireTime < current)
         return 0;
     return m_nextFireTime - current;
 }
 
-WebTaskRunner* TimerBase::timerTaskRunner()
+WebTaskRunner* TimerBase::timerTaskRunner() const
 {
     return m_webTaskRunner;
 }
@@ -121,13 +121,13 @@
     TRACE_EVENT_SET_SAMPLING_STATE("blink", "BlinkInternal");
 
     if (m_repeatInterval) {
-        double now = monotonicallyIncreasingTime();
+        double now = timerMonotonicallyIncreasingTime();
         // This computation should be drift free, and it will cope if we miss a beat,
         // which can easily happen if the thread is busy.  It will also cope if we get
         // called slightly before m_unalignedNextFireTime, which can happen due to lack
         // of timer precision.
         double intervalToNextFireTime = m_repeatInterval - fmod(now - m_nextFireTime, m_repeatInterval);
-        setNextFireTime(monotonicallyIncreasingTime(), intervalToNextFireTime);
+        setNextFireTime(timerMonotonicallyIncreasingTime(), intervalToNextFireTime);
     } else {
         m_nextFireTime = 0;
     }
@@ -146,4 +146,9 @@
     return Platform::current()->currentThread()->taskRunner();
 }
 
+double TimerBase::timerMonotonicallyIncreasingTime() const
+{
+    return timerTaskRunner()->monotonicallyIncreasingVirtualTimeSeconds();
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/Timer.h b/third_party/WebKit/Source/platform/Timer.h
index 8354eca..c5423b6 100644
--- a/third_party/WebKit/Source/platform/Timer.h
+++ b/third_party/WebKit/Source/platform/Timer.h
@@ -67,7 +67,7 @@
     double repeatInterval() const { return m_repeatInterval; }
 
     void augmentRepeatInterval(double delta) {
-        double now = monotonicallyIncreasingTime();
+        double now = timerMonotonicallyIncreasingTime();
         setNextFireTime(now, m_nextFireTime - now + delta);
         m_repeatInterval += delta;
     }
@@ -82,11 +82,13 @@
 private:
     virtual void fired() = 0;
 
-    virtual WebTaskRunner* timerTaskRunner();
+    virtual WebTaskRunner* timerTaskRunner() const;
 
     NO_LAZY_SWEEP_SANITIZE_ADDRESS
     virtual bool canFire() const { return true; }
 
+    double timerMonotonicallyIncreasingTime() const;
+
     void setNextFireTime(double now, double delay);
 
     void runInternal();
diff --git a/third_party/WebKit/Source/platform/TimerTest.cpp b/third_party/WebKit/Source/platform/TimerTest.cpp
index 4284a62..61cc4c0 100644
--- a/third_party/WebKit/Source/platform/TimerTest.cpp
+++ b/third_party/WebKit/Source/platform/TimerTest.cpp
@@ -19,11 +19,6 @@
 namespace {
 double gCurrentTimeSecs = 0.0;
 
-double currentTime()
-{
-    return gCurrentTimeSecs;
-}
-
 // This class exists because gcc doesn't know how to move an OwnPtr.
 class RefCountedTaskContainer : public RefCounted<RefCountedTaskContainer> {
 public:
@@ -44,8 +39,10 @@
 public:
     DelayedTask(WebTaskRunner::Task* task, double delaySeconds)
         : m_task(adoptRef(new RefCountedTaskContainer(task)))
-        , m_runTimeSeconds(monotonicallyIncreasingTime() + delaySeconds)
-        , m_delaySeconds(delaySeconds) { }
+        , m_runTimeSeconds(gCurrentTimeSecs + delaySeconds)
+        , m_delaySeconds(delaySeconds)
+    {
+    }
 
     bool operator<(const DelayedTask& other) const
     {
@@ -94,6 +91,17 @@
         return nullptr;
     }
 
+    double virtualTimeSeconds() const override
+    {
+        ASSERT_NOT_REACHED();
+        return 0.0;
+    }
+
+    double monotonicallyIncreasingVirtualTimeSeconds() const override
+    {
+        return gCurrentTimeSecs;
+    }
+
     std::priority_queue<DelayedTask>* m_timerTasks; // NOT OWNED
 };
 
@@ -280,26 +288,19 @@
 public:
     void SetUp() override
     {
-        m_originalTimeFunction = setTimeFunctionsForTesting(currentTime);
-
         m_runTimes.clear();
         gCurrentTimeSecs = 10.0;
         m_startTime = gCurrentTimeSecs;
     }
 
-    void TearDown() override
-    {
-        setTimeFunctionsForTesting(m_originalTimeFunction);
-    }
-
     void countingTask(Timer<TimerTest>*)
     {
-        m_runTimes.append(monotonicallyIncreasingTime());
+        m_runTimes.append(gCurrentTimeSecs);
     }
 
     void recordNextFireTimeTask(Timer<TimerTest>* timer)
     {
-        m_nextFireTimes.append(monotonicallyIncreasingTime() + timer->nextFireInterval());
+        m_nextFireTimes.append(gCurrentTimeSecs + timer->nextFireInterval());
     }
 
     void advanceTimeBy(double timeSecs)
@@ -339,7 +340,6 @@
 
 private:
     TimerTestPlatform m_platform;
-    TimeFunction m_originalTimeFunction;
 };
 
 TEST_F(TimerTest, StartOneShot_Zero)
@@ -449,7 +449,7 @@
     runUntilIdle();
     EXPECT_FALSE(m_runTimes.size());
 
-    double secondPostTime = monotonicallyIncreasingTime();
+    double secondPostTime = gCurrentTimeSecs;
     timer.startOneShot(10, BLINK_FROM_HERE);
 
     ASSERT(hasOneTimerTask());
diff --git a/third_party/WebKit/Source/platform/TraceEvent.h b/third_party/WebKit/Source/platform/TraceEvent.h
index c39651c4..b2d51c0 100644
--- a/third_party/WebKit/Source/platform/TraceEvent.h
+++ b/third_party/WebKit/Source/platform/TraceEvent.h
@@ -37,7 +37,7 @@
 #include "wtf/Allocator.h"
 #include "wtf/DynamicAnnotations.h"
 #include "wtf/Noncopyable.h"
-#include "wtf/PassRefPtr.h"
+#include "wtf/PassOwnPtr.h"
 #include "wtf/text/CString.h"
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -116,7 +116,7 @@
 //                    const char** arg_names,
 //                    const unsigned char* arg_types,
 //                    const unsigned long long* arg_values,
-//                    PassRefPtr<TracedValue> tracedValues[],
+//                    PassOwnPtr<TracedValue> tracedValues[],
 //                    unsigned char flags)
 #define TRACE_EVENT_API_ADD_TRACE_EVENT \
     blink::EventTracer::addTraceEvent
@@ -427,22 +427,22 @@
     *type = TRACE_VALUE_TYPE_CONVERTABLE;
 }
 
-template<typename T> static inline void setTraceValue(const PassRefPtr<T>& ptr, unsigned char* type, unsigned long long* value)
+template<typename T> static inline void setTraceValue(const PassOwnPtr<T>& ptr, unsigned char* type, unsigned long long* value)
 {
     setTraceValue(ptr.get(), type, value);
 }
 
 template<typename T> struct TracedValueTraits {
     static const bool isTracedValue = false;
-    static PassRefPtr<TracedValue> moveFromIfTracedValue(const T&)
+    static PassOwnPtr<TracedValue> moveFromIfTracedValue(const T&)
     {
         return nullptr;
     }
 };
 
-template<typename T> struct TracedValueTraits<PassRefPtr<T>> {
+template<typename T> struct TracedValueTraits<PassOwnPtr<T>> {
     static const bool isTracedValue = std::is_convertible<T*, TracedValue*>::value;
-    static PassRefPtr<TracedValue> moveFromIfTracedValue(const PassRefPtr<T>& tracedValue)
+    static PassOwnPtr<TracedValue> moveFromIfTracedValue(const PassOwnPtr<T>& tracedValue)
     {
         return tracedValue;
     }
@@ -453,7 +453,7 @@
     return TracedValueTraits<T>::isTracedValue;
 }
 
-template<typename T> PassRefPtr<TracedValue> moveFromIfTracedValue(const T& value)
+template<typename T> PassOwnPtr<TracedValue> moveFromIfTracedValue(const T& value)
 {
     return TracedValueTraits<T>::moveFromIfTracedValue(value);
 }
diff --git a/third_party/WebKit/Source/platform/TraceEventCommon.h b/third_party/WebKit/Source/platform/TraceEventCommon.h
index 967250a..b38208d 100644
--- a/third_party/WebKit/Source/platform/TraceEventCommon.h
+++ b/third_party/WebKit/Source/platform/TraceEventCommon.h
@@ -148,8 +148,8 @@
 //   class MyData {
 //    public:
 //     MyData() {}
-//     PassRefPtr<TracedValue> toTracedValue() {
-//       RefPtr<TracedValue> tracedValue = TracedValue::create();
+//     PassOwnPtr<TracedValue> toTracedValue() {
+//       OwnPtr<TracedValue> tracedValue = TracedValue::create();
 //       tracedValue->setInteger("foo", 1);
 //       tracedValue->beginArray("bar");
 //       tracedValue->pushInteger(2);
diff --git a/third_party/WebKit/Source/platform/TracedValue.cpp b/third_party/WebKit/Source/platform/TracedValue.cpp
index 9464aab..3302698e 100644
--- a/third_party/WebKit/Source/platform/TracedValue.cpp
+++ b/third_party/WebKit/Source/platform/TracedValue.cpp
@@ -9,9 +9,9 @@
 
 namespace blink {
 
-PassRefPtr<TracedValue> TracedValue::create()
+PassOwnPtr<TracedValue> TracedValue::create()
 {
-    return adoptRef(new TracedValue());
+    return adoptPtr(new TracedValue());
 }
 
 TracedValue::TracedValue()
diff --git a/third_party/WebKit/Source/platform/TracedValue.h b/third_party/WebKit/Source/platform/TracedValue.h
index 85887c4..0e691da 100644
--- a/third_party/WebKit/Source/platform/TracedValue.h
+++ b/third_party/WebKit/Source/platform/TracedValue.h
@@ -7,7 +7,7 @@
 
 #include "base/memory/ref_counted.h"
 #include "platform/EventTracer.h"
-#include "wtf/PassRefPtr.h"
+#include "wtf/PassOwnPtr.h"
 #include "wtf/text/WTFString.h"
 
 namespace base {
@@ -19,13 +19,13 @@
 namespace blink {
 
 // TracedValue copies all passed names and values and doesn't retain references.
-class PLATFORM_EXPORT TracedValue final : public RefCounted<TracedValue> {
+class PLATFORM_EXPORT TracedValue final {
     WTF_MAKE_NONCOPYABLE(TracedValue);
 
 public:
     ~TracedValue();
 
-    static PassRefPtr<TracedValue> create();
+    static PassOwnPtr<TracedValue> create();
 
     void endDictionary();
     void endArray();
diff --git a/third_party/WebKit/Source/platform/TracedValueTest.cpp b/third_party/WebKit/Source/platform/TracedValueTest.cpp
index a29ac62..66363ab 100644
--- a/third_party/WebKit/Source/platform/TracedValueTest.cpp
+++ b/third_party/WebKit/Source/platform/TracedValueTest.cpp
@@ -10,7 +10,7 @@
 
 namespace blink {
 
-scoped_ptr<base::Value> parseTracedValue(PassRefPtr<TracedValue> value)
+scoped_ptr<base::Value> parseTracedValue(PassOwnPtr<TracedValue> value)
 {
     base::JSONReader reader;
     CString utf8 = value->toString().utf8();
@@ -19,13 +19,13 @@
 
 TEST(TracedValueTest, FlatDictionary)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setInteger("int", 2014);
     value->setDouble("double", 0.0);
     value->setBoolean("bool", true);
     value->setString("string", "string");
 
-    scoped_ptr<base::Value> parsed = parseTracedValue(value);
+    scoped_ptr<base::Value> parsed = parseTracedValue(value.release());
     base::DictionaryValue* dictionary;
     ASSERT_TRUE(parsed->GetAsDictionary(&dictionary));
     int intValue;
@@ -41,7 +41,7 @@
 
 TEST(TracedValueTest, Hierarchy)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setInteger("i0", 2014);
     value->beginDictionary("dict1");
     value->setInteger("i1", 2014);
@@ -61,7 +61,7 @@
     value->endArray();
     value->setString("s0", "foo");
 
-    scoped_ptr<base::Value> parsed = parseTracedValue(value);
+    scoped_ptr<base::Value> parsed = parseTracedValue(value.release());
     base::DictionaryValue* dictionary;
     ASSERT_TRUE(parsed->GetAsDictionary(&dictionary));
     int i0;
@@ -102,14 +102,14 @@
 
 TEST(TracedValueTest, Escape)
 {
-    RefPtr<TracedValue> value = TracedValue::create();
+    OwnPtr<TracedValue> value = TracedValue::create();
     value->setString("s0", "value0\\");
     value->setString("s1", "value\n1");
     value->setString("s2", "\"value2\"");
     value->setString("s3\\", "value3");
     value->setString("\"s4\"", "value4");
 
-    scoped_ptr<base::Value> parsed = parseTracedValue(value);
+    scoped_ptr<base::Value> parsed = parseTracedValue(value.release());
     base::DictionaryValue* dictionary;
     ASSERT_TRUE(parsed->GetAsDictionary(&dictionary));
     std::string s0;
diff --git a/third_party/WebKit/Source/platform/animation/CompositorAnimationPlayer.cpp b/third_party/WebKit/Source/platform/animation/CompositorAnimationPlayer.cpp
index 4603aaf..21147bd 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorAnimationPlayer.cpp
+++ b/third_party/WebKit/Source/platform/animation/CompositorAnimationPlayer.cpp
@@ -73,8 +73,8 @@
     cc::Animation::TargetProperty targetProperty,
     int group)
 {
-    ASSERT(m_delegate);
-    m_delegate->notifyAnimationStarted((monotonicTime - base::TimeTicks()).InSecondsF(), group);
+    if (m_delegate)
+        m_delegate->notifyAnimationStarted((monotonicTime - base::TimeTicks()).InSecondsF(), group);
 }
 
 void CompositorAnimationPlayer::NotifyAnimationFinished(
@@ -82,8 +82,8 @@
     cc::Animation::TargetProperty targetProperty,
     int group)
 {
-    ASSERT(m_delegate);
-    m_delegate->notifyAnimationFinished((monotonicTime - base::TimeTicks()).InSecondsF(), group);
+    if (m_delegate)
+        m_delegate->notifyAnimationFinished((monotonicTime - base::TimeTicks()).InSecondsF(), group);
 }
 
 void CompositorAnimationPlayer::NotifyAnimationAborted(
@@ -91,8 +91,8 @@
     cc::Animation::TargetProperty targetProperty,
     int group)
 {
-    ASSERT(m_delegate);
-    m_delegate->notifyAnimationAborted((monotonicTime - base::TimeTicks()).InSecondsF(), group);
+    if (m_delegate)
+        m_delegate->notifyAnimationAborted((monotonicTime - base::TimeTicks()).InSecondsF(), group);
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/blink_platform.gypi b/third_party/WebKit/Source/platform/blink_platform.gypi
index 3275e1c..35a2a63 100644
--- a/third_party/WebKit/Source/platform/blink_platform.gypi
+++ b/third_party/WebKit/Source/platform/blink_platform.gypi
@@ -157,29 +157,29 @@
       'animation/UnitBezier.h',
       'animation/CompositorAnimation.cpp',
       'animation/CompositorAnimation.h',
-      'animation/CompositorAnimationCurve.cpp',      
-      'animation/CompositorAnimationCurve.h',            
+      'animation/CompositorAnimationCurve.cpp',
+      'animation/CompositorAnimationCurve.h',
       'animation/CompositorAnimationPlayer.cpp',
       'animation/CompositorAnimationPlayer.h',
       'animation/CompositorAnimationPlayerClient.cpp',
       'animation/CompositorAnimationPlayerClient.h',
-      'animation/CompositorAnimationTimeline.cpp',      
-      'animation/CompositorAnimationTimeline.h',      
+      'animation/CompositorAnimationTimeline.cpp',
+      'animation/CompositorAnimationTimeline.h',
       'animation/CompositorFilterAnimationCurve.cpp',
       'animation/CompositorFilterAnimationCurve.h',
       'animation/CompositorFilterKeyframe.cpp',
-      'animation/CompositorFilterKeyframe.h',      
+      'animation/CompositorFilterKeyframe.h',
       'animation/CompositorFloatAnimationCurve.cpp',
       'animation/CompositorFloatAnimationCurve.h',
       'animation/CompositorFloatKeyframe.h',
-      'animation/CompositorScrollOffsetAnimationCurve.cpp',      
-      'animation/CompositorScrollOffsetAnimationCurve.h',   
+      'animation/CompositorScrollOffsetAnimationCurve.cpp',
+      'animation/CompositorScrollOffsetAnimationCurve.h',
       'animation/CompositorTransformAnimationCurve.cpp',
       'animation/CompositorTransformAnimationCurve.h',
       'animation/CompositorTransformKeyframe.cpp',
       'animation/CompositorTransformKeyframe.h',
-      'animation/CompositorTransformOperations.cpp',      
-      'animation/CompositorTransformOperations.h',      
+      'animation/CompositorTransformOperations.cpp',
+      'animation/CompositorTransformOperations.h',
       'audio/AudioArray.h',
       'audio/AudioBus.cpp',
       'audio/AudioBus.h',
@@ -560,7 +560,7 @@
       'graphics/CompositingReasons.cpp',
       'graphics/CompositingReasons.h',
       'graphics/CompositorFactory.cpp',
-      'graphics/CompositorFactory.h',      
+      'graphics/CompositorFactory.h',
       'graphics/CompositorFilterOperations.cpp',
       'graphics/CompositorFilterOperations.h',
       'graphics/CompositorMutableState.cpp',
@@ -647,6 +647,8 @@
       'graphics/RecordingImageBufferSurface.h',
       'graphics/ReplayingCanvas.cpp',
       'graphics/ReplayingCanvas.h',
+      'graphics/SquashingDisallowedReasons.cpp',
+      'graphics/SquashingDisallowedReasons.h',
       'graphics/StaticBitmapImage.cpp',
       'graphics/StaticBitmapImage.h',
       'graphics/StrokeData.cpp',
@@ -1085,7 +1087,6 @@
       'weborigin/SecurityOriginHash.h',
       'weborigin/SecurityPolicy.cpp',
       'weborigin/SecurityPolicy.h',
-      'win/HWndDC.h',
     ],
     'platform_test_files': [
       'DecimalTest.cpp',
diff --git a/third_party/WebKit/Source/platform/exported/WebSecurityOrigin.cpp b/third_party/WebKit/Source/platform/exported/WebSecurityOrigin.cpp
index fce9c8ae..559b1774 100644
--- a/third_party/WebKit/Source/platform/exported/WebSecurityOrigin.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebSecurityOrigin.cpp
@@ -126,9 +126,9 @@
 bool WebSecurityOrigin::isPotentiallyTrustworthy(WebString& errorMessage) const
 {
     ASSERT(m_private);
-    WTF::String message(errorMessage);
-    bool result = m_private->isPotentiallyTrustworthy(message);
-    errorMessage = message;
+    bool result = m_private->isPotentiallyTrustworthy();
+    if (!result)
+        errorMessage = WTF::String(m_private->isPotentiallyTrustworthyErrorMessage());
     return result;
 }
 
diff --git a/third_party/WebKit/Source/platform/fonts/win/FontFallbackWin.cpp b/third_party/WebKit/Source/platform/fonts/win/FontFallbackWin.cpp
index ed479845..12cb486 100644
--- a/third_party/WebKit/Source/platform/fonts/win/FontFallbackWin.cpp
+++ b/third_party/WebKit/Source/platform/fonts/win/FontFallbackWin.cpp
@@ -100,15 +100,9 @@
     };
 
     static const FontMap fontMap[] = {
-        {USCRIPT_LATIN, L"times new roman"},
-        {USCRIPT_GREEK, L"times new roman"},
-        {USCRIPT_CYRILLIC, L"times new roman"},
-        // FIXME: Consider trying new Vista fonts before XP fonts for CJK.
-        // Some Vista users do want to use Vista cleartype CJK fonts. If we
-        // did, the results of tests with CJK characters would have to be
-        // regenerated for Vista.
-        {USCRIPT_THAANA, L"mv boli"},
-        {USCRIPT_MONGOLIAN, L"mongolian balti"},
+        { USCRIPT_LATIN, L"Times New Roman" },
+        { USCRIPT_GREEK, L"Times New Roman" },
+        { USCRIPT_CYRILLIC, L"Times New Roman" },
         // For USCRIPT_COMMON, we map blocks to scripts when
         // that makes sense.
     };
@@ -118,85 +112,185 @@
         const UChar** families;
     };
 
-    // Kartika on Vista or earlier lacks the support for Chillu
-    // letters added to Unicode 5.1.
-    // Try AnjaliOldLipi (a very widely used Malaylalam font with the full
-    // Unicode 5.x support) before falling back to Kartika.
-    static const UChar* malayalamFonts[] = {L"AnjaliOldLipi", L"Lohit Malayalam", L"Kartika", L"Rachana", L"Nirmala UI", 0};
-    // Try Khmer OS before Vista fonts because 'Khmer OS' goes along better
-    // with Latin and looks better/larger for the same size.
-    static const UChar* khmerFonts[] = {L"Leelawadee UI", L"Khmer OS", L"MoolBoran", L"DaunPenh", L"Code2000", 0};
-    // For the following 6 scripts, two or fonts are listed. The fonts in
-    // the 1st slot are not available on Windows XP. To support these
-    // scripts on XP, listed in the rest of slots are widely used
-    // fonts.
-    static const UChar* ethiopicFonts[] = {L"Nyala", L"Abyssinica SIL", L"Ethiopia Jiret", L"Visual Geez Unicode", L"GF Zemen Unicode", L"Ebrima", 0};
-    static const UChar* oriyaFonts[] = {L"Kalinga", L"ori1Uni", L"Lohit Oriya", L"Nirmala UI", 0};
-    static const UChar* laoFonts[] = {L"Leelawadee UI", L"DokChampa", L"Saysettha OT", L"Phetsarath OT", L"Code2000", 0};
-    static const UChar* tibetanFonts[] = {L"Microsoft Himalaya", L"Jomolhari", L"Tibetan Machine Uni", 0};
-    static const UChar* sinhalaFonts[] = {L"Iskoola Pota", L"AksharUnicode", L"Nirmala UI", 0};
-    static const UChar* yiFonts[] = {L"Microsoft Yi Balti", L"Nuosu SIL", L"Code2000", 0};
-    // http://www.bethmardutho.org/support/meltho/download/index.php
-    static const UChar* syriacFonts[] = {L"Estrangelo Edessa", L"Estrangelo Nisibin", L"Code2000", 0};
-    static const UChar* myanmarFonts[] = {L"Myanmar Text", L"Padauk", L"Parabaik", L"Myanmar3", L"Code2000", 0};
-    static const UChar* gothicFonts[] = {L"Segoe UI Symbol", 0};
-    static const UChar* oghamFonts[] = {L"Segoe UI Symbol", 0};
-    static const UChar* hangulFonts[] = {L"gulim", L"Malgun Gothic", 0};
-    static const UChar* devanagariFonts[] = {L"mangal", L"Nirmala UI", 0};
-    static const UChar* gujaratiFonts[] = {L"shruti", L"Nirmala UI", 0};
-    static const UChar* bengaliFonts[] = {L"vrinda", L"Nirmala UI", 0};
-    static const UChar* teluguFonts[] = {L"gautami", L"Nirmala UI", 0};
-    static const UChar* tamilFonts[] = {L"latha", L"Nirmala UI", 0};
-    static const UChar* kannadaFonts[] = {L"tunga", L"Nirmala UI", 0};
-    static const UChar* gurumukhiFonts[] = {L"raavi", L"Nirmala UI", 0};
-    static const UChar* thaiFonts[] = {L"tahoma", L"Leelawadee UI", L"Leelawadee", 0};
-    static const UChar* hebrewFonts[] = {L"david", L"Segoe UI", 0};
-    static const UChar* arabicFonts[] = {L"tahoma", L"Segoe UI", 0};
-    static const UChar* tifinaghFonts[] = {L"ebrima", 0};
-    static const UChar* georgianFonts[] = {L"sylfaen", L"Segoe UI", 0};
-    static const UChar* armenianFonts[] = {L"sylfaen", L"Segoe UI", 0};
-    static const UChar* canadianAboriginalFonts[] = {L"euphemia", L"Gadugi", 0};
-    static const UChar* cherokeeFonts[] = {L"plantagenet cherokee", L"Gadugi", 0};
-    static const UChar* simplifiedHanFonts[] = {L"simsun", L"Microsoft YaHei", 0};
-    static const UChar* traditionalHanFonts[] = {L"pmingliu", L"Microsoft JhengHei", 0};
-    static const UChar* hiraganaFonts[] = {L"ms pgothic", L"Yu Gothic", L"Microsoft YaHei", 0};
-    static const UChar* katakanaFonts[] = {L"ms pgothic", L"Yu Gothic", L"Microsoft YaHei", 0};
-    static const UChar* katakanaOrHiraganaFonts[] = {L"ms pgothic", L"Yu Gothic", L"Microsoft YaHei", 0};
+    // For the following scripts, multiple fonts may be listed. They are tried
+    // in order. The first slot is preferred but the font may not be available,
+    // if so the remaining slots are tried in order.
+    // In general the order is the Windows 10 font follow by the 8.1, 8.0 and
+    // finally the font for Windows 7.
+    // For scripts where an optional or region specific font may be available
+    // that should be listed before the generic one.
+    // Based on the "Script and Font Support in Windows" MSDN documentation [1]
+    // with overrides and additional fallbacks as needed.
+    // 1: https://msdn.microsoft.com/en-us/goglobal/bb688099.aspx
+    static const UChar* arabicFonts[] = { L"Tahoma", L"Segoe UI", 0 };
+    static const UChar* armenianFonts[] = { L"Segoe UI", L"Sylfaen", 0 };
+    static const UChar* bengaliFonts[] = { L"Nirmala UI", L"Vrinda", 0 };
+    static const UChar* brahmiFonts[] = { L"Segoe UI Historic", 0 };
+    static const UChar* brailleFonts[] = { L"Segoe UI Symbol", 0 };
+    static const UChar* bugineseFonts[] = { L"Leelawadee UI", 0 };
+    static const UChar* canadianAaboriginalFonts[] = { L"Gadugi",
+        L"Euphemia", 0 };
+    static const UChar* carianFonts[] = { L"Segoe UI Historic", 0 };
+    static const UChar* cherokeeFonts[] = { L"Gadugi", L"Plantagenet", 0 };
+    static const UChar* copticFonts[] = { L"Segoe UI Symbol", 0 };
+    static const UChar* cuneiformFonts[] = { L"Segoe UI Historic", 0 };
+    static const UChar* cypriotFonts[] = { L"Segoe UI Historic", 0 };
+    static const UChar* deseretFonts[] = { L"Segoe UI Symbol", 0 };
+    static const UChar* devanagariFonts[] = { L"Nirmala UI", L"Mangal", 0 };
+    static const UChar* egyptianHieroglyphsFonts[] = { L"Segoe UI Historic",
+        0 };
+    static const UChar* ethiopicFonts[] = { L"Nyala", L"Abyssinica SIL",
+        L"Ethiopia Jiret", L"Visual Geez Unicode", L"GF Zemen Unicode",
+        L"Ebrima", 0 };
+    static const UChar* georgianFonts[] = { L"Segoe UI", L"Sylfaen", 0 };
+    static const UChar* glagoliticFonts[] = { L"Segoe UI Historic",
+        L"Segoe UI Symbol", 0 };
+    static const UChar* gothicFonts[] = { L"Segoe UI Historic",
+        L"Segoe UI Symbol", 0 };
+    static const UChar* gujaratiFonts[] = { L"Nirmala UI", L"Shruti", 0 };
+    static const UChar* gurmukhiFonts[] = { L"Nirmala UI", L"Raavi", 0 };
+    static const UChar* hangulFonts[] = { L"Malgun Gothic", L"Gulim", 0 };
+    static const UChar* hebrewFonts[] = { L"David", L"Segoe UI", 0 };
+    static const UChar* hiraganaFonts[] = { L"MS PGothic", L"Yu Gothic",
+        L"Microsoft YaHei", 0 };
+    static const UChar* imperialAramaicFonts[] = { L"Segoe UI Historic", 0 };
+    static const UChar* inscriptionalPahlaviFonts[] = { L"Segoe UI Historic",
+        0 };
+    static const UChar* inscriptionalParthianFonts[] = { L"Segoe UI Historic",
+        0 };
+    static const UChar* javaneseFonts[] = { L"Javanese Text", 0 };
+    static const UChar* kannadaFonts[] = { L"Tunga", L"Nirmala UI", 0 };
+    static const UChar* katakanaFonts[] = { L"MS PGothic", L"Yu Gothic",
+        L"Microsoft YaHei", 0 };
+    static const UChar* katakanaOrHiraganaFonts[] = { L"MS PGothic",
+        L"Yu Gothic", L"Microsoft YaHei", 0 };
+    static const UChar* kharoshthiFonts[] = { L"Segoe UI Historic", 0 };
+    // Try Khmer OS before Vista fonts as it goes along better with Latin
+    // and looks better/larger for the same size.
+    static const UChar* khmerFonts[] = { L"Leelawadee UI", L"Khmer UI",
+        L"Khmer OS", L"MoolBoran", L"DaunPenh", 0 };
+    static const UChar* laoFonts[] = { L"Leelawadee UI", L"Lao UI",
+        L"DokChampa", L"Saysettha OT", L"Phetsarath OT", L"Code2000", 0 };
+    static const UChar* lisuFonts[] = { L"Segoe UI", 0 };
+    static const UChar* lycianFonts[] = { L"Segoe UI Historic", 0 };
+    static const UChar* lydianFonts[] = { L"Segoe UI Historic", 0 };
+    static const UChar* malayalamFonts[] = { L"Nirmala UI", L"Kartika", 0 };
+    static const UChar* meroiticCursiveFonts[] = { L"Segoe UI Historic",
+        L"Segoe UI Symbol", 0 };
+    static const UChar* mongolianFonts[] = { L"Mongolian Baiti", 0 };
+    static const UChar* myanmarFonts[] = { L"Myanmar Text", L"Padauk",
+        L"Parabaik", L"Myanmar3", L"Code2000", 0 };
+    static const UChar* newTaiLueFonts[] = { L"Microsoft New Tai Lue", 0 };
+    static const UChar* nkoFonts[] = { L"Ebrima", 0 };
+    static const UChar* oghamFonts[] = { L"Segoe UI Historic",
+        L"Segoe UI Symbol", 0 };
+    static const UChar* olChikiFonts[] = { L"Nirmala UI", 0 };
+    static const UChar* oldItalicFonts[] = { L"Segoe UI Historic",
+        L"Segoe UI Symbol", 0 };
+    static const UChar* oldPersianFonts[] = { L"Segoe UI Historic", 0 };
+    static const UChar* oldSouthArabianFonts[] = { L"Segoe UI Historic", 0 };
+    static const UChar* oriyaFonts[] = { L"Kalinga", L"ori1Uni",
+        L"Lohit Oriya", L"Nirmala UI", 0 };
+    static const UChar* orkhonFonts[] = { L"Segoe UI Historic",
+        L"Segoe UI Symbol", 0 };
+    static const UChar* osmanyaFonts[] = { L"Ebrima", 0 };
+    static const UChar* phagsPaFonts[] = { L"Microsoft PhagsPa", 0 };
+    static const UChar* runicFonts[] = { L"Segoe UI Historic",
+        L"Segoe UI Symbol", 0 };
+    static const UChar* shavianFonts[] = { L"Segoe UI Historic", 0 };
+    static const UChar* simplifiedHanFonts[] = { L"simsun", L"Microsoft YaHei",
+        0 };
+    static const UChar* sinhalaFonts[] = { L"Iskoola Pota", L"AksharUnicode",
+        L"Nirmala UI", 0 };
+    static const UChar* soraSompengFonts[] = { L"Nirmala UI", 0 };
+    static const UChar* symbolsFonts[] = { L"Segoe UI Symbol", 0 };
+    static const UChar* syriacFonts[] = { L"Estrangelo Edessa",
+        L"Estrangelo Nisibin", L"Code2000", 0 };
+    static const UChar* taiLeFonts[] = { L"Microsoft Tai Le", 0 };
+    static const UChar* tamilFonts[] = { L"Nirmala UI", L"Latha", 0 };
+    static const UChar* teluguFonts[] = { L"Nirmala UI", L"Gautami", 0 };
+    static const UChar* thaanaFonts[] = { L"MV Boli", 0 };
+    static const UChar* thaiFonts[] = { L"Tahoma", L"Leelawadee UI",
+        L"Leelawadee", 0 };
+    static const UChar* tibetanFonts[] = { L"Microsoft Himalaya", L"Jomolhari",
+        L"Tibetan Machine Uni", 0 };
+    static const UChar* tifinaghFonts[] = { L"Ebrima", 0 };
+    static const UChar* traditionalHanFonts[] = { L"pmingliu",
+        L"Microsoft JhengHei", 0 };
+    static const UChar* vaiFonts[] = { L"Ebrima", 0 };
+    static const UChar* yiFonts[] = { L"Microsoft Yi Baiti", L"Nuosu SIL",
+        L"Code2000", 0 };
 
     static const ScriptToFontFamilies scriptToFontFamilies[] = {
-        {USCRIPT_MALAYALAM, malayalamFonts},
-        {USCRIPT_KHMER, khmerFonts},
-        {USCRIPT_ETHIOPIC, ethiopicFonts},
-        {USCRIPT_ORIYA, oriyaFonts},
-        {USCRIPT_LAO, laoFonts},
-        {USCRIPT_TIBETAN, tibetanFonts},
-        {USCRIPT_SINHALA, sinhalaFonts},
-        {USCRIPT_YI, yiFonts},
-        {USCRIPT_SYRIAC, syriacFonts},
-        {USCRIPT_MYANMAR, myanmarFonts},
-        {USCRIPT_GOTHIC, gothicFonts},
-        {USCRIPT_OGHAM, oghamFonts},
-        {USCRIPT_HANGUL, hangulFonts},
-        {USCRIPT_DEVANAGARI, devanagariFonts},
-        {USCRIPT_GUJARATI, gujaratiFonts},
-        {USCRIPT_BENGALI, bengaliFonts},
-        {USCRIPT_TELUGU, teluguFonts},
-        {USCRIPT_TAMIL, tamilFonts},
-        {USCRIPT_KANNADA, kannadaFonts},
-        {USCRIPT_GURMUKHI, gurumukhiFonts},
-        {USCRIPT_THAI, thaiFonts},
-        {USCRIPT_HEBREW, hebrewFonts},
-        {USCRIPT_ARABIC, arabicFonts},
-        {USCRIPT_TIFINAGH, tifinaghFonts},
-        {USCRIPT_GEORGIAN, georgianFonts},
-        {USCRIPT_ARMENIAN, armenianFonts},
-        {USCRIPT_CANADIAN_ABORIGINAL, canadianAboriginalFonts},
-        {USCRIPT_CHEROKEE, cherokeeFonts},
-        {USCRIPT_SIMPLIFIED_HAN, simplifiedHanFonts},
-        {USCRIPT_TRADITIONAL_HAN, traditionalHanFonts},
-        {USCRIPT_HIRAGANA, hiraganaFonts},
-        {USCRIPT_KATAKANA, katakanaFonts},
-        {USCRIPT_KATAKANA_OR_HIRAGANA, katakanaOrHiraganaFonts},
+        { USCRIPT_ARABIC, arabicFonts },
+        { USCRIPT_ARMENIAN, armenianFonts },
+        { USCRIPT_BENGALI, bengaliFonts },
+        { USCRIPT_BRAHMI, brahmiFonts },
+        { USCRIPT_BRAILLE, brailleFonts },
+        { USCRIPT_BUGINESE, bugineseFonts },
+        { USCRIPT_CANADIAN_ABORIGINAL, canadianAaboriginalFonts },
+        { USCRIPT_CARIAN, carianFonts },
+        { USCRIPT_CHEROKEE, cherokeeFonts },
+        { USCRIPT_COPTIC, copticFonts },
+        { USCRIPT_CUNEIFORM, cuneiformFonts },
+        { USCRIPT_CYPRIOT, cypriotFonts },
+        { USCRIPT_DESERET, deseretFonts },
+        { USCRIPT_DEVANAGARI, devanagariFonts },
+        { USCRIPT_EGYPTIAN_HIEROGLYPHS, egyptianHieroglyphsFonts },
+        { USCRIPT_ETHIOPIC, ethiopicFonts },
+        { USCRIPT_GEORGIAN, georgianFonts },
+        { USCRIPT_GLAGOLITIC, glagoliticFonts },
+        { USCRIPT_GOTHIC, gothicFonts },
+        { USCRIPT_GUJARATI, gujaratiFonts },
+        { USCRIPT_GURMUKHI, gurmukhiFonts },
+        { USCRIPT_HANGUL, hangulFonts },
+        { USCRIPT_HEBREW, hebrewFonts },
+        { USCRIPT_HIRAGANA, hiraganaFonts },
+        { USCRIPT_IMPERIAL_ARAMAIC, imperialAramaicFonts },
+        { USCRIPT_INSCRIPTIONAL_PAHLAVI, inscriptionalPahlaviFonts },
+        { USCRIPT_INSCRIPTIONAL_PARTHIAN, inscriptionalParthianFonts },
+        { USCRIPT_JAVANESE, javaneseFonts },
+        { USCRIPT_KANNADA, kannadaFonts },
+        { USCRIPT_KATAKANA, katakanaFonts },
+        { USCRIPT_KATAKANA_OR_HIRAGANA, katakanaOrHiraganaFonts },
+        { USCRIPT_KHAROSHTHI, kharoshthiFonts },
+        { USCRIPT_KHMER, khmerFonts },
+        { USCRIPT_LAO, laoFonts },
+        { USCRIPT_LISU, lisuFonts },
+        { USCRIPT_LYCIAN, lycianFonts },
+        { USCRIPT_LYDIAN, lydianFonts },
+        { USCRIPT_MALAYALAM, malayalamFonts },
+        { USCRIPT_MEROITIC_CURSIVE, meroiticCursiveFonts },
+        { USCRIPT_MONGOLIAN, mongolianFonts },
+        { USCRIPT_MYANMAR, myanmarFonts },
+        { USCRIPT_NEW_TAI_LUE, newTaiLueFonts },
+        { USCRIPT_NKO, nkoFonts },
+        { USCRIPT_OGHAM, oghamFonts },
+        { USCRIPT_OL_CHIKI, olChikiFonts },
+        { USCRIPT_OLD_ITALIC, oldItalicFonts },
+        { USCRIPT_OLD_PERSIAN, oldPersianFonts },
+        { USCRIPT_OLD_SOUTH_ARABIAN, oldSouthArabianFonts },
+        { USCRIPT_ORIYA, oriyaFonts },
+        { USCRIPT_ORKHON, orkhonFonts },
+        { USCRIPT_OSMANYA, osmanyaFonts },
+        { USCRIPT_PHAGS_PA, phagsPaFonts },
+        { USCRIPT_RUNIC, runicFonts },
+        { USCRIPT_SHAVIAN, shavianFonts },
+        { USCRIPT_SIMPLIFIED_HAN, simplifiedHanFonts },
+        { USCRIPT_SINHALA, sinhalaFonts },
+        { USCRIPT_SORA_SOMPENG, soraSompengFonts },
+        { USCRIPT_SYMBOLS, symbolsFonts },
+        { USCRIPT_SYRIAC, syriacFonts },
+        { USCRIPT_TAI_LE, taiLeFonts },
+        { USCRIPT_TAMIL, tamilFonts },
+        { USCRIPT_TELUGU, teluguFonts },
+        { USCRIPT_THAANA, thaanaFonts },
+        { USCRIPT_THAI, thaiFonts },
+        { USCRIPT_TIBETAN, tibetanFonts },
+        { USCRIPT_TIFINAGH, tifinaghFonts },
+        { USCRIPT_TRADITIONAL_HAN, traditionalHanFonts },
+        { USCRIPT_VAI, vaiFonts },
+        { USCRIPT_YI, yiFonts }
     };
 
     for (size_t i = 0; i < WTF_ARRAY_LENGTH(fontMap); ++i)
diff --git a/third_party/WebKit/Source/platform/graphics/CompositingReasons.cpp b/third_party/WebKit/Source/platform/graphics/CompositingReasons.cpp
index a096b707..56085320 100644
--- a/third_party/WebKit/Source/platform/graphics/CompositingReasons.cpp
+++ b/third_party/WebKit/Source/platform/graphics/CompositingReasons.cpp
@@ -69,51 +69,9 @@
     { CompositingReasonNegativeZIndexChildren,
         "negativeZIndexChildren",
         "Parent with composited negative z-index content" },
-    { CompositingReasonScrollsWithRespectToSquashingLayer,
-        "scrollsWithRespectToSquashingLayer",
-        "Cannot be squashed since this layer scrolls with respect to the squashing layer" },
-    { CompositingReasonSquashingSparsityExceeded,
-        "squashingSparsityExceeded",
-        "Cannot be squashed as the squashing layer would become too sparse" },
-    { CompositingReasonSquashingClippingContainerMismatch,
-        "squashingClippingContainerMismatch",
-        "Cannot be squashed because this layer has a different clipping container than the squashing layer" },
-    { CompositingReasonSquashingOpacityAncestorMismatch,
-        "squashingOpacityAncestorMismatch",
-        "Cannot be squashed because this layer has a different opacity ancestor than the squashing layer" },
-    { CompositingReasonSquashingTransformAncestorMismatch,
-        "squashingTransformAncestorMismatch",
-        "Cannot be squashed because this layer has a different transform ancestor than the squashing layer" },
-    { CompositingReasonSquashingFilterMismatch,
-        "squashingFilterAncestorMismatch",
-        "Cannot be squashed because this layer has a different filter ancestor than the squashing layer, or this layer has a filter" },
-    { CompositingReasonSquashingWouldBreakPaintOrder,
-        "squashingWouldBreakPaintOrder",
-        "Cannot be squashed without breaking paint order" },
-    { CompositingReasonSquashingVideoIsDisallowed,
-        "squashingVideoIsDisallowed",
-        "Squashing video is not supported" },
-    { CompositingReasonSquashedLayerClipsCompositingDescendants,
-        "squashedLayerClipsCompositingDescendants",
-        "Squashing a layer that clips composited descendants is not supported." },
-    { CompositingReasonSquashingLayoutPartIsDisallowed,
-        "squashingLayoutPartIsDisallowed",
-        "Squashing a frame, iframe or plugin is not supported." },
-    { CompositingReasonSquashingReflectionIsDisallowed,
-        "squashingReflectionDisallowed",
-        "Squashing a element with a reflection is not supported." },
-    { CompositingReasonSquashingBlendingIsDisallowed,
-        "squashingBlendingDisallowed",
-        "Squashing a layer with blending is not supported." },
-    { CompositingReasonSquashingNearestFixedPositionMismatch,
-        "squashingNearestFixedPositionMismatch",
-        "Cannot be squashed because this layer has a different nearest fixed position layer than the squashing layer" },
-    { CompositingReasonScrollChildWithCompositedDescendants,
-        "scrollChildWithCompositedDescendants",
-        "Squashing a scroll child with composited descendants is not supported." },
-    { CompositingReasonSquashingLayerIsAnimating,
-        "squashingLayerIsAnimating",
-        "Cannot squash into a layer that is animating." },
+    { CompositingReasonSquashingDisallowed,
+        "squashingDisallowed",
+        "Layer was separately composited because it could not be squashed." },
     { CompositingReasonTransformWithCompositedDescendants,
         "transformWithCompositedDescendants",
         "Has a transform that needs to be known by compositor because of composited descendants" },
diff --git a/third_party/WebKit/Source/platform/graphics/CompositingReasons.h b/third_party/WebKit/Source/platform/graphics/CompositingReasons.h
index 542694a0..82cccab9 100644
--- a/third_party/WebKit/Source/platform/graphics/CompositingReasons.h
+++ b/third_party/WebKit/Source/platform/graphics/CompositingReasons.h
@@ -36,63 +36,49 @@
 const uint64_t CompositingReasonAssumedOverlap                           = UINT64_C(1) << 15;
 const uint64_t CompositingReasonOverlap                                  = UINT64_C(1) << 16;
 const uint64_t CompositingReasonNegativeZIndexChildren                   = UINT64_C(1) << 17;
-const uint64_t CompositingReasonScrollsWithRespectToSquashingLayer       = UINT64_C(1) << 18;
-const uint64_t CompositingReasonSquashingSparsityExceeded                = UINT64_C(1) << 19;
-const uint64_t CompositingReasonSquashingClippingContainerMismatch       = UINT64_C(1) << 20;
-const uint64_t CompositingReasonSquashingOpacityAncestorMismatch         = UINT64_C(1) << 21;
-const uint64_t CompositingReasonSquashingTransformAncestorMismatch       = UINT64_C(1) << 22;
-const uint64_t CompositingReasonSquashingFilterMismatch                  = UINT64_C(1) << 23;
-const uint64_t CompositingReasonSquashingWouldBreakPaintOrder            = UINT64_C(1) << 24;
-const uint64_t CompositingReasonSquashingVideoIsDisallowed               = UINT64_C(1) << 25;
-const uint64_t CompositingReasonSquashedLayerClipsCompositingDescendants = UINT64_C(1) << 26;
-const uint64_t CompositingReasonSquashingLayoutPartIsDisallowed          = UINT64_C(1) << 27;
-const uint64_t CompositingReasonSquashingReflectionIsDisallowed          = UINT64_C(1) << 28;
-const uint64_t CompositingReasonSquashingBlendingIsDisallowed            = UINT64_C(1) << 29;
-const uint64_t CompositingReasonSquashingNearestFixedPositionMismatch    = UINT64_C(1) << 30;
-const uint64_t CompositingReasonScrollChildWithCompositedDescendants     = UINT64_C(1) << 31;
-const uint64_t CompositingReasonSquashingLayerIsAnimating                = UINT64_C(1) << 32;
+const uint64_t CompositingReasonSquashingDisallowed                      = UINT64_C(1) << 18;
 
 // Subtree reasons that require knowing what the status of your subtree is before knowing the answer
-const uint64_t CompositingReasonTransformWithCompositedDescendants       = UINT64_C(1) << 33;
-const uint64_t CompositingReasonOpacityWithCompositedDescendants         = UINT64_C(1) << 34;
-const uint64_t CompositingReasonMaskWithCompositedDescendants            = UINT64_C(1) << 35;
-const uint64_t CompositingReasonReflectionWithCompositedDescendants      = UINT64_C(1) << 36;
-const uint64_t CompositingReasonFilterWithCompositedDescendants          = UINT64_C(1) << 37;
-const uint64_t CompositingReasonBlendingWithCompositedDescendants        = UINT64_C(1) << 38;
-const uint64_t CompositingReasonClipsCompositingDescendants              = UINT64_C(1) << 39;
-const uint64_t CompositingReasonPerspectiveWith3DDescendants             = UINT64_C(1) << 40;
-const uint64_t CompositingReasonPreserve3DWith3DDescendants              = UINT64_C(1) << 41;
-const uint64_t CompositingReasonReflectionOfCompositedParent             = UINT64_C(1) << 42;
-const uint64_t CompositingReasonIsolateCompositedDescendants             = UINT64_C(1) << 43;
-const uint64_t CompositingReasonPositionFixedWithCompositedDescendants   = UINT64_C(1) << 44;
+const uint64_t CompositingReasonTransformWithCompositedDescendants       = UINT64_C(1) << 19;
+const uint64_t CompositingReasonOpacityWithCompositedDescendants         = UINT64_C(1) << 20;
+const uint64_t CompositingReasonMaskWithCompositedDescendants            = UINT64_C(1) << 21;
+const uint64_t CompositingReasonReflectionWithCompositedDescendants      = UINT64_C(1) << 22;
+const uint64_t CompositingReasonFilterWithCompositedDescendants          = UINT64_C(1) << 23;
+const uint64_t CompositingReasonBlendingWithCompositedDescendants        = UINT64_C(1) << 24;
+const uint64_t CompositingReasonClipsCompositingDescendants              = UINT64_C(1) << 25;
+const uint64_t CompositingReasonPerspectiveWith3DDescendants             = UINT64_C(1) << 26;
+const uint64_t CompositingReasonPreserve3DWith3DDescendants              = UINT64_C(1) << 27;
+const uint64_t CompositingReasonReflectionOfCompositedParent             = UINT64_C(1) << 28;
+const uint64_t CompositingReasonIsolateCompositedDescendants             = UINT64_C(1) << 29;
+const uint64_t CompositingReasonPositionFixedWithCompositedDescendants   = UINT64_C(1) << 30;
 
 // The root layer is a special case that may be forced to be a layer, but also it needs to be
 // a layer if anything else in the subtree is composited.
-const uint64_t CompositingReasonRoot                                     = UINT64_C(1) << 45;
+const uint64_t CompositingReasonRoot                                     = UINT64_C(1) << 31;
 
 // CompositedLayerMapping internal hierarchy reasons
-const uint64_t CompositingReasonLayerForAncestorClip                     = UINT64_C(1) << 46;
-const uint64_t CompositingReasonLayerForDescendantClip                   = UINT64_C(1) << 47;
-const uint64_t CompositingReasonLayerForPerspective                      = UINT64_C(1) << 48;
-const uint64_t CompositingReasonLayerForHorizontalScrollbar              = UINT64_C(1) << 49;
-const uint64_t CompositingReasonLayerForVerticalScrollbar                = UINT64_C(1) << 50;
-const uint64_t CompositingReasonLayerForOverflowControlsHost             = UINT64_C(1) << 51;
-const uint64_t CompositingReasonLayerForScrollCorner                     = UINT64_C(1) << 52;
-const uint64_t CompositingReasonLayerForScrollingContents                = UINT64_C(1) << 53;
-const uint64_t CompositingReasonLayerForScrollingContainer               = UINT64_C(1) << 54;
-const uint64_t CompositingReasonLayerForSquashingContents                = UINT64_C(1) << 55;
-const uint64_t CompositingReasonLayerForSquashingContainer               = UINT64_C(1) << 56;
-const uint64_t CompositingReasonLayerForForeground                       = UINT64_C(1) << 57;
-const uint64_t CompositingReasonLayerForBackground                       = UINT64_C(1) << 58;
-const uint64_t CompositingReasonLayerForMask                             = UINT64_C(1) << 59;
-const uint64_t CompositingReasonLayerForClippingMask                     = UINT64_C(1) << 60;
-const uint64_t CompositingReasonLayerForScrollingBlockSelection          = UINT64_C(1) << 61;
+const uint64_t CompositingReasonLayerForAncestorClip                     = UINT64_C(1) << 32;
+const uint64_t CompositingReasonLayerForDescendantClip                   = UINT64_C(1) << 33;
+const uint64_t CompositingReasonLayerForPerspective                      = UINT64_C(1) << 34;
+const uint64_t CompositingReasonLayerForHorizontalScrollbar              = UINT64_C(1) << 35;
+const uint64_t CompositingReasonLayerForVerticalScrollbar                = UINT64_C(1) << 36;
+const uint64_t CompositingReasonLayerForOverflowControlsHost             = UINT64_C(1) << 37;
+const uint64_t CompositingReasonLayerForScrollCorner                     = UINT64_C(1) << 38;
+const uint64_t CompositingReasonLayerForScrollingContents                = UINT64_C(1) << 39;
+const uint64_t CompositingReasonLayerForScrollingContainer               = UINT64_C(1) << 40;
+const uint64_t CompositingReasonLayerForSquashingContents                = UINT64_C(1) << 41;
+const uint64_t CompositingReasonLayerForSquashingContainer               = UINT64_C(1) << 42;
+const uint64_t CompositingReasonLayerForForeground                       = UINT64_C(1) << 43;
+const uint64_t CompositingReasonLayerForBackground                       = UINT64_C(1) << 44;
+const uint64_t CompositingReasonLayerForMask                             = UINT64_C(1) << 45;
+const uint64_t CompositingReasonLayerForClippingMask                     = UINT64_C(1) << 46;
+const uint64_t CompositingReasonLayerForScrollingBlockSelection          = UINT64_C(1) << 47;
 
 // Composited elements with inline transforms trigger assumed overlap so that
 // we can update their transforms quickly.
-const uint64_t CompositingReasonInlineTransform                          = UINT64_C(1) << 62;
+const uint64_t CompositingReasonInlineTransform                          = UINT64_C(1) << 48;
 
-const uint64_t CompositingReasonCompositorProxy                          = UINT64_C(1) << 63;
+const uint64_t CompositingReasonCompositorProxy                          = UINT64_C(1) << 49;
 
 // Various combinations of compositing reasons are defined here also, for more intutive and faster bitwise logic.
 const uint64_t CompositingReasonComboAllDirectReasons =
@@ -148,18 +134,7 @@
     | CompositingReasonOverlap
     | CompositingReasonAssumedOverlap
     | CompositingReasonNegativeZIndexChildren
-    | CompositingReasonScrollsWithRespectToSquashingLayer
-    | CompositingReasonSquashingSparsityExceeded
-    | CompositingReasonSquashingClippingContainerMismatch
-    | CompositingReasonSquashingOpacityAncestorMismatch
-    | CompositingReasonSquashingTransformAncestorMismatch
-    | CompositingReasonSquashingFilterMismatch
-    | CompositingReasonSquashingWouldBreakPaintOrder
-    | CompositingReasonSquashingVideoIsDisallowed
-    | CompositingReasonSquashedLayerClipsCompositingDescendants
-    | CompositingReasonSquashingLayoutPartIsDisallowed
-    | CompositingReasonSquashingReflectionIsDisallowed
-    | CompositingReasonSquashingBlendingIsDisallowed
+    | CompositingReasonSquashingDisallowed
     | CompositingReasonTransformWithCompositedDescendants
     | CompositingReasonOpacityWithCompositedDescendants
     | CompositingReasonMaskWithCompositedDescendants
@@ -167,11 +142,8 @@
     | CompositingReasonBlendingWithCompositedDescendants
     | CompositingReasonIsolateCompositedDescendants
     | CompositingReasonPreserve3DWith3DDescendants // preserve-3d has to create backing store to ensure that 3d-transformed elements intersect.
-    | CompositingReasonSquashingNearestFixedPositionMismatch
-    | CompositingReasonScrollChildWithCompositedDescendants
     | CompositingReasonBackdropFilter
-    | CompositingReasonPositionFixedWithCompositedDescendants
-    | CompositingReasonSquashingLayerIsAnimating;
+    | CompositingReasonPositionFixedWithCompositedDescendants;
 
 const uint64_t CompositingReasonComboSquashableReasons =
     CompositingReasonOverlap
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
index 89f0c8e..b273126 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
@@ -315,7 +315,7 @@
 void GraphicsLayer::paint(const IntRect* interestRect, GraphicsContext::DisabledMode disabledMode)
 {
     if (paintWithoutCommit(interestRect, disabledMode))
-        paintController().commitNewDisplayItems();
+        paintController().commitNewDisplayItems(offsetFromLayoutObjectWithSubpixelAccumulation());
 }
 
 bool GraphicsLayer::paintWithoutCommit(const IntRect* interestRect, GraphicsContext::DisabledMode disabledMode)
@@ -783,6 +783,13 @@
                 compositingReasonsJSON->pushString(debug ? kCompositingReasonStringMap[i].description : kCompositingReasonStringMap[i].shortName);
         }
         json->setArray("compositingReasons", compositingReasonsJSON);
+
+        RefPtr<JSONArray> squashingDisallowedReasonsJSON = adoptRef(new JSONArray);
+        for (size_t i = 0; i < kNumberOfSquashingDisallowedReasons; ++i) {
+            if (m_debugInfo.squashingDisallowedReasons() & kSquashingDisallowedReasonStringMap[i].reason)
+                squashingDisallowedReasonsJSON->pushString(debug ? kSquashingDisallowedReasonStringMap[i].description : kSquashingDisallowedReasonStringMap[i].shortName);
+        }
+        json->setArray("squashingDisallowedReasons", squashingDisallowedReasonsJSON);
     }
 
     if (m_children.size()) {
@@ -838,6 +845,11 @@
     m_debugInfo.setCompositingReasons(reasons);
 }
 
+void GraphicsLayer::setSquashingDisallowedReasons(SquashingDisallowedReasons reasons)
+{
+    m_debugInfo.setSquashingDisallowedReasons(reasons);
+}
+
 void GraphicsLayer::setOwnerNodeId(int nodeId)
 {
     m_debugInfo.setOwnerNodeId(nodeId);
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h
index 529ae1f..a565bc6 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h
@@ -86,6 +86,7 @@
 
     void setCompositingReasons(CompositingReasons);
     CompositingReasons compositingReasons() const { return m_debugInfo.compositingReasons(); }
+    void setSquashingDisallowedReasons(SquashingDisallowedReasons);
     void setOwnerNodeId(int);
 
     GraphicsLayer* parent() const { return m_parent; }
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayerDebugInfo.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsLayerDebugInfo.cpp
index 3820b8a..b46bcad0 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayerDebugInfo.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayerDebugInfo.cpp
@@ -25,6 +25,7 @@
 
 GraphicsLayerDebugInfo::GraphicsLayerDebugInfo()
     : m_compositingReasons(CompositingReasonNone)
+    , m_squashingDisallowedReasons(SquashingDisallowedReasonsNone)
     , m_ownerNodeId(0)
 {
 }
@@ -36,6 +37,7 @@
     scoped_refptr<base::trace_event::TracedValue> tracedValue = new base::trace_event::TracedValue;
     appendAnnotatedInvalidateRects(tracedValue.get());
     appendCompositingReasons(tracedValue.get());
+    appendSquashingDisallowedReasons(tracedValue.get());
     appendOwnerNodeId(tracedValue.get());
     return tracedValue;
 }
@@ -69,6 +71,17 @@
     tracedValue->EndArray();
 }
 
+void GraphicsLayerDebugInfo::appendSquashingDisallowedReasons(base::trace_event::TracedValue* tracedValue) const
+{
+    tracedValue->BeginArray("squashing_disallowed_reasons");
+    for (size_t i = 0; i < kNumberOfSquashingDisallowedReasons; ++i) {
+        if (!(m_compositingReasons & kSquashingDisallowedReasonStringMap[i].reason))
+            continue;
+        tracedValue->AppendString(kSquashingDisallowedReasonStringMap[i].description);
+    }
+    tracedValue->EndArray();
+}
+
 void GraphicsLayerDebugInfo::appendOwnerNodeId(base::trace_event::TracedValue* tracedValue) const
 {
     if (!m_ownerNodeId)
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayerDebugInfo.h b/third_party/WebKit/Source/platform/graphics/GraphicsLayerDebugInfo.h
index ccc64fad..fd79f680 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayerDebugInfo.h
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayerDebugInfo.h
@@ -35,6 +35,7 @@
 #include "platform/geometry/FloatRect.h"
 #include "platform/graphics/CompositingReasons.h"
 #include "platform/graphics/PaintInvalidationReason.h"
+#include "platform/graphics/SquashingDisallowedReasons.h"
 #include "wtf/Allocator.h"
 #include "wtf/Noncopyable.h"
 #include "wtf/Vector.h"
@@ -58,6 +59,9 @@
 
     CompositingReasons compositingReasons() const { return m_compositingReasons; }
     void setCompositingReasons(CompositingReasons reasons) { m_compositingReasons = reasons; }
+
+    SquashingDisallowedReasons squashingDisallowedReasons() const { return m_squashingDisallowedReasons; }
+    void setSquashingDisallowedReasons(SquashingDisallowedReasons reasons) { m_squashingDisallowedReasons = reasons; }
     void setOwnerNodeId(int id) { m_ownerNodeId = id; }
 
     void appendAnnotatedInvalidateRect(const FloatRect&, PaintInvalidationReason);
@@ -66,6 +70,7 @@
 private:
     void appendAnnotatedInvalidateRects(base::trace_event::TracedValue*) const;
     void appendCompositingReasons(base::trace_event::TracedValue*) const;
+    void appendSquashingDisallowedReasons(base::trace_event::TracedValue*) const;
     void appendOwnerNodeId(base::trace_event::TracedValue*) const;
 
     struct AnnotatedInvalidationRect {
@@ -75,6 +80,7 @@
     };
 
     CompositingReasons m_compositingReasons;
+    SquashingDisallowedReasons m_squashingDisallowedReasons;
     int m_ownerNodeId;
     Vector<AnnotatedInvalidationRect> m_invalidations;
     Vector<AnnotatedInvalidationRect> m_previousInvalidations;
diff --git a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp
index fc35e53..2cb353f 100644
--- a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp
@@ -263,6 +263,18 @@
             return nullptr;
         }
 
+        double virtualTimeSeconds() const override
+        {
+            ASSERT_NOT_REACHED();
+            return 0.0;
+        }
+
+        double monotonicallyIncreasingVirtualTimeSeconds() const override
+        {
+            ASSERT_NOT_REACHED();
+            return 0.0;
+        }
+
         Task* m_task;
     };
 
diff --git a/third_party/WebKit/Source/platform/graphics/SquashingDisallowedReasons.cpp b/third_party/WebKit/Source/platform/graphics/SquashingDisallowedReasons.cpp
new file mode 100644
index 0000000..5abeb33
--- /dev/null
+++ b/third_party/WebKit/Source/platform/graphics/SquashingDisallowedReasons.cpp
@@ -0,0 +1,61 @@
+// Copyright 2016 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 "platform/graphics/SquashingDisallowedReasons.h"
+
+#include "wtf/StdLibExtras.h"
+
+namespace blink {
+
+const SquashingDisallowedReasonStringMap kSquashingDisallowedReasonStringMap[] = {
+    { SquashingDisallowedReasonScrollsWithRespectToSquashingLayer,
+        "scrollsWithRespectToSquashingLayer",
+        "Cannot be squashed since this layer scrolls with respect to the squashing layer" },
+    { SquashingDisallowedReasonSquashingSparsityExceeded,
+        "squashingSparsityExceeded",
+        "Cannot be squashed as the squashing layer would become too sparse" },
+    { SquashingDisallowedReasonClippingContainerMismatch,
+        "squashingClippingContainerMismatch",
+        "Cannot be squashed because this layer has a different clipping container than the squashing layer" },
+    { SquashingDisallowedReasonOpacityAncestorMismatch,
+        "squashingOpacityAncestorMismatch",
+        "Cannot be squashed because this layer has a different opacity ancestor than the squashing layer" },
+    { SquashingDisallowedReasonTransformAncestorMismatch,
+        "squashingTransformAncestorMismatch",
+        "Cannot be squashed because this layer has a different transform ancestor than the squashing layer" },
+    { SquashingDisallowedReasonFilterMismatch,
+        "squashingFilterAncestorMismatch",
+        "Cannot be squashed because this layer has a different filter ancestor than the squashing layer, or this layer has a filter" },
+    { SquashingDisallowedReasonWouldBreakPaintOrder,
+        "squashingWouldBreakPaintOrder",
+        "Cannot be squashed without breaking paint order" },
+    { SquashingDisallowedReasonSquashingVideoIsDisallowed,
+        "squashingVideoIsDisallowed",
+        "Squashing video is not supported" },
+    { SquashingDisallowedReasonSquashedLayerClipsCompositingDescendants,
+        "squashedLayerClipsCompositingDescendants",
+        "Squashing a layer that clips composited descendants is not supported." },
+    { SquashingDisallowedReasonSquashingLayoutPartIsDisallowed,
+        "squashingLayoutPartIsDisallowed",
+        "Squashing a frame, iframe or plugin is not supported." },
+    { SquashingDisallowedReasonSquashingReflectionIsDisallowed,
+        "squashingReflectionDisallowed",
+        "Squashing a element with a reflection is not supported." },
+    { SquashingDisallowedReasonSquashingBlendingIsDisallowed,
+        "squashingBlendingDisallowed",
+        "Squashing a layer with blending is not supported." },
+    { SquashingDisallowedReasonNearestFixedPositionMismatch,
+        "squashingNearestFixedPositionMismatch",
+        "Cannot be squashed because this layer has a different nearest fixed position layer than the squashing layer" },
+    { SquashingDisallowedReasonScrollChildWithCompositedDescendants,
+        "scrollChildWithCompositedDescendants",
+        "Squashing a scroll child with composited descendants is not supported." },
+    { SquashingDisallowedReasonSquashingLayerIsAnimating,
+        "squashingLayerIsAnimating",
+        "Cannot squash into a layer that is animating." },
+};
+
+const size_t kNumberOfSquashingDisallowedReasons = WTF_ARRAY_LENGTH(kSquashingDisallowedReasonStringMap);
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/SquashingDisallowedReasons.h b/third_party/WebKit/Source/platform/graphics/SquashingDisallowedReasons.h
new file mode 100644
index 0000000..ec290909
--- /dev/null
+++ b/third_party/WebKit/Source/platform/graphics/SquashingDisallowedReasons.h
@@ -0,0 +1,46 @@
+// Copyright 2016 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 SquashingDisallowedReasons_h
+#define SquashingDisallowedReasons_h
+
+#include "platform/PlatformExport.h"
+#include "wtf/Allocator.h"
+#include <stdint.h>
+
+namespace blink {
+
+const uint64_t SquashingDisallowedReasonsNone = 0;
+
+const uint64_t SquashingDisallowedReasonScrollsWithRespectToSquashingLayer       = UINT64_C(1) << 0;
+const uint64_t SquashingDisallowedReasonSquashingSparsityExceeded                = UINT64_C(1) << 1;
+const uint64_t SquashingDisallowedReasonClippingContainerMismatch                = UINT64_C(1) << 2;
+const uint64_t SquashingDisallowedReasonOpacityAncestorMismatch                  = UINT64_C(1) << 3;
+const uint64_t SquashingDisallowedReasonTransformAncestorMismatch                = UINT64_C(1) << 4;
+const uint64_t SquashingDisallowedReasonFilterMismatch                           = UINT64_C(1) << 5;
+const uint64_t SquashingDisallowedReasonWouldBreakPaintOrder                     = UINT64_C(1) << 6;
+const uint64_t SquashingDisallowedReasonSquashingVideoIsDisallowed               = UINT64_C(1) << 7;
+const uint64_t SquashingDisallowedReasonSquashedLayerClipsCompositingDescendants = UINT64_C(1) << 8;
+const uint64_t SquashingDisallowedReasonSquashingLayoutPartIsDisallowed          = UINT64_C(1) << 9;
+const uint64_t SquashingDisallowedReasonSquashingReflectionIsDisallowed          = UINT64_C(1) << 10;
+const uint64_t SquashingDisallowedReasonSquashingBlendingIsDisallowed            = UINT64_C(1) << 11;
+const uint64_t SquashingDisallowedReasonNearestFixedPositionMismatch             = UINT64_C(1) << 12;
+const uint64_t SquashingDisallowedReasonScrollChildWithCompositedDescendants     = UINT64_C(1) << 13;
+const uint64_t SquashingDisallowedReasonSquashingLayerIsAnimating                = UINT64_C(1) << 14;
+
+typedef uint64_t SquashingDisallowedReasons;
+
+struct SquashingDisallowedReasonStringMap {
+    STACK_ALLOCATED();
+    SquashingDisallowedReasons reason;
+    const char* shortName;
+    const char* description;
+};
+
+PLATFORM_EXPORT extern const SquashingDisallowedReasonStringMap kSquashingDisallowedReasonStringMap[];
+PLATFORM_EXPORT extern const size_t kNumberOfSquashingDisallowedReasons;
+
+} // namespace blink
+
+#endif // SquashingDisallowedReasons_h
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DisplayItemList.h b/third_party/WebKit/Source/platform/graphics/paint/DisplayItemList.h
index 15be746..a108185 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/DisplayItemList.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/DisplayItemList.h
@@ -32,15 +32,18 @@
     DisplayItemList(size_t initialSizeBytes)
         : ContiguousContainer(kMaximumDisplayItemSize, initialSizeBytes) {}
     DisplayItemList(DisplayItemList&& source)
-        : ContiguousContainer(std::move(source)) {}
+        : ContiguousContainer(std::move(source))
+        , m_visualRects(std::move(source.m_visualRects))
+    {}
 
     DisplayItemList& operator=(DisplayItemList&& source)
     {
         ContiguousContainer::operator=(std::move(source));
+        m_visualRects = std::move(source.m_visualRects);
         return *this;
     }
 
-    DisplayItem& appendByMoving(DisplayItem& item)
+    DisplayItem& appendByMoving(DisplayItem& item, const IntRect& visualRect)
     {
 #ifndef NDEBUG
         WTF::String originalDebugString = item.asDebugString();
@@ -55,9 +58,21 @@
         // Save original debug string in the old item to help debugging.
         item.setClientDebugString(originalDebugString);
 #endif
+        m_visualRects.append(visualRect);
         return result;
     }
 
+    IntRect visualRect(unsigned index) const
+    {
+        ASSERT(index < m_visualRects.size());
+        return m_visualRects[index];
+    }
+
+    void appendVisualRect(const IntRect& visualRect)
+    {
+        m_visualRects.append(visualRect);
+    }
+
 #if ENABLE(ASSERT)
     void assertDisplayItemClientsAreAlive() const
     {
@@ -85,6 +100,9 @@
     };
     Range<iterator> itemsInPaintChunk(const PaintChunk&);
     Range<const_iterator> itemsInPaintChunk(const PaintChunk&) const;
+
+private:
+    Vector<IntRect> m_visualRects;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.cpp
index 8bcee319..a6259cf82 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.cpp
@@ -48,26 +48,16 @@
 {
 }
 
-static void appendVisualRectForDisplayItem(const DisplayItem& displayItem, const LayoutSize& offsetFromLayoutObject, Vector<IntRect>& visualRects)
-{
-    LayoutRect visualRect = displayItem.client().visualRect();
-    visualRect.move(-offsetFromLayoutObject);
-    visualRects.append(enclosingIntRect(visualRect));
-}
-
-PaintArtifact::PaintArtifact(DisplayItemList displayItems, Vector<PaintChunk> paintChunks, const LayoutSize& offsetFromLayoutObject)
+PaintArtifact::PaintArtifact(DisplayItemList displayItems, Vector<PaintChunk> paintChunks)
     : m_displayItemList(std::move(displayItems))
     , m_paintChunks(std::move(paintChunks))
 {
-    for (const DisplayItem& displayItem : m_displayItemList)
-        appendVisualRectForDisplayItem(displayItem, offsetFromLayoutObject, m_visualRects);
     computeChunkBoundsAndOpaqueness(m_displayItemList, m_paintChunks);
 }
 
 PaintArtifact::PaintArtifact(PaintArtifact&& source)
     : m_displayItemList(std::move(source.m_displayItemList))
     , m_paintChunks(std::move(source.m_paintChunks))
-    , m_visualRects(std::move(source.m_visualRects))
 {
 }
 
@@ -79,7 +69,6 @@
 {
     m_displayItemList = std::move(source.m_displayItemList);
     m_paintChunks = std::move(source.m_paintChunks);
-    m_visualRects = std::move(source.m_visualRects);
     return *this;
 }
 
@@ -108,10 +97,9 @@
 #if ENABLE(ASSERT)
     m_displayItemList.assertDisplayItemClientsAreAlive();
 #endif
-    ASSERT(m_displayItemList.size() == m_visualRects.size());
     unsigned visualRectIndex = 0;
     for (const DisplayItem& displayItem : m_displayItemList) {
-        displayItem.appendToWebDisplayItemList(m_visualRects[visualRectIndex], list);
+        displayItem.appendToWebDisplayItemList(m_displayItemList.visualRect(visualRectIndex), list);
         visualRectIndex++;
     }
 }
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.h b/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.h
index 4b8e1a7..20ffee7 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.h
@@ -35,7 +35,7 @@
     WTF_MAKE_NONCOPYABLE(PaintArtifact);
 public:
     PaintArtifact();
-    PaintArtifact(DisplayItemList, Vector<PaintChunk>, const LayoutSize& offsetFromLayoutObject);
+    PaintArtifact(DisplayItemList, Vector<PaintChunk>);
     PaintArtifact(PaintArtifact&&);
     ~PaintArtifact();
 
@@ -63,11 +63,8 @@
     void appendToWebDisplayItemList(WebDisplayItemList*) const;
 
 private:
-    IntRect visualRect(unsigned index) const { return m_visualRects[index]; }
-
     DisplayItemList m_displayItemList;
     Vector<PaintChunk> m_paintChunks;
-    Vector<IntRect> m_visualRects;
 
     friend class PaintControllerTest;
 };
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
index d98ac276..f14c0f14 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
@@ -240,7 +240,7 @@
     return currentEnd;
 }
 
-void PaintController::copyCachedSubsequence(DisplayItemList::iterator& currentIt, DisplayItemList& updatedList)
+void PaintController::copyCachedSubsequence(const DisplayItemList& currentList, DisplayItemList::iterator& currentIt, DisplayItemList& updatedList)
 {
     ASSERT(currentIt->type() == DisplayItem::Subsequence);
     ASSERT(!currentIt->scope());
@@ -249,7 +249,7 @@
         // We should always find the EndSubsequence display item.
         ASSERT(currentIt != m_currentPaintArtifact.displayItemList().end());
         ASSERT(currentIt->hasValidClient());
-        updatedList.appendByMoving(*currentIt);
+        updatedList.appendByMoving(*currentIt, currentList.visualRect(currentIt - m_currentPaintArtifact.displayItemList().begin()));
         ++currentIt;
     } while (!endSubsequenceId.matches(updatedList.last()));
 }
@@ -265,6 +265,13 @@
 #endif
 }
 
+static IntRect visualRectForDisplayItem(const DisplayItem& displayItem, const LayoutSize& offsetFromLayoutObject)
+{
+    LayoutRect visualRect = displayItem.client().visualRect();
+    visualRect.move(-offsetFromLayoutObject);
+    return enclosingIntRect(visualRect);
+}
+
 // Update the existing display items by removing invalidated entries, updating
 // repainted ones, and appending new items.
 // - For cached drawing display item, copy the corresponding cached DrawingDisplayItem;
@@ -302,8 +309,10 @@
         for (const auto& item : m_newDisplayItemList)
             ASSERT(!item.isCached());
 #endif
+        for (const auto& item : m_newDisplayItemList)
+            m_newDisplayItemList.appendVisualRect(visualRectForDisplayItem(item, offsetFromLayoutObject));
 
-        m_currentPaintArtifact = PaintArtifact(std::move(m_newDisplayItemList), m_newPaintChunks.releasePaintChunks(), offsetFromLayoutObject);
+        m_currentPaintArtifact = PaintArtifact(std::move(m_newDisplayItemList), m_newPaintChunks.releasePaintChunks());
         m_newDisplayItemList = DisplayItemList(kInitialDisplayItemListCapacityBytes);
         m_validlyCachedClientsDirty = true;
         return;
@@ -355,11 +364,11 @@
             }
 #endif
             if (newDisplayItem.isCachedDrawing()) {
-                updatedList.appendByMoving(*currentIt);
+                updatedList.appendByMoving(*currentIt, m_currentPaintArtifact.displayItemList().visualRect(currentIt - m_currentPaintArtifact.displayItemList().begin()));
                 ++currentIt;
             } else {
                 ASSERT(newDisplayItem.type() == DisplayItem::CachedSubsequence);
-                copyCachedSubsequence(currentIt, updatedList);
+                copyCachedSubsequence(m_currentPaintArtifact.displayItemList(), currentIt, updatedList);
                 ASSERT(updatedList.last().type() == DisplayItem::EndSubsequence);
             }
         } else {
@@ -368,7 +377,7 @@
                 || !clientCacheIsValid(newDisplayItem.client())
                 || (RuntimeEnabledFeatures::slimmingPaintOffsetCachingEnabled() && paintOffsetWasInvalidated(newDisplayItem.client())));
 
-            updatedList.appendByMoving(*newIt);
+            updatedList.appendByMoving(*newIt, visualRectForDisplayItem(*newIt, offsetFromLayoutObject));
 
             if (isSynchronized)
                 ++currentIt;
@@ -385,7 +394,7 @@
 
     // TODO(jbroman): When subsequence caching applies to SPv2, we'll need to
     // merge the paint chunks as well.
-    m_currentPaintArtifact = PaintArtifact(std::move(updatedList), m_newPaintChunks.releasePaintChunks(), offsetFromLayoutObject);
+    m_currentPaintArtifact = PaintArtifact(std::move(updatedList), m_newPaintChunks.releasePaintChunks());
 
     m_newDisplayItemList = DisplayItemList(kInitialDisplayItemListCapacityBytes);
     m_validlyCachedClientsDirty = true;
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintController.h b/third_party/WebKit/Source/platform/graphics/paint/PaintController.h
index d1fdd98..fab3dbc 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintController.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintController.h
@@ -208,7 +208,7 @@
     struct OutOfOrderIndexContext;
     DisplayItemList::iterator findOutOfOrderCachedItem(const DisplayItem::Id&, OutOfOrderIndexContext&);
     DisplayItemList::iterator findOutOfOrderCachedItemForward(const DisplayItem::Id&, OutOfOrderIndexContext&);
-    void copyCachedSubsequence(DisplayItemList::iterator& currentIt, DisplayItemList& updatedList);
+    void copyCachedSubsequence(const DisplayItemList& currentList, DisplayItemList::iterator& currentIt, DisplayItemList& updatedList);
 
 #if ENABLE(ASSERT)
     // The following two methods are for checking under-invalidations
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintControllerTest.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintControllerTest.cpp
index 1df44824..0e616f6 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintControllerTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintControllerTest.cpp
@@ -24,7 +24,7 @@
 
     IntRect visualRect(const PaintArtifact& paintArtifact, unsigned index)
     {
-        return paintArtifact.visualRect(index);
+        return paintArtifact.displayItemList().visualRect(index);
     }
 
 protected:
diff --git a/third_party/WebKit/Source/platform/heap/BUILD.gn b/third_party/WebKit/Source/platform/heap/BUILD.gn
index 93e56e6..0af30da1 100644
--- a/third_party/WebKit/Source/platform/heap/BUILD.gn
+++ b/third_party/WebKit/Source/platform/heap/BUILD.gn
@@ -59,5 +59,6 @@
     "//base",
     "//third_party/WebKit/Source/platform/heap/asm",
     "//third_party/icu",
+    "//v8",
   ]
 }
diff --git a/third_party/WebKit/Source/platform/heap/Heap.cpp b/third_party/WebKit/Source/platform/heap/Heap.cpp
index eed2697..d998535 100644
--- a/third_party/WebKit/Source/platform/heap/Heap.cpp
+++ b/third_party/WebKit/Source/platform/heap/Heap.cpp
@@ -657,6 +657,8 @@
     s_markedObjectSize = 0;
     s_wrapperCountAtLastGC = s_wrapperCount;
     s_collectedWrapperCount = 0;
+    for (ThreadState* state : ThreadState::attachedThreads())
+        state->resetHeapCounters();
 }
 
 CallbackStack* Heap::s_markingStack;
diff --git a/third_party/WebKit/Source/platform/heap/HeapPage.cpp b/third_party/WebKit/Source/platform/heap/HeapPage.cpp
index 3804479..771c7f6 100644
--- a/third_party/WebKit/Source/platform/heap/HeapPage.cpp
+++ b/third_party/WebKit/Source/platform/heap/HeapPage.cpp
@@ -544,7 +544,7 @@
         if (startOfGap != page->payloadEnd())
             addToFreeList(startOfGap, page->payloadEnd() - startOfGap);
     }
-    Heap::decreaseAllocatedObjectSize(freedSize);
+    threadState()->decreaseAllocatedObjectSize(freedSize);
     ASSERT(m_promptlyFreedSize == freedSize);
     m_promptlyFreedSize = 0;
     return true;
@@ -662,16 +662,16 @@
     //  - if previous alloc checkpoint is larger, allocation size has increased.
     //  - if smaller, a net reduction in size since last call to updateRemainingAllocationSize().
     if (m_lastRemainingAllocationSize > m_remainingAllocationSize)
-        Heap::increaseAllocatedObjectSize(m_lastRemainingAllocationSize - m_remainingAllocationSize);
+        threadState()->increaseAllocatedObjectSize(m_lastRemainingAllocationSize - m_remainingAllocationSize);
     else if (m_lastRemainingAllocationSize != m_remainingAllocationSize)
-        Heap::decreaseAllocatedObjectSize(m_remainingAllocationSize - m_lastRemainingAllocationSize);
+        threadState()->decreaseAllocatedObjectSize(m_remainingAllocationSize - m_lastRemainingAllocationSize);
     m_lastRemainingAllocationSize = m_remainingAllocationSize;
 }
 
 void NormalPageHeap::updateRemainingAllocationSize()
 {
     if (m_lastRemainingAllocationSize > remainingAllocationSize()) {
-        Heap::increaseAllocatedObjectSize(m_lastRemainingAllocationSize - remainingAllocationSize());
+        threadState()->increaseAllocatedObjectSize(m_lastRemainingAllocationSize - remainingAllocationSize());
         m_lastRemainingAllocationSize = remainingAllocationSize();
     }
     ASSERT(m_lastRemainingAllocationSize == remainingAllocationSize());
@@ -838,7 +838,7 @@
     largeObject->link(&m_firstPage);
 
     Heap::increaseAllocatedSpace(largeObject->size());
-    Heap::increaseAllocatedObjectSize(largeObject->size());
+    threadState()->increaseAllocatedObjectSize(largeObject->size());
     return result;
 }
 
@@ -1117,6 +1117,7 @@
 {
     size_t markedObjectSize = 0;
     Address startOfGap = payload();
+    NormalPageHeap* pageHeap = heapForNormalPage();
     for (Address headerAddress = startOfGap; headerAddress < payloadEnd(); ) {
         HeapObjectHeader* header = reinterpret_cast<HeapObjectHeader*>(headerAddress);
         size_t size = header->size();
@@ -1124,7 +1125,7 @@
         ASSERT(size < blinkPagePayloadSize());
 
         if (header->isPromptlyFreed())
-            heapForNormalPage()->decreasePromptlyFreedSize(size);
+            pageHeap->decreasePromptlyFreedSize(size);
         if (header->isFree()) {
             // Zero the memory in the free list header to maintain the
             // invariant that memory on the free list is zero filled.
@@ -1155,7 +1156,7 @@
             continue;
         }
         if (startOfGap != headerAddress) {
-            heapForNormalPage()->addToFreeList(startOfGap, headerAddress - startOfGap);
+            pageHeap->addToFreeList(startOfGap, headerAddress - startOfGap);
 #if !ENABLE(ASSERT) && !defined(LEAK_SANITIZER) && !defined(ADDRESS_SANITIZER)
             // Discarding pages increases page faults and may regress performance.
             // So we enable this only on low-RAM devices.
@@ -1169,7 +1170,7 @@
         startOfGap = headerAddress;
     }
     if (startOfGap != payloadEnd()) {
-        heapForNormalPage()->addToFreeList(startOfGap, payloadEnd() - startOfGap);
+        pageHeap->addToFreeList(startOfGap, payloadEnd() - startOfGap);
 #if !ENABLE(ASSERT) && !defined(LEAK_SANITIZER) && !defined(ADDRESS_SANITIZER)
         if (Heap::isLowEndDevice())
             discardPages(startOfGap + sizeof(FreeListEntry), payloadEnd());
@@ -1177,7 +1178,7 @@
     }
 
     if (markedObjectSize)
-        Heap::increaseMarkedObjectSize(markedObjectSize);
+        pageHeap->threadState()->increaseMarkedObjectSize(markedObjectSize);
 }
 
 void NormalPage::makeConsistentForGC()
@@ -1202,7 +1203,7 @@
         headerAddress += header->size();
     }
     if (markedObjectSize)
-        Heap::increaseMarkedObjectSize(markedObjectSize);
+        heapForNormalPage()->threadState()->increaseMarkedObjectSize(markedObjectSize);
 }
 
 void NormalPage::makeConsistentForMutator()
@@ -1466,7 +1467,7 @@
 void LargeObjectPage::sweep()
 {
     heapObjectHeader()->unmark();
-    Heap::increaseMarkedObjectSize(size());
+    heap()->threadState()->increaseMarkedObjectSize(size());
 }
 
 void LargeObjectPage::makeConsistentForGC()
@@ -1474,7 +1475,7 @@
     HeapObjectHeader* header = heapObjectHeader();
     if (header->isMarked()) {
         header->unmark();
-        Heap::increaseMarkedObjectSize(size());
+        heap()->threadState()->increaseMarkedObjectSize(size());
     } else {
         header->markDead();
     }
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.cpp b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
index 3d4af7e..360938d 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadState.cpp
+++ b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
@@ -64,6 +64,8 @@
 #include <pthread_np.h>
 #endif
 
+#include <v8.h>
+
 namespace blink {
 
 WTF::ThreadSpecific<ThreadState*>* ThreadState::s_threadSpecific = nullptr;
@@ -99,6 +101,7 @@
     , m_gcMixinMarker(nullptr)
     , m_shouldFlushHeapDoesNotContainCache(false)
     , m_gcState(NoGCScheduled)
+    , m_isolate(nullptr)
     , m_traceDOMWrappers(nullptr)
 #if defined(ADDRESS_SANITIZER)
     , m_asanFakeStack(__asan_get_current_fake_stack())
@@ -106,6 +109,9 @@
 #if defined(LEAK_SANITIZER)
     , m_disabledStaticPersistentsRegistration(0)
 #endif
+    , m_allocatedObjectSize(0)
+    , m_markedObjectSize(0)
+    , m_reportedMemoryToV8(0)
 {
     ASSERT(checkThread());
     ASSERT(!**s_threadSpecific);
@@ -691,6 +697,8 @@
         return;
     ASSERT(!sweepForbidden());
 
+    reportMemoryToV8();
+
     if (shouldForceMemoryPressureGC()) {
         completeSweep();
         if (shouldForceMemoryPressureGC()) {
@@ -1250,6 +1258,41 @@
     preSweep();
 }
 
+void ThreadState::reportMemoryToV8()
+{
+    if (!m_isolate)
+        return;
+
+    size_t currentHeapSize = m_allocatedObjectSize + m_markedObjectSize;
+    int64_t diff = static_cast<int64_t>(currentHeapSize) - static_cast<int64_t>(m_reportedMemoryToV8);
+    m_isolate->AdjustAmountOfExternalAllocatedMemory(diff);
+    m_reportedMemoryToV8 = currentHeapSize;
+}
+
+void ThreadState::resetHeapCounters()
+{
+    m_allocatedObjectSize = 0;
+    m_markedObjectSize = 0;
+}
+
+void ThreadState::increaseAllocatedObjectSize(size_t delta)
+{
+    m_allocatedObjectSize += delta;
+    Heap::increaseAllocatedObjectSize(delta);
+}
+
+void ThreadState::decreaseAllocatedObjectSize(size_t delta)
+{
+    m_allocatedObjectSize -= delta;
+    Heap::decreaseAllocatedObjectSize(delta);
+}
+
+void ThreadState::increaseMarkedObjectSize(size_t delta)
+{
+    m_markedObjectSize += delta;
+    Heap::increaseMarkedObjectSize(delta);
+}
+
 void ThreadState::copyStackUntilSafePointScope()
 {
     if (!m_safePointScopeMarker || m_stackState == BlinkGC::NoHeapPointersOnStack)
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.h b/third_party/WebKit/Source/platform/heap/ThreadState.h
index d4ad238..885b66d87 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadState.h
+++ b/third_party/WebKit/Source/platform/heap/ThreadState.h
@@ -520,6 +520,11 @@
     void leaveStaticReferenceRegistrationDisabledScope();
 #endif
 
+    void resetHeapCounters();
+    void increaseAllocatedObjectSize(size_t);
+    void decreaseAllocatedObjectSize(size_t);
+    void increaseMarkedObjectSize(size_t);
+
 private:
     enum SnapshotType {
         HeapSnapshot,
@@ -598,6 +603,8 @@
     void clearHeapAges();
     int heapIndexOfVectorHeapLeastRecentlyExpanded(int beginHeapIndex, int endHeapIndex);
 
+    void reportMemoryToV8();
+
     // Should only be called under protection of threadAttachMutex().
     const Vector<OwnPtr<BlinkGCInterruptor>>& interruptors() const { return m_interruptors; }
 
@@ -678,6 +685,11 @@
     static const int likelyToBePromptlyFreedArraySize = (1 << 8);
     static const int likelyToBePromptlyFreedArrayMask = likelyToBePromptlyFreedArraySize - 1;
     OwnPtr<int[]> m_likelyToBePromptlyFreed;
+
+    // Stats for heap memory of this thread.
+    size_t m_allocatedObjectSize;
+    size_t m_markedObjectSize;
+    size_t m_reportedMemoryToV8;
 };
 
 template<ThreadAffinity affinity> class ThreadStateFor;
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp b/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp
index a5fadca..bb9b623 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp
@@ -34,6 +34,7 @@
 #include "platform/animation/CompositorAnimation.h"
 #include "platform/graphics/CompositorFactory.h"
 #include "platform/graphics/GraphicsLayer.h"
+#include "platform/scroll/MainThreadScrollingReason.h"
 #include "platform/scroll/ScrollableArea.h"
 #include "public/platform/Platform.h"
 #include "public/platform/WebCompositorSupport.h"
@@ -42,6 +43,15 @@
 
 namespace blink {
 
+namespace {
+
+WebLayer* toWebLayer(GraphicsLayer* layer)
+{
+    return layer ? layer->platformLayer() : nullptr;
+}
+
+} // namespace
+
 PassOwnPtrWillBeRawPtr<ScrollAnimatorBase> ScrollAnimatorBase::create(ScrollableArea* scrollableArea)
 {
     if (scrollableArea && scrollableArea->scrollAnimatorEnabled())
@@ -190,10 +200,21 @@
     notifyPositionChanged();
 }
 
+void ScrollAnimator::postAnimationCleanupAndReset()
+{
+    // Remove the temporary main thread scrolling reason that was added while
+    // main thread had scheduled an animation.
+    removeMainThreadScrollingReason();
+
+    resetAnimationState();
+}
+
 void ScrollAnimator::updateCompositorAnimations()
 {
-    if (m_runState == RunState::PostAnimationCleanup)
-        return resetAnimationState();
+    if (m_runState == RunState::PostAnimationCleanup) {
+        postAnimationCleanupAndReset();
+        return;
+    }
 
     if (m_compositorAnimationId && m_runState != RunState::RunningOnCompositor
         && m_runState != RunState::RunningOnCompositorButNeedsUpdate) {
@@ -209,7 +230,8 @@
         m_compositorAnimationId = 0;
         m_compositorAnimationGroupId = 0;
         if (m_runState == RunState::WaitingToCancelOnCompositor) {
-            return resetAnimationState();
+            postAnimationCleanupAndReset();
+            return;
         }
     }
 
@@ -263,10 +285,34 @@
             }
         }
 
+        bool runningOnMainThread = false;
         if (!sentToCompositor) {
-            if (registerAndScheduleAnimation())
+            runningOnMainThread = registerAndScheduleAnimation();
+            if (runningOnMainThread)
                 m_runState = RunState::RunningOnMainThread;
         }
+
+        // Main thread should deal with the scroll animations it started.
+        if (sentToCompositor || runningOnMainThread)
+            addMainThreadScrollingReason();
+        else
+            removeMainThreadScrollingReason();
+    }
+}
+
+void ScrollAnimator::addMainThreadScrollingReason()
+{
+    if (WebLayer* scrollLayer = toWebLayer(scrollableArea()->layerForScrolling())) {
+        scrollLayer->addMainThreadScrollingReasons(
+            MainThreadScrollingReason::kAnimatingScrollOnMainThread);
+    }
+}
+
+void ScrollAnimator::removeMainThreadScrollingReason()
+{
+    if (WebLayer* scrollLayer = toWebLayer(scrollableArea()->layerForScrolling())) {
+        scrollLayer->clearMainThreadScrollingReasons(
+            MainThreadScrollingReason::kAnimatingScrollOnMainThread);
     }
 }
 
@@ -290,7 +336,8 @@
 void ScrollAnimator::layerForCompositedScrollingDidChange(
     CompositorAnimationTimeline* timeline)
 {
-    reattachCompositorPlayerIfNeeded(timeline);
+    if (reattachCompositorPlayerIfNeeded(timeline) && m_animationCurve)
+        addMainThreadScrollingReason();
 }
 
 bool ScrollAnimator::registerAndScheduleAnimation()
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimator.h b/third_party/WebKit/Source/platform/scroll/ScrollAnimator.h
index 5f021c4..18469bd 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollAnimator.h
+++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimator.h
@@ -48,7 +48,7 @@
     explicit ScrollAnimator(ScrollableArea*, WTF::TimeFunction = WTF::monotonicallyIncreasingTime);
     ~ScrollAnimator() override;
 
-    bool hasRunningAnimation() const;
+    bool hasRunningAnimation() const override;
     float computeDeltaToConsume(ScrollbarOrientation, float pixelDelta) const override;
 
     ScrollResultOneDimensional userScroll(ScrollbarOrientation, ScrollGranularity, float step, float delta) override;
@@ -77,6 +77,11 @@
     // immediately to the target and returns false.
     bool registerAndScheduleAnimation();
 
+    void postAnimationCleanupAndReset();
+
+    void addMainThreadScrollingReason();
+    void removeMainThreadScrollingReason();
+
     FloatPoint m_targetOffset;
     ScrollGranularity m_lastGranularity;
 };
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.cpp b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.cpp
index 917fc23..d35fe84 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.cpp
@@ -21,6 +21,9 @@
     , m_compositorAnimationId(0)
     , m_compositorAnimationGroupId(0)
 {
+#if ENABLE(OILPAN)
+    ThreadState::current()->registerPreFinalizer(this);
+#endif
     if (RuntimeEnabledFeatures::compositorAnimationTimelinesEnabled()) {
         ASSERT(Platform::current()->compositorSupport());
         m_compositorPlayer = adoptPtr(CompositorFactory::current().createAnimationPlayer());
@@ -31,6 +34,13 @@
 
 ScrollAnimatorCompositorCoordinator::~ScrollAnimatorCompositorCoordinator()
 {
+#if !ENABLE(OILPAN)
+    ScrollAnimatorCompositorCoordinator::dispose();
+#endif
+}
+
+void ScrollAnimatorCompositorCoordinator::dispose()
+{
     if (m_compositorPlayer) {
         m_compositorPlayer->setAnimationDelegate(nullptr);
         m_compositorPlayer.clear();
@@ -153,9 +163,10 @@
     }
 }
 
-void ScrollAnimatorCompositorCoordinator::reattachCompositorPlayerIfNeeded(
+bool ScrollAnimatorCompositorCoordinator::reattachCompositorPlayerIfNeeded(
     CompositorAnimationTimeline* timeline)
 {
+    bool reattached = false;
     int compositorAnimationAttachedToLayerId = 0;
     if (scrollableArea()->layerForScrolling())
         compositorAnimationAttachedToLayerId = scrollableArea()->layerForScrolling()->platformLayer()->id();
@@ -174,10 +185,13 @@
                 timeline->playerAttached(*this);
                 m_compositorPlayer->attachLayer(
                     scrollableArea()->layerForScrolling()->platformLayer());
+                reattached = true;
             }
             m_compositorAnimationAttachedToLayerId = compositorAnimationAttachedToLayerId;
         }
     }
+
+    return reattached;
 }
 
 void ScrollAnimatorCompositorCoordinator::notifyAnimationStarted(
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.h b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.h
index c81fcb9..55018f48 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.h
+++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.h
@@ -24,10 +24,14 @@
 class PLATFORM_EXPORT ScrollAnimatorCompositorCoordinator : public NoBaseWillBeGarbageCollectedFinalized<ScrollAnimatorCompositorCoordinator>, private CompositorAnimationPlayerClient, WebCompositorAnimationDelegate {
     USING_FAST_MALLOC_WILL_BE_REMOVED(ScrollAnimatorCompositorCoordinator);
     WTF_MAKE_NONCOPYABLE(ScrollAnimatorCompositorCoordinator);
+    WILL_BE_USING_PRE_FINALIZER(ScrollAnimatorCompositorCoordinator, dispose);
 public:
     virtual ~ScrollAnimatorCompositorCoordinator();
 
     bool hasAnimationThatRequiresService() const;
+    void dispose();
+
+    virtual bool hasRunningAnimation() const { return false; }
 
     virtual void resetAnimationState();
     virtual void cancelAnimation();
@@ -49,7 +53,8 @@
     void abortAnimation();
 
     void compositorAnimationFinished(int groupId);
-    void reattachCompositorPlayerIfNeeded(CompositorAnimationTimeline*);
+    // Returns true if the compositor player was attached to a new layer.
+    bool reattachCompositorPlayerIfNeeded(CompositorAnimationTimeline*);
 
     // WebCompositorAnimationDelegate implementation.
     void notifyAnimationStarted(double monotonicTime, int group) override;
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp b/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp
index f91bc0f..e915c36 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp
+++ b/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp
@@ -37,6 +37,7 @@
 #include "platform/geometry/FloatPoint.h"
 #include "platform/geometry/LayoutRect.h"
 #include "platform/graphics/GraphicsLayer.h"
+#include "platform/scroll/MainThreadScrollingReason.h"
 #include "platform/scroll/ProgrammaticScrollAnimator.h"
 #include "platform/scroll/ScrollbarTheme.h"
 #include "wtf/PassOwnPtr.h"
@@ -95,6 +96,8 @@
 void ScrollableArea::clearScrollAnimators()
 {
 #if OS(MACOSX) && ENABLE(OILPAN)
+    // TODO(ymalik): Let oilpan decide when to call dispose rather than
+    // explicitly calling it here to cleanup.
     if (m_scrollAnimator)
         m_scrollAnimator->dispose();
 #endif
@@ -528,7 +531,14 @@
 bool ScrollableArea::shouldScrollOnMainThread() const
 {
     if (GraphicsLayer* layer = layerForScrolling()) {
-        return layer->platformLayer()->shouldScrollOnMainThread();
+        uint32_t reasons = layer->platformLayer()->mainThreadScrollingReasons();
+        // Should scroll on main thread unless the reason is the one that is set
+        // by the ScrollAnimator, in which case, the animation can still be
+        // scheduled on the compositor.
+        // TODO(ymalik): We have a non-transient "main thread scrolling reason"
+        // that doesn't actually cause shouldScrollOnMainThread() to be true.
+        // This is confusing and should be cleaned up.
+        return !!(reasons & ~MainThreadScrollingReason::kAnimatingScrollOnMainThread);
     }
     return true;
 }
diff --git a/third_party/WebKit/Source/platform/testing/TestPaintArtifact.cpp b/third_party/WebKit/Source/platform/testing/TestPaintArtifact.cpp
index 7de22860b..ea199b5 100644
--- a/third_party/WebKit/Source/platform/testing/TestPaintArtifact.cpp
+++ b/third_party/WebKit/Source/platform/testing/TestPaintArtifact.cpp
@@ -84,7 +84,7 @@
 
     if (!m_paintChunks.isEmpty())
         m_paintChunks.last().endIndex = m_displayItemList.size();
-    m_paintArtifact = PaintArtifact(std::move(m_displayItemList), std::move(m_paintChunks), LayoutSize());
+    m_paintArtifact = PaintArtifact(std::move(m_displayItemList), std::move(m_paintChunks));
     m_built = true;
     return m_paintArtifact;
 }
diff --git a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp
index 810f287..53124475 100644
--- a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp
+++ b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp
@@ -130,6 +130,18 @@
         return new TestingPlatformMockWebTaskRunner(m_tasks);
     }
 
+    double virtualTimeSeconds() const override
+    {
+        ASSERT_NOT_REACHED();
+        return 0.0;
+    }
+
+    double monotonicallyIncreasingVirtualTimeSeconds() const override
+    {
+        ASSERT_NOT_REACHED();
+        return 0.0;
+    }
+
 private:
     Deque<OwnPtr<WebTaskRunner::Task>>* m_tasks; // NOT OWNED
 };
diff --git a/third_party/WebKit/Source/platform/text/BidiResolver.h b/third_party/WebKit/Source/platform/text/BidiResolver.h
index ee0dc077..bf81eab 100644
--- a/third_party/WebKit/Source/platform/text/BidiResolver.h
+++ b/third_party/WebKit/Source/platform/text/BidiResolver.h
@@ -66,8 +66,8 @@
     // Adding a pair of midpoints before a character will split it out into a new line box.
     void ensureCharacterGetsLineBox(Iterator& textParagraphSeparator)
     {
-        startIgnoringSpaces(Iterator(0, textParagraphSeparator.object(), textParagraphSeparator.offset() - 1));
-        stopIgnoringSpaces(Iterator(0, textParagraphSeparator.object(), textParagraphSeparator.offset()));
+        startIgnoringSpaces(Iterator(0, textParagraphSeparator.lineLayoutItem(), textParagraphSeparator.offset() - 1));
+        stopIgnoringSpaces(Iterator(0, textParagraphSeparator.lineLayoutItem(), textParagraphSeparator.offset()));
     }
 
     void checkMidpoints(Iterator& lBreak)
@@ -75,7 +75,7 @@
         // Check to see if our last midpoint is a start point beyond the line break. If so,
         // shave it off the list, and shave off a trailing space if the previous end point doesn't
         // preserve whitespace.
-        if (lBreak.object() && m_numMidpoints && !(m_numMidpoints % 2)) {
+        if (lBreak.lineLayoutItem() && m_numMidpoints && !(m_numMidpoints % 2)) {
             Iterator* midpointsIterator = m_midpoints.data();
             Iterator& endpoint = midpointsIterator[m_numMidpoints - 2];
             const Iterator& startpoint = midpointsIterator[m_numMidpoints - 1];
@@ -85,7 +85,7 @@
             if (currpoint == lBreak) {
                 // We hit the line break before the start point. Shave off the start point.
                 m_numMidpoints--;
-                if (endpoint.object().style()->collapseWhiteSpace() && endpoint.object().isText())
+                if (endpoint.lineLayoutItem().style()->collapseWhiteSpace() && endpoint.lineLayoutItem().isText())
                     endpoint.setOffset(endpoint.offset() - 1);
             }
         }
diff --git a/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.cpp b/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.cpp
index 81e51aa5..61fffb7 100644
--- a/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.cpp
+++ b/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.cpp
@@ -353,15 +353,6 @@
     return true;
 }
 
-bool SecurityOrigin::isPotentiallyTrustworthy(String& errorMessage) const
-{
-    if (isPotentiallyTrustworthy())
-        return true;
-
-    errorMessage = "Only secure origins are allowed (see: https://goo.gl/Y0ZkNV).";
-    return false;
-}
-
 bool SecurityOrigin::isPotentiallyTrustworthy() const
 {
     ASSERT(m_protocol != "data");
@@ -374,6 +365,12 @@
     return false;
 }
 
+// static
+String SecurityOrigin::isPotentiallyTrustworthyErrorMessage()
+{
+    return "Only secure origins are allowed (see: https://goo.gl/Y0ZkNV).";
+}
+
 void SecurityOrigin::grantLoadLocalResources()
 {
     // Granting privileges to some, but not all, documents in a SecurityOrigin
diff --git a/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h b/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h
index bf542df..4cdc68a 100644
--- a/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h
+++ b/third_party/WebKit/Source/platform/weborigin/SecurityOrigin.h
@@ -139,9 +139,11 @@
     // machine or over the network from a
     // cryptographically-authenticated origin, as described in
     // https://w3c.github.io/webappsec/specs/powerfulfeatures/#is-origin-trustworthy.
-    bool isPotentiallyTrustworthy(String& errorMessage) const;
     bool isPotentiallyTrustworthy() const;
 
+    // Returns a human-readable error message describing that a non-secure origin's access to a feature is denied.
+    static String isPotentiallyTrustworthyErrorMessage();
+
     // Returns true if this SecurityOrigin can load local resources, such
     // as images, iframes, and style sheets, and can link to local URLs.
     // For example, call this function before creating an iframe to a
diff --git a/third_party/WebKit/Source/platform/weborigin/SecurityOriginTest.cpp b/third_party/WebKit/Source/platform/weborigin/SecurityOriginTest.cpp
index 3c46272..c04fd58 100644
--- a/third_party/WebKit/Source/platform/weborigin/SecurityOriginTest.cpp
+++ b/third_party/WebKit/Source/platform/weborigin/SecurityOriginTest.cpp
@@ -157,15 +157,12 @@
         SCOPED_TRACE(i);
         RefPtr<SecurityOrigin> origin = SecurityOrigin::createFromString(inputs[i].url);
         String errorMessage;
-        EXPECT_EQ(inputs[i].accessGranted, origin->isPotentiallyTrustworthy(errorMessage));
-        EXPECT_EQ(inputs[i].accessGranted, errorMessage.isEmpty());
+        EXPECT_EQ(inputs[i].accessGranted, origin->isPotentiallyTrustworthy());
     }
 
     // Unique origins are not considered secure.
     RefPtr<SecurityOrigin> uniqueOrigin = SecurityOrigin::createUnique();
-    String errorMessage;
-    EXPECT_FALSE(uniqueOrigin->isPotentiallyTrustworthy(errorMessage));
-    EXPECT_EQ("Only secure origins are allowed (see: https://goo.gl/Y0ZkNV).", errorMessage);
+    EXPECT_FALSE(uniqueOrigin->isPotentiallyTrustworthy());
 }
 
 TEST_F(SecurityOriginTest, IsSecure)
diff --git a/third_party/WebKit/Source/platform/weborigin/SecurityPolicyTest.cpp b/third_party/WebKit/Source/platform/weborigin/SecurityPolicyTest.cpp
index e6ed820..ae54ed6a 100644
--- a/third_party/WebKit/Source/platform/weborigin/SecurityPolicyTest.cpp
+++ b/third_party/WebKit/Source/platform/weborigin/SecurityPolicyTest.cpp
@@ -170,11 +170,10 @@
     };
 
     for (const char* url : insecureURLs) {
-        String errorMessage;
         RefPtr<SecurityOrigin> origin = SecurityOrigin::createFromString(url);
-        EXPECT_FALSE(origin->isPotentiallyTrustworthy(errorMessage));
+        EXPECT_FALSE(origin->isPotentiallyTrustworthy());
         SecurityPolicy::addOriginTrustworthyWhiteList(origin);
-        EXPECT_TRUE(origin->isPotentiallyTrustworthy(errorMessage));
+        EXPECT_TRUE(origin->isPotentiallyTrustworthy());
     }
 
     // Tests that adding URLs that have inner-urls to the whitelist
@@ -199,17 +198,15 @@
         },
     };
     for (const TestCase& test : insecureURLsWithInnerOrigin) {
-        String errorMessage;
-
         // Actually origins of both URLs should be same.
         RefPtr<SecurityOrigin> origin1 = SecurityOrigin::createFromString(test.url);
         RefPtr<SecurityOrigin> origin2 = SecurityOrigin::createFromString(test.anotherUrlInOrigin);
 
-        EXPECT_FALSE(origin1->isPotentiallyTrustworthy(errorMessage));
-        EXPECT_FALSE(origin2->isPotentiallyTrustworthy(errorMessage));
+        EXPECT_FALSE(origin1->isPotentiallyTrustworthy());
+        EXPECT_FALSE(origin2->isPotentiallyTrustworthy());
         SecurityPolicy::addOriginTrustworthyWhiteList(origin1);
-        EXPECT_TRUE(origin1->isPotentiallyTrustworthy(errorMessage));
-        EXPECT_TRUE(origin2->isPotentiallyTrustworthy(errorMessage));
+        EXPECT_TRUE(origin1->isPotentiallyTrustworthy());
+        EXPECT_TRUE(origin2->isPotentiallyTrustworthy());
     }
 }
 
diff --git a/third_party/WebKit/Source/platform/win/HWndDC.h b/third_party/WebKit/Source/platform/win/HWndDC.h
deleted file mode 100644
index 29da03c..0000000
--- a/third_party/WebKit/Source/platform/win/HWndDC.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef HWndDC_h
-#define HWndDC_h
-
-#include <windows.h>
-#include "wtf/NonCopyable.h"
-
-namespace blink {
-
-class HWndDC {
-    WTF_MAKE_NONCOPYABLE(HWndDC);
-public:
-    HWndDC()
-        : m_hwnd(0)
-        , m_hdc(0)
-    {
-    }
-
-    explicit HWndDC(HWND hwnd)
-        : m_hwnd(hwnd)
-        , m_hdc(::GetDC(hwnd))
-    {
-    }
-
-    HWndDC(HWND hwnd, HRGN hrgnClip, DWORD flags)
-        : m_hwnd(hwnd)
-        , m_hdc(::GetDCEx(hwnd, hrgnClip, flags))
-    {
-    }
-
-    ~HWndDC()
-    {
-        clear();
-    }
-
-    HDC setHWnd(HWND hwnd)
-    {
-        clear();
-        m_hwnd = hwnd;
-        m_hdc = ::GetDC(hwnd);
-        return m_hdc;
-    }
-
-    void clear()
-    {
-        if (!m_hdc)
-            return;
-        ::ReleaseDC(m_hwnd, m_hdc);
-        m_hwnd = 0;
-        m_hdc = 0;
-    }
-
-    operator HDC()
-    {
-        return m_hdc;
-    }
-
-private:
-    HWND m_hwnd;
-    HDC m_hdc;
-};
-
-} // namespace blink
-
-#endif // HWndDC_h
diff --git a/third_party/WebKit/Source/web/AssertMatchingEnums.cpp b/third_party/WebKit/Source/web/AssertMatchingEnums.cpp
index 48641832..30f80ef 100644
--- a/third_party/WebKit/Source/web/AssertMatchingEnums.cpp
+++ b/third_party/WebKit/Source/web/AssertMatchingEnums.cpp
@@ -547,7 +547,7 @@
 STATIC_ASSERT_ENUM(WebIDBKeyPathTypeString, IDBKeyPath::StringType);
 STATIC_ASSERT_ENUM(WebIDBKeyPathTypeArray, IDBKeyPath::ArrayType);
 
-STATIC_ASSERT_ENUM(WebIDBMetadata::NoIntVersion, IDBDatabaseMetadata::NoIntVersion);
+STATIC_ASSERT_ENUM(WebIDBMetadata::NoVersion, IDBDatabaseMetadata::NoVersion);
 
 STATIC_ASSERT_ENUM(WebFileSystem::TypeTemporary, FileSystemTypeTemporary);
 STATIC_ASSERT_ENUM(WebFileSystem::TypePersistent, FileSystemTypePersistent);
diff --git a/third_party/WebKit/Source/web/BUILD.gn b/third_party/WebKit/Source/web/BUILD.gn
index aec18f44..0f4092bc 100644
--- a/third_party/WebKit/Source/web/BUILD.gn
+++ b/third_party/WebKit/Source/web/BUILD.gn
@@ -159,6 +159,7 @@
   if (is_android) {
     deps += [
       "//base:base_java",
+      "//content/public/android:content_java",
       "//content/shell/android:content_shell_assets",
       "//net/android:net_java",
     ]
diff --git a/third_party/WebKit/Source/web/DevToolsEmulator.cpp b/third_party/WebKit/Source/web/DevToolsEmulator.cpp
index 6d05aa87..098d985 100644
--- a/third_party/WebKit/Source/web/DevToolsEmulator.cpp
+++ b/third_party/WebKit/Source/web/DevToolsEmulator.cpp
@@ -8,6 +8,7 @@
 #include "core/frame/FrameView.h"
 #include "core/frame/Settings.h"
 #include "core/page/Page.h"
+#include "core/style/ComputedStyle.h"
 #include "platform/RuntimeEnabledFeatures.h"
 #include "public/platform/WebLayerTreeView.h"
 #include "web/WebInputEventConversion.h"
@@ -52,6 +53,7 @@
     , m_emulateMobileEnabled(false)
     , m_isOverlayScrollbarsEnabled(false)
     , m_isOrientationEventEnabled(false)
+    , m_isMobileLayoutThemeEnabled(false)
     , m_originalDefaultMinimumPageScaleFactor(0)
     , m_originalDefaultMaximumPageScaleFactor(0)
     , m_embedderTextAutosizingEnabled(webViewImpl->page()->settings().textAutosizingEnabled())
@@ -258,6 +260,9 @@
     RuntimeEnabledFeatures::setOverlayScrollbarsEnabled(true);
     m_isOrientationEventEnabled = RuntimeEnabledFeatures::orientationEventEnabled();
     RuntimeEnabledFeatures::setOrientationEventEnabled(true);
+    m_isMobileLayoutThemeEnabled = RuntimeEnabledFeatures::mobileLayoutThemeEnabled();
+    RuntimeEnabledFeatures::setMobileLayoutThemeEnabled(true);
+    ComputedStyle::invalidateInitialStyle();
     m_webViewImpl->page()->settings().setUseMobileViewportStyle(true);
     m_webViewImpl->enableViewport();
     m_webViewImpl->settings()->setViewportMetaEnabled(true);
@@ -288,6 +293,8 @@
         return;
     RuntimeEnabledFeatures::setOverlayScrollbarsEnabled(m_isOverlayScrollbarsEnabled);
     RuntimeEnabledFeatures::setOrientationEventEnabled(m_isOrientationEventEnabled);
+    RuntimeEnabledFeatures::setMobileLayoutThemeEnabled(m_isMobileLayoutThemeEnabled);
+    ComputedStyle::invalidateInitialStyle();
     m_webViewImpl->disableViewport();
     m_webViewImpl->settings()->setViewportMetaEnabled(false);
     m_webViewImpl->page()->frameHost().visualViewport().initializeScrollbars();
diff --git a/third_party/WebKit/Source/web/DevToolsEmulator.h b/third_party/WebKit/Source/web/DevToolsEmulator.h
index 74fe391..b4038fa5 100644
--- a/third_party/WebKit/Source/web/DevToolsEmulator.h
+++ b/third_party/WebKit/Source/web/DevToolsEmulator.h
@@ -63,6 +63,7 @@
 
     bool m_isOverlayScrollbarsEnabled;
     bool m_isOrientationEventEnabled;
+    bool m_isMobileLayoutThemeEnabled;
     float m_originalDefaultMinimumPageScaleFactor;
     float m_originalDefaultMaximumPageScaleFactor;
     bool m_embedderTextAutosizingEnabled;
diff --git a/third_party/WebKit/Source/web/ExternalPopupMenu.cpp b/third_party/WebKit/Source/web/ExternalPopupMenu.cpp
index 906dbdf..2b89766 100644
--- a/third_party/WebKit/Source/web/ExternalPopupMenu.cpp
+++ b/third_party/WebKit/Source/web/ExternalPopupMenu.cpp
@@ -159,7 +159,7 @@
 {
     if (!m_webExternalPopupMenu || !m_ownerElement)
         return;
-    m_ownerElement->document().updateLayoutTreeIfNeeded();
+    m_ownerElement->document().updateLayoutTree();
     // disconnectClient() might have been called.
     if (!m_ownerElement)
         return;
diff --git a/third_party/WebKit/Source/web/PopupMenuImpl.cpp b/third_party/WebKit/Source/web/PopupMenuImpl.cpp
index 74ca47c..93373ab 100644
--- a/third_party/WebKit/Source/web/PopupMenuImpl.cpp
+++ b/third_party/WebKit/Source/web/PopupMenuImpl.cpp
@@ -495,7 +495,7 @@
 {
     if (!m_popup || !m_ownerElement)
         return;
-    ownerElement().document().updateLayoutTreeIfNeeded();
+    ownerElement().document().updateLayoutTree();
     // disconnectClient() might have been called.
     if (!m_ownerElement)
         return;
diff --git a/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp b/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp
index a673ecf..c2383a70b 100644
--- a/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp
+++ b/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp
@@ -230,8 +230,8 @@
 
 void ServiceWorkerGlobalScopeProxy::didInitializeWorkerContext()
 {
-    ScriptState::Scope scope(workerGlobalScope()->script()->scriptState());
-    client().didInitializeWorkerContext(workerGlobalScope()->script()->context(), WebURL(m_documentURL));
+    ScriptState::Scope scope(workerGlobalScope()->scriptController()->scriptState());
+    client().didInitializeWorkerContext(workerGlobalScope()->scriptController()->context(), WebURL(m_documentURL));
 }
 
 void ServiceWorkerGlobalScopeProxy::workerGlobalScopeStarted(WorkerGlobalScope* workerGlobalScope)
@@ -250,7 +250,7 @@
 void ServiceWorkerGlobalScopeProxy::willDestroyWorkerGlobalScope()
 {
     v8::HandleScope handleScope(workerGlobalScope()->thread()->isolate());
-    client().willDestroyWorkerContext(workerGlobalScope()->script()->context());
+    client().willDestroyWorkerContext(workerGlobalScope()->scriptController()->context());
     m_workerGlobalScope = nullptr;
 }
 
diff --git a/third_party/WebKit/Source/web/StorageQuotaClientImpl.cpp b/third_party/WebKit/Source/web/StorageQuotaClientImpl.cpp
index bfc0124..bc3ea503 100644
--- a/third_party/WebKit/Source/web/StorageQuotaClientImpl.cpp
+++ b/third_party/WebKit/Source/web/StorageQuotaClientImpl.cpp
@@ -68,7 +68,7 @@
         webFrame->client()->requestStorageQuota(storageType, newQuotaInBytes, callbacks);
     } else {
         // Requesting quota in Worker is not supported.
-        executionContext->postTask(BLINK_FROM_HERE, StorageErrorCallback::CallbackTask::create(errorCallback, NotSupportedError));
+        executionContext->postTask(BLINK_FROM_HERE, StorageErrorCallback::createSameThreadTask(errorCallback, NotSupportedError));
     }
 }
 
diff --git a/third_party/WebKit/Source/web/TextFinder.cpp b/third_party/WebKit/Source/web/TextFinder.cpp
index bdaf155..2b239c6 100644
--- a/third_party/WebKit/Source/web/TextFinder.cpp
+++ b/third_party/WebKit/Source/web/TextFinder.cpp
@@ -112,7 +112,7 @@
     const bool m_reset;
 };
 
-bool TextFinder::find(int identifier, const WebString& searchText, const WebFindOptions& options, bool wrapWithinFrame, WebRect* selectionRect)
+bool TextFinder::find(int identifier, const WebString& searchText, const WebFindOptions& options, bool wrapWithinFrame, WebRect* selectionRect, bool* activeNow)
 {
     if (!ownerFrame().frame() || !ownerFrame().frame()->page())
         return false;
@@ -163,17 +163,22 @@
         ownerFrame().viewImpl()->zoomToFindInPageRect(ownerFrame().frameView()->contentsToRootFrame(enclosingIntRect(LayoutObject::absoluteBoundingBoxRectForRange(m_activeMatch.get()))));
     }
 
-    setMarkerActive(m_activeMatch.get(), true);
     WebLocalFrameImpl* oldActiveFrame = mainFrameImpl->ensureTextFinder().m_currentActiveMatchFrame;
     mainFrameImpl->ensureTextFinder().m_currentActiveMatchFrame = &ownerFrame();
 
     // Make sure no node is focused. See http://crbug.com/38700.
     ownerFrame().frame()->document()->clearFocusedElement();
 
-    if (!options.findNext || activeSelection) {
-        // This is either a Find operation or a Find-next from a new start point
-        // due to a selection, so we set the flag to ask the scoping effort
-        // to find the active rect for us and report it back to the UI.
+    bool isActive = setMarkerActive(m_activeMatch.get(), true);
+    if (activeNow)
+        *activeNow = isActive;
+
+    if (!options.findNext || activeSelection || !isActive) {
+        // This is either a Find operation, a Find-next from a new start point
+        // due to a selection, or new matches were found during Find-next due
+        // to DOM alteration (that couldn't be set as active), so we set the
+        // flag to ask the scoping effort to find the active rect for us and
+        // report it back to the UI.
         m_locatingActiveRect = true;
     } else {
         if (oldActiveFrame != &ownerFrame()) {
@@ -680,11 +685,11 @@
     ownerFrame().frame()->document()->markers().addTextMatchMarker(range, activeMatch);
 }
 
-void TextFinder::setMarkerActive(Range* range, bool active)
+bool TextFinder::setMarkerActive(Range* range, bool active)
 {
     if (!range || range->collapsed())
-        return;
-    ownerFrame().frame()->document()->markers().setMarkersActive(range, active);
+        return false;
+    return ownerFrame().frame()->document()->markers().setMarkersActive(range, active);
 }
 
 void TextFinder::unmarkAllTextMatches()
diff --git a/third_party/WebKit/Source/web/TextFinder.h b/third_party/WebKit/Source/web/TextFinder.h
index cddbb97..58458c8 100644
--- a/third_party/WebKit/Source/web/TextFinder.h
+++ b/third_party/WebKit/Source/web/TextFinder.h
@@ -56,7 +56,7 @@
 
     bool find(
         int identifier, const WebString& searchText, const WebFindOptions&,
-        bool wrapWithinFrame, WebRect* selectionRect);
+        bool wrapWithinFrame, WebRect* selectionRect, bool* activeNow = nullptr);
     void stopFindingAndClearSelection();
     void scopeStringMatches(
         int identifier, const WebString& searchText, const WebFindOptions&,
@@ -148,8 +148,9 @@
     // Add a WebKit TextMatch-highlight marker to nodes in a range.
     void addMarker(Range*, bool activeMatch);
 
-    // Sets the markers within a range as active or inactive.
-    void setMarkerActive(Range*, bool active);
+    // Sets the markers within a range as active or inactive. Returns true if at least
+    // one such marker found.
+    bool setMarkerActive(Range*, bool active);
 
     // Removes all markers.
     void unmarkAllTextMatches();
diff --git a/third_party/WebKit/Source/web/WebAXObject.cpp b/third_party/WebKit/Source/web/WebAXObject.cpp
index 9d8e9c6..19c5b66 100644
--- a/third_party/WebKit/Source/web/WebAXObject.cpp
+++ b/third_party/WebKit/Source/web/WebAXObject.cpp
@@ -1108,7 +1108,7 @@
 
     Document* document = m_private->document();
     if (document)
-        document->updateLayoutTreeIfNeeded();
+        document->updateLayoutTree();
 
     Node* node = m_private->node();
     if (!node)
@@ -1124,7 +1124,7 @@
 
     Document* document = m_private->document();
     if (document)
-        document->updateLayoutTreeIfNeeded();
+        document->updateLayoutTree();
 
     Node* node = m_private->node();
     if (!node)
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
index 1fd3dd06..5f6fe7f 100644
--- a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
+++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
@@ -927,32 +927,11 @@
     load(request, WebFrameLoadType::BackForward, item, loadType, false);
 }
 
-void WebLocalFrameImpl::loadData(const WebData& data, const WebString& mimeType, const WebString& textEncoding, const WebURL& baseURL, const WebURL& unreachableURL, bool replace)
-{
-    ASSERT(frame());
-
-    // If we are loading substitute data to replace an existing load, then
-    // inherit all of the properties of that original request. This way,
-    // reload will re-attempt the original request. It is essential that
-    // we only do this when there is an unreachableURL since a non-empty
-    // unreachableURL informs FrameLoader::reload to load unreachableURL
-    // instead of the currently loaded URL.
-    ResourceRequest request;
-    if (replace && !unreachableURL.isEmpty() && frame()->loader().provisionalDocumentLoader())
-        request = frame()->loader().provisionalDocumentLoader()->originalRequest();
-    request.setURL(baseURL);
-    request.setCheckForBrowserSideNavigation(false);
-
-    FrameLoadRequest frameRequest(0, request, SubstituteData(data, mimeType, textEncoding, unreachableURL));
-    ASSERT(frameRequest.substituteData().isValid());
-    frameRequest.setReplacesCurrentItem(replace);
-    frame()->loader().load(frameRequest);
-}
-
 void WebLocalFrameImpl::loadHTMLString(const WebData& data, const WebURL& baseURL, const WebURL& unreachableURL, bool replace)
 {
     ASSERT(frame());
-    loadData(data, WebString::fromUTF8("text/html"), WebString::fromUTF8("UTF-8"), baseURL, unreachableURL, replace);
+    loadData(data, WebString::fromUTF8("text/html"), WebString::fromUTF8("UTF-8"), baseURL, unreachableURL, replace,
+        WebFrameLoadType::Standard, WebHistoryItem(), WebHistoryDifferentDocumentLoad, false);
 }
 
 void WebLocalFrameImpl::stopLoading()
@@ -1979,6 +1958,37 @@
         static_cast<HistoryLoadType>(webHistoryLoadType));
 }
 
+void WebLocalFrameImpl::loadData(const WebData& data, const WebString& mimeType,
+    const WebString& textEncoding, const WebURL& baseURL, const WebURL& unreachableURL, bool replace,
+    WebFrameLoadType webFrameLoadType, const WebHistoryItem& item,
+    WebHistoryLoadType webHistoryLoadType, bool isClientRedirect)
+{
+    ASSERT(frame());
+
+    // If we are loading substitute data to replace an existing load, then
+    // inherit all of the properties of that original request. This way,
+    // reload will re-attempt the original request. It is essential that
+    // we only do this when there is an unreachableURL since a non-empty
+    // unreachableURL informs FrameLoader::reload to load unreachableURL
+    // instead of the currently loaded URL.
+    ResourceRequest request;
+    if (replace && !unreachableURL.isEmpty() && frame()->loader().provisionalDocumentLoader())
+        request = frame()->loader().provisionalDocumentLoader()->originalRequest();
+    request.setURL(baseURL);
+    request.setCheckForBrowserSideNavigation(false);
+
+    FrameLoadRequest frameRequest(0, request, SubstituteData(data, mimeType, textEncoding, unreachableURL));
+    ASSERT(frameRequest.substituteData().isValid());
+    frameRequest.setReplacesCurrentItem(replace);
+    if (isClientRedirect)
+        frameRequest.setClientRedirect(ClientRedirect);
+
+    RefPtrWillBeRawPtr<HistoryItem> historyItem = PassRefPtrWillBeRawPtr<HistoryItem>(item);
+    frame()->loader().load(
+        frameRequest, static_cast<FrameLoadType>(webFrameLoadType), historyItem.get(),
+        static_cast<HistoryLoadType>(webHistoryLoadType));
+}
+
 bool WebLocalFrameImpl::isLoading() const
 {
     if (!frame() || !frame()->document())
@@ -2043,9 +2053,9 @@
     UseCounter::count(frame(), UseCounter::ExternalIsSearchProviderInstalled);
 }
 
-bool WebLocalFrameImpl::find(int identifier, const WebString& searchText, const WebFindOptions& options, bool wrapWithinFrame, WebRect* selectionRect)
+bool WebLocalFrameImpl::find(int identifier, const WebString& searchText, const WebFindOptions& options, bool wrapWithinFrame, WebRect* selectionRect, bool* activeNow)
 {
-    return ensureTextFinder().find(identifier, searchText, options, wrapWithinFrame, selectionRect);
+    return ensureTextFinder().find(identifier, searchText, options, wrapWithinFrame, selectionRect, activeNow);
 }
 
 void WebLocalFrameImpl::stopFinding(bool clearSelection)
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.h b/third_party/WebKit/Source/web/WebLocalFrameImpl.h
index a286e03..2e7a368 100644
--- a/third_party/WebKit/Source/web/WebLocalFrameImpl.h
+++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.h
@@ -131,9 +131,6 @@
     void reloadLoFiImages() override;
     void loadRequest(const WebURLRequest&) override;
     void loadHistoryItem(const WebHistoryItem&, WebHistoryLoadType, WebURLRequest::CachePolicy) override;
-    void loadData(
-        const WebData&, const WebString& mimeType, const WebString& textEncoding,
-        const WebURL& baseURL, const WebURL& unreachableURL, bool replace) override;
     void loadHTMLString(
         const WebData& html, const WebURL& baseURL, const WebURL& unreachableURL,
         bool replace) override;
@@ -225,6 +222,10 @@
     WebURLRequest requestForReload(WebFrameLoadType, const WebURL&) const override;
     void load(const WebURLRequest&, WebFrameLoadType, const WebHistoryItem&,
         WebHistoryLoadType, bool isClientRedirect) override;
+    void loadData(
+        const WebData&, const WebString& mimeType, const WebString& textEncoding,
+        const WebURL& baseURL, const WebURL& unreachableURL, bool replace, WebFrameLoadType,
+        const WebHistoryItem&, WebHistoryLoadType, bool isClientRedirect) override;
     bool isLoading() const override;
     bool isResourceLoadInProgress() const override;
     bool isNavigationScheduled() const override;
@@ -239,7 +240,7 @@
     void replaceSelection(const WebString&) override;
     bool find(
         int identifier, const WebString& searchText, const WebFindOptions&,
-        bool wrapWithinFrame, WebRect* selectionRect) override;
+        bool wrapWithinFrame, WebRect* selectionRect, bool* activeNow = nullptr) override;
     void stopFinding(bool clearSelection) override;
     void scopeStringMatches(
         int identifier, const WebString& searchText, const WebFindOptions&,
diff --git a/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp b/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp
index 4d67baee..b39e219d 100644
--- a/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp
+++ b/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp
@@ -306,13 +306,6 @@
     ASSERT_NOT_REACHED();
 }
 
-void WebRemoteFrameImpl::loadData(
-    const WebData&, const WebString& mimeType, const WebString& textEncoding,
-    const WebURL& baseURL, const WebURL& unreachableURL, bool replace)
-{
-    ASSERT_NOT_REACHED();
-}
-
 void WebRemoteFrameImpl::loadHTMLString(
     const WebData& html, const WebURL& baseURL, const WebURL& unreachableURL,
     bool replace)
diff --git a/third_party/WebKit/Source/web/WebRemoteFrameImpl.h b/third_party/WebKit/Source/web/WebRemoteFrameImpl.h
index 4bcd318..6b7930a 100644
--- a/third_party/WebKit/Source/web/WebRemoteFrameImpl.h
+++ b/third_party/WebKit/Source/web/WebRemoteFrameImpl.h
@@ -75,9 +75,6 @@
     void reloadWithOverrideURL(const WebURL& overrideUrl, bool ignoreCache) override;
     void loadRequest(const WebURLRequest&) override;
     void loadHistoryItem(const WebHistoryItem&, WebHistoryLoadType, WebURLRequest::CachePolicy) override;
-    void loadData(
-        const WebData&, const WebString& mimeType, const WebString& textEncoding,
-        const WebURL& baseURL, const WebURL& unreachableURL, bool replace) override;
     void loadHTMLString(
         const WebData& html, const WebURL& baseURL, const WebURL& unreachableURL,
         bool replace) override;
diff --git a/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp b/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp
index 8c8dc85a..f300283 100644
--- a/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp
+++ b/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp
@@ -225,11 +225,6 @@
     RuntimeEnabledFeatures::setTouchEnabled(enable);
 }
 
-void WebRuntimeFeatures::enableWebAudio(bool enable)
-{
-    RuntimeEnabledFeatures::setWebAudioEnabled(enable);
-}
-
 void WebRuntimeFeatures::enableWebGLDraftExtensions(bool enable)
 {
     RuntimeEnabledFeatures::setWebGLDraftExtensionsEnabled(enable);
@@ -330,6 +325,11 @@
     RuntimeEnabledFeatures::setScrollAnchoringEnabled(enable);
 }
 
+void WebRuntimeFeatures::enableRenderingPipelineThrottling(bool enable)
+{
+    RuntimeEnabledFeatures::setRenderingPipelineThrottlingEnabled(enable);
+}
+
 bool WebRuntimeFeatures::isServiceWorkerExtendableMessageEventEnabled()
 {
     return RuntimeEnabledFeatures::serviceWorkerExtendableMessageEventEnabled();
diff --git a/third_party/WebKit/Source/web/WebSettingsImpl.cpp b/third_party/WebKit/Source/web/WebSettingsImpl.cpp
index 2a36fbc..a096948 100644
--- a/third_party/WebKit/Source/web/WebSettingsImpl.cpp
+++ b/third_party/WebKit/Source/web/WebSettingsImpl.cpp
@@ -482,11 +482,6 @@
     m_settings->setOfflineWebApplicationCacheEnabled(enabled);
 }
 
-void WebSettingsImpl::setWebAudioEnabled(bool enabled)
-{
-    m_settings->setWebAudioEnabled(enabled);
-}
-
 void WebSettingsImpl::setExperimentalWebGLEnabled(bool enabled)
 {
     m_settings->setWebGLEnabled(enabled);
diff --git a/third_party/WebKit/Source/web/WebSettingsImpl.h b/third_party/WebKit/Source/web/WebSettingsImpl.h
index 3748748..a178079 100644
--- a/third_party/WebKit/Source/web/WebSettingsImpl.h
+++ b/third_party/WebKit/Source/web/WebSettingsImpl.h
@@ -187,7 +187,6 @@
     void setViewportMetaMergeContentQuirk(bool) override;
     void setViewportMetaNonUserScalableQuirk(bool) override;
     void setViewportMetaZeroValuesQuirk(bool) override;
-    void setWebAudioEnabled(bool) override;
     void setWebGLErrorsToConsoleEnabled(bool) override;
     void setWebSecurityEnabled(bool) override;
     void setWideViewportQuirkEnabled(bool) override;
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp
index a1c1a2c..6bdb139 100644
--- a/third_party/WebKit/Source/web/WebViewImpl.cpp
+++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -1793,7 +1793,7 @@
     // controls hide so that the ICB will always be the same size as the
     // viewport with the top controls shown.
     IntSize ICBSize = m_size;
-    if (!topControls().shrinkViewport())
+    if (RuntimeEnabledFeatures::inertTopControlsEnabled() && !topControls().shrinkViewport())
         ICBSize.expand(0, -topControls().height());
 
     pageScaleConstraintsSet().didChangeInitialContainingBlockSize(ICBSize);
@@ -1946,7 +1946,7 @@
         }
     }
 
-    if (!m_page)
+    if (!mainFrameImpl())
         return;
 
     DocumentLifecycle::AllowThrottlingScope throttlingScope(mainFrameImpl()->frame()->document()->lifecycle());
@@ -4462,6 +4462,11 @@
     return true;
 }
 
+WebViewScheduler* WebViewImpl::scheduler() const
+{
+    return m_scheduler.get();
+}
+
 void WebViewImpl::setVisibilityState(WebPageVisibilityState visibilityState,
                                      bool isInitialState) {
     ASSERT(visibilityState == WebPageVisibilityStateVisible || visibilityState == WebPageVisibilityStateHidden || visibilityState == WebPageVisibilityStatePrerender);
diff --git a/third_party/WebKit/Source/web/WebViewImpl.h b/third_party/WebKit/Source/web/WebViewImpl.h
index 7d95760..9858b0af 100644
--- a/third_party/WebKit/Source/web/WebViewImpl.h
+++ b/third_party/WebKit/Source/web/WebViewImpl.h
@@ -446,6 +446,7 @@
     void detachCompositorAnimationTimeline(CompositorAnimationTimeline*);
     CompositorAnimationTimeline* linkHighlightsTimeline() const { return m_linkHighlightsTimeline.get(); }
 
+    WebViewScheduler* scheduler() const override;
     void setVisibilityState(WebPageVisibilityState, bool) override;
 
     bool hasOpenedPopup() const { return m_pagePopup; }
@@ -525,8 +526,6 @@
 
     FloatSize elasticOverscroll() const { return m_elasticOverscroll; }
 
-    WebViewScheduler* scheduler() const { return m_scheduler.get(); }
-
     // Attaches the PaintArtifactCompositor's tree to this WebView's layer tree
     // view.
     void attachPaintArtifactCompositor();
diff --git a/third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp b/third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp
index 6bc0b87..48feb2a 100644
--- a/third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp
+++ b/third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp
@@ -279,6 +279,42 @@
     EXPECT_TRUE(displayItems2.contains(SimCanvas::Rect, "green"));
 }
 
+TEST_F(FrameThrottlingTest, UnthrottlingTriggersRepaintInCompositedChild)
+{
+    // Create a hidden frame with a composited child layer.
+    SimRequest mainResource("https://example.com/", "text/html");
+    SimRequest frameResource("https://example.com/iframe.html", "text/html");
+
+    loadURL("https://example.com/");
+    mainResource.complete("<iframe id=frame sandbox src=iframe.html></iframe>");
+    frameResource.complete(
+        "<style>"
+        "div { "
+        "  width: 100px;"
+        "  height: 100px;"
+        "  background-color: green;"
+        "  transform: translateZ(0);"
+        "}"
+        "</style><div></div>");
+
+    // Move the frame offscreen to throttle it.
+    auto* frameElement = toHTMLIFrameElement(document().getElementById("frame"));
+    frameElement->setAttribute(styleAttr, "transform: translateY(480px)");
+    EXPECT_FALSE(frameElement->contentDocument()->view()->canThrottleRendering());
+    compositeFrame();
+    EXPECT_TRUE(frameElement->contentDocument()->view()->canThrottleRendering());
+
+    // Scroll down to unthrottle the frame. The first frame we composite after
+    // scrolling won't contain the frame yet, but will schedule another repaint.
+    webView().mainFrameImpl()->frameView()->setScrollPosition(DoublePoint(0, 480), ProgrammaticScroll);
+    auto displayItems = compositeFrame();
+    EXPECT_FALSE(displayItems.contains(SimCanvas::Rect, "green"));
+
+    // Now the composited child contents should be visible again.
+    auto displayItems2 = compositeFrame();
+    EXPECT_TRUE(displayItems2.contains(SimCanvas::Rect, "green"));
+}
+
 TEST_F(FrameThrottlingTest, ChangeStyleInThrottledFrame)
 {
     // Create a hidden frame which is throttled.
diff --git a/third_party/WebKit/Source/web/tests/TextFinderTest.cpp b/third_party/WebKit/Source/web/tests/TextFinderTest.cpp
index e3e716d..653ce70 100644
--- a/third_party/WebKit/Source/web/tests/TextFinderTest.cpp
+++ b/third_party/WebKit/Source/web/tests/TextFinderTest.cpp
@@ -394,6 +394,58 @@
     EXPECT_EQ(findInPageRect(textNode, 4, textNode, 6), matchRects[2]);
 }
 
+TEST_F(TextFinderTest, FindTextJavaScriptUpdatesDOM)
+{
+    document().body()->setInnerHTML("<b>XXXXFindMeYYYY</b><i></i>", ASSERT_NO_EXCEPTION);
+
+    int identifier = 0;
+    WebString searchText(String("FindMe"));
+    WebFindOptions findOptions; // Default.
+    bool wrapWithinFrame = true;
+    WebRect* selectionRect = nullptr;
+    bool activeNow;
+
+    textFinder().resetMatchCount();
+    textFinder().scopeStringMatches(identifier, searchText, findOptions, true);
+    while (textFinder().scopingInProgress())
+        runPendingTasks();
+
+    findOptions.findNext = true;
+    ASSERT_TRUE(textFinder().find(identifier, searchText, findOptions, wrapWithinFrame, selectionRect, &activeNow));
+    EXPECT_TRUE(activeNow);
+    ASSERT_TRUE(textFinder().find(identifier, searchText, findOptions, wrapWithinFrame, selectionRect, &activeNow));
+    EXPECT_TRUE(activeNow);
+
+    // Add new text to DOM and try FindNext.
+    Element* iElement = toElement(document().body()->lastChild());
+    ASSERT_TRUE(iElement);
+    iElement->setInnerHTML("ZZFindMe", ASSERT_NO_EXCEPTION);
+
+    ASSERT_TRUE(textFinder().find(identifier, searchText, findOptions, wrapWithinFrame, selectionRect, &activeNow));
+    Range* activeMatch = textFinder().activeMatch();
+    ASSERT_TRUE(activeMatch);
+    EXPECT_FALSE(activeNow);
+    EXPECT_EQ(2, activeMatch->startOffset());
+    EXPECT_EQ(8, activeMatch->endOffset());
+
+    // Restart full search and check that added text is found.
+    findOptions.findNext = false;
+    textFinder().resetMatchCount();
+    textFinder().cancelPendingScopingEffort();
+    textFinder().scopeStringMatches(identifier, searchText, findOptions, true);
+    while (textFinder().scopingInProgress())
+        runPendingTasks();
+    EXPECT_EQ(2, textFinder().totalMatchCount());
+
+    WebVector<WebFloatRect> matchRects;
+    textFinder().findMatchRects(matchRects);
+    ASSERT_EQ(2u, matchRects.size());
+    Node* textInBElement = document().body()->firstChild()->firstChild();
+    Node* textInIElement = document().body()->lastChild()->firstChild();
+    EXPECT_EQ(findInPageRect(textInBElement, 4, textInBElement, 10), matchRects[0]);
+    EXPECT_EQ(findInPageRect(textInIElement, 2, textInIElement, 8), matchRects[1]);
+}
+
 class TextFinderFakeTimerTest : public TextFinderTest {
 protected:
     void SetUp() override
diff --git a/third_party/WebKit/Source/web/tests/TopControlsTest.cpp b/third_party/WebKit/Source/web/tests/TopControlsTest.cpp
index 5ed7c95..c7b5ff4 100644
--- a/third_party/WebKit/Source/web/tests/TopControlsTest.cpp
+++ b/third_party/WebKit/Source/web/tests/TopControlsTest.cpp
@@ -72,6 +72,8 @@
 
     WebViewImpl* initialize(const std::string& pageName = "large-div.html")
     {
+        RuntimeEnabledFeatures::setInertTopControlsEnabled(true);
+
         // Load a page with large body and set viewport size to 400x400 to ensure
         // main frame is scrollable.
         m_helper.initializeAndLoad(m_baseURL + pageName, true, 0, 0, &configureSettings);
diff --git a/third_party/WebKit/Source/web/tests/VirtualTimeTest.cpp b/third_party/WebKit/Source/web/tests/VirtualTimeTest.cpp
new file mode 100644
index 0000000..be024f2
--- /dev/null
+++ b/third_party/WebKit/Source/web/tests/VirtualTimeTest.cpp
@@ -0,0 +1,108 @@
+// Copyright 2016 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 "platform/testing/UnitTestHelpers.h"
+#include "public/platform/Platform.h"
+#include "public/platform/WebViewScheduler.h"
+#include "public/web/WebLocalFrame.h"
+#include "public/web/WebScriptExecutionCallback.h"
+#include "public/web/WebScriptSource.h"
+#include "public/web/WebView.h"
+#include "web/tests/sim/SimTest.h"
+
+namespace blink {
+
+namespace {
+class ScriptExecutionCallbackHelper : public WebScriptExecutionCallback {
+public:
+    const String result() const { return m_result; }
+
+private:
+    void completed(const WebVector<v8::Local<v8::Value>>& values) override
+    {
+        if (!values.isEmpty() && !values[0].IsEmpty() && values[0]->IsString()) {
+            m_result = toCoreString(v8::Local<v8::String>::Cast(values[0]));
+        }
+    }
+
+    String m_result;
+};
+} // namespace
+
+class VirtualTimeTest : public SimTest {
+protected:
+    String ExecuteJavaScript(String scriptSource)
+    {
+        ScriptExecutionCallbackHelper callbackHelper;
+        webView().mainFrame()->toWebLocalFrame()->requestExecuteScriptAndReturnValue(
+            WebScriptSource(WebString(scriptSource)), false, &callbackHelper);
+        testing::runPendingTasks();
+        return callbackHelper.result();
+    }
+};
+
+TEST_F(VirtualTimeTest, DOMTimersFireInExpectedOrder)
+{
+    webView().scheduler()->enableVirtualTime();
+
+    ExecuteJavaScript(
+        "var run_order = [];"
+        "function timerFn(delay, value) {"
+        "  setTimeout(function() { run_order.push(value); }, delay);"
+        "};"
+        "var one_hour = 60 * 60 * 1000;"
+        "timerFn(one_hour * 100, 'a');"
+        "timerFn(one_hour * 10, 'b');"
+        "timerFn(one_hour, 'c');");
+
+    // Normally the JS runs pretty much instantly but the timer callbacks will
+    // take 100h to fire, but thanks to timer fast forwarding we can make them
+    // fire immediatly.
+
+    EXPECT_EQ("c, b, a", ExecuteJavaScript("run_order.join(', ')"));
+}
+
+TEST_F(VirtualTimeTest, SetInterval)
+{
+    webView().scheduler()->enableVirtualTime();
+
+    ExecuteJavaScript(
+        "var run_order = [];"
+        "var count = 10;"
+        "var interval_handle = setInterval(function() {"
+        "  if (--window.count == 0) {"
+        "     clearInterval(interval_handle);"
+        "  }"
+        "  run_order.push(count);"
+        "}, 1000);"
+        "setTimeout(function() { run_order.push('timer'); }, 1500);");
+
+    // If virtual time is not supplied to TimerBase then the setInterval
+    // won't fire 10x.
+    EXPECT_EQ("9, timer, 8, 7, 6, 5, 4, 3, 2, 1, 0", ExecuteJavaScript("run_order.join(', ')"));
+}
+
+TEST_F(VirtualTimeTest, AllowVirtualTimeToAdvance)
+{
+    webView().scheduler()->enableVirtualTime();
+    webView().scheduler()->setAllowVirtualTimeToAdvance(false);
+
+    ExecuteJavaScript(
+        "var run_order = [];"
+        "timerFn = function(delay, value) {"
+        "  setTimeout(function() { run_order.push(value); }, delay);"
+        "};"
+        "timerFn(100, 'a');"
+        "timerFn(10, 'b');"
+        "timerFn(1, 'c');");
+
+    EXPECT_EQ("", ExecuteJavaScript("run_order.join(', ')"));
+
+    webView().scheduler()->setAllowVirtualTimeToAdvance(true);
+    testing::runPendingTasks();
+
+    EXPECT_EQ("c, b, a", ExecuteJavaScript("run_order.join(', ')"));
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/web/tests/WebDocumentTest.cpp b/third_party/WebKit/Source/web/tests/WebDocumentTest.cpp
index 1453aea..a451a14 100644
--- a/third_party/WebKit/Source/web/tests/WebDocumentTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebDocumentTest.cpp
@@ -84,7 +84,7 @@
     ASSERT_EQ(Color(0, 0, 0), styleBeforeInsertion.visitedDependentColor(CSSPropertyColor));
 
     // Apply inserted stylesheet.
-    coreDoc->updateLayoutTreeIfNeeded();
+    coreDoc->updateLayoutTree();
 
     const ComputedStyle& styleAfterInsertion = bodyElement->computedStyleRef();
 
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
index 7457545..480a913 100644
--- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -4112,6 +4112,53 @@
     EXPECT_EQ(originalTickmarks, originalTickmarksAfterReset);
 }
 
+TEST_P(ParameterizedWebFrameTest, FindInPageJavaScriptUpdatesDOM)
+{
+    registerMockedHttpURLLoad("find.html");
+
+    FindUpdateWebFrameClient client;
+    FrameTestHelpers::WebViewHelper webViewHelper(this);
+    webViewHelper.initializeAndLoad(m_baseURL + "find.html", true, &client);
+    webViewHelper.resize(WebSize(640, 480));
+    runPendingTasks();
+
+    WebLocalFrame* frame = webViewHelper.webView()->mainFrame()->toWebLocalFrame();
+    const int findIdentifier = 12345;
+    static const char* kFindString = "foo";
+    WebString searchText = WebString::fromUTF8(kFindString);
+    WebFindOptions options;
+    bool activeNow;
+
+    frame->resetMatchCount();
+    frame->scopeStringMatches(findIdentifier, searchText, options, true);
+    runPendingTasks();
+    EXPECT_TRUE(client.findResultsAreReady());
+
+    // Find in a <div> element.
+    options.findNext = true;
+    EXPECT_TRUE(frame->find(findIdentifier, searchText, options, false, 0, &activeNow));
+    EXPECT_TRUE(activeNow);
+
+    // Insert new text, which contains occurence of |searchText|.
+    frame->executeScript(WebScriptSource(
+        "var newTextNode = document.createTextNode('bar5 foo5');"
+        "var textArea = document.getElementsByTagName('textarea')[0];"
+        "document.body.insertBefore(newTextNode, textArea);"));
+
+    // Find in a <input> element.
+    EXPECT_TRUE(frame->find(findIdentifier, searchText, options, false, 0, &activeNow));
+    EXPECT_TRUE(activeNow);
+
+    // Find in the inserted text node.
+    EXPECT_TRUE(frame->find(findIdentifier, searchText, options, false, 0, &activeNow));
+    frame->stopFinding(false);
+    WebRange range = frame->selectionRange();
+    EXPECT_EQ(5, range.startOffset());
+    EXPECT_EQ(8, range.endOffset());
+    EXPECT_TRUE(frame->document().focusedElement().isNull());
+    EXPECT_FALSE(activeNow);
+}
+
 static WebPoint topLeft(const WebRect& rect)
 {
     return WebPoint(rect.x, rect.y);
@@ -4691,7 +4738,12 @@
 TEST_F(CompositedSelectionBoundsTest, EmptyEditableInput) { runTest("composited_selection_bounds_empty_editable_input.html"); }
 TEST_F(CompositedSelectionBoundsTest, EmptyEditableArea) { runTest("composited_selection_bounds_empty_editable_area.html"); }
 
+// Fails on Mac ASan 64 bot. https://crbug.com/588769.
+#if OS(MACOSX) && defined(ADDRESS_SANITIZER)
+TEST_P(ParameterizedWebFrameTest, DISABLED_CompositedSelectionBoundsCleared)
+#else
 TEST_P(ParameterizedWebFrameTest, CompositedSelectionBoundsCleared)
+#endif
 {
     RuntimeEnabledFeatures::setCompositedSelectionUpdateEnabled(true);
 
@@ -8030,7 +8082,7 @@
     MOCK_METHOD4(didOverscroll, void(const WebFloatSize&, const WebFloatSize&, const WebFloatPoint&, const WebFloatSize&));
 };
 
-class WebFrameOverscrollTest : public WebFrameTest {
+class WebFrameOverscrollTest : public WebFrameTest, public ::testing::WithParamInterface<blink::WebGestureDevice> {
 protected:
     WebGestureEvent generateEvent(WebInputEvent::Type type, float deltaX = 0.0, float deltaY = 0.0)
     {
@@ -8038,7 +8090,7 @@
         event.type = type;
         // TODO(wjmaclean): Make sure that touchpad device is only ever used for
         // gesture scrolling event types.
-        event.sourceDevice = WebGestureDeviceTouchpad;
+        event.sourceDevice = GetParam();
         event.x = 100;
         event.y = 100;
         if (type == WebInputEvent::GestureScrollUpdate) {
@@ -8076,12 +8128,17 @@
     }
 };
 
-TEST_F(WebFrameOverscrollTest, AccumulatedRootOverscrollAndUnsedDeltaValuesOnOverscroll)
+INSTANTIATE_TEST_CASE_P(All, WebFrameOverscrollTest, ::testing::Values(
+    WebGestureDeviceTouchpad,
+    WebGestureDeviceTouchscreen));
+
+TEST_P(WebFrameOverscrollTest, AccumulatedRootOverscrollAndUnsedDeltaValuesOnOverscroll)
 {
     OverscrollWebViewClient client;
     registerMockedHttpURLLoad("overscroll/overscroll.html");
     FrameTestHelpers::WebViewHelper webViewHelper;
     webViewHelper.initializeAndLoad(m_baseURL + "overscroll/overscroll.html", true, 0, &client, configureAndroid);
+    webViewHelper.resize(WebSize(200, 200));
 
     // Calculation of accumulatedRootOverscroll and unusedDelta on multiple scrollUpdate.
     ScrollBegin(&webViewHelper);
@@ -8117,12 +8174,13 @@
     Mock::VerifyAndClearExpectations(&client);
 }
 
-TEST_F(WebFrameOverscrollTest, AccumulatedOverscrollAndUnusedDeltaValuesOnDifferentAxesOverscroll)
+TEST_P(WebFrameOverscrollTest, AccumulatedOverscrollAndUnusedDeltaValuesOnDifferentAxesOverscroll)
 {
     OverscrollWebViewClient client;
     registerMockedHttpURLLoad("overscroll/div-overscroll.html");
     FrameTestHelpers::WebViewHelper webViewHelper;
     webViewHelper.initializeAndLoad(m_baseURL + "overscroll/div-overscroll.html", true, 0, &client, configureAndroid);
+    webViewHelper.resize(WebSize(200, 200));
 
     ScrollBegin(&webViewHelper);
 
@@ -8131,33 +8189,41 @@
     ScrollUpdate(&webViewHelper, 0, -316);
     Mock::VerifyAndClearExpectations(&client);
 
+    ScrollEnd(&webViewHelper);
+    ScrollBegin(&webViewHelper);
+
     // Now On Scrolling DIV, scroll is bubbled and root layer is over-scrolled.
     EXPECT_CALL(client, didOverscroll(WebFloatSize(0, 100), WebFloatSize(0, 100), WebFloatPoint(100, 100), WebFloatSize()));
     ScrollUpdate(&webViewHelper, 0, -100);
+    ScrollUpdate(&webViewHelper, 0, -100);
     Mock::VerifyAndClearExpectations(&client);
 
+    // TODO(bokan): This has never worked but by the accident that this test was being
+    // run in a WebView without a size. This test should be fixed along with the bug.
+    // crbug.com/589320.
     // Page scrolls vertically, but over-scrolls horizontally.
-    EXPECT_CALL(client, didOverscroll(WebFloatSize(-100, 0), WebFloatSize(-100, 0), WebFloatPoint(100, 100), WebFloatSize()));
-    ScrollUpdate(&webViewHelper, 100, 50);
-    Mock::VerifyAndClearExpectations(&client);
+    // EXPECT_CALL(client, didOverscroll(WebFloatSize(-100, 0), WebFloatSize(-100, 0), WebFloatPoint(100, 100), WebFloatSize()));
+    // ScrollUpdate(&webViewHelper, 100, 50);
+    // Mock::VerifyAndClearExpectations(&client);
 
     // Scrolling up, Overscroll is not reported.
-    EXPECT_CALL(client, didOverscroll(_, _, _, _)).Times(0);
-    ScrollUpdate(&webViewHelper, 0, -50);
-    Mock::VerifyAndClearExpectations(&client);
+    // EXPECT_CALL(client, didOverscroll(_, _, _, _)).Times(0);
+    // ScrollUpdate(&webViewHelper, 0, -50);
+    // Mock::VerifyAndClearExpectations(&client);
 
     // Page scrolls horizontally, but over-scrolls vertically.
-    EXPECT_CALL(client, didOverscroll(WebFloatSize(0, 100), WebFloatSize(0, 100), WebFloatPoint(100, 100), WebFloatSize()));
-    ScrollUpdate(&webViewHelper, -100, -100);
-    Mock::VerifyAndClearExpectations(&client);
+    // EXPECT_CALL(client, didOverscroll(WebFloatSize(0, 100), WebFloatSize(0, 100), WebFloatPoint(100, 100), WebFloatSize()));
+    // ScrollUpdate(&webViewHelper, -100, -100);
+    // Mock::VerifyAndClearExpectations(&client);
 }
 
-TEST_F(WebFrameOverscrollTest, RootLayerOverscrolledOnInnerDivOverScroll)
+TEST_P(WebFrameOverscrollTest, RootLayerOverscrolledOnInnerDivOverScroll)
 {
     OverscrollWebViewClient client;
     registerMockedHttpURLLoad("overscroll/div-overscroll.html");
     FrameTestHelpers::WebViewHelper webViewHelper;
     webViewHelper.initializeAndLoad(m_baseURL + "overscroll/div-overscroll.html", true, 0, &client, configureAndroid);
+    webViewHelper.resize(WebSize(200, 200));
 
     ScrollBegin(&webViewHelper);
 
@@ -8166,38 +8232,55 @@
     ScrollUpdate(&webViewHelper, 0, -316);
     Mock::VerifyAndClearExpectations(&client);
 
+    ScrollEnd(&webViewHelper);
+    ScrollBegin(&webViewHelper);
+
     // Now On Scrolling DIV, scroll is bubbled and root layer is over-scrolled.
     EXPECT_CALL(client, didOverscroll(WebFloatSize(0, 50), WebFloatSize(0, 50), WebFloatPoint(100, 100), WebFloatSize()));
-    ScrollUpdate(&webViewHelper, 0, -50);
+    ScrollUpdate(&webViewHelper, 0, -150);
     Mock::VerifyAndClearExpectations(&client);
 }
 
-TEST_F(WebFrameOverscrollTest, RootLayerOverscrolledOnInnerIFrameOverScroll)
+TEST_P(WebFrameOverscrollTest, RootLayerOverscrolledOnInnerIFrameOverScroll)
 {
     OverscrollWebViewClient client;
     registerMockedHttpURLLoad("overscroll/iframe-overscroll.html");
     registerMockedHttpURLLoad("overscroll/scrollable-iframe.html");
     FrameTestHelpers::WebViewHelper webViewHelper;
     webViewHelper.initializeAndLoad(m_baseURL + "overscroll/iframe-overscroll.html", true, 0, &client, configureAndroid);
+    webViewHelper.resize(WebSize(200, 200));
 
     ScrollBegin(&webViewHelper);
     // Scroll the IFrame to the end.
     EXPECT_CALL(client, didOverscroll(_, _, _, _)).Times(0);
+
+    // This scroll will fully scroll the iframe but will be consumed before being
+    // counted as overscroll.
     ScrollUpdate(&webViewHelper, 0, -320);
+
+    // This scroll will again target the iframe but wont bubble further up. Make sure
+    // that the unused scroll isn't handled as overscroll.
+    ScrollUpdate(&webViewHelper, 0, -50);
     Mock::VerifyAndClearExpectations(&client);
 
+    ScrollEnd(&webViewHelper);
+    ScrollBegin(&webViewHelper);
+
     // Now On Scrolling IFrame, scroll is bubbled and root layer is over-scrolled.
     EXPECT_CALL(client, didOverscroll(WebFloatSize(0, 50), WebFloatSize(0, 50), WebFloatPoint(100, 100), WebFloatSize()));
-    ScrollUpdate(&webViewHelper, 0, -50);
+    ScrollUpdate(&webViewHelper, 0, -150);
     Mock::VerifyAndClearExpectations(&client);
+
+    ScrollEnd(&webViewHelper);
 }
 
-TEST_F(WebFrameOverscrollTest, ScaledPageRootLayerOverscrolled)
+TEST_P(WebFrameOverscrollTest, ScaledPageRootLayerOverscrolled)
 {
     OverscrollWebViewClient client;
     registerMockedHttpURLLoad("overscroll/overscroll.html");
     FrameTestHelpers::WebViewHelper webViewHelper;
     WebViewImpl* webViewImpl = webViewHelper.initializeAndLoad(m_baseURL + "overscroll/overscroll.html", true, 0, &client, configureAndroid);
+    webViewHelper.resize(WebSize(200, 200));
     webViewImpl->setPageScaleFactor(3.0);
 
     // Calculation of accumulatedRootOverscroll and unusedDelta on scaled page.
@@ -8224,12 +8307,13 @@
     Mock::VerifyAndClearExpectations(&client);
 }
 
-TEST_F(WebFrameOverscrollTest, NoOverscrollForSmallvalues)
+TEST_P(WebFrameOverscrollTest, NoOverscrollForSmallvalues)
 {
     OverscrollWebViewClient client;
     registerMockedHttpURLLoad("overscroll/overscroll.html");
     FrameTestHelpers::WebViewHelper webViewHelper;
     webViewHelper.initializeAndLoad(m_baseURL + "overscroll/overscroll.html", true, 0, &client, configureAndroid);
+    webViewHelper.resize(WebSize(200, 200));
 
     ScrollBegin(&webViewHelper);
     EXPECT_CALL(client, didOverscroll(WebFloatSize(-10, -10), WebFloatSize(-10, -10), WebFloatPoint(100, 100), WebFloatSize()));
@@ -8274,12 +8358,13 @@
     Mock::VerifyAndClearExpectations(&client);
 }
 
-TEST_F(WebFrameOverscrollTest, ReportingLatestOverscrollForElasticOverscroll)
+TEST_P(WebFrameOverscrollTest, ReportingLatestOverscrollForElasticOverscroll)
 {
     OverscrollWebViewClient client;
     registerMockedHttpURLLoad("overscroll/overscroll.html");
     FrameTestHelpers::WebViewHelper webViewHelper;
     webViewHelper.initializeAndLoad(m_baseURL + "overscroll/overscroll.html", true, 0, &client, configureAndroid);
+    webViewHelper.resize(WebSize(200, 200));
 
     // On disabling ReportWheelOverscroll, overscroll is not reported on MouseWheel.
     webViewHelper.webView()->settings()->setReportWheelOverscroll(false);
diff --git a/third_party/WebKit/Source/web/tests/data/overscroll/div-overscroll.html b/third_party/WebKit/Source/web/tests/data/overscroll/div-overscroll.html
index 6481c2f..dff5a52 100644
--- a/third_party/WebKit/Source/web/tests/data/overscroll/div-overscroll.html
+++ b/third_party/WebKit/Source/web/tests/data/overscroll/div-overscroll.html
@@ -11,6 +11,9 @@
       width: 500px;
       height: 500px;
     }
+    body {
+      margin: 0px;
+    }
   </style>
 </head>
 
diff --git a/third_party/WebKit/Source/web/tests/data/overscroll/iframe-overscroll.html b/third_party/WebKit/Source/web/tests/data/overscroll/iframe-overscroll.html
index 24ad825..61d98984 100644
--- a/third_party/WebKit/Source/web/tests/data/overscroll/iframe-overscroll.html
+++ b/third_party/WebKit/Source/web/tests/data/overscroll/iframe-overscroll.html
@@ -1,4 +1,14 @@
 <!DOCTYPE html>
+<head>
+  <style>
+    body {
+      margin: 0px;
+    }
+    iframe {
+      border-width: 0px;
+    }
+  </style>
+</head>
 <body>
   <iframe width="300px" height="300px" src="scrollable-iframe.html"></iframe>
-</body>
\ No newline at end of file
+</body>
diff --git a/third_party/WebKit/Source/web/tests/data/overscroll/overscroll.html b/third_party/WebKit/Source/web/tests/data/overscroll/overscroll.html
index 279eca4..2a39ef87 100644
--- a/third_party/WebKit/Source/web/tests/data/overscroll/overscroll.html
+++ b/third_party/WebKit/Source/web/tests/data/overscroll/overscroll.html
@@ -2,14 +2,9 @@
 <html>
 <head>
 <style type="text/css">
-html {
-    padding: 0px;
-    margin: 0px
-}
 body {
-    height: 300px;
-    width:  300px;
-    padding: 0px;
+    height: 500px;
+    width:  500px;
     margin: 0px;
 }
 </style>
diff --git a/third_party/WebKit/Source/web/web.gypi b/third_party/WebKit/Source/web/web.gypi
index a3cd53e..831a696c 100644
--- a/third_party/WebKit/Source/web/web.gypi
+++ b/third_party/WebKit/Source/web/web.gypi
@@ -282,6 +282,7 @@
       'tests/TopControlsTest.cpp',
       'tests/TouchActionTest.cpp',
       'tests/ViewportTest.cpp',
+      'tests/VirtualTimeTest.cpp',
       'tests/VisualViewportTest.cpp',
       'tests/WebDocumentTest.cpp',
       'tests/WebFrameSerializerTest.cpp',
diff --git a/third_party/WebKit/Source/wtf/DEPS b/third_party/WebKit/Source/wtf/DEPS
index 3e52ed6..980a6db 100644
--- a/third_party/WebKit/Source/wtf/DEPS
+++ b/third_party/WebKit/Source/wtf/DEPS
@@ -2,6 +2,7 @@
     # To whitelist base/ stuff Blink is allowed to include, we list up all
     # directories and files instead of writing 'base/'.
     "+base/debug",
+    "+base/numerics",
     "+base/rand_util.h",
     "+base/strings",
     "+base/time/time.h",
diff --git a/third_party/WebKit/Source/wtf/PageAllocator.cpp b/third_party/WebKit/Source/wtf/PageAllocator.cpp
index 121b687..7f7a884 100644
--- a/third_party/WebKit/Source/wtf/PageAllocator.cpp
+++ b/third_party/WebKit/Source/wtf/PageAllocator.cpp
@@ -37,6 +37,7 @@
 
 #if OS(POSIX)
 
+#include <errno.h>
 #include <sys/mman.h>
 
 #ifndef MADV_FREE
@@ -49,6 +50,7 @@
 
 // On POSIX memmap uses a nearby address if the hint address is blocked.
 static const bool kHintIsAdvisory = true;
+static uint32_t allocPageErrorCode = 0;
 
 #elif OS(WIN)
 
@@ -56,6 +58,7 @@
 
 // VirtualAlloc will fail if allocation at the hint address is blocked.
 static const bool kHintIsAdvisory = false;
+static uint32_t allocPageErrorCode = ERROR_SUCCESS;
 
 #else
 #error Unknown OS
@@ -76,11 +79,16 @@
 #if OS(WIN)
     DWORD accessFlag = pageAccessibility == PageAccessible ? PAGE_READWRITE : PAGE_NOACCESS;
     ret = VirtualAlloc(hint, len, MEM_RESERVE | MEM_COMMIT, accessFlag);
+    allocPageErrorCode = !ret ? GetLastError() : ERROR_SUCCESS;
 #else
     int accessFlag = pageAccessibility == PageAccessible ? (PROT_READ | PROT_WRITE) : PROT_NONE;
     ret = mmap(hint, len, accessFlag, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
-    if (ret == MAP_FAILED)
+    if (ret == MAP_FAILED) {
+        allocPageErrorCode = errno;
         ret = 0;
+    } else {
+        allocPageErrorCode = 0;
+    }
 #endif
     return ret;
 }
@@ -261,5 +269,10 @@
 #endif
 }
 
+uint32_t getAllocPageErrorCode()
+{
+    return allocPageErrorCode;
+}
+
 } // namespace WTF
 
diff --git a/third_party/WebKit/Source/wtf/PageAllocator.h b/third_party/WebKit/Source/wtf/PageAllocator.h
index 5714f169..59bc7ea 100644
--- a/third_party/WebKit/Source/wtf/PageAllocator.h
+++ b/third_party/WebKit/Source/wtf/PageAllocator.h
@@ -136,6 +136,12 @@
     return address & kSystemPageBaseMask;
 }
 
+// Only allowed inside WTF for investigating WTF::initializeWithoutV8 crashes.
+// Guess, the function fails because of mmap (or VirtualAlloc) failure.
+// The following function returns errno (or GetLastError code) when mmap
+// (or VirtualAlloc) fails.
+uint32_t getAllocPageErrorCode();
+
 } // namespace WTF
 
 #endif // WTF_PageAllocator_h
diff --git a/third_party/WebKit/Source/wtf/Partitions.cpp b/third_party/WebKit/Source/wtf/Partitions.cpp
index b0e587d..f86bf23 100644
--- a/third_party/WebKit/Source/wtf/Partitions.cpp
+++ b/third_party/WebKit/Source/wtf/Partitions.cpp
@@ -195,6 +195,8 @@
 void Partitions::handleOutOfMemory()
 {
     volatile size_t totalUsage = totalSizeOfCommittedPages();
+    uint32_t allocPageErrorCode = getAllocPageErrorCode();
+    base::debug::Alias(&allocPageErrorCode);
 
     if (totalUsage >= 2UL * 1024 * 1024 * 1024)
         partitionsOutOfMemoryUsing2G();
diff --git a/third_party/WebKit/Source/wtf/text/AtomicString.cpp b/third_party/WebKit/Source/wtf/text/AtomicString.cpp
index 723d8bd69..cad9b6d2 100644
--- a/third_party/WebKit/Source/wtf/text/AtomicString.cpp
+++ b/third_party/WebKit/Source/wtf/text/AtomicString.cpp
@@ -487,34 +487,41 @@
     return atomicString;
 }
 
+template<typename IntegerType>
+static AtomicString integerToAtomicString(IntegerType input)
+{
+    IntegerToStringConverter<IntegerType> converter(input);
+    return AtomicString(converter.characters8(), converter.length());
+}
+
 AtomicString AtomicString::number(int number)
 {
-    return numberToStringSigned<AtomicString>(number);
+    return integerToAtomicString(number);
 }
 
 AtomicString AtomicString::number(unsigned number)
 {
-    return numberToStringUnsigned<AtomicString>(number);
+    return integerToAtomicString(number);
 }
 
 AtomicString AtomicString::number(long number)
 {
-    return numberToStringSigned<AtomicString>(number);
+    return integerToAtomicString(number);
 }
 
 AtomicString AtomicString::number(unsigned long number)
 {
-    return numberToStringUnsigned<AtomicString>(number);
+    return integerToAtomicString(number);
 }
 
 AtomicString AtomicString::number(long long number)
 {
-    return numberToStringSigned<AtomicString>(number);
+    return integerToAtomicString(number);
 }
 
 AtomicString AtomicString::number(unsigned long long number)
 {
-    return numberToStringUnsigned<AtomicString>(number);
+    return integerToAtomicString(number);
 }
 
 AtomicString AtomicString::number(double number, unsigned precision, TrailingZerosTruncatingPolicy trailingZerosTruncatingPolicy)
diff --git a/third_party/WebKit/Source/wtf/text/IntegerToStringConversion.h b/third_party/WebKit/Source/wtf/text/IntegerToStringConversion.h
index 30c917c..bd99dc63 100644
--- a/third_party/WebKit/Source/wtf/text/IntegerToStringConversion.h
+++ b/third_party/WebKit/Source/wtf/text/IntegerToStringConversion.h
@@ -22,78 +22,61 @@
 #ifndef IntegerToStringConversion_h
 #define IntegerToStringConversion_h
 
-#include "wtf/text/StringBuilder.h"
-#include "wtf/text/StringImpl.h"
+#include "base/numerics/safe_conversions.h"
+#include "wtf/StdLibExtras.h"
+#include <limits>
+#include <type_traits>
 
 namespace WTF {
 
-enum PositiveOrNegativeNumber {
-    PositiveNumber,
-    NegativeNumber
+// TODO(esprehn): See if we can generalize IntToStringT in
+// base/strings/string_number_conversions.cc, and use unsigned type expansion
+// optimization here instead of CheckedNumeric::UnsignedAbs().
+template<typename IntegerType>
+class IntegerToStringConverter {
+public:
+    static_assert(std::is_integral<IntegerType>::value,
+        "IntegerType must be a type of integer.");
+
+    explicit IntegerToStringConverter(IntegerType input)
+    {
+        LChar* end = m_buffer + WTF_ARRAY_LENGTH(m_buffer);
+        m_begin = end;
+
+        // We need to switch to the unsigned type when negating the value since
+        // abs(INT_MIN) == INT_MAX + 1.
+        bool isNegative = base::IsValueNegative(input);
+        UnsignedIntegerType value = isNegative ? 0u-input : input;
+
+        do {
+            --m_begin;
+            ASSERT(m_begin != m_buffer);
+            *m_begin = static_cast<LChar>((value % 10) + '0');
+            value /= 10;
+        } while (value);
+
+        if (isNegative) {
+            --m_begin;
+            ASSERT(m_begin != m_buffer);
+            *m_begin = static_cast<LChar>('-');
+        }
+
+        m_length = static_cast<unsigned>(end - m_begin);
+    }
+
+    const LChar* characters8() const { return m_begin; }
+    unsigned length() const { return m_length; }
+
+private:
+    using UnsignedIntegerType = typename std::make_unsigned<IntegerType>::type;
+    static const size_t kBufferSize = 3 * sizeof(UnsignedIntegerType) +
+        std::numeric_limits<IntegerType>::is_signed;
+
+    LChar m_buffer[kBufferSize];
+    LChar* m_begin;
+    unsigned m_length;
 };
 
-template<typename T> struct ConversionTrait;
-
-template<> struct ConversionTrait<String> {
-    typedef PassRefPtr<StringImpl> ReturnType;
-    typedef void AdditionalArgumentType;
-    static inline ReturnType flush(LChar* characters, unsigned length, void*) { return StringImpl::create(characters, length); }
-};
-template<> struct ConversionTrait<StringBuilder> {
-    typedef void ReturnType;
-    typedef StringBuilder AdditionalArgumentType;
-    static inline ReturnType flush(LChar* characters, unsigned length, StringBuilder* stringBuilder) { stringBuilder->append(characters, length); }
-};
-template<> struct ConversionTrait<AtomicString> {
-    typedef AtomicString ReturnType;
-    typedef void AdditionalArgumentType;
-    static inline ReturnType flush(LChar* characters, unsigned length, void*) { return AtomicString(characters, length); }
-};
-
-template<typename T> struct UnsignedIntegerTrait;
-
-template<> struct UnsignedIntegerTrait<int> {
-    typedef unsigned Type;
-};
-template<> struct UnsignedIntegerTrait<long> {
-    typedef unsigned long Type;
-};
-template<> struct UnsignedIntegerTrait<long long> {
-    typedef unsigned long long Type;
-};
-
-template<typename T, typename UnsignedIntegerType, PositiveOrNegativeNumber NumberType>
-static typename ConversionTrait<T>::ReturnType numberToStringImpl(UnsignedIntegerType number, typename ConversionTrait<T>::AdditionalArgumentType* additionalArgument)
-{
-    LChar buf[sizeof(UnsignedIntegerType) * 3 + 1];
-    LChar* end = buf + WTF_ARRAY_LENGTH(buf);
-    LChar* p = end;
-
-    do {
-        *--p = static_cast<LChar>((number % 10) + '0');
-        number /= 10;
-    } while (number);
-
-    if (NumberType == NegativeNumber)
-        *--p = '-';
-
-    return ConversionTrait<T>::flush(p, static_cast<unsigned>(end - p), additionalArgument);
-}
-
-template<typename T, typename SignedIntegerType>
-inline typename ConversionTrait<T>::ReturnType numberToStringSigned(SignedIntegerType number, typename ConversionTrait<T>::AdditionalArgumentType* additionalArgument = 0)
-{
-    if (number < 0)
-        return numberToStringImpl<T, typename UnsignedIntegerTrait<SignedIntegerType>::Type, NegativeNumber>(-number, additionalArgument);
-    return numberToStringImpl<T, typename UnsignedIntegerTrait<SignedIntegerType>::Type, PositiveNumber>(number, additionalArgument);
-}
-
-template<typename T, typename UnsignedIntegerType>
-inline typename ConversionTrait<T>::ReturnType numberToStringUnsigned(UnsignedIntegerType number, typename ConversionTrait<T>::AdditionalArgumentType* additionalArgument = 0)
-{
-    return numberToStringImpl<T, UnsignedIntegerType, PositiveNumber>(number, additionalArgument);
-}
-
 } // namespace WTF
 
 #endif // IntegerToStringConversion_h
diff --git a/third_party/WebKit/Source/wtf/text/StringBuilder.cpp b/third_party/WebKit/Source/wtf/text/StringBuilder.cpp
index 251a89e9..0dcbdd5 100644
--- a/third_party/WebKit/Source/wtf/text/StringBuilder.cpp
+++ b/third_party/WebKit/Source/wtf/text/StringBuilder.cpp
@@ -306,34 +306,41 @@
     }
 }
 
+template<typename IntegerType>
+static void appendIntegerInternal(StringBuilder& builder, IntegerType input)
+{
+    IntegerToStringConverter<IntegerType> converter(input);
+    builder.append(converter.characters8(), converter.length());
+}
+
 void StringBuilder::appendNumber(int number)
 {
-    numberToStringSigned<StringBuilder>(number, this);
+    appendIntegerInternal(*this, number);
 }
 
 void StringBuilder::appendNumber(unsigned number)
 {
-    numberToStringUnsigned<StringBuilder>(number, this);
+    appendIntegerInternal(*this, number);
 }
 
 void StringBuilder::appendNumber(long number)
 {
-    numberToStringSigned<StringBuilder>(number, this);
+    appendIntegerInternal(*this, number);
 }
 
 void StringBuilder::appendNumber(unsigned long number)
 {
-    numberToStringUnsigned<StringBuilder>(number, this);
+    appendIntegerInternal(*this, number);
 }
 
 void StringBuilder::appendNumber(long long number)
 {
-    numberToStringSigned<StringBuilder>(number, this);
+    appendIntegerInternal(*this, number);
 }
 
 void StringBuilder::appendNumber(unsigned long long number)
 {
-    numberToStringUnsigned<StringBuilder>(number, this);
+    appendIntegerInternal(*this, number);
 }
 
 static void expandLCharToUCharInplace(UChar* buffer, size_t length)
diff --git a/third_party/WebKit/Source/wtf/text/WTFString.cpp b/third_party/WebKit/Source/wtf/text/WTFString.cpp
index f647d173..b6738751 100644
--- a/third_party/WebKit/Source/wtf/text/WTFString.cpp
+++ b/third_party/WebKit/Source/wtf/text/WTFString.cpp
@@ -481,34 +481,41 @@
     return StringImpl::create(reinterpret_cast<const LChar*>(buffer.data()), len);
 }
 
+template<typename IntegerType>
+static String integerToString(IntegerType input)
+{
+    IntegerToStringConverter<IntegerType> converter(input);
+    return StringImpl::create(converter.characters8(), converter.length());
+}
+
 String String::number(int number)
 {
-    return numberToStringSigned<String>(number);
+    return integerToString(number);
 }
 
 String String::number(unsigned number)
 {
-    return numberToStringUnsigned<String>(number);
+    return integerToString(number);
 }
 
 String String::number(long number)
 {
-    return numberToStringSigned<String>(number);
+    return integerToString(number);
 }
 
 String String::number(unsigned long number)
 {
-    return numberToStringUnsigned<String>(number);
+    return integerToString(number);
 }
 
 String String::number(long long number)
 {
-    return numberToStringSigned<String>(number);
+    return integerToString(number);
 }
 
 String String::number(unsigned long long number)
 {
-    return numberToStringUnsigned<String>(number);
+    return integerToString(number);
 }
 
 String String::number(double number, unsigned precision, TrailingZerosTruncatingPolicy trailingZerosTruncatingPolicy)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py
index 619585f..da2f098 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py
@@ -515,7 +515,7 @@
 
         _log.debug("Uploading JSON files for builder: %s", self._options.builder_name)
         attrs = [("builder", self._options.builder_name),
-                 ("testtype", "layout-tests"),
+                 ("testtype", "webkit_tests"),
                  ("master", self._options.master_name)]
 
         files = [(file, self._filesystem.join(self._results_directory, file)) for file in ["failing_results.json", "full_results.json", "times_ms.json"]]
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/layout_package/bot_test_expectations.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/layout_package/bot_test_expectations.py
index e0134b8..91344b2 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/layout_package/bot_test_expectations.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/layout_package/bot_test_expectations.py
@@ -106,7 +106,7 @@
 
 
 class BotTestExpectationsFactory(object):
-    RESULTS_URL_PREFIX = 'http://test-results.appspot.com/testfile?master=ChromiumWebkit&testtype=layout-tests&name=results-small.json&builder='
+    RESULTS_URL_PREFIX = 'http://test-results.appspot.com/testfile?master=ChromiumWebkit&testtype=webkit_tests&name=results-small.json&builder='
 
     def _results_json_for_port(self, port_name, builder_category):
         builder = builders.builder_name_for_port_name(port_name)
diff --git a/third_party/WebKit/public/platform/WebLayer.h b/third_party/WebKit/public/platform/WebLayer.h
index ff846d5..51c8619d 100644
--- a/third_party/WebKit/public/platform/WebLayer.h
+++ b/third_party/WebKit/public/platform/WebLayer.h
@@ -201,8 +201,8 @@
 
     // Indicates that this layer will always scroll on the main thread for the provided reason.
     virtual void addMainThreadScrollingReasons(uint32_t) = 0;
-    // Indicates that the layer could scroll on the compositor thread.
-    virtual void clearMainThreadScrollingReasons() = 0;
+    virtual void clearMainThreadScrollingReasons(uint32_t mainThreadScrollingReasonsToClear) = 0;
+    virtual uint32_t mainThreadScrollingReasons() = 0;
     virtual bool shouldScrollOnMainThread() const = 0;
 
     virtual void setNonFastScrollableRegion(const WebVector<WebRect>&) = 0;
diff --git a/third_party/WebKit/public/platform/WebMediaConstraints.h b/third_party/WebKit/public/platform/WebMediaConstraints.h
index b53fbce..5e2b52d 100644
--- a/third_party/WebKit/public/platform/WebMediaConstraints.h
+++ b/third_party/WebKit/public/platform/WebMediaConstraints.h
@@ -216,6 +216,7 @@
     bool isEmpty() const override;
     bool hasMandatory() const override;
     WebString toString() const override;
+    bool hasExact() const { return m_hasExact; }
 
 private:
     unsigned m_ideal : 1;
diff --git a/third_party/WebKit/public/platform/WebTaskRunner.h b/third_party/WebKit/public/platform/WebTaskRunner.h
index defe4a1..57638175 100644
--- a/third_party/WebKit/public/platform/WebTaskRunner.h
+++ b/third_party/WebKit/public/platform/WebTaskRunner.h
@@ -37,6 +37,24 @@
     // Returns a clone of the WebTaskRunner.
     virtual WebTaskRunner* clone() = 0;
 
+    // ---
+
+    // Headless Chrome virtualises time for determinism and performance (fast forwarding
+    // of timers). To make this work some parts of blink (e.g. Timers) need to use virtual
+    // time, however by default new code should use the normal non-virtual time APIs.
+
+    // Returns a double which is the number of seconds since epoch (Jan 1, 1970).
+    // This may represent either the real time, or a virtual time depending on
+    // whether or not the WebTaskRunner is associated with a virtual time domain or a
+    // real time domain.
+    virtual double virtualTimeSeconds() const = 0;
+
+    // Returns a microsecond resolution platform dependant time source.
+    // This may represent either the real time, or a virtual time depending on
+    // whether or not the WebTaskRunner is associated with a virtual time domain or a
+    // real time domain.
+    virtual double monotonicallyIncreasingVirtualTimeSeconds() const = 0;
+
 #ifdef INSIDE_BLINK
     // Helpers for posting bound functions as tasks.
     typedef Function<void()> ClosureTask;
diff --git a/third_party/WebKit/public/platform/WebViewScheduler.h b/third_party/WebKit/public/platform/WebViewScheduler.h
index 0e1630c..bee6dce 100644
--- a/third_party/WebKit/public/platform/WebViewScheduler.h
+++ b/third_party/WebKit/public/platform/WebViewScheduler.h
@@ -21,6 +21,25 @@
 
     // Creaters a new WebFrameScheduler, the caller is responsible for deleting it.
     virtual WebPassOwnPtr<WebFrameScheduler> createFrameScheduler() = 0;
+
+    // Instructs this WebViewScheduler to use virtual time. When virtual time is enabled
+    // the system doesn't actually sleep for the delays between tasks before executing
+    // them. E.g: A-E are delayed tasks
+    //
+    // |    A   B C  D           E  (normal)
+    // |-----------------------------> time
+    //
+    // |ABCDE                       (virtual time)
+    // |-----------------------------> time
+    virtual void enableVirtualTime() = 0;
+
+    // Controls whether or not virtual time is allowed to advance. If virtual time
+    // is not allowed to advance then delayed tasks posted to the WebTaskRunners owned
+    // by any child WebFrameSchedulers will be paused. If virtual time is allowed to
+    // advance then tasks will be run in time order (as usual) but virtual time will
+    // fast forward so that the system doesn't actually sleep for the delays between
+    // tasks before executing them.
+    virtual void setAllowVirtualTimeToAdvance(bool) = 0;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothError.h b/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothError.h
index db987e5..f116b9c 100644
--- a/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothError.h
+++ b/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothError.h
@@ -55,6 +55,7 @@
     GATTUntranslatedErrorCode,
     // SecurityError:
     GATTNotAuthorized,
+    BlacklistedCharacteristicUUID,
     NotAllowedToAccessService,
     RequestDeviceWithBlacklistedUUID,
     RequestDeviceWithUniqueOrigin,
diff --git a/third_party/WebKit/public/platform/modules/indexeddb/WebIDBMetadata.h b/third_party/WebKit/public/platform/modules/indexeddb/WebIDBMetadata.h
index b7a29df..4dc59a0 100644
--- a/third_party/WebKit/public/platform/modules/indexeddb/WebIDBMetadata.h
+++ b/third_party/WebKit/public/platform/modules/indexeddb/WebIDBMetadata.h
@@ -35,22 +35,20 @@
 
 struct WebIDBMetadata {
     enum {
-        NoIntVersion = -1
+        NoVersion = -1
     };
     struct Index;
     struct ObjectStore;
 
     WebString name;
-    // FIXME: Both version members need to be present while we support both the
-    // old setVersion and new upgradeneeded API. Once we no longer support
-    // setVersion, WebString version can be removed.
-    WebString version;
-    long long intVersion;
+    long long version;
     long long id;
     long long maxObjectStoreId;
     WebVector<ObjectStore> objectStores;
     WebIDBMetadata()
-        : intVersion(NoIntVersion) { }
+        : version(NoVersion)
+    {
+    }
 
     struct ObjectStore {
         WebString name;
diff --git a/third_party/WebKit/public/web/WebFrame.h b/third_party/WebKit/public/web/WebFrame.h
index 4388083..9c32018c 100644
--- a/third_party/WebKit/public/web/WebFrame.h
+++ b/third_party/WebKit/public/web/WebFrame.h
@@ -362,19 +362,6 @@
         WebHistoryLoadType,
         WebURLRequest::CachePolicy = WebURLRequest::UseProtocolCachePolicy) = 0;
 
-    // Loads the given data with specific mime type and optional text
-    // encoding.  For HTML data, baseURL indicates the security origin of
-    // the document and is used to resolve links.  If specified,
-    // unreachableURL is reported via WebDataSource::unreachableURL.  If
-    // replace is false, then this data will be loaded as a normal
-    // navigation.  Otherwise, the current history item will be replaced.
-    virtual void loadData(const WebData& data,
-                          const WebString& mimeType,
-                          const WebString& textEncoding,
-                          const WebURL& baseURL,
-                          const WebURL& unreachableURL = WebURL(),
-                          bool replace = false) = 0;
-
     // This method is short-hand for calling LoadData, where mime_type is
     // "text/html" and text_encoding is "UTF-8".
     virtual void loadHTMLString(const WebData& html,
diff --git a/third_party/WebKit/public/web/WebLocalFrame.h b/third_party/WebKit/public/web/WebLocalFrame.h
index ba4eb4e..17cba72a 100644
--- a/third_party/WebKit/public/web/WebLocalFrame.h
+++ b/third_party/WebKit/public/web/WebLocalFrame.h
@@ -105,6 +105,24 @@
         bool isClientRedirect = false)
         = 0;
 
+    // Loads the given data with specific mime type and optional text
+    // encoding.  For HTML data, baseURL indicates the security origin of
+    // the document and is used to resolve links.  If specified,
+    // unreachableURL is reported via WebDataSource::unreachableURL.  If
+    // replace is false, then this data will be loaded as a normal
+    // navigation.  Otherwise, the current history item will be replaced.
+    virtual void loadData(const WebData&,
+        const WebString& mimeType,
+        const WebString& textEncoding,
+        const WebURL& baseURL,
+        const WebURL& unreachableURL = WebURL(),
+        bool replace = false,
+        WebFrameLoadType = WebFrameLoadType::Standard,
+        const WebHistoryItem& = WebHistoryItem(),
+        WebHistoryLoadType = WebHistoryDifferentDocumentLoad,
+        bool isClientRedirect = false)
+        = 0;
+
     // Navigation State -------------------------------------------------------
 
     // Returns true if the current frame's load event has not completed.
@@ -235,7 +253,8 @@
         const WebString& searchText,
         const WebFindOptions&,
         bool wrapWithinFrame,
-        WebRect* selectionRect) = 0;
+        WebRect* selectionRect,
+        bool* activeNow = nullptr) = 0;
 
     // Notifies the frame that we are no longer interested in searching.
     // This will abort any asynchronous scoping effort already under way
diff --git a/third_party/WebKit/public/web/WebRuntimeFeatures.h b/third_party/WebKit/public/web/WebRuntimeFeatures.h
index f96ba67..328e3b7 100644
--- a/third_party/WebKit/public/web/WebRuntimeFeatures.h
+++ b/third_party/WebKit/public/web/WebRuntimeFeatures.h
@@ -120,8 +120,6 @@
 
     BLINK_EXPORT static void enableTouch(bool);
 
-    BLINK_EXPORT static void enableWebAudio(bool);
-
     BLINK_EXPORT static void enableWebGLDraftExtensions(bool);
 
     BLINK_EXPORT static void enableWebGLImageChromium(bool);
@@ -166,6 +164,8 @@
 
     BLINK_EXPORT static void enableScrollAnchoring(bool);
 
+    BLINK_EXPORT static void enableRenderingPipelineThrottling(bool);
+
     // TODO(nhiroki): Remove after ExtendableMessageEvent is shipped
     // (crbug.com/543198).
     BLINK_EXPORT static bool isServiceWorkerExtendableMessageEventEnabled();
diff --git a/third_party/WebKit/public/web/WebSettings.h b/third_party/WebKit/public/web/WebSettings.h
index 64b5a80c..b486a00 100644
--- a/third_party/WebKit/public/web/WebSettings.h
+++ b/third_party/WebKit/public/web/WebSettings.h
@@ -249,7 +249,6 @@
     virtual void setViewportMetaMergeContentQuirk(bool) = 0;
     virtual void setViewportMetaNonUserScalableQuirk(bool) = 0;
     virtual void setViewportMetaZeroValuesQuirk(bool) = 0;
-    virtual void setWebAudioEnabled(bool) = 0;
     virtual void setWebGLErrorsToConsoleEnabled(bool) = 0;
     virtual void setWebSecurityEnabled(bool) = 0;
     virtual void setWideViewportQuirkEnabled(bool) = 0;
diff --git a/third_party/WebKit/public/web/WebView.h b/third_party/WebKit/public/web/WebView.h
index 0f417ca..66eb058 100644
--- a/third_party/WebKit/public/web/WebView.h
+++ b/third_party/WebKit/public/web/WebView.h
@@ -60,6 +60,7 @@
 class WebSpellCheckClient;
 class WebString;
 class WebViewClient;
+class WebViewScheduler;
 struct WebActiveWheelFlingParameters;
 struct WebDeviceEmulationParams;
 struct WebFloatPoint;
@@ -454,6 +455,10 @@
     virtual void setShowFPSCounter(bool) = 0;
     virtual void setShowScrollBottleneckRects(bool) = 0;
 
+    // Scheduling -----------------------------------------------------------
+
+    virtual WebViewScheduler* scheduler() const = 0;
+
     // Visibility -----------------------------------------------------------
 
     // Sets the visibility of the WebView.
diff --git a/third_party/haha/BUILD.gn b/third_party/haha/BUILD.gn
index d26f384..6e7a2626 100644
--- a/third_party/haha/BUILD.gn
+++ b/third_party/haha/BUILD.gn
@@ -4,6 +4,6 @@
 
 import("//build/config/android/rules.gni")
 
-java_prebuilt("haha") {
+android_java_prebuilt("haha") {
   jar_path = "haha-2.0.2.jar"
 }
diff --git a/third_party/harfbuzz-ng/NEWS b/third_party/harfbuzz-ng/NEWS
index 698256d..b1b63b2c 100644
--- a/third_party/harfbuzz-ng/NEWS
+++ b/third_party/harfbuzz-ng/NEWS
@@ -1,3 +1,36 @@
+Overview of changes leading to 1.2.1
+Friday, February 23, 2016
+====================================
+
+- CoreText: Fix bug with wrong scale if font scale was changed later.
+  https://github.com/libass/libass/issues/212
+- CoreText: Drastically speed up font initialization.
+- CoreText: Fix tiny leak.
+- Group ZWJ/ZWNJ with previous syllable under cluster-level=0.
+  https://github.com/behdad/harfbuzz/issues/217
+- Add test/shaping/README.md about how to add tests to the suite.
+
+
+Overview of changes leading to 1.2.0
+Friday, February 19, 2016
+====================================
+
+- Fix various issues (hangs mostly) in case of memory allocation failure.
+- Change mark zeroing types of most shapers from BY_UNICODE_LATE to
+  BY_GDEF_LATE.  This seems to be what Uniscribe does.
+- Change mark zeroing of USE shaper from NONE to BY_GDEF_EARLY.  That's
+  what Windows does.
+- Allow GPOS cursive connection on marks, and fix the interaction with
+  mark attachment.  This work resulted in some changes to how mark
+  attachments work.  See:
+  https://github.com/behdad/harfbuzz/issues/211
+  https://github.com/behdad/harfbuzz/commit/86c68c7a2c971efe8e35b1f1bd99401dc8b688d2
+- Graphite2 shaper: improved negative advance handling (eg. Nastaliq).
+- Add nmake-based build system for Windows.
+- Minor speedup.
+- Misc. improvements.
+
+
 Overview of changes leading to 1.1.3
 Monday, January 11, 2016
 ====================================
diff --git a/third_party/harfbuzz-ng/README.chromium b/third_party/harfbuzz-ng/README.chromium
index 16fad937..f6c9be9 100644
--- a/third_party/harfbuzz-ng/README.chromium
+++ b/third_party/harfbuzz-ng/README.chromium
@@ -1,8 +1,8 @@
 Name: harfbuzz-ng
 Short Name: harfbuzz-ng
 URL: http://harfbuzz.org
-Version: 1.1.3
-Date: 20151124
+Version: 1.2.1
+Date: 20160222
 Security Critical: yes
 License: MIT
 License File: COPYING
@@ -20,5 +20,11 @@
 in README.chromium.
 
 Local changes:
-* Disabled test_langs_sorted() in hb-ot-tag.cc to fix
-  "unused function" compile error
+    * Custom revert: Change mark strategy back to UNICODE_LATE from
+      GDEF_LATE for the default shaper - contributed by Behdad to unblock
+      the HarfBuzz roll in Blink while the issue about broken quote glyphs
+      in Times New Roman Italic can be resolved in upstream.
+    * Upstream commit ebd7431f824
+      "Partially revert 86c68c7a2c97"
+      in order to fix mark positioning in
+      fast/text/international/arabic-vertical-offset.html
diff --git a/third_party/harfbuzz-ng/src/hb-blob.cc b/third_party/harfbuzz-ng/src/hb-blob.cc
index a6870dc..fb48f03c 100644
--- a/third_party/harfbuzz-ng/src/hb-blob.cc
+++ b/third_party/harfbuzz-ng/src/hb-blob.cc
@@ -104,7 +104,6 @@
 
   if (!length ||
       length >= 1u << 31 ||
-      data + length < data /* overflows */ ||
       !(blob = hb_object_create<hb_blob_t> ())) {
     if (destroy)
       destroy (user_data);
diff --git a/third_party/harfbuzz-ng/src/hb-buffer-private.hh b/third_party/harfbuzz-ng/src/hb-buffer-private.hh
index 4983f849..c8eec3c 100644
--- a/third_party/harfbuzz-ng/src/hb-buffer-private.hh
+++ b/third_party/harfbuzz-ng/src/hb-buffer-private.hh
@@ -56,8 +56,7 @@
   HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII			= 0x00000001u,
   HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES		= 0x00000002u,
   HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK		= 0x00000004u,
-  HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_CURSIVE		= 0x00000008u,
-  HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT		= 0x00000010u,
+  HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT		= 0x00000008u,
   /* Reserved for complex shapers' internal use. */
   HB_BUFFER_SCRATCH_FLAG_COMPLEX0			= 0x01000000u,
   HB_BUFFER_SCRATCH_FLAG_COMPLEX1			= 0x02000000u,
diff --git a/third_party/harfbuzz-ng/src/hb-buffer.cc b/third_party/harfbuzz-ng/src/hb-buffer.cc
index c731ed1..5f320bd7 100644
--- a/third_party/harfbuzz-ng/src/hb-buffer.cc
+++ b/third_party/harfbuzz-ng/src/hb-buffer.cc
@@ -407,6 +407,8 @@
     idx = i;
     return true;
   }
+  if (unlikely (in_error))
+    return false;
 
   assert (i <= out_len + (len - idx));
 
diff --git a/third_party/harfbuzz-ng/src/hb-common.cc b/third_party/harfbuzz-ng/src/hb-common.cc
index e091190..140ee0a 100644
--- a/third_party/harfbuzz-ng/src/hb-common.cc
+++ b/third_party/harfbuzz-ng/src/hb-common.cc
@@ -540,7 +540,7 @@
 void *
 hb_user_data_array_t::get (hb_user_data_key_t *key)
 {
-  hb_user_data_item_t item = {NULL };
+  hb_user_data_item_t item = {NULL, NULL, NULL};
 
   return items.find (key, &item, lock) ? item.data : NULL;
 }
diff --git a/third_party/harfbuzz-ng/src/hb-coretext.cc b/third_party/harfbuzz-ng/src/hb-coretext.cc
index 04cf057..90c6653 100644
--- a/third_party/harfbuzz-ng/src/hb-coretext.cc
+++ b/third_party/harfbuzz-ng/src/hb-coretext.cc
@@ -27,7 +27,6 @@
  */
 
 #define HB_SHAPER coretext
-#define hb_coretext_shaper_face_data_t CGFont
 #include "hb-shaper-impl-private.hh"
 
 #include "hb-coretext.h"
@@ -78,6 +77,29 @@
  * shaper face data
  */
 
+static CTFontDescriptorRef
+get_last_resort_font_desc (void)
+{
+  // TODO Handle allocation failures?
+  CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize (CFSTR("LastResort"), 0);
+  CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault,
+					   (const void **) &last_resort,
+					   1,
+					   &kCFTypeArrayCallBacks);
+  CFRelease (last_resort);
+  CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
+						   (const void **) &kCTFontCascadeListAttribute,
+						   (const void **) &cascade_list,
+						   1,
+						   &kCFTypeDictionaryKeyCallBacks,
+						   &kCFTypeDictionaryValueCallBacks);
+  CFRelease (cascade_list);
+
+  CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
+  CFRelease (attributes);
+  return font_desc;
+}
+
 static void
 release_data (void *info, const void *data, size_t size)
 {
@@ -87,14 +109,13 @@
   hb_blob_destroy ((hb_blob_t *) info);
 }
 
-hb_coretext_shaper_face_data_t *
-_hb_coretext_shaper_face_data_create (hb_face_t *face)
+static CGFontRef
+create_cg_font (hb_face_t *face)
 {
-  hb_coretext_shaper_face_data_t *data = NULL;
-
+  CGFontRef cg_font = NULL;
   if (face->destroy == (hb_destroy_func_t) CGFontRelease)
   {
-    data = CGFontRetain ((CGFontRef) face->user_data);
+    cg_font = CGFontRetain ((CGFontRef) face->user_data);
   }
   else
   {
@@ -107,13 +128,76 @@
     CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
     if (likely (provider))
     {
-      data = CGFontCreateWithDataProvider (provider);
+      cg_font = CGFontCreateWithDataProvider (provider);
+      if (unlikely (!cg_font))
+	DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
       CGDataProviderRelease (provider);
     }
   }
+  return cg_font;
+}
 
-  if (unlikely (!data)) {
-    DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
+static CTFontRef
+create_ct_font (CGFontRef cg_font, CGFloat font_size)
+{
+  CTFontRef ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, NULL, NULL);
+  if (unlikely (!ct_font)) {
+    DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
+    return NULL;
+  }
+
+  /* Create font copy with cascade list that has LastResort first; this speeds up CoreText
+   * font fallback which we don't need anyway. */
+  {
+    CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc ();
+    CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, NULL, last_resort_font_desc);
+    CFRelease (last_resort_font_desc);
+    if (new_ct_font)
+    {
+      CFRelease (ct_font);
+      ct_font = new_ct_font;
+    }
+    else
+      DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed");
+  }
+
+ return ct_font;
+}
+
+struct hb_coretext_shaper_face_data_t {
+  CGFontRef cg_font;
+  CTFontRef ct_font;
+};
+
+hb_coretext_shaper_face_data_t *
+_hb_coretext_shaper_face_data_create (hb_face_t *face)
+{
+  hb_coretext_shaper_face_data_t *data = (hb_coretext_shaper_face_data_t *) calloc (1, sizeof (hb_coretext_shaper_face_data_t));
+  if (unlikely (!data))
+    return NULL;
+
+  data->cg_font = create_cg_font (face);
+  if (unlikely (!data->cg_font))
+  {
+    DEBUG_MSG (CORETEXT, face, "CGFont creation failed..");
+    free (data);
+    return NULL;
+  }
+
+  /* We use 36pt size instead of UPEM, because CoreText implements the 'trak' table,
+   * which can make the font too tight at large sizes.  36pt should be a good semi-neutral
+   * size.
+   *
+   * Since we always create CTFont at a fixed size, our CTFont lives in face_data
+   * instead of font_data.  Which is good, because when people change scale on
+   * hb_font_t, we won't need to update our CTFont. */
+  data->ct_font = create_ct_font (data->cg_font, 36.);
+  if (unlikely (!data->ct_font))
+  {
+    DEBUG_MSG (CORETEXT, face, "CTFont creation failed.");
+    CFRelease (data->cg_font);
+    free (data);
+    return NULL;
   }
 
   return data;
@@ -122,7 +206,9 @@
 void
 _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
 {
-  CFRelease (data);
+  CFRelease (data->ct_font);
+  CFRelease (data->cg_font);
+  free (data);
 }
 
 /*
@@ -133,7 +219,7 @@
 {
   if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL;
   hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
-  return face_data;
+  return face_data->cg_font;
 }
 
 
@@ -141,86 +227,17 @@
  * shaper font data
  */
 
-struct hb_coretext_shaper_font_data_t {
-  CTFontRef ct_font;
-  CGFloat x_mult, y_mult; /* From CT space to HB space. */
-};
+struct hb_coretext_shaper_font_data_t {};
 
 hb_coretext_shaper_font_data_t *
-_hb_coretext_shaper_font_data_create (hb_font_t *font)
+_hb_coretext_shaper_font_data_create (hb_font_t *font HB_UNUSED)
 {
-  if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL;
-
-  hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) calloc (1, sizeof (hb_coretext_shaper_font_data_t));
-  if (unlikely (!data))
-    return NULL;
-
-  hb_face_t *face = font->face;
-  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
-
-  /* Choose a CoreText font size and calculate multipliers to convert to HarfBuzz space. */
-  /* TODO: use upem instead of 36? */
-  CGFloat font_size = 36.; /* Default... */
-  /* No idea if the following is even a good idea. */
-  if (font->y_ppem)
-    font_size = font->y_ppem;
-
-  if (font_size < 0)
-    font_size = -font_size;
-  data->x_mult = (CGFloat) font->x_scale / font_size;
-  data->y_mult = (CGFloat) font->y_scale / font_size;
-  data->ct_font = CTFontCreateWithGraphicsFont (face_data, font_size, NULL, NULL);
-  if (unlikely (!data->ct_font)) {
-    DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed");
-    free (data);
-    return NULL;
-  }
-
-  /* Create font copy with cascade list that has LastResort first; this speeds up CoreText
-   * font fallback which we don't need anyway. */
-  {
-    // TODO Handle allocation failures?
-    CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize(CFSTR("LastResort"), 0);
-    CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault,
-					     (const void **) &last_resort,
-					     1,
-					     &kCFTypeArrayCallBacks);
-    CFRelease (last_resort);
-    CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
-						     (const void **) &kCTFontCascadeListAttribute,
-						     (const void **) &cascade_list,
-						     1,
-						     &kCFTypeDictionaryKeyCallBacks,
-						     &kCFTypeDictionaryValueCallBacks);
-    CFRelease (cascade_list);
-
-    CTFontDescriptorRef new_font_desc = CTFontDescriptorCreateWithAttributes (attributes);
-    CFRelease (attributes);
-
-    CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (data->ct_font, 0.0, NULL, new_font_desc);
-    if (new_ct_font)
-    {
-      CFRelease (data->ct_font);
-      data->ct_font = new_ct_font;
-    }
-    else
-      DEBUG_MSG (CORETEXT, font, "Font copy with empty cascade list failed");
-  }
-
-  if (unlikely (!data->ct_font)) {
-    DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed");
-    free (data);
-    return NULL;
-  }
-
-  return data;
+  return (hb_coretext_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
 
 void
 _hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
 {
-  CFRelease (data->ct_font);
-  free (data);
 }
 
 
@@ -246,9 +263,10 @@
 CTFontRef
 hb_coretext_font_get_ct_font (hb_font_t *font)
 {
-  if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return NULL;
-  hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
-  return font_data->ct_font;
+  hb_face_t *face = font->face;
+  if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL;
+  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+  return face_data->ct_font;
 }
 
 
@@ -481,7 +499,10 @@
 {
   hb_face_t *face = font->face;
   hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
-  hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
+
+  CGFloat ct_font_size = CTFontGetSize (face_data->ct_font);
+  CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
+  CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
 
   /* Attach marks to their bases, to match the 'ot' shaper.
    * Adapted from hb-ot-shape:hb_form_clusters().
@@ -490,6 +511,7 @@
    * B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will
    * continue pointing to B2 even though B2 was merged into B1's
    * cluster... */
+  if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
   {
     hb_unicode_funcs_t *unicode = buffer->unicode;
     unsigned int count = buffer->len;
@@ -612,7 +634,7 @@
 	  CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
 	  CFRelease (attributes);
 
-	  range->font = CTFontCreateCopyWithAttributes (font_data->ct_font, 0.0, NULL, font_desc);
+	  range->font = CTFontCreateCopyWithAttributes (face_data->ct_font, 0.0, NULL, font_desc);
 	  CFRelease (font_desc);
 	}
 	else
@@ -769,7 +791,7 @@
 	CFRelease (lang);
       }
       CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
-				      kCTFontAttributeName, font_data->ct_font);
+				      kCTFontAttributeName, face_data->ct_font);
 
       if (num_features)
       {
@@ -862,7 +884,7 @@
        */
       CFDictionaryRef attributes = CTRunGetAttributes (run);
       CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName));
-      if (!CFEqual (run_ct_font, font_data->ct_font))
+      if (!CFEqual (run_ct_font, face_data->ct_font))
       {
 	/* The run doesn't use our main font instance.  We have to figure out
 	 * whether font fallback happened, or this is just CoreText giving us
@@ -902,13 +924,13 @@
 	  CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0);
 	  if (run_cg_font)
 	  {
-	    matched = CFEqual (run_cg_font, face_data);
+	    matched = CFEqual (run_cg_font, face_data->cg_font);
 	    CFRelease (run_cg_font);
 	  }
 	}
 	if (!matched)
 	{
-	  CFStringRef font_ps_name = CTFontCopyName (font_data->ct_font, kCTFontPostScriptNameKey);
+	  CFStringRef font_ps_name = CTFontCopyName (face_data->ct_font, kCTFontPostScriptNameKey);
 	  CFStringRef run_ps_name = CTFontCopyName (run_ct_font, kCTFontPostScriptNameKey);
 	  CFComparisonResult result = CFStringCompare (run_ps_name, font_ps_name, 0);
 	  CFRelease (run_ps_name);
@@ -1028,7 +1050,6 @@
 	  positions = position_buf;
 	}
 	hb_glyph_info_t *info = run_info;
-	CGFloat x_mult = font_data->x_mult, y_mult = font_data->y_mult;
 	if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
 	{
 	  hb_position_t x_offset = (positions[0].x - advances_so_far) * x_mult;
diff --git a/third_party/harfbuzz-ng/src/hb-directwrite.cc b/third_party/harfbuzz-ng/src/hb-directwrite.cc
new file mode 100644
index 0000000..af0fd3da
--- /dev/null
+++ b/third_party/harfbuzz-ng/src/hb-directwrite.cc
@@ -0,0 +1,827 @@
+/*
+ * Copyright © 2015  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#define HB_SHAPER directwrite
+#include "hb-shaper-impl-private.hh"
+
+#include <dwrite.h>
+
+#include "hb-directwrite.h"
+
+#include "hb-open-file-private.hh"
+#include "hb-ot-name-table.hh"
+#include "hb-ot-tag.h"
+
+
+#ifndef HB_DEBUG_DIRECTWRITE
+#define HB_DEBUG_DIRECTWRITE (HB_DEBUG+0)
+#endif
+
+HB_SHAPER_DATA_ENSURE_DECLARE(directwrite, face)
+HB_SHAPER_DATA_ENSURE_DECLARE(directwrite, font)
+
+/*
+* shaper face data
+*/
+
+struct hb_directwrite_shaper_face_data_t {
+  HANDLE fh;
+  wchar_t face_name[LF_FACESIZE];
+};
+
+/* face_name should point to a wchar_t[LF_FACESIZE] object. */
+static void
+_hb_generate_unique_face_name(wchar_t *face_name, unsigned int *plen)
+{
+  /* We'll create a private name for the font from a UUID using a simple,
+  * somewhat base64-like encoding scheme */
+  const char *enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
+  UUID id;
+  UuidCreate ((UUID*)&id);
+  ASSERT_STATIC (2 + 3 * (16 / 2) < LF_FACESIZE);
+  unsigned int name_str_len = 0;
+  face_name[name_str_len++] = 'F';
+  face_name[name_str_len++] = '_';
+  unsigned char *p = (unsigned char *)&id;
+  for (unsigned int i = 0; i < 16; i += 2)
+  {
+    /* Spread the 16 bits from two bytes of the UUID across three chars of face_name,
+    * using the bits in groups of 5,5,6 to select chars from enc.
+    * This will generate 24 characters; with the 'F_' prefix we already provided,
+    * the name will be 26 chars (plus the NUL terminator), so will always fit within
+    * face_name (LF_FACESIZE = 32). */
+    face_name[name_str_len++] = enc[p[i] >> 3];
+    face_name[name_str_len++] = enc[((p[i] << 2) | (p[i + 1] >> 6)) & 0x1f];
+    face_name[name_str_len++] = enc[p[i + 1] & 0x3f];
+  }
+  face_name[name_str_len] = 0;
+  if (plen)
+    *plen = name_str_len;
+}
+
+/* Destroys blob. */
+static hb_blob_t *
+_hb_rename_font(hb_blob_t *blob, wchar_t *new_name)
+{
+  /* Create a copy of the font data, with the 'name' table replaced by a
+   * table that names the font with our private F_* name created above.
+   * For simplicity, we just append a new 'name' table and update the
+   * sfnt directory; the original table is left in place, but unused.
+   *
+   * The new table will contain just 5 name IDs: family, style, unique,
+   * full, PS. All of them point to the same name data with our unique name.
+   */
+
+  blob = OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (blob);
+
+  unsigned int length, new_length, name_str_len;
+  const char *orig_sfnt_data = hb_blob_get_data (blob, &length);
+
+  _hb_generate_unique_face_name (new_name, &name_str_len);
+
+  static const uint16_t name_IDs[] = { 1, 2, 3, 4, 6 };
+
+  unsigned int name_table_length = OT::name::min_size +
+    ARRAY_LENGTH(name_IDs) * OT::NameRecord::static_size +
+    name_str_len * 2; /* for name data in UTF16BE form */
+  unsigned int name_table_offset = (length + 3) & ~3;
+
+  new_length = name_table_offset + ((name_table_length + 3) & ~3);
+  void *new_sfnt_data = calloc(1, new_length);
+  if (!new_sfnt_data)
+  {
+    hb_blob_destroy (blob);
+    return NULL;
+  }
+
+  memcpy(new_sfnt_data, orig_sfnt_data, length);
+
+  OT::name &name = OT::StructAtOffset<OT::name> (new_sfnt_data, name_table_offset);
+  name.format.set (0);
+  name.count.set (ARRAY_LENGTH (name_IDs));
+  name.stringOffset.set (name.get_size());
+  for (unsigned int i = 0; i < ARRAY_LENGTH (name_IDs); i++)
+  {
+    OT::NameRecord &record = name.nameRecord[i];
+    record.platformID.set(3);
+    record.encodingID.set(1);
+    record.languageID.set(0x0409u); /* English */
+    record.nameID.set(name_IDs[i]);
+    record.length.set(name_str_len * 2);
+    record.offset.set(0);
+  }
+
+  /* Copy string data from new_name, converting wchar_t to UTF16BE. */
+  unsigned char *p = &OT::StructAfter<unsigned char>(name);
+  for (unsigned int i = 0; i < name_str_len; i++)
+  {
+    *p++ = new_name[i] >> 8;
+    *p++ = new_name[i] & 0xff;
+  }
+
+  /* Adjust name table entry to point to new name table */
+  const OT::OpenTypeFontFile &file = *(OT::OpenTypeFontFile *) (new_sfnt_data);
+  unsigned int face_count = file.get_face_count ();
+  for (unsigned int face_index = 0; face_index < face_count; face_index++)
+  {
+    /* Note: doing multiple edits (ie. TTC) can be unsafe.  There may be
+    * toe-stepping.  But we don't really care. */
+    const OT::OpenTypeFontFace &face = file.get_face (face_index);
+    unsigned int index;
+    if (face.find_table_index (HB_OT_TAG_name, &index))
+    {
+      OT::TableRecord &record = const_cast<OT::TableRecord &> (face.get_table (index));
+      record.checkSum.set_for_data (&name, name_table_length);
+      record.offset.set (name_table_offset);
+      record.length.set (name_table_length);
+    }
+    else if (face_index == 0) /* Fail if first face doesn't have 'name' table. */
+    {
+      free (new_sfnt_data);
+      hb_blob_destroy (blob);
+      return NULL;
+    }
+  }
+
+  /* The checkSumAdjustment field in the 'head' table is now wrong,
+  * but that doesn't actually seem to cause any problems so we don't
+  * bother. */
+
+  hb_blob_destroy (blob);
+  return hb_blob_create ((const char *)new_sfnt_data, new_length,
+    HB_MEMORY_MODE_WRITABLE, NULL, free);
+}
+
+hb_directwrite_shaper_face_data_t *
+_hb_directwrite_shaper_face_data_create(hb_face_t *face)
+{
+  hb_directwrite_shaper_face_data_t *data = (hb_directwrite_shaper_face_data_t *)calloc(1, sizeof (hb_directwrite_shaper_face_data_t));
+  if (unlikely (!data))
+    return NULL;
+
+  hb_blob_t *blob = hb_face_reference_blob (face);
+  if (unlikely (!hb_blob_get_length (blob)))
+    DEBUG_MSG(DIRECTWRITE, face, "Face has empty blob");
+
+  blob = _hb_rename_font (blob, data->face_name);
+  if (unlikely (!blob))
+  {
+    free(data);
+    return NULL;
+  }
+
+  DWORD num_fonts_installed;
+  data->fh = AddFontMemResourceEx ((void *)hb_blob_get_data(blob, NULL),
+    hb_blob_get_length (blob),
+    0, &num_fonts_installed);
+  if (unlikely (!data->fh))
+  {
+    DEBUG_MSG (DIRECTWRITE, face, "Face AddFontMemResourceEx() failed");
+    free (data);
+    return NULL;
+  }
+
+  return data;
+}
+
+void
+_hb_directwrite_shaper_face_data_destroy(hb_directwrite_shaper_face_data_t *data)
+{
+  RemoveFontMemResourceEx(data->fh);
+  free(data);
+}
+
+
+/*
+ * shaper font data
+ */
+
+struct hb_directwrite_shaper_font_data_t {
+  HDC hdc;
+  LOGFONTW log_font;
+  HFONT hfont;
+};
+
+static bool
+populate_log_font (LOGFONTW  *lf,
+       hb_font_t *font)
+{
+  memset (lf, 0, sizeof (*lf));
+  lf->lfHeight = -font->y_scale;
+  lf->lfCharSet = DEFAULT_CHARSET;
+
+  hb_face_t *face = font->face;
+  hb_directwrite_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+
+  memcpy (lf->lfFaceName, face_data->face_name, sizeof (lf->lfFaceName));
+
+  return true;
+}
+
+hb_directwrite_shaper_font_data_t *
+_hb_directwrite_shaper_font_data_create (hb_font_t *font)
+{
+  if (unlikely (!hb_directwrite_shaper_face_data_ensure (font->face))) return NULL;
+
+  hb_directwrite_shaper_font_data_t *data = (hb_directwrite_shaper_font_data_t *) calloc (1, sizeof (hb_directwrite_shaper_font_data_t));
+  if (unlikely (!data))
+    return NULL;
+
+  data->hdc = GetDC (NULL);
+
+  if (unlikely (!populate_log_font (&data->log_font, font))) {
+    DEBUG_MSG (DIRECTWRITE, font, "Font populate_log_font() failed");
+    _hb_directwrite_shaper_font_data_destroy (data);
+    return NULL;
+  }
+
+  data->hfont = CreateFontIndirectW (&data->log_font);
+  if (unlikely (!data->hfont)) {
+    DEBUG_MSG (DIRECTWRITE, font, "Font CreateFontIndirectW() failed");
+    _hb_directwrite_shaper_font_data_destroy (data);
+     return NULL;
+  }
+
+  if (!SelectObject (data->hdc, data->hfont)) {
+    DEBUG_MSG (DIRECTWRITE, font, "Font SelectObject() failed");
+    _hb_directwrite_shaper_font_data_destroy (data);
+     return NULL;
+  }
+
+  return data;
+}
+
+void
+_hb_directwrite_shaper_font_data_destroy (hb_directwrite_shaper_font_data_t *data)
+{
+  if (data->hdc)
+    ReleaseDC (NULL, data->hdc);
+  if (data->hfont)
+    DeleteObject (data->hfont);
+  free (data);
+}
+
+LOGFONTW *
+hb_directwrite_font_get_logfontw (hb_font_t *font)
+{
+  if (unlikely (!hb_directwrite_shaper_font_data_ensure (font))) return NULL;
+  hb_directwrite_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
+  return &font_data->log_font;
+}
+
+HFONT
+hb_directwrite_font_get_hfont (hb_font_t *font)
+{
+  if (unlikely (!hb_directwrite_shaper_font_data_ensure (font))) return NULL;
+  hb_directwrite_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
+  return font_data->hfont;
+}
+
+
+/*
+ * shaper shape_plan data
+ */
+
+struct hb_directwrite_shaper_shape_plan_data_t {};
+
+hb_directwrite_shaper_shape_plan_data_t *
+_hb_directwrite_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
+               const hb_feature_t *user_features HB_UNUSED,
+               unsigned int        num_user_features HB_UNUSED)
+{
+  return (hb_directwrite_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_directwrite_shaper_shape_plan_data_destroy (hb_directwrite_shaper_shape_plan_data_t *data HB_UNUSED)
+{
+}
+
+// Most of here TextAnalysis is originally written by Bas Schouten for Mozilla project
+// but now is relicensed to MIT for HarfBuzz use
+class TextAnalysis
+  : public IDWriteTextAnalysisSource, public IDWriteTextAnalysisSink
+{
+public:
+
+  IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) { return S_OK; }
+  IFACEMETHOD_(ULONG, AddRef)() { return 1; }
+  IFACEMETHOD_(ULONG, Release)() { return 1; }
+
+  // A single contiguous run of characters containing the same analysis 
+  // results.
+  struct Run
+  {
+    UINT32 mTextStart;   // starting text position of this run
+    UINT32 mTextLength;  // number of contiguous code units covered
+    UINT32 mGlyphStart;  // starting glyph in the glyphs array
+    UINT32 mGlyphCount;  // number of glyphs associated with this run of 
+    // text
+    DWRITE_SCRIPT_ANALYSIS mScript;
+    UINT8 mBidiLevel;
+    bool mIsSideways;
+
+    inline bool ContainsTextPosition(UINT32 aTextPosition) const
+    {
+      return aTextPosition >= mTextStart
+        && aTextPosition <  mTextStart + mTextLength;
+    }
+
+    Run *nextRun;
+  };
+
+public:
+  TextAnalysis(const wchar_t* text,
+    UINT32 textLength,
+    const wchar_t* localeName,
+    DWRITE_READING_DIRECTION readingDirection)
+    : mText(text)
+    , mTextLength(textLength)
+    , mLocaleName(localeName)
+    , mReadingDirection(readingDirection)
+    , mCurrentRun(NULL) { };
+
+  ~TextAnalysis() {
+    // delete runs, except mRunHead which is part of the TextAnalysis object
+    for (Run *run = mRunHead.nextRun; run;) {
+      Run *origRun = run;
+      run = run->nextRun;
+      delete origRun;
+    }
+  }
+
+  STDMETHODIMP GenerateResults(IDWriteTextAnalyzer* textAnalyzer,
+    Run **runHead) {
+    // Analyzes the text using the script analyzer and returns
+    // the result as a series of runs.
+
+    HRESULT hr = S_OK;
+
+    // Initially start out with one result that covers the entire range.
+    // This result will be subdivided by the analysis processes.
+    mRunHead.mTextStart = 0;
+    mRunHead.mTextLength = mTextLength;
+    mRunHead.mBidiLevel =
+      (mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
+    mRunHead.nextRun = NULL;
+    mCurrentRun = &mRunHead;
+
+    // Call each of the analyzers in sequence, recording their results.
+    if (SUCCEEDED(hr = textAnalyzer->AnalyzeScript(this,
+      0,
+      mTextLength,
+      this))) {
+      *runHead = &mRunHead;
+    }
+
+    return hr;
+  }
+
+  // IDWriteTextAnalysisSource implementation
+
+  IFACEMETHODIMP GetTextAtPosition(UINT32 textPosition,
+    OUT WCHAR const** textString,
+    OUT UINT32* textLength)
+  {
+    if (textPosition >= mTextLength) {
+      // No text at this position, valid query though.
+      *textString = NULL;
+      *textLength = 0;
+    }
+    else {
+      *textString = mText + textPosition;
+      *textLength = mTextLength - textPosition;
+    }
+    return S_OK;
+  }
+
+  IFACEMETHODIMP GetTextBeforePosition(UINT32 textPosition,
+    OUT WCHAR const** textString,
+    OUT UINT32* textLength)
+  {
+    if (textPosition == 0 || textPosition > mTextLength) {
+      // Either there is no text before here (== 0), or this
+      // is an invalid position. The query is considered valid thouh.
+      *textString = NULL;
+      *textLength = 0;
+    }
+    else {
+      *textString = mText;
+      *textLength = textPosition;
+    }
+    return S_OK;
+  }
+
+  IFACEMETHODIMP_(DWRITE_READING_DIRECTION)
+    GetParagraphReadingDirection() { return mReadingDirection; }
+
+  IFACEMETHODIMP GetLocaleName(UINT32 textPosition,
+    UINT32* textLength,
+    WCHAR const** localeName) {
+    return S_OK;
+  }
+
+  IFACEMETHODIMP
+    GetNumberSubstitution(UINT32 textPosition,
+    OUT UINT32* textLength,
+    OUT IDWriteNumberSubstitution** numberSubstitution)
+  {
+    // We do not support number substitution.
+    *numberSubstitution = NULL;
+    *textLength = mTextLength - textPosition;
+
+    return S_OK;
+  }
+
+  // IDWriteTextAnalysisSink implementation
+
+  IFACEMETHODIMP
+    SetScriptAnalysis(UINT32 textPosition,
+    UINT32 textLength,
+    DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis)
+  {
+    SetCurrentRun(textPosition);
+    SplitCurrentRun(textPosition);
+    while (textLength > 0) {
+      Run *run = FetchNextRun(&textLength);
+      run->mScript = *scriptAnalysis;
+    }
+
+    return S_OK;
+  }
+
+  IFACEMETHODIMP
+    SetLineBreakpoints(UINT32 textPosition,
+    UINT32 textLength,
+    const DWRITE_LINE_BREAKPOINT* lineBreakpoints) { return S_OK; }
+
+  IFACEMETHODIMP SetBidiLevel(UINT32 textPosition,
+    UINT32 textLength,
+    UINT8 explicitLevel,
+    UINT8 resolvedLevel) { return S_OK; }
+
+  IFACEMETHODIMP
+    SetNumberSubstitution(UINT32 textPosition,
+    UINT32 textLength,
+    IDWriteNumberSubstitution* numberSubstitution) { return S_OK; }
+
+protected:
+  Run *FetchNextRun(IN OUT UINT32* textLength)
+  {
+    // Used by the sink setters, this returns a reference to the next run.
+    // Position and length are adjusted to now point after the current run
+    // being returned.
+
+    Run *origRun = mCurrentRun;
+    // Split the tail if needed (the length remaining is less than the
+    // current run's size).
+    if (*textLength < mCurrentRun->mTextLength) {
+      SplitCurrentRun(mCurrentRun->mTextStart + *textLength);
+    }
+    else {
+      // Just advance the current run.
+      mCurrentRun = mCurrentRun->nextRun;
+    }
+    *textLength -= origRun->mTextLength;
+
+    // Return a reference to the run that was just current.
+    return origRun;
+  }
+
+  void SetCurrentRun(UINT32 textPosition)
+  {
+    // Move the current run to the given position.
+    // Since the analyzers generally return results in a forward manner,
+    // this will usually just return early. If not, find the
+    // corresponding run for the text position.
+
+    if (mCurrentRun && mCurrentRun->ContainsTextPosition(textPosition)) {
+      return;
+    }
+
+    for (Run *run = &mRunHead; run; run = run->nextRun) {
+      if (run->ContainsTextPosition(textPosition)) {
+        mCurrentRun = run;
+        return;
+      }
+    }
+    //NS_NOTREACHED("We should always be able to find the text position in one \
+            //                of our runs");
+  }
+
+  void SplitCurrentRun(UINT32 splitPosition)
+  {
+    if (!mCurrentRun) {
+      //NS_ASSERTION(false, "SplitCurrentRun called without current run.");
+      // Shouldn't be calling this when no current run is set!
+      return;
+    }
+    // Split the current run.
+    if (splitPosition <= mCurrentRun->mTextStart) {
+      // No need to split, already the start of a run
+      // or before it. Usually the first.
+      return;
+    }
+    Run *newRun = new Run;
+
+    *newRun = *mCurrentRun;
+
+    // Insert the new run in our linked list.
+    newRun->nextRun = mCurrentRun->nextRun;
+    mCurrentRun->nextRun = newRun;
+
+    // Adjust runs' text positions and lengths.
+    UINT32 splitPoint = splitPosition - mCurrentRun->mTextStart;
+    newRun->mTextStart += splitPoint;
+    newRun->mTextLength -= splitPoint;
+    mCurrentRun->mTextLength = splitPoint;
+    mCurrentRun = newRun;
+  }
+
+protected:
+  // Input
+  // (weak references are fine here, since this class is a transient
+  //  stack-based helper that doesn't need to copy data)
+  UINT32 mTextLength;
+  const WCHAR* mText;
+  const WCHAR* mLocaleName;
+  DWRITE_READING_DIRECTION mReadingDirection;
+
+  // Current processing state.
+  Run *mCurrentRun;
+
+  // Output is a list of runs starting here
+  Run  mRunHead;
+};
+
+
+/*
+ * shaper
+ */
+
+hb_bool_t
+_hb_directwrite_shape(hb_shape_plan_t    *shape_plan,
+  hb_font_t          *font,
+  hb_buffer_t        *buffer,
+  const hb_feature_t *features,
+  unsigned int        num_features)
+{
+  hb_face_t *face = font->face;
+  hb_directwrite_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+  hb_directwrite_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
+
+  // factory probably should be cached
+  IDWriteFactory* dwriteFactory;
+  DWriteCreateFactory(
+    DWRITE_FACTORY_TYPE_SHARED,
+    __uuidof(IDWriteFactory),
+    reinterpret_cast<IUnknown**>(&dwriteFactory)
+    );
+
+  IDWriteGdiInterop *gdiInterop;
+  dwriteFactory->GetGdiInterop (&gdiInterop);
+  IDWriteFontFace* fontFace;
+  gdiInterop->CreateFontFaceFromHdc (font_data->hdc, &fontFace);
+
+  IDWriteTextAnalyzer* analyzer;
+  dwriteFactory->CreateTextAnalyzer (&analyzer);
+
+  unsigned int scratch_size;
+  hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
+#define ALLOCATE_ARRAY(Type, name, len) \
+  Type *name = (Type *) scratch; \
+  { \
+    unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
+    assert (_consumed <= scratch_size); \
+    scratch += _consumed; \
+    scratch_size -= _consumed; \
+  }
+
+#define utf16_index() var1.u32
+
+  ALLOCATE_ARRAY(WCHAR, pchars, buffer->len * 2);
+
+  unsigned int chars_len = 0;
+  for (unsigned int i = 0; i < buffer->len; i++)
+  {
+    hb_codepoint_t c = buffer->info[i].codepoint;
+    buffer->info[i].utf16_index() = chars_len;
+    if (likely(c <= 0xFFFFu))
+      pchars[chars_len++] = c;
+    else if (unlikely(c > 0x10FFFFu))
+      pchars[chars_len++] = 0xFFFDu;
+    else {
+      pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
+      pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1));
+    }
+  }
+
+  ALLOCATE_ARRAY(WORD, log_clusters, chars_len);
+  if (num_features)
+  {
+    /* Need log_clusters to assign features. */
+    chars_len = 0;
+    for (unsigned int i = 0; i < buffer->len; i++)
+    {
+      hb_codepoint_t c = buffer->info[i].codepoint;
+      unsigned int cluster = buffer->info[i].cluster;
+      log_clusters[chars_len++] = cluster;
+      if (hb_in_range(c, 0x10000u, 0x10FFFFu))
+        log_clusters[chars_len++] = cluster; /* Surrogates. */
+    }
+  }
+
+  HRESULT hr;
+  // TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES
+
+  DWRITE_READING_DIRECTION readingDirection = buffer->props.direction ? 
+    DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
+    DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
+
+  /*
+  * There's an internal 16-bit limit on some things inside the analyzer,
+  * but we never attempt to shape a word longer than 64K characters
+  * in a single gfxShapedWord, so we cannot exceed that limit.
+  */
+  UINT32 length = buffer->len;
+
+  TextAnalysis analysis(pchars, length, NULL, readingDirection);
+  TextAnalysis::Run *runHead;
+  hr = analysis.GenerateResults(analyzer, &runHead);
+
+  if (FAILED(hr)) {
+    //NS_WARNING("Analyzer failed to generate results.");
+    return false;
+  }
+
+  UINT32 maxGlyphs = 3 * length / 2 + 16;
+
+#define INITIAL_GLYPH_SIZE 400
+  UINT16* clusters = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16));
+  UINT16* glyphs = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16));
+  DWRITE_SHAPING_TEXT_PROPERTIES* textProperties = (DWRITE_SHAPING_TEXT_PROPERTIES*)
+    malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_TEXT_PROPERTIES));
+  DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties = (DWRITE_SHAPING_GLYPH_PROPERTIES*)
+    malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
+
+  UINT32 actualGlyphs;
+
+  bool backward = HB_DIRECTION_IS_BACKWARD(buffer->props.direction);
+
+  wchar_t lang[4];
+  mbstowcs(lang, hb_language_to_string(buffer->props.language), 4);
+  hr = analyzer->GetGlyphs(pchars, length,
+    fontFace, FALSE,
+    buffer->props.direction,
+    &runHead->mScript, (const wchar_t*)lang, NULL, NULL, NULL, 0,
+    maxGlyphs, clusters, textProperties,
+    glyphs, glyphProperties, &actualGlyphs);
+
+  if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) {
+    free(clusters);
+    free(glyphs);
+    free(textProperties);
+    free(glyphProperties);
+
+    clusters = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16));
+    glyphs = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16));
+    textProperties = (DWRITE_SHAPING_TEXT_PROPERTIES*)
+      malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_TEXT_PROPERTIES));
+    glyphProperties = (DWRITE_SHAPING_GLYPH_PROPERTIES*)
+      malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
+
+    hr = analyzer->GetGlyphs(pchars, length,
+      fontFace, FALSE,
+      buffer->props.direction,
+      &runHead->mScript, (const wchar_t*)lang, NULL, NULL, NULL, 0,
+      maxGlyphs, clusters, textProperties,
+      glyphs, glyphProperties, &actualGlyphs);
+  }
+  if (FAILED(hr)) {
+    //NS_WARNING("Analyzer failed to get glyphs.");
+    return false;
+  }
+
+  FLOAT advances[400];
+  DWRITE_GLYPH_OFFSET offsets[400];
+
+
+  /* The -2 in the following is to compensate for possible
+   * alignment needed after the WORD array.  sizeof(WORD) == 2. */
+  unsigned int glyphs_size = (scratch_size * sizeof (int)-2)
+    / (sizeof (WORD) +
+    4 + // sizeof (SCRIPT_GLYPHPROP) +
+    sizeof (int) +
+    8 + // sizeof (GOFFSET) +
+    sizeof (uint32_t));
+  ALLOCATE_ARRAY(uint32_t, vis_clusters, glyphs_size);
+
+#undef ALLOCATE_ARRAY
+
+  hr = analyzer->GetGlyphPlacements(pchars,
+    clusters,
+    textProperties,
+    length,
+    glyphs,
+    glyphProperties,
+    actualGlyphs,
+    fontFace,
+    face->get_upem(),
+    FALSE,
+    FALSE,
+    &runHead->mScript,
+    NULL,
+    NULL,
+    NULL,
+    0,
+    advances,
+    offsets);
+
+  if (FAILED(hr)) {
+    //NS_WARNING("Analyzer failed to get glyph placements.");
+    return false;
+  }
+
+  unsigned int glyphs_len = actualGlyphs;
+
+  /* Ok, we've got everything we need, now compose output buffer,
+   * very, *very*, carefully! */
+
+  /* Calculate visual-clusters.  That's what we ship. */
+  for (unsigned int i = 0; i < glyphs_len; i++)
+    vis_clusters[i] = -1;
+  for (unsigned int i = 0; i < buffer->len; i++) {
+    uint32_t *p = &vis_clusters[log_clusters[buffer->info[i].utf16_index()]];
+    //*p = MIN (*p, buffer->info[i].cluster);
+  }
+  for (unsigned int i = 1; i < glyphs_len; i++)
+    if (vis_clusters[i] == -1)
+      vis_clusters[i] = vis_clusters[i - 1];
+
+#undef utf16_index
+
+  //if (unlikely (!buffer->ensure (glyphs_len)))
+  //  FAIL ("Buffer in error");
+
+#undef FAIL
+
+  /* Set glyph infos */
+  buffer->len = 0;
+  for (unsigned int i = 0; i < glyphs_len; i++)
+  {
+    hb_glyph_info_t *info = &buffer->info[buffer->len++];
+
+    info->codepoint = glyphs[i];
+    info->cluster = vis_clusters[i];
+
+    /* The rest is crap.  Let's store position info there for now. */
+    info->mask = advances[i];
+    info->var1.u32 = offsets[i].ascenderOffset;
+    info->var2.u32 = -offsets[i].advanceOffset;
+  }
+
+  free(clusters);
+  free(glyphs);
+  free(textProperties);
+  free(glyphProperties);
+
+  /* Set glyph positions */
+  buffer->clear_positions ();
+  for (unsigned int i = 0; i < glyphs_len; i++)
+  {
+    hb_glyph_info_t *info = &buffer->info[i];
+    hb_glyph_position_t *pos = &buffer->pos[i];
+
+    /* TODO vertical */
+    pos->x_advance = info->mask;
+    pos->x_offset = backward ? -info->var1.u32 : info->var1.u32;
+    pos->y_offset = info->var2.u32;
+  }
+
+  if (backward)
+    hb_buffer_reverse (buffer);
+
+  /* Wow, done! */
+  return true;
+}
diff --git a/third_party/harfbuzz-ng/src/hb-directwrite.h b/third_party/harfbuzz-ng/src/hb-directwrite.h
new file mode 100644
index 0000000..adf33df
--- /dev/null
+++ b/third_party/harfbuzz-ng/src/hb-directwrite.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright © 2015  Ebrahim Byagowi
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#ifndef HB_DIRECTWRITE_H
+#define HB_DIRECTWRITE_H
+
+#include "hb.h"
+
+HB_BEGIN_DECLS
+
+HB_END_DECLS
+
+#endif /* HB_UNISCRIBE_H */
diff --git a/third_party/harfbuzz-ng/src/hb-graphite2.cc b/third_party/harfbuzz-ng/src/hb-graphite2.cc
index f41093ae..c32318d 100644
--- a/third_party/harfbuzz-ng/src/hb-graphite2.cc
+++ b/third_party/harfbuzz-ng/src/hb-graphite2.cc
@@ -216,6 +216,7 @@
   unsigned int base_glyph;
   unsigned int num_glyphs;
   unsigned int cluster;
+  float advance;
 };
 
 hb_bool_t
@@ -310,6 +311,12 @@
 
   hb_codepoint_t *pg = gids;
   clusters[0].cluster = buffer->info[0].cluster;
+  float curradv = HB_DIRECTION_IS_BACKWARD(buffer->props.direction) ? gr_slot_origin_X(gr_seg_first_slot(seg)) : 0.;
+  if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
+  {
+    curradv = gr_slot_origin_X(gr_seg_first_slot(seg));
+    clusters[0].advance = gr_seg_advance_X(seg) - curradv;
+  }
   for (is = gr_seg_first_slot (seg), ic = 0; is; is = gr_slot_next_in_segment (is), ic++)
   {
     unsigned int before = gr_slot_before (is);
@@ -320,6 +327,7 @@
     {
       clusters[ci-1].num_chars += clusters[ci].num_chars;
       clusters[ci-1].num_glyphs += clusters[ci].num_glyphs;
+      clusters[ci-1].advance += clusters[ci].advance;
       ci--;
     }
 
@@ -331,13 +339,24 @@
       c->num_chars = before - c->base_char;
       c->base_glyph = ic;
       c->num_glyphs = 0;
-      ci++;
+      if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
+      {
+        ci++;
+        clusters[ci].advance = curradv - gr_slot_origin_X(is);
+      } else {
+        clusters[ci].advance = gr_slot_origin_X(is) - curradv;
+        ci++;
+      }
+      curradv = gr_slot_origin_X(is);
     }
     clusters[ci].num_glyphs++;
 
     if (clusters[ci].base_char + clusters[ci].num_chars < after + 1)
 	clusters[ci].num_chars = after + 1 - clusters[ci].base_char;
   }
+
+  if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
+    clusters[ci].advance = gr_seg_advance_X(seg) - curradv;
   ci++;
 
   for (unsigned int i = 0; i < ci; ++i)
@@ -347,6 +366,7 @@
       hb_glyph_info_t *info = &buffer->info[clusters[i].base_glyph + j];
       info->codepoint = gids[clusters[i].base_glyph + j];
       info->cluster = clusters[i].cluster;
+      info->var1.i32 = clusters[i].advance;     // all glyphs in the cluster get the same advance
     }
   }
   buffer->len = glyph_count;
@@ -355,49 +375,44 @@
   /* Positioning. */
   if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
   {
-    hb_glyph_position_t *pPos;
-    for (pPos = hb_buffer_get_glyph_positions (buffer, NULL), is = gr_seg_first_slot (seg);
-         is; pPos++, is = gr_slot_next_in_segment (is))
+    int currclus = -1;
+    const hb_glyph_info_t *info = buffer->info;
+    hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, NULL);
+    curradvx = 0;
+    for (is = gr_seg_first_slot (seg); is; pPos++, ++info, is = gr_slot_next_in_segment (is))
     {
       pPos->x_offset = gr_slot_origin_X (is) - curradvx;
       pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
-      pPos->x_advance = gr_slot_advance_X (is, grface, grfont);
+      if (info->cluster != currclus) {
+        pPos->x_advance = info->var1.i32;
+        curradvx += pPos->x_advance;
+        currclus = info->cluster;
+      } else
+        pPos->x_advance = 0.;
+
       pPos->y_advance = gr_slot_advance_Y (is, grface, grfont) * yscale;
-      curradvx += pPos->x_advance;
       curradvy += pPos->y_advance;
     }
-    pPos[-1].x_advance += gr_seg_advance_X(seg) - curradvx;
   }
   else
   {
-    hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, NULL) + buffer->len - 1;
-    const hb_glyph_info_t *info = buffer->info + buffer->len - 1;
-    const hb_glyph_info_t *tinfo;
-    const gr_slot *tis;
     int currclus = -1;
-    float clusx = 0., clusy = 0.;
-    for (is = gr_seg_last_slot (seg); is; pPos--, info--, is = gr_slot_prev_in_segment (is))
+    const hb_glyph_info_t *info = buffer->info;
+    hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, NULL);
+    curradvx = gr_seg_advance_X(seg);
+    for (is = gr_seg_first_slot (seg); is; pPos++, info++, is = gr_slot_next_in_segment (is))
     {
       if (info->cluster != currclus)
       {
-        curradvx += clusx;
-        curradvy += clusy;
+        pPos->x_advance = info->var1.i32;
+        if (currclus != -1) curradvx -= info[-1].var1.i32;
         currclus = info->cluster;
-        clusx = 0.;
-        clusy = 0.;
-        for (tis = is, tinfo = info; tis && tinfo->cluster == currclus; tis = gr_slot_prev_in_segment (tis), tinfo--)
-        {
-          clusx += gr_slot_advance_X (tis, grface, grfont);
-          clusy += gr_slot_advance_Y (tis, grface, grfont) * yscale;
-        }
-        curradvx += clusx;
-        curradvy += clusy;
-      }
-      pPos->x_advance = gr_slot_advance_X (is, grface, grfont);
+      } else
+      pPos->x_advance = 0.;
+
       pPos->y_advance = gr_slot_advance_Y (is, grface, grfont) * yscale;
-      curradvx -= pPos->x_advance;
       curradvy -= pPos->y_advance;
-      pPos->x_offset = gr_slot_origin_X (is) - curradvx;
+      pPos->x_offset = gr_slot_origin_X (is) - curradvx + pPos->x_advance;
       pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
     }
     hb_buffer_reverse_clusters (buffer);
diff --git a/third_party/harfbuzz-ng/src/hb-open-file-private.hh b/third_party/harfbuzz-ng/src/hb-open-file-private.hh
index 152230a..5357ddc 100644
--- a/third_party/harfbuzz-ng/src/hb-open-file-private.hh
+++ b/third_party/harfbuzz-ng/src/hb-open-file-private.hh
@@ -140,7 +140,7 @@
 
   protected:
   Tag		ttcTag;		/* TrueType Collection ID string: 'ttcf' */
-  FixedVersion	version;	/* Version of the TTC Header (1.0),
+  FixedVersion<>version;	/* Version of the TTC Header (1.0),
 				 * 0x00010000u */
   ArrayOf<OffsetTo<OffsetTable, ULONG>, ULONG>
 		table;		/* Array of offsets to the OffsetTable for each font
@@ -187,7 +187,7 @@
   union {
   struct {
   Tag		ttcTag;		/* TrueType Collection ID string: 'ttcf' */
-  FixedVersion	version;	/* Version of the TTC Header (1.0 or 2.0),
+  FixedVersion<>version;	/* Version of the TTC Header (1.0 or 2.0),
 				 * 0x00010000u or 0x00020000u */
   }			header;
   TTCHeaderVersion1	version1;
diff --git a/third_party/harfbuzz-ng/src/hb-open-type-private.hh b/third_party/harfbuzz-ng/src/hb-open-type-private.hh
index 6323da8..6a52000 100644
--- a/third_party/harfbuzz-ng/src/hb-open-type-private.hh
+++ b/third_party/harfbuzz-ng/src/hb-open-type-private.hh
@@ -739,9 +739,10 @@
  * Version Numbers
  */
 
+template <typename FixedType=USHORT>
 struct FixedVersion
 {
-  inline uint32_t to_int (void) const { return (major << 16) + minor; }
+  inline uint32_t to_int (void) const { return (major << sizeof(FixedType)) + minor; }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -749,10 +750,10 @@
     return_trace (c->check_struct (this));
   }
 
-  USHORT major;
-  USHORT minor;
+  FixedType major;
+  FixedType minor;
   public:
-  DEFINE_SIZE_STATIC (4);
+  DEFINE_SIZE_STATIC (2 * sizeof(FixedType));
 };
 
 
diff --git a/third_party/harfbuzz-ng/src/hb-ot-head-table.hh b/third_party/harfbuzz-ng/src/hb-ot-head-table.hh
index 60644be..9c3e51eb 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-head-table.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-head-table.hh
@@ -61,9 +61,9 @@
   }
 
   protected:
-  FixedVersion	version;		/* Version of the head table--currently
+  FixedVersion<>version;		/* Version of the head table--currently
 					 * 0x00010000u for version 1.0. */
-  FixedVersion	fontRevision;		/* Set by font manufacturer. */
+  FixedVersion<>fontRevision;		/* Set by font manufacturer. */
   ULONG		checkSumAdjustment;	/* To compute: set it to 0, sum the
 					 * entire font as ULONG, then store
 					 * 0xB1B0AFBAu - sum. */
diff --git a/third_party/harfbuzz-ng/src/hb-ot-hhea-table.hh b/third_party/harfbuzz-ng/src/hb-ot-hhea-table.hh
index 2411453..c8e9536 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-hhea-table.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-hhea-table.hh
@@ -56,7 +56,7 @@
   }
 
   public:
-  FixedVersion	version;		/* 0x00010000u for version 1.0. */
+  FixedVersion<>version;		/* 0x00010000u for version 1.0. */
   FWORD		ascender;		/* Typographic ascent. */
   FWORD		descender;		/* Typographic descent. */
   FWORD		lineGap;		/* Typographic line gap. */
diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-common-private.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-common-private.hh
index 64829ac..6c7bac09 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-layout-common-private.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-layout-common-private.hh
@@ -1170,6 +1170,21 @@
   inline hb_position_t get_y_delta (hb_font_t *font) const
   { return get_delta (font->y_ppem, font->y_scale); }
 
+  inline unsigned int get_size (void) const
+  {
+    unsigned int f = deltaFormat;
+    if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size;
+    return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f)));
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && c->check_range (this, this->get_size ()));
+  }
+
+  private:
+
   inline int get_delta (unsigned int ppem, int scale) const
   {
     if (!ppem) return 0;
@@ -1180,8 +1195,6 @@
 
     return (int) (pixels * (int64_t) scale / ppem);
   }
-
-
   inline int get_delta_pixels (unsigned int ppem_size) const
   {
     unsigned int f = deltaFormat;
@@ -1205,19 +1218,6 @@
     return delta;
   }
 
-  inline unsigned int get_size (void) const
-  {
-    unsigned int f = deltaFormat;
-    if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size;
-    return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f)));
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && c->check_range (this, this->get_size ()));
-  }
-
   protected:
   USHORT	startSize;		/* Smallest size to correct--in ppem */
   USHORT	endSize;		/* Largest size to correct--in ppem */
diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-gdef-table.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-gdef-table.hh
index bc36436..2b4bc5a 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-layout-gdef-table.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-layout-gdef-table.hh
@@ -409,7 +409,7 @@
 
 
   protected:
-  FixedVersion	version;		/* Version of the GDEF table--currently
+  FixedVersion<>version;		/* Version of the GDEF table--currently
 					 * 0x00010002u */
   OffsetTo<ClassDef>
 		glyphClassDef;		/* Offset to class definition table
diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-gpos-table.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-gpos-table.hh
index 5ea70fb..bbe390c 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-layout-gpos-table.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-layout-gpos-table.hh
@@ -36,8 +36,17 @@
 
 
 /* buffer **position** var allocations */
-#define attach_lookback() var.u16[0] /* number of glyphs to go back to attach this glyph to its base */
-#define cursive_chain() var.i16[1] /* character to which this connects, may be positive or negative */
+#define attach_chain() var.i16[0] /* glyph to which this attaches to, relative to current glyphs; negative for going back, positive for forward. */
+#define attach_type() var.u8[2] /* attachment type */
+/* Note! if attach_chain() is zero, the value of attach_type() is irrelevant. */
+
+enum attach_type_t {
+  ATTACH_TYPE_NONE	= 0X00,
+
+  /* Each attachment should be either a mark or a cursive; can't be both. */
+  ATTACH_TYPE_MARK	= 0X01,
+  ATTACH_TYPE_CURSIVE	= 0X02,
+};
 
 
 /* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
@@ -425,7 +434,8 @@
     hb_glyph_position_t &o = buffer->cur_pos();
     o.x_offset = base_x - mark_x;
     o.y_offset = base_y - mark_y;
-    o.attach_lookback() = buffer->idx - glyph_pos;
+    o.attach_type() = ATTACH_TYPE_MARK;
+    o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
     buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
 
     buffer->idx++;
@@ -907,9 +917,6 @@
     TRACE_APPLY (this);
     hb_buffer_t *buffer = c->buffer;
 
-    /* We don't handle mark glyphs here. */
-    if (unlikely (_hb_glyph_info_is_mark (&buffer->cur()))) return_trace (false);
-
     const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (buffer->cur().codepoint)];
     if (!this_record.exitAnchor) return_trace (false);
 
@@ -993,8 +1000,9 @@
      */
     reverse_cursive_minor_offset (pos, child, c->direction, parent);
 
-    pos[child].cursive_chain() = parent - child;
-    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_CURSIVE;
+    pos[child].attach_type() = ATTACH_TYPE_CURSIVE;
+    pos[child].attach_chain() = (int) parent - (int) child;
+    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
     if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
       pos[child].y_offset = y_offset;
     else
@@ -1069,7 +1077,7 @@
     unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
     if (likely (mark_index == NOT_COVERED)) return_trace (false);
 
-    /* now we search backwards for a non-mark glyph */
+    /* Now we search backwards for a non-mark glyph */
     hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
     skippy_iter.reset (buffer->idx, 1);
     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
@@ -1081,7 +1089,7 @@
     } while (1);
 
     /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
-    if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { /*return_trace (false);*/ }
+    //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); }
 
     unsigned int base_index = (this+baseCoverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint);
     if (base_index == NOT_COVERED) return_trace (false);
@@ -1170,14 +1178,14 @@
     unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
     if (likely (mark_index == NOT_COVERED)) return_trace (false);
 
-    /* now we search backwards for a non-mark glyph */
+    /* Now we search backwards for a non-mark glyph */
     hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
     skippy_iter.reset (buffer->idx, 1);
     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
     if (!skippy_iter.prev ()) return_trace (false);
 
     /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
-    if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { /*return_trace (false);*/ }
+    //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); }
 
     unsigned int j = skippy_iter.idx;
     unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[j].codepoint);
@@ -1501,7 +1509,8 @@
   { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
 
   static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
-  static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer);
+  static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer);
+  static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer);
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -1518,13 +1527,13 @@
 static void
 reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent)
 {
-  unsigned int j = pos[i].cursive_chain();
-  if (likely (!j))
+  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
+  if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE)))
     return;
 
-  j += i;
+  pos[i].attach_chain() = 0;
 
-  pos[i].cursive_chain() = 0;
+  unsigned int j = (int) i + chain;
 
   /* Stop if we see new parent in the chain. */
   if (j == new_parent)
@@ -1537,62 +1546,68 @@
   else
     pos[j].x_offset = -pos[i].x_offset;
 
-  pos[j].cursive_chain() = i - j;
+  pos[j].attach_chain() = -chain;
+  pos[j].attach_type() = type;
 }
 static void
-fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
+propagate_attachment_offsets (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
 {
-  unsigned int j = pos[i].cursive_chain();
-  if (likely (!j))
+  /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate
+   * offset of glyph they are attached to. */
+  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
+  if (likely (!chain))
     return;
 
-  j += i;
+  unsigned int j = (int) i + chain;
 
-  pos[i].cursive_chain() = 0;
+  pos[i].attach_chain() = 0;
 
-  fix_cursive_minor_offset (pos, j, direction);
+  propagate_attachment_offsets (pos, j, direction);
 
-  if (HB_DIRECTION_IS_HORIZONTAL (direction))
-    pos[i].y_offset += pos[j].y_offset;
-  else
+  assert (!!(type & ATTACH_TYPE_MARK) ^ !!(type & ATTACH_TYPE_CURSIVE));
+
+  if (type & ATTACH_TYPE_CURSIVE)
+  {
+    if (HB_DIRECTION_IS_HORIZONTAL (direction))
+      pos[i].y_offset += pos[j].y_offset;
+    else
+      pos[i].x_offset += pos[j].x_offset;
+  }
+  else /*if (type & ATTACH_TYPE_MARK)*/
+  {
     pos[i].x_offset += pos[j].x_offset;
-}
+    pos[i].y_offset += pos[j].y_offset;
 
-static void
-fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
-{
-  if (likely (!(pos[i].attach_lookback())))
-    return;
-
-  unsigned int j = i - pos[i].attach_lookback();
-
-  pos[i].x_offset += pos[j].x_offset;
-  pos[i].y_offset += pos[j].y_offset;
-
-  if (HB_DIRECTION_IS_FORWARD (direction))
-    for (unsigned int k = j; k < i; k++) {
-      pos[i].x_offset -= pos[k].x_advance;
-      pos[i].y_offset -= pos[k].y_advance;
-    }
-  else
-    for (unsigned int k = j + 1; k < i + 1; k++) {
-      pos[i].x_offset += pos[k].x_advance;
-      pos[i].y_offset += pos[k].y_advance;
-    }
+    assert (j < i);
+    if (HB_DIRECTION_IS_FORWARD (direction))
+      for (unsigned int k = j; k < i; k++) {
+	pos[i].x_offset -= pos[k].x_advance;
+	pos[i].y_offset -= pos[k].y_advance;
+      }
+    else
+      for (unsigned int k = j + 1; k < i + 1; k++) {
+	pos[i].x_offset += pos[k].x_advance;
+	pos[i].y_offset += pos[k].y_advance;
+      }
+  }
 }
 
 void
 GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
 {
-  buffer->clear_positions ();
-
   unsigned int count = buffer->len;
   for (unsigned int i = 0; i < count; i++)
-    buffer->pos[i].attach_lookback() = buffer->pos[i].cursive_chain() = 0;
+    buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0;
 }
 
 void
-GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
+GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
+{
+  //_hb_buffer_assert_gsubgpos_vars (buffer);
+}
+
+void
+GPOS::position_finish_offsets (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
 {
   _hb_buffer_assert_gsubgpos_vars (buffer);
 
@@ -1600,15 +1615,10 @@
   hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
   hb_direction_t direction = buffer->props.direction;
 
-  /* Handle cursive connections */
-  if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_CURSIVE)
-    for (unsigned int i = 0; i < len; i++)
-      fix_cursive_minor_offset (pos, i, direction);
-
   /* Handle attachments */
   if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
     for (unsigned int i = 0; i < len; i++)
-      fix_mark_attachment (pos, i, direction);
+      propagate_attachment_offsets (pos, i, direction);
 }
 
 
@@ -1637,8 +1647,8 @@
 }
 
 
-#undef attach_lookback
-#undef cursive_chain
+#undef attach_chain
+#undef attach_type
 
 
 } /* namespace OT */
diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-gsub-table.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-gsub-table.hh
index 459a1a3..38c2c64 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-layout-gsub-table.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-layout-gsub-table.hh
@@ -1268,7 +1268,6 @@
   { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
 
   static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
-  static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer);
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -1297,11 +1296,6 @@
   }
 }
 
-void
-GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
-{
-}
-
 
 /* Out-of-class implementation for methods recursing */
 
diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh
index d6db0056..691334c 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh
@@ -971,7 +971,7 @@
       match_positions[j] += delta;
   }
 
-  for (unsigned int i = 0; i < lookupCount; i++)
+  for (unsigned int i = 0; i < lookupCount && !buffer->in_error; i++)
   {
     unsigned int idx = lookupRecord[i].sequenceIndex;
     if (idx >= count)
@@ -2277,7 +2277,7 @@
   }
 
   protected:
-  FixedVersion	version;	/* Version of the GSUB/GPOS table--initially set
+  FixedVersion<>version;	/* Version of the GSUB/GPOS table--initially set
 				 * to 0x00010000u */
   OffsetTo<ScriptList>
 		scriptList;  	/* ScriptList table */
diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-jstf-table.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-jstf-table.hh
index 7e199c2..c306849 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-layout-jstf-table.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-layout-jstf-table.hh
@@ -218,7 +218,7 @@
   }
 
   protected:
-  FixedVersion	version;	/* Version of the JSTF table--initially set
+  FixedVersion<>version;	/* Version of the JSTF table--initially set
 				 * to 0x00010000u */
   RecordArrayOf<JstfScript>
 		scriptList;  	/* Array of JstfScripts--listed
diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh
index f48184fd..b5c670f 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh
@@ -99,21 +99,20 @@
 				const hb_ot_layout_lookup_accelerator_t &accel);
 
 
-/* Should be called after all the substitute_lookup's are done */
-HB_INTERNAL void
-hb_ot_layout_substitute_finish (hb_font_t    *font,
-				hb_buffer_t  *buffer);
-
-
-/* Should be called before all the position_lookup's are done.  Resets positions to zero. */
+/* Should be called before all the position_lookup's are done. */
 HB_INTERNAL void
 hb_ot_layout_position_start (hb_font_t    *font,
 			     hb_buffer_t  *buffer);
 
-/* Should be called after all the position_lookup's are done */
+/* Should be called after all the position_lookup's are done, to finish advances. */
 HB_INTERNAL void
-hb_ot_layout_position_finish (hb_font_t    *font,
-			      hb_buffer_t  *buffer);
+hb_ot_layout_position_finish_advances (hb_font_t    *font,
+				       hb_buffer_t  *buffer);
+
+/* Should be called after hb_ot_layout_position_finish_advances, to finish offsets. */
+HB_INTERNAL void
+hb_ot_layout_position_finish_offsets (hb_font_t    *font,
+				      hb_buffer_t  *buffer);
 
 
 
@@ -257,8 +256,11 @@
       if (u == 0x200Cu) props |= UPROPS_MASK_ZWNJ;
       if (u == 0x200Du) props |= UPROPS_MASK_ZWJ;
     }
-    else if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK (gen_cat)))
+    else if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK_OR_MODIFIER_SYMBOL (gen_cat)))
     {
+      /* The above check is just an optimization to let in only things we need further
+       * processing on. */
+
       /* Only Mn and Mc can have non-zero ccc:
        * http://www.unicode.org/policies/stability_policy.html#Property_Value
        * """
@@ -273,6 +275,16 @@
        * the "else if".
        */
       props |= unicode->modified_combining_class (info->codepoint)<<8;
+
+      /* Recategorize emoji skin-tone modifiers as Unicode mark, so they
+       * behave correctly in non-native directionality.  They originally
+       * are MODIFIER_SYMBOL.  Fixes:
+       * https://github.com/behdad/harfbuzz/issues/169
+       */
+      if (unlikely (hb_in_range (u, 0x1F3FBu, 0x1F3FFu)))
+      {
+	props = gen_cat = HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK;
+      }
     }
   }
 
@@ -353,6 +365,12 @@
   return !!(info->unicode_props() & UPROPS_MASK_ZWJ);
 }
 
+static inline hb_bool_t
+_hb_glyph_info_is_joiner (const hb_glyph_info_t *info)
+{
+  return !!(info->unicode_props() & (UPROPS_MASK_ZWNJ | UPROPS_MASK_ZWJ));
+}
+
 static inline void
 _hb_glyph_info_flip_joiners (hb_glyph_info_t *info)
 {
diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout.cc b/third_party/harfbuzz-ng/src/hb-ot-layout.cc
index 9fc88f6..adf232bf1 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-layout.cc
+++ b/third_party/harfbuzz-ng/src/hb-ot-layout.cc
@@ -771,12 +771,6 @@
   OT::GSUB::substitute_start (font, buffer);
 }
 
-void
-hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer)
-{
-  OT::GSUB::substitute_finish (font, buffer);
-}
-
 /**
  * hb_ot_layout_lookup_substitute_closure:
  *
@@ -811,9 +805,15 @@
 }
 
 void
-hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer)
+hb_ot_layout_position_finish_advances (hb_font_t *font, hb_buffer_t *buffer)
 {
-  OT::GPOS::position_finish (font, buffer);
+  OT::GPOS::position_finish_advances (font, buffer);
+}
+
+void
+hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
+{
+  OT::GPOS::position_finish_offsets (font, buffer);
 }
 
 /**
@@ -902,20 +902,79 @@
 };
 
 
-template <typename Obj>
+struct hb_get_subtables_context_t :
+       OT::hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY>
+{
+  template <typename Type>
+  static inline bool apply_to (const void *obj, OT::hb_apply_context_t *c)
+  {
+    const Type *typed_obj = (const Type *) obj;
+    return typed_obj->apply (c);
+  }
+
+  typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_apply_context_t *c);
+
+  struct hb_applicable_t
+  {
+    inline void init (const void *obj_, hb_apply_func_t apply_func_)
+    {
+      obj = obj_;
+      apply_func = apply_func_;
+    }
+
+    inline bool apply (OT::hb_apply_context_t *c) const { return apply_func (obj, c); }
+
+    private:
+    const void *obj;
+    hb_apply_func_t apply_func;
+  };
+
+  typedef hb_auto_array_t<hb_applicable_t> array_t;
+
+  /* Dispatch interface. */
+  inline const char *get_name (void) { return "GET_SUBTABLES"; }
+  template <typename T>
+  inline return_t dispatch (const T &obj)
+  {
+    hb_applicable_t *entry = array.push();
+    if (likely (entry))
+      entry->init (&obj, apply_to<T>);
+    return HB_VOID;
+  }
+  static return_t default_return_value (void) { return HB_VOID; }
+  bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
+
+  hb_get_subtables_context_t (array_t &array_) :
+			      array (array_),
+			      debug_depth (0) {}
+
+  array_t &array;
+  unsigned int debug_depth;
+};
+
 static inline bool
 apply_forward (OT::hb_apply_context_t *c,
-	       const Obj &obj,
-	       const hb_ot_layout_lookup_accelerator_t &accel)
+	       const hb_ot_layout_lookup_accelerator_t &accel,
+	       const hb_get_subtables_context_t::array_t &subtables)
 {
   bool ret = false;
   hb_buffer_t *buffer = c->buffer;
   while (buffer->idx < buffer->len && !buffer->in_error)
   {
+    bool applied = false;
     if (accel.may_have (buffer->cur().codepoint) &&
 	(buffer->cur().mask & c->lookup_mask) &&
-	c->check_glyph_property (&buffer->cur(), c->lookup_props) &&
-	obj.apply (c))
+	c->check_glyph_property (&buffer->cur(), c->lookup_props))
+     {
+       for (unsigned int i = 0; i < subtables.len; i++)
+         if (subtables[i].apply (c))
+	 {
+	   applied = true;
+	   break;
+	 }
+     }
+
+    if (applied)
       ret = true;
     else
       buffer->next_glyph ();
@@ -923,11 +982,10 @@
   return ret;
 }
 
-template <typename Obj>
 static inline bool
 apply_backward (OT::hb_apply_context_t *c,
-		const Obj &obj,
-		const hb_ot_layout_lookup_accelerator_t &accel)
+	       const hb_ot_layout_lookup_accelerator_t &accel,
+	       const hb_get_subtables_context_t::array_t &subtables)
 {
   bool ret = false;
   hb_buffer_t *buffer = c->buffer;
@@ -935,9 +993,15 @@
   {
     if (accel.may_have (buffer->cur().codepoint) &&
 	(buffer->cur().mask & c->lookup_mask) &&
-	c->check_glyph_property (&buffer->cur(), c->lookup_props) &&
-	obj.apply (c))
-      ret = true;
+	c->check_glyph_property (&buffer->cur(), c->lookup_props))
+    {
+     for (unsigned int i = 0; i < subtables.len; i++)
+       if (subtables[i].apply (c))
+       {
+	 ret = true;
+	 break;
+       }
+    }
     /* The reverse lookup doesn't "advance" cursor (for good reason). */
     buffer->idx--;
 
@@ -946,26 +1010,6 @@
   return ret;
 }
 
-struct hb_apply_forward_context_t :
-       OT::hb_dispatch_context_t<hb_apply_forward_context_t, bool, HB_DEBUG_APPLY>
-{
-  inline const char *get_name (void) { return "APPLY_FWD"; }
-  template <typename T>
-  inline return_t dispatch (const T &obj) { return apply_forward (c, obj, accel); }
-  static return_t default_return_value (void) { return false; }
-  bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return true; }
-
-  hb_apply_forward_context_t (OT::hb_apply_context_t *c_,
-			      const hb_ot_layout_lookup_accelerator_t &accel_) :
-				c (c_),
-				accel (accel_),
-				debug_depth (0) {}
-
-  OT::hb_apply_context_t *c;
-  const hb_ot_layout_lookup_accelerator_t &accel;
-  unsigned int debug_depth;
-};
-
 template <typename Proxy>
 static inline void
 apply_string (OT::hb_apply_context_t *c,
@@ -979,6 +1023,10 @@
 
   c->set_lookup_props (lookup.get_props ());
 
+  hb_get_subtables_context_t::array_t subtables;
+  hb_get_subtables_context_t c_get_subtables (subtables);
+  lookup.dispatch (&c_get_subtables);
+
   if (likely (!lookup.is_reverse ()))
   {
     /* in/out forward substitution/positioning */
@@ -987,13 +1035,7 @@
     buffer->idx = 0;
 
     bool ret;
-    if (lookup.get_subtable_count () == 1)
-    {
-      hb_apply_forward_context_t c_forward (c, accel);
-      ret = lookup.dispatch (&c_forward);
-    }
-    else
-      ret = apply_forward (c, lookup, accel);
+    ret = apply_forward (c, accel, subtables);
     if (ret)
     {
       if (!Proxy::inplace)
@@ -1009,7 +1051,7 @@
       buffer->remove_output ();
     buffer->idx = buffer->len - 1;
 
-    apply_backward (c, lookup, accel);
+    apply_backward (c, accel, subtables);
   }
 }
 
diff --git a/third_party/harfbuzz-ng/src/hb-ot-maxp-table.hh b/third_party/harfbuzz-ng/src/hb-ot-maxp-table.hh
index 27105af1..943e390 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-maxp-table.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-maxp-table.hh
@@ -58,7 +58,7 @@
 
   /* We only implement version 0.5 as none of the extra fields in version 1.0 are useful. */
   protected:
-  FixedVersion	version;		/* Version of the maxp table (0.5 or 1.0),
+  FixedVersion<>version;		/* Version of the maxp table (0.5 or 1.0),
 					 * 0x00005000u or 0x00010000u. */
   USHORT	numGlyphs;		/* The number of glyphs in the font. */
   public:
diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic.cc b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic.cc
index 880aa91..21256de 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic.cc
+++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic.cc
@@ -1246,7 +1246,7 @@
       /* TODO Set glyph_props? */
 
       /* Insert dottedcircle after possible Repha. */
-      while (buffer->idx < buffer->len &&
+      while (buffer->idx < buffer->len && !buffer->in_error &&
 	     last_syllable == buffer->cur().syllable() &&
 	     buffer->cur().indic_category() == OT_Repha)
         buffer->next_glyph ();
diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-myanmar.cc b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-myanmar.cc
index 4d34468..7b043440 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-myanmar.cc
+++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-myanmar.cc
@@ -451,7 +451,7 @@
 
   buffer->idx = 0;
   unsigned int last_syllable = 0;
-  while (buffer->idx < buffer->len)
+  while (buffer->idx < buffer->len && !buffer->in_error)
   {
     unsigned int syllable = buffer->cur().syllable();
     syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-thai.cc b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-thai.cc
index bd7c5e14..58392b6 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-thai.cc
+++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-thai.cc
@@ -377,6 +377,6 @@
   NULL, /* decompose */
   NULL, /* compose */
   NULL, /* setup_masks */
-  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE,
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   false,/* fallback_position */
 };
diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-tibetan.cc b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-tibetan.cc
index 03bcfee..a77b531 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-tibetan.cc
+++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-tibetan.cc
@@ -57,6 +57,6 @@
   NULL, /* decompose */
   NULL, /* compose */
   NULL, /* setup_masks */
-  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE,
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
   true, /* fallback_position */
 };
diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-use.cc b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-use.cc
index 0f667833..6fbfe2b5 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-use.cc
+++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-use.cc
@@ -522,7 +522,7 @@
       /* TODO Set glyph_props? */
 
       /* Insert dottedcircle after possible Repha. */
-      while (buffer->idx < buffer->len &&
+      while (buffer->idx < buffer->len && !buffer->in_error &&
 	     last_syllable == buffer->cur().syllable() &&
 	     buffer->cur().use_category() == USE_R)
         buffer->next_glyph ();
@@ -583,6 +583,6 @@
   NULL, /* decompose */
   compose_use,
   setup_masks_use,
-  HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
   false, /* fallback_position */
 };
diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape.cc b/third_party/harfbuzz-ng/src/hb-ot-shape.cc
index 1d9783e..c13d94b 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-shape.cc
+++ b/third_party/harfbuzz-ng/src/hb-ot-shape.cc
@@ -145,7 +145,7 @@
 struct hb_ot_shaper_font_data_t {};
 
 hb_ot_shaper_font_data_t *
-_hb_ot_shaper_font_data_create (hb_font_t *font)
+_hb_ot_shaper_font_data_create (hb_font_t *font HB_UNUSED)
 {
   return (hb_ot_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
@@ -267,13 +267,14 @@
       buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
     return;
 
-  /* Loop duplicated in hb_ensure_native_direction(). */
+  /* Loop duplicated in hb_ensure_native_direction(), and in _hb-coretext.cc */
   unsigned int base = 0;
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 1; i < count; i++)
   {
-    if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i]))))
+    if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])) &&
+		!_hb_glyph_info_is_joiner (&info[i])))
     {
       buffer->merge_clusters (base, i);
       base = i;
@@ -584,8 +585,6 @@
 
   c->plan->substitute (c->font, buffer);
 
-  hb_ot_layout_substitute_finish (c->font, buffer);
-
   return;
 }
 
@@ -635,10 +634,6 @@
 static inline void
 zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets)
 {
-  /* This one is a hack; Technically GDEF can mark ASCII glyphs as marks, but we don't listen. */
-  if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII))
-    return;
-
   unsigned int count = buffer->len;
   hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
@@ -686,9 +681,12 @@
 static inline bool
 hb_ot_position_complex (hb_ot_shape_context_t *c)
 {
+  hb_ot_layout_position_start (c->font, c->buffer);
+
   bool ret = false;
   unsigned int count = c->buffer->len;
   bool has_positioning = (bool) hb_ot_layout_has_positioning (c->face);
+
   /* If the font has no GPOS, AND, no fallback positioning will
    * happen, AND, direction is forward, then when zeroing mark
    * widths, we shift the mark with it, such that the mark
@@ -763,22 +761,23 @@
       break;
   }
 
+  /* Finishing off GPOS has to follow a certain order. */
+  hb_ot_layout_position_finish_advances (c->font, c->buffer);
+  hb_ot_zero_width_default_ignorables (c);
+  hb_ot_layout_position_finish_offsets (c->font, c->buffer);
+
   return ret;
 }
 
 static inline void
 hb_ot_position (hb_ot_shape_context_t *c)
 {
-  hb_ot_layout_position_start (c->font, c->buffer);
+  c->buffer->clear_positions ();
 
   hb_ot_position_default (c);
 
   hb_bool_t fallback = !hb_ot_position_complex (c);
 
-  hb_ot_zero_width_default_ignorables (c);
-
-  hb_ot_layout_position_finish (c->font, c->buffer);
-
   if (fallback && c->plan->shaper->fallback_position)
     _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer);
 
diff --git a/third_party/harfbuzz-ng/src/hb-ot-tag.cc b/third_party/harfbuzz-ng/src/hb-ot-tag.cc
index 5a3f4f9..9a6a120 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-tag.cc
+++ b/third_party/harfbuzz-ng/src/hb-ot-tag.cc
@@ -927,7 +927,7 @@
   }
 }
 
-#if 0
+#ifdef MAIN
 static inline void
 test_langs_sorted (void)
 {
@@ -942,9 +942,7 @@
     }
   }
 }
-#endif
 
-#ifdef MAIN
 int
 main (void)
 {
diff --git a/third_party/harfbuzz-ng/src/hb-unicode-private.hh b/third_party/harfbuzz-ng/src/hb-unicode-private.hh
index ecbec51..44fbe582 100644
--- a/third_party/harfbuzz-ng/src/hb-unicode-private.hh
+++ b/third_party/harfbuzz-ng/src/hb-unicode-private.hh
@@ -357,9 +357,10 @@
 	  FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | \
 	  FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
 
-#define HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK(gen_cat) \
+#define HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK_OR_MODIFIER_SYMBOL(gen_cat) \
 	(FLAG_SAFE (gen_cat) & \
 	 (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
-	  FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
+	  FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | \
+	  FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL)))
 
 #endif /* HB_UNICODE_PRIVATE_HH */
diff --git a/third_party/harfbuzz-ng/src/hb-version.h b/third_party/harfbuzz-ng/src/hb-version.h
index 848720f..3456e7d 100644
--- a/third_party/harfbuzz-ng/src/hb-version.h
+++ b/third_party/harfbuzz-ng/src/hb-version.h
@@ -37,10 +37,10 @@
 
 
 #define HB_VERSION_MAJOR 1
-#define HB_VERSION_MINOR 1
-#define HB_VERSION_MICRO 3
+#define HB_VERSION_MINOR 2
+#define HB_VERSION_MICRO 1
 
-#define HB_VERSION_STRING "1.1.3"
+#define HB_VERSION_STRING "1.2.1"
 
 #define HB_VERSION_ATLEAST(major,minor,micro) \
 	((major)*10000+(minor)*100+(micro) <= \
diff --git a/third_party/leakcanary/BUILD.gn b/third_party/leakcanary/BUILD.gn
new file mode 100644
index 0000000..e88a64fa
--- /dev/null
+++ b/third_party/leakcanary/BUILD.gn
@@ -0,0 +1,126 @@
+# Copyright 2016 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("//build/config/android/rules.gni")
+import("config.gni")
+
+java_group("leakcanary_java") {
+  if (enable_leakcanary) {
+    deps = [
+      ":leakcanary_impl_java",
+    ]
+  } else {
+    deps = [
+      ":leakcanary_noop_java",
+    ]
+  }
+}
+
+android_library("leakcanary_noop_java") {
+  java_files = [
+    "src/leakcanary-android-no-op/src/main/java/com/squareup/leakcanary/LeakCanary.java",
+    "src/leakcanary-android-no-op/src/main/java/com/squareup/leakcanary/RefWatcher.java",
+  ]
+}
+
+_wanted_resource_files = [
+  "src/leakcanary-android/src/main/res/drawable-xxxhdpi-v11/leak_canary_notification.png",
+  "src/leakcanary-android/src/main/res/drawable-xxhdpi-v11/leak_canary_notification.png",
+  "src/leakcanary-android/src/main/res/drawable-xhdpi/leak_canary_notification.png",
+  "src/leakcanary-android/src/main/res/drawable-xhdpi/leak_canary_icon.png",
+  "src/leakcanary-android/src/main/res/drawable-mdpi-v11/leak_canary_notification.png",
+  "src/leakcanary-android/src/main/res/drawable-xxxhdpi/leak_canary_notification.png",
+  "src/leakcanary-android/src/main/res/drawable-xxxhdpi/leak_canary_icon.png",
+  "src/leakcanary-android/src/main/res/drawable-hdpi/leak_canary_notification.png",
+  "src/leakcanary-android/src/main/res/drawable-hdpi/leak_canary_icon.png",
+  "src/leakcanary-android/src/main/res/drawable-hdpi-v11/leak_canary_notification.png",
+  "src/leakcanary-android/src/main/res/values/leak_canary_themes.xml",
+  "src/leakcanary-android/src/main/res/values/leak_canary_int.xml",
+  "src/leakcanary-android/src/main/res/values/leak_canary_strings.xml",
+  "src/leakcanary-android/src/main/res/drawable/leak_canary_toast_background.xml",
+  "src/leakcanary-android/src/main/res/drawable-xxhdpi/leak_canary_notification.png",
+  "src/leakcanary-android/src/main/res/drawable-xxhdpi/leak_canary_icon.png",
+  "src/leakcanary-android/src/main/res/drawable-xhdpi-v11/leak_canary_notification.png",
+  "src/leakcanary-android/src/main/res/drawable-mdpi/leak_canary_notification.png",
+  "src/leakcanary-android/src/main/res/drawable-mdpi/leak_canary_icon.png",
+  "src/leakcanary-android/src/main/res/values-v21/leak_canary_themes.xml",
+  "src/leakcanary-android/src/main/res/layout/leak_canary_leak_row.xml",
+  "src/leakcanary-android/src/main/res/layout/leak_canary_heap_dump_toast.xml",
+  "src/leakcanary-android/src/main/res/layout/leak_canary_display_leak.xml",
+  "src/leakcanary-android/src/main/res/layout/leak_canary_ref_top_row.xml",
+  "src/leakcanary-android/src/main/res/layout/leak_canary_ref_row.xml",
+  "src/leakcanary-android/src/main/res/values-v14/leak_canary_themes.xml",
+]
+
+# This is required to remove:
+#   "src/leakcanary-android/src/main/res/values/leak_canary_public.xml",
+# which is meant for .aar, and breaks aapt normally.
+copy("leakcanary_resources_copy") {
+  sources = _wanted_resource_files
+  outputs = [
+    "$target_gen_dir/copied-resources/{{source}}",
+  ]
+}
+
+android_resources("leakcanary_resources") {
+  custom_package = "com.squareup.leakcanary"
+  resource_dirs = []
+  generated_resource_dirs = [ "$target_gen_dir/copied-resources/third_party/leakcanary/src/leakcanary-android/src/main/res" ]
+  generated_resource_files =
+      process_file_template(_wanted_resource_files,
+                            [ "$target_gen_dir/copied-resources/{{source}}" ])
+  deps = [
+    ":leakcanary_resources_copy",
+  ]
+}
+
+android_library("leakcanary_impl_java") {
+  chromium_code = false
+  java_files = [
+    "leakcanary-android-build-config/com/squareup/leakcanary/BuildConfig.java",
+    "src/leakcanary-analyzer/src/main/java/com/squareup/haha/perflib/HahaSpy.java",
+    "src/leakcanary-analyzer/src/main/java/com/squareup/leakcanary/AnalysisResult.java",
+    "src/leakcanary-analyzer/src/main/java/com/squareup/leakcanary/HahaHelper.java",
+    "src/leakcanary-analyzer/src/main/java/com/squareup/leakcanary/HeapAnalyzer.java",
+    "src/leakcanary-analyzer/src/main/java/com/squareup/leakcanary/LeakNode.java",
+    "src/leakcanary-analyzer/src/main/java/com/squareup/leakcanary/LeakTraceElement.java",
+    "src/leakcanary-analyzer/src/main/java/com/squareup/leakcanary/LeakTrace.java",
+    "src/leakcanary-analyzer/src/main/java/com/squareup/leakcanary/ShortestPathFinder.java",
+    "src/leakcanary-android/src/main/java/com/squareup/leakcanary/AbstractAnalysisResultService.java",
+    "src/leakcanary-android/src/main/java/com/squareup/leakcanary/ActivityRefWatcher.java",
+    "src/leakcanary-android/src/main/java/com/squareup/leakcanary/AndroidDebuggerControl.java",
+    "src/leakcanary-android/src/main/java/com/squareup/leakcanary/AndroidExcludedRefs.java",
+    "src/leakcanary-android/src/main/java/com/squareup/leakcanary/AndroidHeapDumper.java",
+    "src/leakcanary-android/src/main/java/com/squareup/leakcanary/AndroidWatchExecutor.java",
+    "src/leakcanary-android/src/main/java/com/squareup/leakcanary/CanaryLog.java",
+    "src/leakcanary-android/src/main/java/com/squareup/leakcanary/DefaultLeakDirectoryProvider.java",
+    "src/leakcanary-android/src/main/java/com/squareup/leakcanary/DisplayLeakService.java",
+    "src/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/DisplayLeakActivity.java",
+    "src/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/DisplayLeakAdapter.java",
+    "src/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/DisplayLeakConnectorView.java",
+    "src/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/FutureResult.java",
+    "src/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/HeapAnalyzerService.java",
+    "src/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/LeakCanaryInternals.java",
+    "src/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/LeakCanarySingleThreadFactory.java",
+    "src/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/LeakCanaryUi.java",
+    "src/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/MoreDetailsView.java",
+    "src/leakcanary-android/src/main/java/com/squareup/leakcanary/internal/RequestStoragePermissionActivity.java",
+    "src/leakcanary-android/src/main/java/com/squareup/leakcanary/LeakCanary.java",
+    "src/leakcanary-android/src/main/java/com/squareup/leakcanary/LeakDirectoryProvider.java",
+    "src/leakcanary-android/src/main/java/com/squareup/leakcanary/ServiceHeapDumpListener.java",
+    "src/leakcanary-watcher/src/main/java/com/squareup/leakcanary/DebuggerControl.java",
+    "src/leakcanary-watcher/src/main/java/com/squareup/leakcanary/ExcludedRefs.java",
+    "src/leakcanary-watcher/src/main/java/com/squareup/leakcanary/Exclusion.java",
+    "src/leakcanary-watcher/src/main/java/com/squareup/leakcanary/GcTrigger.java",
+    "src/leakcanary-watcher/src/main/java/com/squareup/leakcanary/HeapDumper.java",
+    "src/leakcanary-watcher/src/main/java/com/squareup/leakcanary/HeapDump.java",
+    "src/leakcanary-watcher/src/main/java/com/squareup/leakcanary/KeyedWeakReference.java",
+    "src/leakcanary-watcher/src/main/java/com/squareup/leakcanary/Preconditions.java",
+    "src/leakcanary-watcher/src/main/java/com/squareup/leakcanary/RefWatcher.java",
+  ]
+  deps = [
+    ":leakcanary_resources",
+    "//third_party/haha",
+  ]
+}
diff --git a/third_party/leakcanary/LICENSE b/third_party/leakcanary/LICENSE
new file mode 100644
index 0000000..7a4a3ea
--- /dev/null
+++ b/third_party/leakcanary/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
\ No newline at end of file
diff --git a/third_party/leakcanary/OWNERS b/third_party/leakcanary/OWNERS
new file mode 100644
index 0000000..dbccb98
--- /dev/null
+++ b/third_party/leakcanary/OWNERS
@@ -0,0 +1,2 @@
+agrieve@chromium.org
+yfriedman@chromium.org
diff --git a/third_party/leakcanary/README.chromium b/third_party/leakcanary/README.chromium
new file mode 100644
index 0000000..483fe2047
--- /dev/null
+++ b/third_party/leakcanary/README.chromium
@@ -0,0 +1,20 @@
+Name: LeakCanary
+URL: https://github.com/square/leakcanary
+Version: 1.4-beta1
+Revision: 608ded739e036a3aa69db47ac43777dcee506f8e
+License: Apache 2.0
+License File: LICENSE
+Security Critical: no
+
+Description:
+A Java memory leak detection library for Android.
+
+Local Modifications:
+* Added leakcanary-android-build-config/com/squareup/leakcanary/BuildConfig.java
+
+How to Roll:
+1. Update hash in DEPS
+2. Update list of Java and resource files in BUILD.gn
+3. Update any AndroidManifest.xml within the codebase that contains "leakcanary"
+4. Update version in:
+   leakcanary-android-build-config/com/squareup/leakcanary/BuildConfig.java
diff --git a/third_party/leakcanary/config.gni b/third_party/leakcanary/config.gni
new file mode 100644
index 0000000..f6adcddf
--- /dev/null
+++ b/third_party/leakcanary/config.gni
@@ -0,0 +1,7 @@
+# Copyright 2016 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.
+
+declare_args() {
+  enable_leakcanary = false
+}
diff --git a/third_party/leakcanary/leakcanary-android-build-config/com/squareup/leakcanary/BuildConfig.java b/third_party/leakcanary/leakcanary-android-build-config/com/squareup/leakcanary/BuildConfig.java
new file mode 100644
index 0000000..4882cad
--- /dev/null
+++ b/third_party/leakcanary/leakcanary-android-build-config/com/squareup/leakcanary/BuildConfig.java
@@ -0,0 +1,10 @@
+// Copyright 2015 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.
+package com.squareup.leakcanary;
+
+// Normally generated by Gradle.
+class BuildConfig {
+    static final String LIBRARY_VERSION = "1.4-beta1 (chromium)";
+    static final String GIT_SHA = "unknown"; // Unlikely to be kept up-to-date, so don't try.
+}
diff --git a/third_party/leakcanary/leakcanary.gyp b/third_party/leakcanary/leakcanary.gyp
new file mode 100644
index 0000000..eb143e7
--- /dev/null
+++ b/third_party/leakcanary/leakcanary.gyp
@@ -0,0 +1,18 @@
+# Copyright 2016 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.
+
+{
+  'targets': [
+    {
+      # Leak Canary added to GN only.
+      'target_name': 'leakcanary_java',
+      'type': 'none',
+      'variables': {
+        'java_in_dir': 'src/leakcanary-android-no-op/src/main',
+        'java_in_dir_suffix': '/java',
+      },
+      'includes': [ '../../build/java.gypi' ],
+    },
+  ],
+}
diff --git a/third_party/lzma_sdk/CpuArch.c b/third_party/lzma_sdk/CpuArch.c
index edb6b08..8f009459 100644
--- a/third_party/lzma_sdk/CpuArch.c
+++ b/third_party/lzma_sdk/CpuArch.c
@@ -79,8 +79,11 @@
 
   #else
 
+  // When built using GCC and -fPIC (until GCC 5.0), ebx points to the global
+  // offset table, so the value must be preserved before executing cpuid.
+  // Attempting to explicitly clobber ebx is a compile-time error.
   __asm__ __volatile__ (
-  #if defined(MY_CPU_AMD64)
+  #if defined(MY_CPU_AMD64) && defined(__PIC__)
     "mov %%rbx, %%rdi\n"
     "cpuid\n"
     "xchg %%rdi, %%rbx\n"
@@ -102,7 +105,7 @@
     : "0" (function)) ;
 
   #endif
-  
+
   #else
 
   int CPUInfo[4];
diff --git a/third_party/lzma_sdk/README.chromium b/third_party/lzma_sdk/README.chromium
index 4b2106b..bcd3d21 100644
--- a/third_party/lzma_sdk/README.chromium
+++ b/third_party/lzma_sdk/README.chromium
@@ -14,5 +14,5 @@
 compression has been included.
 
 The patch in chromium.patch was applied to CpuArch.c to fix register corruption
-that can occur on 64-bit platforms and register clobbering that occurred on Mac
-builds (but in principle can occur anywhere).
+that can occur on 64-bit platforms built with -fPIC and register clobbering that
+occurred on Mac builds (but in principle can occur anywhere).
diff --git a/third_party/lzma_sdk/chromium.patch b/third_party/lzma_sdk/chromium.patch
index ec15101..1c5c880 100644
--- a/third_party/lzma_sdk/chromium.patch
+++ b/third_party/lzma_sdk/chromium.patch
@@ -1,5 +1,5 @@
---- a\CpuArch.c	2015-03-25 08:17:41.042711000 -0400
-+++ lzma_sdk\CpuArch.c	2016-02-12 16:32:45.484718900 -0500
+--- /usr/local/google/home/waffles/Downloads/C/CpuArch.c	2015-03-25 05:17:41.000000000 -0700
++++ CpuArch.c	2016-02-19 12:42:20.327993932 -0800
 @@ -45,7 +45,8 @@
      "push %%EDX\n\t"
      "popf\n\t"
@@ -10,12 +10,16 @@
    #endif
    return flag;
  }
-@@ -79,7 +80,13 @@
+@@ -78,8 +79,17 @@
+ 
    #else
  
++  // When built using GCC and -fPIC (until GCC 5.0), ebx points to the global
++  // offset table, so the value must be preserved before executing cpuid.
++  // Attempting to explicitly clobber ebx is a compile-time error.
    __asm__ __volatile__ (
 -  #if defined(MY_CPU_X86) && defined(__PIC__)
-+  #if defined(MY_CPU_AMD64)
++  #if defined(MY_CPU_AMD64) && defined(__PIC__)
 +    "mov %%rbx, %%rdi\n"
 +    "cpuid\n"
 +    "xchg %%rdi, %%rbx\n"
diff --git a/third_party/minigbm/BUILD.gn b/third_party/minigbm/BUILD.gn
index 03b6f5d243..d76c3ac 100644
--- a/third_party/minigbm/BUILD.gn
+++ b/third_party/minigbm/BUILD.gn
@@ -23,7 +23,7 @@
     packages = [ "libdrm" ]
   }
 
-  static_library("minigbm") {
+  shared_library("minigbm") {
     sources = [
       "src/cirrus.c",
       "src/exynos.c",
diff --git a/third_party/minigbm/minigbm.gyp b/third_party/minigbm/minigbm.gyp
index 564f0e8..3a07fe6 100644
--- a/third_party/minigbm/minigbm.gyp
+++ b/third_party/minigbm/minigbm.gyp
@@ -11,7 +11,7 @@
       'targets': [
         {
           'target_name': 'minigbm',
-          'type': 'static_library',
+          'type': 'shared_library',
           'dependencies' : [
             '../../build/linux/system.gyp:libdrm',
           ],
diff --git a/tools/android/loading/chrome_cache.py b/tools/android/loading/chrome_cache.py
new file mode 100644
index 0000000..d6d65a2
--- /dev/null
+++ b/tools/android/loading/chrome_cache.py
@@ -0,0 +1,295 @@
+# Copyright 2016 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.
+
+"""Takes care of manipulating the chrome's HTTP cache.
+"""
+
+from datetime import datetime
+import json
+import os
+import subprocess
+import sys
+import tempfile
+import zipfile
+
+_SRC_DIR = os.path.abspath(os.path.join(
+    os.path.dirname(__file__), '..', '..', '..'))
+
+sys.path.append(os.path.join(_SRC_DIR, 'build', 'android'))
+from pylib import constants
+
+import options
+
+
+OPTIONS = options.OPTIONS
+
+
+# Cache back-end types supported by cachetool.
+BACKEND_TYPES = ['simple']
+
+# Default build output directory.
+OUT_DIRECTORY = os.getenv('CR_OUT_FULL', os.path.join(
+    os.path.dirname(__file__), '../../../out/Release'))
+
+# Default cachetool binary location.
+CACHETOOL_BIN_PATH = os.path.join(OUT_DIRECTORY, 'cachetool')
+
+
+def _RemoteCacheDirectory():
+  """Returns the path of the cache directory's on the remote device."""
+  return '/data/data/{}/cache/Cache'.format(
+      constants.PACKAGE_INFO[OPTIONS.chrome_package_name].package)
+
+
+def _UpdateTimestampFromAdbStat(filename, stat):
+  os.utime(filename, (stat.st_time, stat.st_time))
+
+
+def _AdbShell(adb, cmd):
+  adb.Shell(subprocess.list2cmdline(cmd))
+
+
+def _AdbUtime(adb, filename, timestamp):
+  """Adb equivalent of os.utime(filename, (timestamp, timestamp))
+  """
+  touch_stamp = datetime.fromtimestamp(timestamp).strftime('%Y%m%d.%H%M%S')
+  _AdbShell(adb, ['touch', '-t', touch_stamp, filename])
+
+
+def PullBrowserCache(device):
+  """Pulls the browser cache from the device and saves it locally.
+
+  Cache is saved with the same file structure as on the device. Timestamps are
+  important to preserve because indexing and eviction depends on them.
+
+  Returns:
+    Temporary directory containing all the browser cache.
+  """
+  _INDEX_DIRECTORY_NAME = 'index-dir'
+  _REAL_INDEX_FILE_NAME = 'the-real-index'
+
+  remote_cache_directory = _RemoteCacheDirectory()
+  print remote_cache_directory
+  save_target = tempfile.mkdtemp(suffix='.cache')
+  for filename, stat in device.adb.Ls(remote_cache_directory):
+    if filename == '..':
+      continue
+    if filename == '.':
+      cache_directory_stat = stat
+      continue
+    original_file = os.path.join(remote_cache_directory, filename)
+    saved_file = os.path.join(save_target, filename)
+    device.adb.Pull(original_file, saved_file)
+    _UpdateTimestampFromAdbStat(saved_file, stat)
+    if filename == _INDEX_DIRECTORY_NAME:
+      # The directory containing the index was pulled recursively, update the
+      # timestamps for known files. They are ignored by cache backend, but may
+      # be useful for debugging.
+      index_dir_stat = stat
+      saved_index_dir = os.path.join(save_target, _INDEX_DIRECTORY_NAME)
+      saved_index_file = os.path.join(saved_index_dir, _REAL_INDEX_FILE_NAME)
+      for sub_file, sub_stat in device.adb.Ls(original_file):
+        if sub_file == _REAL_INDEX_FILE_NAME:
+          _UpdateTimestampFromAdbStat(saved_index_file, sub_stat)
+          break
+      _UpdateTimestampFromAdbStat(saved_index_dir, index_dir_stat)
+
+  # Store the cache directory modification time. It is important to update it
+  # after all files in it have been written. The timestamp is compared with
+  # the contents of the index file when freshness is determined.
+  _UpdateTimestampFromAdbStat(save_target, cache_directory_stat)
+  return save_target
+
+
+def PushBrowserCache(device, local_cache_path):
+  """Pushes the browser cache saved locally to the device.
+
+  Args:
+    device: Android device.
+    local_cache_path: The directory's path containing the cache locally.
+  """
+  remote_cache_directory = _RemoteCacheDirectory()
+
+  # Clear previous cache.
+  _AdbShell(device.adb, ['rm', '-rf', remote_cache_directory])
+  _AdbShell(device.adb, ['mkdir', remote_cache_directory])
+
+  # Push cache content.
+  device.adb.Push(local_cache_path, remote_cache_directory)
+
+  # Walk through the local cache to update mtime on the device.
+  def MirrorMtime(local_path):
+    cache_relative_path = os.path.relpath(local_path, start=local_cache_path)
+    remote_path = os.path.join(remote_cache_directory, cache_relative_path)
+    _AdbUtime(device.adb, remote_path, os.stat(local_path).st_mtime)
+
+  for local_directory_path, dirnames, filenames in os.walk(
+        local_cache_path, topdown=False):
+    for filename in filenames:
+      MirrorMtime(os.path.join(local_directory_path, filename))
+    for dirname in dirnames:
+      MirrorMtime(os.path.join(local_directory_path, dirname))
+  MirrorMtime(local_cache_path)
+
+
+def ZipDirectoryContent(root_directory_path, archive_dest_path):
+  """Zip a directory's content recursively with all the directories'
+  timestamps preserved.
+
+  Args:
+    root_directory_path: The directory's path to archive.
+    archive_dest_path: Archive destination's path.
+  """
+  with zipfile.ZipFile(archive_dest_path, 'w') as zip_output:
+    timestamps = {}
+    root_directory_stats = os.stat(root_directory_path)
+    timestamps['.'] = {
+        'atime': root_directory_stats.st_atime,
+        'mtime': root_directory_stats.st_mtime}
+    for directory_path, dirnames, filenames in os.walk(root_directory_path):
+      for dirname in dirnames:
+        subdirectory_path = os.path.join(directory_path, dirname)
+        subdirectory_relative_path = os.path.relpath(subdirectory_path,
+                                                     root_directory_path)
+        subdirectory_stats = os.stat(subdirectory_path)
+        timestamps[subdirectory_relative_path] = {
+            'atime': subdirectory_stats.st_atime,
+            'mtime': subdirectory_stats.st_mtime}
+      for filename in filenames:
+        file_path = os.path.join(directory_path, filename)
+        file_archive_name = os.path.join('content',
+            os.path.relpath(file_path, root_directory_path))
+        file_stats = os.stat(file_path)
+        timestamps[file_archive_name[8:]] = {
+            'atime': file_stats.st_atime,
+            'mtime': file_stats.st_mtime}
+        zip_output.write(file_path, arcname=file_archive_name)
+    zip_output.writestr('timestamps.json',
+                        json.dumps(timestamps, indent=2))
+
+
+def UnzipDirectoryContent(archive_path, directory_dest_path):
+  """Unzip a directory's content recursively with all the directories'
+  timestamps preserved.
+
+  Args:
+    archive_path: Archive's path to unzip.
+    directory_dest_path: Directory destination path.
+  """
+  if not os.path.exists(directory_dest_path):
+    os.makedirs(directory_dest_path)
+
+  with zipfile.ZipFile(archive_path) as zip_input:
+    timestamps = None
+    for file_archive_name in zip_input.namelist():
+      if file_archive_name == 'timestamps.json':
+        timestamps = json.loads(zip_input.read(file_archive_name))
+      elif file_archive_name.startswith('content/'):
+        file_relative_path = file_archive_name[8:]
+        file_output_path = os.path.join(directory_dest_path, file_relative_path)
+        file_parent_directory_path = os.path.dirname(file_output_path)
+        if not os.path.exists(file_parent_directory_path):
+          os.makedirs(file_parent_directory_path)
+        with open(file_output_path, 'w') as f:
+          f.write(zip_input.read(file_archive_name))
+
+    assert timestamps
+    for relative_path, stats in timestamps.iteritems():
+      output_path = os.path.join(directory_dest_path, relative_path)
+      if not os.path.exists(output_path):
+        os.makedirs(output_path)
+      os.utime(output_path, (stats['atime'], stats['mtime']))
+
+
+class CacheBackend(object):
+  """Takes care of reading and deleting cached keys.
+  """
+
+  def __init__(self, cache_directory_path, cache_backend_type,
+               cachetool_bin_path=CACHETOOL_BIN_PATH):
+    """Chrome cache back-end constructor.
+
+    Args:
+      cache_directory_path: The directory path where the cache is locally
+        stored.
+      cache_backend_type: A cache back-end type in BACKEND_TYPES.
+      cachetool_bin_path: Path of the cachetool binary.
+    """
+    assert os.path.isdir(cache_directory_path)
+    assert cache_backend_type in BACKEND_TYPES
+    assert os.path.isfile(cachetool_bin_path), 'invalid ' + cachetool_bin_path
+    self._cache_directory_path = cache_directory_path
+    self._cache_backend_type = cache_backend_type
+    self._cachetool_bin_path = cachetool_bin_path
+    # Make sure cache_directory_path is a valid cache.
+    self._CachetoolCmd('validate')
+
+  def ListKeys(self):
+    """Lists cache's keys.
+
+    Returns:
+      A list of all keys stored in the cache.
+    """
+    return [k.strip() for k in self._CachetoolCmd('list_keys').split('\n')[:-1]]
+
+  def GetStreamForKey(self, key, index):
+    """Gets a key's stream.
+
+    Args:
+      key: The key to access the stream.
+      index: The stream index:
+          index=0 is the HTTP response header;
+          index=1 is the transport encoded content;
+          index=2 is the compiled content.
+
+    Returns:
+      String holding stream binary content.
+    """
+    return self._CachetoolCmd('get_stream', key, str(index))
+
+  def DeleteKey(self, key):
+    """Deletes a key from the cache.
+
+    Args:
+      key: The key delete.
+    """
+    self._CachetoolCmd('delete_key', key)
+
+  def _CachetoolCmd(self, operation, *args):
+    """Runs the cache editor tool and return the stdout.
+
+    Args:
+      operation: Cachetool operation.
+      *args: Additional operation argument to append to the command line.
+
+    Returns:
+      Cachetool's stdout string.
+    """
+    editor_tool_cmd = [
+        self._cachetool_bin_path,
+        self._cache_directory_path,
+        self._cache_backend_type,
+        operation]
+    editor_tool_cmd.extend(args)
+    process = subprocess.Popen(editor_tool_cmd, stdout=subprocess.PIPE)
+    stdout_data, _ = process.communicate()
+    assert process.returncode == 0
+    return stdout_data
+
+
+if __name__ == '__main__':
+  import argparse
+  parser = argparse.ArgumentParser(description='Tests cache back-end.')
+  parser.add_argument('cache_path', type=str)
+  parser.add_argument('backend_type', type=str, choices=BACKEND_TYPES)
+  command_line_args = parser.parse_args()
+
+  cache_backend = CacheBackend(
+      cache_directory_path=command_line_args.cache_path,
+      cache_backend_type=command_line_args.backend_type)
+  keys = cache_backend.ListKeys()
+  print '{}\'s HTTP response header:'.format(keys[0])
+  print cache_backend.GetStreamForKey(keys[0], 0)
+  cache_backend.DeleteKey(keys[1])
+  assert keys[1] not in cache_backend.ListKeys()
diff --git a/tools/android/loading/loading_model.py b/tools/android/loading/loading_model.py
index f9905a05..923183e 100644
--- a/tools/android/loading/loading_model.py
+++ b/tools/android/loading/loading_model.py
@@ -38,6 +38,7 @@
   EDGE_KIND_KEY = 'edge_kind'
   EDGE_KINDS = request_track.Request.INITIATORS + (
       'script_inferred', 'after-load', 'before-load', 'timing')
+
   def __init__(self, trace, content_lens=None, frame_lens=None,
                activity=None):
     """Create from a LoadingTrace (or json of a trace).
@@ -179,11 +180,13 @@
       if self._node_filter(n.Node()) and n.Url() in other_map:
         yield(n, other_map[n.Url()])
 
-  def Cost(self, path_list=None):
+  def Cost(self, path_list=None, costs_out=None):
     """Compute cost of current model.
 
     Args:
       path_list: if not None, gets a list of NodeInfo in the longest path.
+      costs_out: if not None, gets a vector of node costs by node index. Any
+        filtered nodes will have zero cost.
 
     Returns:
       Cost of the longest path.
@@ -199,6 +202,9 @@
         cost += self.NodeCost(n)
       costs[n.Index()] = cost
     max_cost = max(costs)
+    if costs_out is not None:
+      del costs_out[:-1]
+      costs_out.extend(costs)
     assert max_cost > 0  # Otherwise probably the filter went awry.
     if path_list is not None:
       del path_list[:-1]
@@ -385,7 +391,7 @@
 
     def EdgeAnnotations(self, s):
       assert s.Node() in self.Node().Successors()
-      return self._edge_annotations.get(s, [])
+      return self._edge_annotations.get(s, {})
 
     def ContentType(self):
       if self._request is None:
diff --git a/tools/android/loading/resource_sack.py b/tools/android/loading/resource_sack.py
new file mode 100644
index 0000000..493029c
--- /dev/null
+++ b/tools/android/loading/resource_sack.py
@@ -0,0 +1,181 @@
+# Copyright 2016 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.
+
+"""A collection of ResourceGraphs.
+
+Processes multiple ResourceGraphs, all presumably from requests to the same
+site. Common urls are collected in Bags and different statistics on the
+relationship between bags are collected.
+"""
+
+import collections
+import json
+import sys
+import urlparse
+
+from collections import defaultdict
+
+import content_classification_lens
+import dag
+import user_satisfied_lens
+
+class GraphSack(object):
+  """Aggreate of ResourceGraphs.
+
+  Collects ResourceGraph nodes into bags, where each bag contains the nodes with
+  common urls. Dependency edges are tracked between bags (so that each bag may
+  be considered as a node of a graph). This graph of bags is referred to as a
+  sack.
+
+  Each bag is associated with a dag.Node, even though the bag graph may not be a
+  DAG. The edges are annotated with list of graphs and nodes that generated
+  them.
+  """
+  _GraphInfo = collections.namedtuple('_GraphInfo', (
+      'cost',   # The graph cost (aka critical path length).
+      'total_costs',  # A vector by node index of total cost of each node.
+      ))
+
+  def __init__(self):
+    # A bag is a node in our combined graph.
+    self._bags = []
+    # Each bag in our sack corresponds to a url, as expressed by this map.
+    self._url_to_bag = {}
+    # Maps graph -> _GraphInfo structures for each graph we've consumed.
+    self._graph_info = {}
+
+  def ConsumeGraph(self, graph):
+    """Add a graph and process.
+
+    Args:
+      graph: (ResourceGraph) the graph to add. The graph is processed sorted
+        according to its current filter.
+    """
+    assert graph not in self._graph_info
+    critical_path = []
+    total_costs = []
+    cost = graph.Cost(path_list=critical_path,
+                      costs_out=total_costs)
+    self._graph_info[graph] = self._GraphInfo(
+        cost=cost, total_costs=total_costs)
+    for n in graph.Nodes(sort=True):
+      assert graph._node_filter(n.Node())
+      self.AddNode(graph, n)
+    for node in critical_path:
+      self._url_to_bag[node.Url()].MarkCritical()
+
+  def AddNode(self, graph, node):
+    """Add a node to our collection.
+
+    Args:
+      graph: (ResourceGraph) the graph in which the node lives.
+      node: (NodeInfo) the node to add.
+
+    Returns:
+      The Bag containing the node.
+    """
+    if not graph._node_filter(node):
+      return
+    if node.Url() not in self._url_to_bag:
+      new_index = len(self._bags)
+      self._bags.append(Bag(self, new_index, node.Url()))
+      self._url_to_bag[node.Url()] = self._bags[-1]
+    self._url_to_bag[node.Url()].AddNode(graph, node)
+    return self._url_to_bag[node.Url()]
+
+  @property
+  def graph_info(self):
+    return self._graph_info
+
+  @property
+  def bags(self):
+    return self._bags
+
+class Bag(dag.Node):
+  def __init__(self, sack, index, url):
+    super(Bag, self).__init__(index)
+    self._sack = sack
+    self._url = url
+    self._label = self._MakeShortname(url)
+    # Maps a ResourceGraph to its Nodes contained in this Bag.
+    self._graphs = defaultdict(set)
+    # Maps each successor bag to the set of (graph, node, graph-successor)
+    # tuples that generated it.
+    self._successor_sources = defaultdict(set)
+    # Maps each successor bag to a set of edge costs. This is just used to
+    # track min and max; if we want more statistics we'd have to count the
+    # costs with multiplicity.
+    self._successor_edge_costs = defaultdict(set)
+
+    # Miscellaneous counts and costs used in display.
+    self._total_costs = []
+    self._relative_costs = []
+    self._num_critical = 0
+
+  @property
+  def url(self):
+    return self._url
+
+  @property
+  def label(self):
+    return self._label
+
+  @property
+  def graphs(self):
+    return self._graphs
+
+  @property
+  def successor_sources(self):
+    return self._successor_sources
+
+  @property
+  def successor_edge_costs(self):
+    return self._successor_edge_costs
+
+  @property
+  def total_costs(self):
+    return self._total_costs
+
+  @property
+  def relative_costs(self):
+    return self._relative_costs
+
+  @property
+  def num_critical(self):
+    return self._num_critical
+
+  @property
+  def num_nodes(self):
+    return len(self._total_costs)
+
+  def MarkCritical(self):
+    self._num_critical += 1
+
+  def AddNode(self, graph, node):
+    if node in self._graphs[graph]:
+      return  # Already added.
+    graph_info = self._sack.graph_info[graph]
+    self._graphs[graph].add(node)
+    node_total_cost = graph_info.total_costs[node.Index()]
+    self._total_costs.append(node_total_cost)
+    self._relative_costs.append(
+        float(node_total_cost) / graph_info.cost)
+    for s in node.Node().Successors():
+      if not graph._node_filter(s):
+        continue
+      node_info = graph.NodeInfo(s)
+      successor_bag = self._sack.AddNode(graph, node_info)
+      self.AddSuccessor(successor_bag)
+      self._successor_sources[successor_bag].add((graph, node, s))
+      self._successor_edge_costs[successor_bag].add(graph.EdgeCost(node, s))
+
+  @classmethod
+  def _MakeShortname(cls, url):
+    parsed = urlparse.urlparse(url)
+    if parsed.scheme == 'data':
+      kind, _ = parsed.path.split(';', 1)
+      return 'data:' + kind
+    path = parsed.path[:10]
+    hostname = parsed.hostname if parsed.hostname else '?.?.?'
+    return hostname + '/' + path
diff --git a/tools/android/loading/resource_sack_display.py b/tools/android/loading/resource_sack_display.py
new file mode 100644
index 0000000..210f4da5
--- /dev/null
+++ b/tools/android/loading/resource_sack_display.py
@@ -0,0 +1,135 @@
+# Copyright 2016 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.
+
+"""Utilities for displaying a ResourceSack.
+
+When run standalone, takes traces on the command line and produces a dot file to
+stdout.
+"""
+
+
+def ToDot(sack, output, prune=-1, long_edge_msec=2000):
+  """Output as a dot file.
+
+  Args:
+    sack: (ResourceSack) the sack to convert to dot.
+    output: a file-like output stream.
+    prune: if positive, prune & coalesce nodes under the specified threshold
+      of repeated views, as fraction node views / total graphs. All pruned
+      nodes are represented by a single node, and an edge is connected only if
+      the view count is greater than 1.
+    long_edge_msec: if positive, the definition of a long edge. Long edges are
+      distinguished in graph.
+  """
+  output.write("""digraph dependencies {
+  rankdir = LR;
+  """)
+
+  pruned = set()
+  num_graphs = len(sack.graph_info)
+  for bag in sack.bags:
+    if prune > 0 and float(len(bag.graphs)) / num_graphs < prune:
+      pruned.add(bag)
+      continue
+    output.write('%d [label="%s (%d)\n(%d, %d)\n(%.2f, %.2f)" shape=%s; '
+                 'style=filled; fillcolor=%s];\n' % (
+        bag.Index(), bag.label, len(bag.graphs),
+        min(bag.total_costs), max(bag.total_costs),
+        min(bag.relative_costs), max(bag.relative_costs),
+        _CriticalToShape(bag),
+        _AmountToNodeColor(len(bag.graphs), num_graphs)))
+
+  if pruned:
+    pruned_index = num_graphs
+    output.write('%d [label="Pruned at %.0f%%\n(%d)"; '
+                 'shape=polygon; style=dotted];\n' %
+                 (pruned_index, 100 * prune, len(pruned)))
+
+  for bag in sack.bags:
+    if bag in pruned:
+      for succ in bag.Successors():
+        if succ not in pruned:
+          output.write('%d -> %d [style=dashed];\n' % (
+              pruned_index, succ.Index()))
+    for succ in bag.Successors():
+      if succ in pruned:
+        if len(bag.successor_sources[succ]) > 1:
+          output.write('%d -> %d [label="%d"; style=dashed];\n' % (
+              bag.Index(), pruned_index, len(bag.successor_sources[succ])))
+      else:
+        num_succ = len(bag.successor_sources[succ])
+        num_long = 0
+        for graph, source, target in bag.successor_sources[succ]:
+          if graph.EdgeCost(source, target) > long_edge_msec:
+            num_long += 1
+        if num_long > 0:
+          long_frac = float(num_long) / num_succ
+          long_edge_style = '; penwidth=%f' % (2 + 6.0 * long_frac)
+          if long_frac < 0.75:
+            long_edge_style += '; style=dashed'
+        else:
+          long_edge_style = ''
+        min_edge = min(bag.successor_edge_costs[succ])
+        max_edge = max(bag.successor_edge_costs[succ])
+        output.write('%d -> %d [label="%d\n(%f,%f)"; color=%s %s];\n' % (
+            bag.Index(), succ.Index(), num_succ, min_edge, max_edge,
+            _AmountToEdgeColor(num_succ, len(bag.graphs)),
+            long_edge_style))
+
+  output.write('}')
+
+
+def _CriticalToShape(bag):
+  frac = float(bag.num_critical) / bag.num_nodes
+  if frac < 0.4:
+    return 'oval'
+  elif frac < 0.7:
+    return 'polygon'
+  elif frac < 0.9:
+    return 'trapezium'
+  return 'box'
+
+
+def _AmountToNodeColor(numer, denom):
+  if denom <= 0:
+    return 'grey72'
+  ratio = 1.0 * numer / denom
+  if ratio < .3:
+    return 'white'
+  elif ratio < .6:
+    return 'yellow'
+  elif ratio < .8:
+    return 'orange'
+  return 'green'
+
+
+def _AmountToEdgeColor(numer, denom):
+  color = _AmountToNodeColor(numer, denom)
+  if color == 'white' or color == 'grey72':
+    return 'black'
+  return color
+
+
+def _Main():
+  import json
+  import logging
+  import sys
+
+  import loading_model
+  import loading_trace
+  import resource_sack
+
+  sack = resource_sack.GraphSack()
+  for fname in sys.argv[1:]:
+    trace = loading_trace.LoadingTrace.FromJsonDict(
+      json.load(open(fname)))
+    logging.info('Making graph from %s', fname)
+    model = loading_model.ResourceGraph(trace, content_lens=None)
+    sack.ConsumeGraph(model)
+    logging.info('Finished %s', fname)
+  ToDot(sack, sys.stdout, prune=.1)
+
+
+if __name__ == '__main__':
+  _Main()
diff --git a/tools/android/loading/resource_sack_display_unittest.py b/tools/android/loading/resource_sack_display_unittest.py
new file mode 100644
index 0000000..65b53ff
--- /dev/null
+++ b/tools/android/loading/resource_sack_display_unittest.py
@@ -0,0 +1,42 @@
+# Copyright 2016 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 re
+from StringIO import StringIO
+import unittest
+
+import resource_sack
+import resource_sack_display
+from test_utils import (MakeRequest,
+                        TestResourceGraph)
+
+
+class ResourceSackDispayTestCase(unittest.TestCase):
+  def test_SimpleOutput(self):
+    g1 = TestResourceGraph.FromRequestList([
+        MakeRequest(0, 'null'),
+        MakeRequest(1, 0),
+        MakeRequest(2, 0),
+        MakeRequest(3, 1)])
+    g2 = TestResourceGraph.FromRequestList([
+        MakeRequest(0, 'null'),
+        MakeRequest(1, 0),
+        MakeRequest(2, 0),
+        MakeRequest(4, 2)])
+    sack = resource_sack.GraphSack()
+    sack.ConsumeGraph(g1)
+    sack.ConsumeGraph(g2)
+    buf = StringIO()
+    resource_sack_display.ToDot(sack, buf,
+                                long_edge_msec=1000)
+    dot = buf.getvalue()
+    # Short edge.
+    self.assertTrue(re.search(r'0 -> 1[^]]+color=green \]', dot, re.MULTILINE))
+    # Long edge.
+    self.assertTrue(re.search(r'0 -> 3[^]]+penwidth=8', dot))
+
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/tools/android/loading/resource_sack_unittest.py b/tools/android/loading/resource_sack_unittest.py
new file mode 100644
index 0000000..417918db6b
--- /dev/null
+++ b/tools/android/loading/resource_sack_unittest.py
@@ -0,0 +1,64 @@
+# Copyright 2016 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 unittest
+
+import resource_sack
+from test_utils import (MakeRequest,
+                        TestResourceGraph)
+
+
+class ResourceSackTestCase(unittest.TestCase):
+  def test_NodeMerge(self):
+    g1 = TestResourceGraph.FromRequestList([
+        MakeRequest(0, 'null'),
+        MakeRequest(1, 0),
+        MakeRequest(2, 0),
+        MakeRequest(3, 1)])
+    g2 = TestResourceGraph.FromRequestList([
+        MakeRequest(0, 'null'),
+        MakeRequest(1, 0),
+        MakeRequest(2, 0),
+        MakeRequest(4, 2)])
+    sack = resource_sack.GraphSack()
+    sack.ConsumeGraph(g1)
+    sack.ConsumeGraph(g2)
+    self.assertEqual(5, len(sack.bags))
+    for bag in sack.bags:
+      if bag.label not in ('3/', '4/'):
+        self.assertEqual(2, bag.num_nodes)
+      else:
+        self.assertEqual(1, bag.num_nodes)
+
+  def test_MultiParents(self):
+    g1 = TestResourceGraph.FromRequestList([
+        MakeRequest(0, 'null'),
+        MakeRequest(2, 0)])
+    g2 = TestResourceGraph.FromRequestList([
+        MakeRequest(1, 'null'),
+        MakeRequest(2, 1)])
+    sack = resource_sack.GraphSack()
+    sack.ConsumeGraph(g1)
+    sack.ConsumeGraph(g2)
+    self.assertEqual(3, len(sack.bags))
+    labels = {bag.label: bag for bag in sack.bags}
+    self.assertEqual(
+        set(['0/', '1/']),
+        set([bag.label for bag in labels['2/'].Predecessors()]))
+    self.assertFalse(labels['0/'].Predecessors())
+    self.assertFalse(labels['1/'].Predecessors())
+
+  def test_Shortname(self):
+    root = MakeRequest(0, 'null')
+    shortname = MakeRequest(1, 0)
+    shortname.url = 'data:fake/content;' + 'lotsand' * 50 + 'lotsofdata'
+    g1 = TestResourceGraph.FromRequestList([root, shortname])
+    sack = resource_sack.GraphSack()
+    sack.ConsumeGraph(g1)
+    self.assertEqual(set(['0/', 'data:fake/content']),
+                     set([bag.label for bag in sack.bags]))
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/tools/android/loading/run_sandwich.py b/tools/android/loading/run_sandwich.py
index 0572d5b2..ff98acb9 100755
--- a/tools/android/loading/run_sandwich.py
+++ b/tools/android/loading/run_sandwich.py
@@ -12,16 +12,13 @@
 """
 
 import argparse
-from datetime import datetime
 import json
 import logging
 import os
 import shutil
-import subprocess
 import sys
 import tempfile
 import time
-import zipfile
 
 _SRC_DIR = os.path.abspath(os.path.join(
     os.path.dirname(__file__), '..', '..', '..'))
@@ -33,6 +30,7 @@
 from pylib import constants
 import devil_chromium
 
+import chrome_cache
 import chrome_setup
 import device_setup
 import devtools_monitor
@@ -48,24 +46,11 @@
 
 _JOB_SEARCH_PATH = 'sandwich_jobs'
 
-# Directory name under --output to save the cache from the device.
-_CACHE_DIRECTORY_NAME = 'cache'
-
-# Name of cache subdirectory on the device where the cache index is stored.
-_INDEX_DIRECTORY_NAME = 'index-dir'
-
-# Name of the file containing the cache index. This file is stored on the device
-# in the cache directory under _INDEX_DIRECTORY_NAME.
-_REAL_INDEX_FILE_NAME = 'the-real-index'
-
 # An estimate of time to wait for the device to become idle after expensive
 # operations, such as opening the launcher activity.
 _TIME_TO_DEVICE_IDLE_SECONDS = 2
 
 
-def _RemoteCacheDirectory():
-  return '/data/data/{}/cache/Cache'.format(OPTIONS.chrome_package_name)
-
 # Devtools timeout of 1 minute to avoid websocket timeout on slow
 # network condition.
 _DEVTOOLS_TIMEOUT = 60
@@ -92,159 +77,6 @@
   raise Exception('Job description does not define a list named "urls"')
 
 
-def _UpdateTimestampFromAdbStat(filename, stat):
-  os.utime(filename, (stat.st_time, stat.st_time))
-
-
-def _AdbShell(adb, cmd):
-  adb.Shell(subprocess.list2cmdline(cmd))
-
-
-def _AdbUtime(adb, filename, timestamp):
-  """Adb equivalent of os.utime(filename, (timestamp, timestamp))
-  """
-  touch_stamp = datetime.fromtimestamp(timestamp).strftime('%Y%m%d.%H%M%S')
-  _AdbShell(adb, ['touch', '-t', touch_stamp, filename])
-
-
-def _PullBrowserCache(device):
-  """Pulls the browser cache from the device and saves it locally.
-
-  Cache is saved with the same file structure as on the device. Timestamps are
-  important to preserve because indexing and eviction depends on them.
-
-  Returns:
-    Temporary directory containing all the browser cache.
-  """
-  save_target = tempfile.mkdtemp(suffix='.cache')
-  for filename, stat in device.adb.Ls(_RemoteCacheDirectory()):
-    if filename == '..':
-      continue
-    if filename == '.':
-      cache_directory_stat = stat
-      continue
-    original_file = os.path.join(_RemoteCacheDirectory(), filename)
-    saved_file = os.path.join(save_target, filename)
-    device.adb.Pull(original_file, saved_file)
-    _UpdateTimestampFromAdbStat(saved_file, stat)
-    if filename == _INDEX_DIRECTORY_NAME:
-      # The directory containing the index was pulled recursively, update the
-      # timestamps for known files. They are ignored by cache backend, but may
-      # be useful for debugging.
-      index_dir_stat = stat
-      saved_index_dir = os.path.join(save_target, _INDEX_DIRECTORY_NAME)
-      saved_index_file = os.path.join(saved_index_dir, _REAL_INDEX_FILE_NAME)
-      for sub_file, sub_stat in device.adb.Ls(original_file):
-        if sub_file == _REAL_INDEX_FILE_NAME:
-          _UpdateTimestampFromAdbStat(saved_index_file, sub_stat)
-          break
-      _UpdateTimestampFromAdbStat(saved_index_dir, index_dir_stat)
-
-  # Store the cache directory modification time. It is important to update it
-  # after all files in it have been written. The timestamp is compared with
-  # the contents of the index file when freshness is determined.
-  _UpdateTimestampFromAdbStat(save_target, cache_directory_stat)
-  return save_target
-
-
-def _PushBrowserCache(device, local_cache_path):
-  """Pushes the browser cache saved locally to the device.
-
-  Args:
-    device: Android device.
-    local_cache_path: The directory's path containing the cache locally.
-  """
-  # Clear previous cache.
-  _AdbShell(device.adb, ['rm', '-rf', _RemoteCacheDirectory()])
-  _AdbShell(device.adb, ['mkdir', _RemoteCacheDirectory()])
-
-  # Push cache content.
-  device.adb.Push(local_cache_path, _RemoteCacheDirectory())
-
-  # Walk through the local cache to update mtime on the device.
-  def MirrorMtime(local_path):
-    cache_relative_path = os.path.relpath(local_path, start=local_cache_path)
-    remote_path = os.path.join(_RemoteCacheDirectory(), cache_relative_path)
-    _AdbUtime(device.adb, remote_path, os.stat(local_path).st_mtime)
-
-  for local_directory_path, dirnames, filenames in os.walk(
-        local_cache_path, topdown=False):
-    for filename in filenames:
-      MirrorMtime(os.path.join(local_directory_path, filename))
-    for dirname in dirnames:
-      MirrorMtime(os.path.join(local_directory_path, dirname))
-  MirrorMtime(local_cache_path)
-
-
-def _ZipDirectoryContent(root_directory_path, archive_dest_path):
-  """Zip a directory's content recursively with all the directories'
-  timestamps preserved.
-
-  Args:
-    root_directory_path: The directory's path to archive.
-    archive_dest_path: Archive destination's path.
-  """
-  with zipfile.ZipFile(archive_dest_path, 'w') as zip_output:
-    timestamps = {}
-    root_directory_stats = os.stat(root_directory_path)
-    timestamps['.'] = {
-        'atime': root_directory_stats.st_atime,
-        'mtime': root_directory_stats.st_mtime}
-    for directory_path, dirnames, filenames in os.walk(root_directory_path):
-      for dirname in dirnames:
-        subdirectory_path = os.path.join(directory_path, dirname)
-        subdirectory_relative_path = os.path.relpath(subdirectory_path,
-                                                     root_directory_path)
-        subdirectory_stats = os.stat(subdirectory_path)
-        timestamps[subdirectory_relative_path] = {
-            'atime': subdirectory_stats.st_atime,
-            'mtime': subdirectory_stats.st_mtime}
-      for filename in filenames:
-        file_path = os.path.join(directory_path, filename)
-        file_archive_name = os.path.join('content',
-            os.path.relpath(file_path, root_directory_path))
-        file_stats = os.stat(file_path)
-        timestamps[file_archive_name[8:]] = {
-            'atime': file_stats.st_atime,
-            'mtime': file_stats.st_mtime}
-        zip_output.write(file_path, arcname=file_archive_name)
-    zip_output.writestr('timestamps.json',
-                        json.dumps(timestamps, indent=2))
-
-
-def _UnzipDirectoryContent(archive_path, directory_dest_path):
-  """Unzip a directory's content recursively with all the directories'
-  timestamps preserved.
-
-  Args:
-    archive_path: Archive's path to unzip.
-    directory_dest_path: Directory destination path.
-  """
-  if not os.path.exists(directory_dest_path):
-    os.makedirs(directory_dest_path)
-
-  with zipfile.ZipFile(archive_path) as zip_input:
-    timestamps = None
-    for file_archive_name in zip_input.namelist():
-      if file_archive_name == 'timestamps.json':
-        timestamps = json.loads(zip_input.read(file_archive_name))
-      elif file_archive_name.startswith('content/'):
-        file_relative_path = file_archive_name[8:]
-        file_output_path = os.path.join(directory_dest_path, file_relative_path)
-        file_parent_directory_path = os.path.dirname(file_output_path)
-        if not os.path.exists(file_parent_directory_path):
-          os.makedirs(file_parent_directory_path)
-        with open(file_output_path, 'w') as f:
-          f.write(zip_input.read(file_archive_name))
-
-    assert timestamps
-    for relative_path, stats in timestamps.iteritems():
-      output_path = os.path.join(directory_dest_path, relative_path)
-      if not os.path.exists(output_path):
-        os.makedirs(output_path)
-      os.utime(output_path, (stats['atime'], stats['mtime']))
-
-
 def _CleanPreviousTraces(output_directories_path):
   """Cleans previous traces from the output directory.
 
@@ -337,7 +169,8 @@
   if args.cache_op == 'push':
     assert os.path.isfile(local_cache_archive_path)
     local_cache_directory_path = tempfile.mkdtemp(suffix='.cache')
-    _UnzipDirectoryContent(local_cache_archive_path, local_cache_directory_path)
+    chrome_cache.UnzipDirectoryContent(
+        local_cache_archive_path, local_cache_directory_path)
 
   with device_setup.WprHost(device, args.wpr_archive,
       record=args.wpr_record,
@@ -373,7 +206,7 @@
           clear_cache = True
         elif args.cache_op == 'push':
           device.KillAll(OPTIONS.chrome_package_name, quiet=True)
-          _PushBrowserCache(device, local_cache_directory_path)
+          chrome_cache.PushBrowserCache(device, local_cache_directory_path)
         elif args.cache_op == 'reload':
           _RunNavigation(url, clear_cache=True, trace_id=None)
         elif args.cache_op == 'save':
@@ -392,8 +225,9 @@
     device.KillAll(OPTIONS.chrome_package_name, quiet=True)
     time.sleep(_TIME_TO_DEVICE_IDLE_SECONDS)
 
-    cache_directory_path = _PullBrowserCache(device)
-    _ZipDirectoryContent(cache_directory_path, local_cache_archive_path)
+    cache_directory_path = chrome_cache.PullBrowserCache(device)
+    chrome_cache.ZipDirectoryContent(
+        cache_directory_path, local_cache_archive_path)
     shutil.rmtree(cache_directory_path)
 
   with open(os.path.join(args.output, 'run_infos.json'), 'w') as file_output:
diff --git a/tools/android/loading/test_utils.py b/tools/android/loading/test_utils.py
index aea73a7..2d80d1a 100644
--- a/tools/android/loading/test_utils.py
+++ b/tools/android/loading/test_utils.py
@@ -43,8 +43,39 @@
 
 
 def MakeRequest(
-    url, source_url, start_time, headers_time, end_time,
+    url, source_url, start_time=None, headers_time=None, end_time=None,
     magic_content_type=False, initiator_type='other'):
+  """Make a dependent request.
+
+  Args:
+    url: a url, or number which will be used as a url.
+    source_url: a url or number which will be used as the source (initiating)
+      url. If the source url is not present, then url will be a root. The
+      convention in tests is to use a source_url of 'null' in this case.
+    start_time: The request start time in milliseconds. If None, this is set to
+      the current request id in seconds. If None, the two other time parameters
+      below must also be None.
+    headers_time: The timestamp when resource headers were received, or None.
+    end_time: The timestamp when the resource was finished, or None.
+    magic_content_type (bool): if true, set a magic content type that makes url
+      always be detected as a valid source and destination request.
+    initiator_type: the initiator type to use.
+
+  Returns:
+    A request_track.Request.
+
+  """
+  assert ((start_time is None and
+           headers_time is None and
+           end_time is None) or
+          (start_time is not None and
+           headers_time is not None and
+           end_time is not None)), \
+      'Need no time specified or all times specified'
+  if start_time is None:
+    # Use the request id in seconds for timestamps. This guarantees increasing
+    # times which makes request dependencies behave as expected.
+    start_time = headers_time = end_time = MakeRequest._next_request_id * 1000
   assert initiator_type in ('other', 'parser')
   timing = request_track.TimingAsList(request_track.TimingFromDict({
       # connectEnd should be ignored.
diff --git a/tools/battor_agent/battor_agent_bin.cc b/tools/battor_agent/battor_agent_bin.cc
index f6e7c43..7ba898f 100644
--- a/tools/battor_agent/battor_agent_bin.cc
+++ b/tools/battor_agent/battor_agent_bin.cc
@@ -14,8 +14,10 @@
 #include "base/at_exit.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/command_line.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread.h"
 #include "tools/battor_agent/battor_agent.h"
 #include "tools/battor_agent/battor_error.h"
@@ -32,16 +34,20 @@
 const int32_t kBattOrCommandTimeoutSeconds = 10;
 
 void PrintUsage() {
-  cout << "Usage: battor_agent <command> <arguments>" << endl
+  cout << "Usage: battor_agent <command> <arguments> <switches>" << endl
        << endl
        << "Commands:" << endl
        << endl
-       << "  StartTracing <path>" << endl
-       << "  StopTracing <path>" << endl
+       << "  StartTracing" << endl
+       << "  StopTracing" << endl
        << "  SupportsExplicitClockSync" << endl
-       << "  RecordClockSyncMarker <path> <marker>" << endl
-       << "  IssueClockSyncMarker <path>" << endl
-       << "  Help" << endl;
+       << "  RecordClockSyncMarker <marker>" << endl
+       << "  IssueClockSyncMarker" << endl
+       << "  Help" << endl
+       << endl
+       << "Switches:" << endl
+       << endl
+       << "  --battor-path=<path> Uses the specified BattOr path." << endl;
 }
 
 void PrintSupportsExplicitClockSync() {
@@ -50,12 +56,16 @@
 
 // Retrieves argument argnum from the argument list, or an empty string if the
 // argument doesn't exist.
-std::string GetArg(int argnum, int argc, char* argv[]) {
-  if (argnum >= argc) {
+std::string GetArg(size_t argnum, base::CommandLine::StringVector args) {
+  if (argnum >= args.size()) {
     return std::string();
   }
 
-  return argv[argnum];
+#if defined(OS_WIN)
+  return base::WideToUTF8(args[argnum]);
+#else
+  return args[argnum];
+#endif
 }
 
 // Checks if an error occurred and, if it did, prints the error and exits
@@ -88,7 +98,8 @@
 
   // Runs the BattOr binary and returns the exit code.
   int Run(int argc, char* argv[]) {
-    std::string cmd = GetArg(1, argc, argv);
+    base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+    std::string cmd = GetArg(0, command_line->GetArgs());
     if (cmd.empty()) {
       PrintUsage();
       exit(1);
@@ -101,16 +112,10 @@
       return 0;
     }
 
-    std::string path = GetArg(2, argc, argv);
-    // If no path is specified, see if we can find a BattOr and use that.
-    if (path.empty())
-      path = BattOrFinder::FindBattOr();
-
     // If we don't have any BattOr to use, exit.
+    std::string path = BattOrFinder::FindBattOr();
     if (path.empty()) {
-      cout << "Unable to find a BattOr, and no explicit BattOr path was "
-              "specified."
-           << endl;
+      cout << "Unable to find a BattOr." << endl;
       exit(1);
     }
 
@@ -253,6 +258,7 @@
 
 int main(int argc, char* argv[]) {
   base::AtExitManager exit_manager;
+  base::CommandLine::Init(argc, argv);
   battor::BattOrAgentBin bin;
   return bin.Run(argc, argv);
 }
diff --git a/tools/battor_agent/battor_finder.cc b/tools/battor_agent/battor_finder.cc
index b0e32db..a8248e5 100644
--- a/tools/battor_agent/battor_finder.cc
+++ b/tools/battor_agent/battor_finder.cc
@@ -4,6 +4,8 @@
 
 #include "tools/battor_agent/battor_finder.h"
 
+#include "base/command_line.h"
+#include "base/logging.h"
 #include "device/serial/serial.mojom.h"
 #include "device/serial/serial_device_enumerator.h"
 #include "mojo/public/cpp/bindings/array.h"
@@ -15,9 +17,13 @@
 // The USB display name prefix that all BattOrs have.
 const char kBattOrDisplayNamePrefix[] = "BattOr";
 
+// The command line switch used to hard-code a BattOr path. Hard-coding
+// this path disables the normal method of finding a BattOr, which is to
+// search through serial devices for one with a matching display name.
+const char kBattOrPathSwitch[] = "battor-path";
+
 }  // namespace
 
-// Returns the path of the first BattOr that we find.
 std::string BattOrFinder::FindBattOr() {
   scoped_ptr<device::SerialDeviceEnumerator> serial_device_enumerator =
       device::SerialDeviceEnumerator::Create();
@@ -25,11 +31,26 @@
   mojo::Array<device::serial::DeviceInfoPtr> devices =
       serial_device_enumerator->GetDevices();
 
-  for (size_t i = 0; i < devices.size(); i++) {
-    std::string display_name = devices[i]->display_name.get();
-
-    if (display_name.find(kBattOrDisplayNamePrefix) != std::string::npos) {
-      return devices[i]->path;
+  std::string switch_specified_path =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          kBattOrPathSwitch);
+  if (switch_specified_path.empty()) {
+    // If we have no switch-specified path, look for a device with the right
+    // display name.
+    for (size_t i = 0; i < devices.size(); i++) {
+      std::string display_name = devices[i]->display_name.get();
+      if (display_name.find(kBattOrDisplayNamePrefix) != std::string::npos) {
+        LOG(INFO) << "Found BattOr with display name " << display_name
+                  << " at path " << devices[i]->path;
+        return devices[i]->path;
+      }
+    }
+  } else {
+    // If we have a switch-specified path, make sure it actually exists before
+    // returning it.
+    for (size_t i = 0; i < devices.size(); i++) {
+      if (devices[i]->path == switch_specified_path)
+        return switch_specified_path;
     }
   }
 
diff --git a/tools/battor_agent/battor_finder.h b/tools/battor_agent/battor_finder.h
index fe6fa79..06d24ab9 100644
--- a/tools/battor_agent/battor_finder.h
+++ b/tools/battor_agent/battor_finder.h
@@ -13,6 +13,7 @@
 
 class BattOrFinder {
  public:
+  // Returns the path of the first BattOr that we find.
   static std::string FindBattOr();
 
   DISALLOW_COPY_AND_ASSIGN(BattOrFinder);
diff --git a/tools/checklicenses/checklicenses.py b/tools/checklicenses/checklicenses.py
index 9b821e0..100faa7 100755
--- a/tools/checklicenses/checklicenses.py
+++ b/tools/checklicenses/checklicenses.py
@@ -486,6 +486,16 @@
         'UNKNOWN',
     ],
 
+    # New BSD license. http://crbug.com/98455
+    'tools/swarming_client/third_party/google': [
+        'UNKNOWN',
+    ],
+
+    # Apache v2.0.
+    'tools/swarming_client/third_party/googleapiclient': [
+        'UNKNOWN',
+    ],
+
     # http://crbug.com/334668
     # MIT license.
     'tools/swarming_client/third_party/httplib2': [
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index a57c967..d1f7a35 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -26,7 +26,7 @@
 # Do NOT CHANGE this if you don't know what you're doing -- see
 # https://chromium.googlesource.com/chromium/src/+/master/docs/updating_clang.md
 # Reverting problematic clang rolls is safe, though.
-CLANG_REVISION = '259396'
+CLANG_REVISION = '261368'
 
 use_head_revision = 'LLVM_FORCE_HEAD_REVISION' in os.environ
 if use_head_revision:
diff --git a/tools/generate_library_loader/generate_library_loader.gni b/tools/generate_library_loader/generate_library_loader.gni
index c714c12..1e1d5d77 100644
--- a/tools/generate_library_loader/generate_library_loader.gni
+++ b/tools/generate_library_loader/generate_library_loader.gni
@@ -20,9 +20,6 @@
     visibility = action_visibility
 
     script = "//tools/generate_library_loader/generate_library_loader.py"
-    if (defined(invoker.visibility)) {
-      visibility = invoker.visibility
-    }
 
     outputs = [
       output_h,
diff --git a/tools/gn/docs/cookbook.md b/tools/gn/docs/cookbook.md
index c328563..3fa16e2f 100644
--- a/tools/gn/docs/cookbook.md
+++ b/tools/gn/docs/cookbook.md
@@ -241,10 +241,10 @@
 | `enable_chromevox_next` (0/1)           | `enable_chromevox_next` (true/false)           | `//build/config/features.gni` |
 | `enable_extensions` (0/1)               | `enable_extensions` (true/false)               | `//build/config/features.gni` |
 | `enable_google_now` (0/1)               | `enable_google_now` (true/false)               | `//build/config/features.gni` |
-| `enable_hidpi` (0/1)                    | `enable_hidpi` (true/false)                    | `//build/config/ui.gni`       |
+| `enable_hidpi` (0/1)                    | `enable_hidpi` (true/false)                    | `//ui/base/ui_features.gni`   |
 | `enable_managed_users` (0/1)            | `enable_managed_users` (true/false)            | `//build/config/features.gni` |
 | `enable_mdns` (0/1)                     | `enable_mdns` (true/false)                     | `//build/config/features.gni` |
-| `enable_one_click_signin` (0/1)         | `enable_one_click_signin` (true/false)         | `//build/config/features.gni` |
+| `enable_one_click_signin` (0/1)         | `enable_one_click_signin` (true/false)         | `//chrome/common/features.gni` |
 | `enable_pepper_cdms` (0/1)              | `enable_pepper_cdms` (true/false)              | `//build/config/features.gni` |
 | `enable_plugins` (0/1)                  | `enable_plugins` (true/false)                  | `//build/config/features.gni` |
 | `enable_plugin_installation` (0/1)      | `enable_plugin_installation` (true/false)      | `//build/config/features.gni` |
diff --git a/tools/gn/err.cc b/tools/gn/err.cc
index 378fb7e5..56e93bd 100644
--- a/tools/gn/err.cc
+++ b/tools/gn/err.cc
@@ -144,6 +144,8 @@
   }
 }
 
+Err::Err(const Err& other) = default;
+
 Err::~Err() {
 }
 
diff --git a/tools/gn/err.h b/tools/gn/err.h
index 3e077e9..eeec31a 100644
--- a/tools/gn/err.h
+++ b/tools/gn/err.h
@@ -54,6 +54,8 @@
       const std::string msg,
       const std::string& help_text = std::string());
 
+  Err(const Err& other);
+
   ~Err();
 
   bool has_error() const { return has_error_; }
diff --git a/tools/gn/function_exec_script.cc b/tools/gn/function_exec_script.cc
index d5e66ae7..231693b5 100644
--- a/tools/gn/function_exec_script.cc
+++ b/tools/gn/function_exec_script.cc
@@ -171,6 +171,13 @@
   // Make the command line.
   const base::FilePath& python_path = build_settings->python_path();
   base::CommandLine cmdline(python_path);
+
+  // CommandLine tries to interpret arguments by default.  Passing "--" disables
+  // this for everything following the "--", so pass this as the very first
+  // thing to python.  Python ignores a -- before the .py file, and this makes
+  // CommandLine let through arguments without modifying them.
+  cmdline.AppendArg("--");
+
   cmdline.AppendArgPath(script_path);
 
   if (args.size() >= 2) {
diff --git a/tools/gn/label.cc b/tools/gn/label.cc
index 7c13ed274..94c0e718 100644
--- a/tools/gn/label.cc
+++ b/tools/gn/label.cc
@@ -214,6 +214,8 @@
   name_.assign(name.data(), name.size());
 }
 
+Label::Label(const Label& other) = default;
+
 Label::~Label() {
 }
 
diff --git a/tools/gn/label.h b/tools/gn/label.h
index 469e8b6..cbeb177 100644
--- a/tools/gn/label.h
+++ b/tools/gn/label.h
@@ -29,6 +29,7 @@
 
   // Makes a label with an empty toolchain.
   Label(const SourceDir& dir, const base::StringPiece& name);
+  Label(const Label& other);
   ~Label();
 
   // Resolives a string from a build file that may be relative to the
diff --git a/tools/gn/label_pattern.cc b/tools/gn/label_pattern.cc
index 98a4138a..e107ba4 100644
--- a/tools/gn/label_pattern.cc
+++ b/tools/gn/label_pattern.cc
@@ -61,6 +61,8 @@
   name.CopyToString(&name_);
 }
 
+LabelPattern::LabelPattern(const LabelPattern& other) = default;
+
 LabelPattern::~LabelPattern() {
 }
 
diff --git a/tools/gn/label_pattern.h b/tools/gn/label_pattern.h
index 5c032603..7d0768c 100644
--- a/tools/gn/label_pattern.h
+++ b/tools/gn/label_pattern.h
@@ -31,6 +31,7 @@
                const SourceDir& dir,
                const base::StringPiece& name,
                const Label& toolchain_label);
+  LabelPattern(const LabelPattern& other);
   ~LabelPattern();
 
   // Converts the given input string to a pattern. This does special stuff
diff --git a/tools/gn/pattern.cc b/tools/gn/pattern.cc
index 4b14d2a..3de96a3 100644
--- a/tools/gn/pattern.cc
+++ b/tools/gn/pattern.cc
@@ -60,6 +60,8 @@
        subranges_[1].type == Subrange::LITERAL);
 }
 
+Pattern::Pattern(const Pattern& other) = default;
+
 Pattern::~Pattern() {
 }
 
@@ -151,6 +153,8 @@
 PatternList::PatternList() {
 }
 
+PatternList::PatternList(const PatternList& other) = default;
+
 PatternList::~PatternList() {
 }
 
diff --git a/tools/gn/pattern.h b/tools/gn/pattern.h
index 1aa70970..f141f3ea 100644
--- a/tools/gn/pattern.h
+++ b/tools/gn/pattern.h
@@ -47,6 +47,7 @@
   };
 
   explicit Pattern(const std::string& s);
+  Pattern(const Pattern& other);
   ~Pattern();
 
   // Returns true if the current pattern matches the given string.
@@ -70,6 +71,7 @@
 class PatternList {
  public:
   PatternList();
+  PatternList(const PatternList& other);
   ~PatternList();
 
   bool is_empty() const { return patterns_.empty(); }
diff --git a/tools/gn/setup.cc b/tools/gn/setup.cc
index 79814e6..9661506 100644
--- a/tools/gn/setup.cc
+++ b/tools/gn/setup.cc
@@ -226,6 +226,21 @@
 }
 #endif
 
+// Expands all ./, ../, and symbolic links in the given path.
+bool GetRealPath(const base::FilePath& path, base::FilePath* out) {
+#if defined(OS_POSIX)
+  char buf[PATH_MAX];
+  if (!realpath(path.value().c_str(), buf)) {
+    return false;
+  }
+  *out = base::FilePath(buf);
+#else
+  // Do nothing on a non-POSIX system.
+  *out = path;
+#endif
+  return true;
+}
+
 }  // namespace
 
 const char Setup::kBuildArgFileName[] = "args.gn";
@@ -513,9 +528,16 @@
     root_path = dotfile_name_.DirName();
   }
 
+  base::FilePath root_realpath;
+  if (!GetRealPath(root_path, &root_realpath)) {
+    Err(Location(), "Can't get the real root path.",
+        "I could not get the real path of \"" + FilePathToUTF8(root_path) +
+        "\".").PrintToStdout();
+    return false;
+  }
   if (scheduler_.verbose_logging())
-    scheduler_.Log("Using source root", FilePathToUTF8(root_path));
-  build_settings_.SetRootPath(root_path);
+    scheduler_.Log("Using source root", FilePathToUTF8(root_realpath));
+  build_settings_.SetRootPath(root_realpath);
 
   return true;
 }
@@ -531,11 +553,27 @@
     return false;
   }
 
+  base::FilePath build_dir_path = build_settings_.GetFullPath(resolved);
+  if (!base::CreateDirectory(build_dir_path)) {
+    Err(Location(), "Can't create the build dir.",
+        "I could not create the build dir \"" + FilePathToUTF8(build_dir_path) +
+        "\".").PrintToStdout();
+    return false;
+  }
+  base::FilePath build_dir_realpath;
+  if (!GetRealPath(build_dir_path, &build_dir_realpath)) {
+    Err(Location(), "Can't get the real build dir path.",
+        "I could not get the real path of \"" + FilePathToUTF8(build_dir_path) +
+        "\".").PrintToStdout();
+    return false;
+  }
+  resolved = SourceDirForPath(build_settings_.root_path(),
+                              build_dir_realpath);
+
   if (scheduler_.verbose_logging())
     scheduler_.Log("Using build dir", resolved.value());
 
   if (require_exists) {
-    base::FilePath build_dir_path = build_settings_.GetFullPath(resolved);
     if (!base::PathExists(build_dir_path.Append(
             FILE_PATH_LITERAL("build.ninja")))) {
       Err(Location(), "Not a build directory.",
diff --git a/tools/gn/substitution_list.cc b/tools/gn/substitution_list.cc
index 40042861..517f327 100644
--- a/tools/gn/substitution_list.cc
+++ b/tools/gn/substitution_list.cc
@@ -12,6 +12,8 @@
 SubstitutionList::SubstitutionList() {
 }
 
+SubstitutionList::SubstitutionList(const SubstitutionList& other) = default;
+
 SubstitutionList::~SubstitutionList() {
 }
 
diff --git a/tools/gn/substitution_list.h b/tools/gn/substitution_list.h
index f3e3c01..7273ece 100644
--- a/tools/gn/substitution_list.h
+++ b/tools/gn/substitution_list.h
@@ -14,6 +14,7 @@
 class SubstitutionList {
  public:
   SubstitutionList();
+  SubstitutionList(const SubstitutionList& other);
   ~SubstitutionList();
 
   bool Parse(const Value& value, Err* err);
diff --git a/tools/gn/substitution_pattern.cc b/tools/gn/substitution_pattern.cc
index dd703d7..c8e54899 100644
--- a/tools/gn/substitution_pattern.cc
+++ b/tools/gn/substitution_pattern.cc
@@ -28,6 +28,9 @@
 SubstitutionPattern::SubstitutionPattern() : origin_(nullptr) {
 }
 
+SubstitutionPattern::SubstitutionPattern(const SubstitutionPattern& other) =
+    default;
+
 SubstitutionPattern::~SubstitutionPattern() {
 }
 
diff --git a/tools/gn/substitution_pattern.h b/tools/gn/substitution_pattern.h
index 76edf8cb..5389806 100644
--- a/tools/gn/substitution_pattern.h
+++ b/tools/gn/substitution_pattern.h
@@ -34,6 +34,7 @@
   };
 
   SubstitutionPattern();
+  SubstitutionPattern(const SubstitutionPattern& other);
   ~SubstitutionPattern();
 
   // Parses the given string and fills in the pattern. The pattern must only
diff --git a/tools/gn/token.cc b/tools/gn/token.cc
index 70ce2a1..6721619 100644
--- a/tools/gn/token.cc
+++ b/tools/gn/token.cc
@@ -17,6 +17,8 @@
       location_(location) {
 }
 
+Token::Token(const Token& other) = default;
+
 bool Token::IsIdentifierEqualTo(const char* v) const {
   return type_ == IDENTIFIER && value_ == v;
 }
diff --git a/tools/gn/token.h b/tools/gn/token.h
index bf87283..24c4e9c 100644
--- a/tools/gn/token.h
+++ b/tools/gn/token.h
@@ -58,6 +58,7 @@
 
   Token();
   Token(const Location& location, Type t, const base::StringPiece& v);
+  Token(const Token& other);
 
   Type type() const { return type_; }
   const base::StringPiece& value() const { return value_; }
diff --git a/tools/gn/visual_studio_writer.cc b/tools/gn/visual_studio_writer.cc
index 7748fbe..a404461c 100644
--- a/tools/gn/visual_studio_writer.cc
+++ b/tools/gn/visual_studio_writer.cc
@@ -179,7 +179,10 @@
 
 VisualStudioWriter::VisualStudioWriter(const BuildSettings* build_settings,
                                        Version version)
-    : build_settings_(build_settings) {
+    : build_settings_(build_settings),
+      ninja_path_output_(build_settings->build_dir(),
+                         build_settings->root_path_utf8(),
+                         EscapingMode::ESCAPE_NINJA_COMMAND) {
   const Value* value = build_settings->build_args().GetArgOverride("is_debug");
   is_debug_config_ = value == nullptr || value->boolean_value();
   config_platform_ = "Win32";
@@ -496,12 +499,14 @@
                     "$(VCTargetsPath)\\BuildCustomizations\\masm.targets"));
   project.SubElement("ImportGroup", XmlAttributes("Label", "ExtensionTargets"));
 
+  std::string ninja_target = GetNinjaTarget(target);
+
   {
     scoped_ptr<XmlElementWriter> build =
         project.SubElement("Target", XmlAttributes("Name", "Build"));
     build->SubElement(
-        "Exec",
-        XmlAttributes("Command", "call ninja.exe -C $(OutDir) $(ProjectName)"));
+        "Exec", XmlAttributes("Command",
+                              "call ninja.exe -C $(OutDir) " + ninja_target));
   }
 
   {
@@ -510,7 +515,7 @@
     clean->SubElement(
         "Exec",
         XmlAttributes("Command",
-                      "call ninja.exe -C $(OutDir) -tclean $(ProjectName)"));
+                      "call ninja.exe -C $(OutDir) -tclean " + ninja_target));
   }
 
   return true;
@@ -606,14 +611,14 @@
   SourceDir solution_dir(FilePathToUTF8(solution_dir_path));
   for (const SolutionEntry* folder : folders_) {
     out << "Project(\"" << kGuidTypeFolder << "\") = \"(" << folder->name
-        << ")\", \"" << RebasePath(folder->path, solution_dir, "/") << "\", \""
+        << ")\", \"" << RebasePath(folder->path, solution_dir) << "\", \""
         << folder->guid << "\"" << std::endl;
     out << "EndProject" << std::endl;
   }
 
   for (const SolutionEntry* project : projects_) {
     out << "Project(\"" << kGuidTypeProject << "\") = \"" << project->name
-        << "\", \"" << RebasePath(project->path, solution_dir, "/") << "\", \""
+        << "\", \"" << RebasePath(project->path, solution_dir) << "\", \""
         << project->guid << "\"" << std::endl;
     out << "EndProject" << std::endl;
   }
@@ -751,3 +756,11 @@
     parents.push_back(folder);
   }
 }
+
+std::string VisualStudioWriter::GetNinjaTarget(const Target* target) {
+  std::ostringstream ninja_target_out;
+  DCHECK(!target->dependency_output_file().value().empty());
+  ninja_path_output_.WriteFile(ninja_target_out,
+                               target->dependency_output_file());
+  return ninja_target_out.str();
+}
diff --git a/tools/gn/visual_studio_writer.h b/tools/gn/visual_studio_writer.h
index 0409220..8ca92fb 100644
--- a/tools/gn/visual_studio_writer.h
+++ b/tools/gn/visual_studio_writer.h
@@ -11,6 +11,7 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
+#include "tools/gn/path_output.h"
 
 namespace base {
 class FilePath;
@@ -91,6 +92,8 @@
   // and updates |root_folder_dir_|. Also sets |parent_folder| for |projects_|.
   void ResolveSolutionFolders();
 
+  std::string GetNinjaTarget(const Target* target);
+
   const BuildSettings* build_settings_;
 
   // Toolset version.
@@ -121,6 +124,9 @@
   // Semicolon-separated Windows SDK include directories.
   std::string windows_kits_include_dirs_;
 
+  // Path formatter for ninja targets.
+  PathOutput ninja_path_output_;
+
   DISALLOW_COPY_AND_ASSIGN(VisualStudioWriter);
 };
 
diff --git a/tools/ipc_fuzzer/fuzzer/fuzzer.cc b/tools/ipc_fuzzer/fuzzer/fuzzer.cc
index 54d94616..497619a 100644
--- a/tools/ipc_fuzzer/fuzzer/fuzzer.cc
+++ b/tools/ipc_fuzzer/fuzzer/fuzzer.cc
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/memory/shared_memory_handle.h"
 #include "base/strings/string_util.h"
 #include "build/build_config.h"
 #include "ipc/ipc_message.h"
@@ -452,6 +453,18 @@
   }
 };
 
+#if defined(OS_WIN) || defined(OS_MACOSX)
+template <>
+struct FuzzTraits<base::SharedMemoryHandle> {
+  static bool Fuzz(base::SharedMemoryHandle* p, Fuzzer* fuzzer) {
+    // This generates an invalid SharedMemoryHandle. Generating a valid
+    // SharedMemoryHandle requires setting/knowing state in both the sending and
+    // receiving process, which is not currently possible.
+    return true;
+  }
+};
+#endif  // defined(OS_WIN) || defined(OS_MACOSX)
+
 template <>
 struct FuzzTraits<base::Time> {
   static bool Fuzz(base::Time* p, Fuzzer* fuzzer) {
diff --git a/tools/json_schema_compiler/js_externs_generator_test.py b/tools/json_schema_compiler/js_externs_generator_test.py
index 7447ea74..917ce637 100755
--- a/tools/json_schema_compiler/js_externs_generator_test.py
+++ b/tools/json_schema_compiler/js_externs_generator_test.py
@@ -44,6 +44,7 @@
     long? maybe;
     (DOMString or Greek or long[]) choice;
     object plainObj;
+    ArrayBuffer arrayBuff;
   };
 
   callback VoidCallback = void();
@@ -123,7 +124,8 @@
  *   obj: !chrome.fakeApi.Bar,
  *   maybe: (number|undefined),
  *   choice: (string|!chrome.fakeApi.Greek|!Array<number>),
- *   plainObj: Object
+ *   plainObj: Object,
+ *   arrayBuff: ArrayBuffer
  * }}
  * @see https://developer.chrome.com/extensions/fakeApi#type-Baz
  */
@@ -202,6 +204,10 @@
                   "type": "integer"
                 }
               }
+            },
+            "quu": {
+              "type": "binary",
+              "description": "The array buffer"
             }
           }
         },
@@ -266,7 +272,8 @@
  *   bar: number,
  *   baz: {
  *     depth: number
- *   }
+ *   },
+ *   quu: ArrayBuffer
  * }} inlineObj Evil inline object! With a super duper duper long string
  *     description that causes problems!
  * @param {function({
diff --git a/tools/json_schema_compiler/js_util.py b/tools/json_schema_compiler/js_util.py
index 25995c0..2549aef 100644
--- a/tools/json_schema_compiler/js_util.py
+++ b/tools/json_schema_compiler/js_util.py
@@ -148,6 +148,8 @@
       return c
     if js_type.property_type is PropertyType.FUNCTION:
       return self._FunctionToJsFunction(namespace_name, js_type.function)
+    if js_type.property_type is PropertyType.BINARY:
+      return Code().Append('ArrayBuffer')
     if js_type.property_type is PropertyType.ANY:
       return Code().Append('*')
     if js_type.property_type.is_fundamental:
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 7e1237e2..10388ae 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -691,6 +691,8 @@
     },
     'official.desktop.continuous': {
       'precise64 trunk': 'gn_official',
+      'precise64 beta': 'gn_official',
+      'precise64 stable': 'gn_official',
     },
     'tryserver.blink': {
       'linux_blink_dbg': 'swarming_gn_debug_bot_minimal_symbols_x64',
@@ -705,15 +707,15 @@
       'win_blink_compile_dbg': 'swarming_gyp_debug_bot_minimal_symbols_x86',
       'win_blink_compile_rel': 'swarming_gyp_release_trybot_minimal_symbols_x86',
       'win_blink_rel': 'swarming_gyp_release_trybot_minimal_symbols_x86',
-      'linux_blink_non_oilpan_dbg': 'swarming_gn_non_oilpan_debug_bot_minimal_symbols_x64',
-      'linux_blink_non_oilpan_rel': 'swarming_gn_non_oilpan_release_trybot_minimal_symbols_x64',
-      'linux_blink_non_oilpan_compile_rel': 'swarming_gn_non_oilpan_release_trybot_minimal_symbols_x64',
-      'mac_blink_non_oilpan_dbg': 'swarming_gyp_non_oilpan_debug_bot_minimal_symbols_x64',
-      'mac_blink_non_oilpan_rel': 'swarming_gyp_non_oilpan_release_trybot_minimal_symbols_x64',
-      'mac_blink_non_oilpan_compile_rel': 'swarming_gyp_non_oilpan_release_trybot_minimal_symbols_x64',
-      'win_blink_non_oilpan_dbg': 'swarming_gyp_non_oilpan_debug_bot_minimal_symbols_x86',
-      'win_blink_non_oilpan_rel': 'swarming_gyp_non_oilpan_release_trybot_minimal_symbols_x86',
-      'win_blink_non_oilpan_compile_rel': 'swarming_gyp_non_oilpan_release_trybot_minimal_symbols_x86',
+      'linux_blink_oilpan_dbg': 'swarming_gn_non_oilpan_debug_bot_minimal_symbols_x64',
+      'linux_blink_oilpan_rel': 'swarming_gn_non_oilpan_release_trybot_minimal_symbols_x64',
+      'linux_blink_oilpan_compile_rel': 'swarming_gn_non_oilpan_release_trybot_minimal_symbols_x64',
+      'mac_blink_oilpan_dbg': 'swarming_gyp_non_oilpan_debug_bot_minimal_symbols_x64',
+      'mac_blink_oilpan_rel': 'swarming_gyp_non_oilpan_release_trybot_minimal_symbols_x64',
+      'mac_blink_oilpan_compile_rel': 'swarming_gyp_non_oilpan_release_trybot_minimal_symbols_x64',
+      'win_blink_oilpan_dbg': 'swarming_gyp_non_oilpan_debug_bot_minimal_symbols_x86',
+      'win_blink_oilpan_rel': 'swarming_gyp_non_oilpan_release_trybot_minimal_symbols_x86',
+      'win_blink_oilpan_compile_rel': 'swarming_gyp_non_oilpan_release_trybot_minimal_symbols_x86',
       'linux_blink_rel_ng': 'swarming_gn_release_trybot_minimal_symbols_x64',
       'blink_presubmit': 'none',
     },
@@ -756,6 +758,7 @@
       'cast_shell_linux': 'cast_gn_release_trybot',
       'linux_deterministic': 'swarming_deterministic_gyp_release_bot',
       'linux_ecs_ozone': 'embedded_gyp_debug_bot',
+      'linux_optional_gpu_tests_rel': 'swarming_gpu_fyi_tests_gn_release_trybot',
     },
     'tryserver.chromium.mac': {
       'mac_chromium_gn_dbg': 'gn_debug_static_bot',
@@ -799,6 +802,7 @@
     'tryserver.chromium.win': {
       'win_chromium_gn_x64_dbg': 'gn_debug_bot_minimal_symbols',
       'win_chromium_gn_x64_rel': 'gn_release_trybot',
+      'win_chromium_x64_rel_ng': 'gn_release_trybot',
       'win8_chromium_ng': 'gn_release_trybot_x86',
       'win8_chromium_gn_dbg': 'gn_debug_bot_minimal_symbols_x86',
       'win8_chromium_gn_rel': 'gn_release_trybot_x86',
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index bce3cf4..193d9d9 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -18932,6 +18932,27 @@
   </summary>
 </histogram>
 
+<histogram name="Media.Audio.InputDevicePropertyChangedMac"
+    enum="AudioDevicePropertyResult">
+  <owner>henrika@chromium.org</owner>
+  <summary>
+    Lists device properties that have been changed during an audio input stream
+    session. We update a map of different property changes during a session and
+    all these values are recorded when an AUAudioInputStream object is closed,
+    hence multiple enum values can be emitted when the histogram is stored.
+  </summary>
+</histogram>
+
+<histogram name="Media.Audio.InputDevicePropertyChangedStartupFailedMac"
+    enum="AudioDevicePropertyResult">
+  <owner>henrika@chromium.org</owner>
+  <summary>
+    Lists device properties that have been changed during an audio input stream
+    session. Only sampled when Media.Audio.InputStartupSuccessMac reports
+    'Failure' and multiple enum values can be emitted each time that happens.
+  </summary>
+</histogram>
+
 <histogram name="Media.Audio.InputStartupSuccessMac" enum="BooleanSuccess">
   <owner>henrika@chromium.org</owner>
   <summary>
@@ -19273,6 +19294,14 @@
   </summary>
 </histogram>
 
+<histogram name="Media.Controls.Show" enum="MediaControlsShowReason">
+  <owner>mlamouri@chromium.org</owner>
+  <summary>
+    Record whether the default media controls where shown and why every time
+    they could be shown.
+  </summary>
+</histogram>
+
 <histogram name="Media.CrosBeamformingDeviceState"
     enum="CrosBeamformingDeviceState">
   <owner>ajm@chromium.org</owner>
@@ -31342,6 +31371,15 @@
   </summary>
 </histogram>
 
+<histogram name="NewTabPage.TileOfflineAvailable">
+  <owner>treib@chromium.org</owner>
+  <summary>
+    The number of times a tile was available offline, per tile index - compare
+    to the NewTabPage.SuggestionsImpression.* histograms. This is recorded when
+    the NTP finishes loading. Only measured on Android.
+  </summary>
+</histogram>
+
 <histogram name="NewTabPage.TileType" enum="MostVisitedTileType">
   <owner>newt@chromium.org</owner>
   <summary>
@@ -31540,6 +31578,35 @@
   </summary>
 </histogram>
 
+<histogram name="Notifications.Icon.FileSize" units="bytes">
+  <owner>mvanouwerkerk@chromium.org</owner>
+  <summary>The number of bytes loaded for a Web Notification icon.</summary>
+</histogram>
+
+<histogram name="Notifications.Icon.LoadFailTime" units="ms">
+  <owner>mvanouwerkerk@chromium.org</owner>
+  <summary>
+    The number of milliseconds it took to fail loading an icon for a Web
+    Notification.
+  </summary>
+</histogram>
+
+<histogram name="Notifications.Icon.LoadFinishTime" units="ms">
+  <owner>mvanouwerkerk@chromium.org</owner>
+  <summary>
+    The number of milliseconds it took to finish successfully loading an icon
+    for a Web Notification.
+  </summary>
+</histogram>
+
+<histogram name="Notifications.Icon.ScaleDownTime" units="ms">
+  <owner>mvanouwerkerk@chromium.org</owner>
+  <summary>
+    The number of milliseconds it took to scale down an icon for a Web
+    Notification.
+  </summary>
+</histogram>
+
 <histogram name="Notifications.PerNotificationActions"
     enum="NotificationActionType">
   <owner>dewittj@chromium.org</owner>
@@ -33020,6 +33087,14 @@
   </summary>
 </histogram>
 
+<histogram name="PageLoad.AbortTiming.UnknownNavigation" units="ms">
+  <owner>csharrison@chromium.org</owner>
+  <summary>
+    Measures the time from navigation start to the time the page load was
+    aborted by a navigation with unknown transition type.
+  </summary>
+</histogram>
+
 <histogram name="PageLoad.Clients.GoogleCaptcha.Events"
     enum="GoogleCaptchaEvent">
   <owner>mdw@chromium.org</owner>
@@ -47071,6 +47146,30 @@
   </summary>
 </histogram>
 
+<histogram name="SiteEngagementService.EngagementScore.HTTP">
+  <owner>calamity@chromium.org</owner>
+  <owner>dominickn@chromium.org</owner>
+  <owner>felt@chromium.org</owner>
+  <summary>
+    Distribution of the engagement scores accumulated by a user, recorded at
+    startup per non-incognito profile, and then upon the first
+    engagement-increasing event every hour thereafter. Limited specifically to
+    HTTP URLs.
+  </summary>
+</histogram>
+
+<histogram name="SiteEngagementService.EngagementScore.HTTPS">
+  <owner>calamity@chromium.org</owner>
+  <owner>dominickn@chromium.org</owner>
+  <owner>felt@chromium.org</owner>
+  <summary>
+    Distribution of the engagement scores accumulated by a user, recorded at
+    startup per non-incognito profile, and then upon the first
+    engagement-increasing event every hour thereafter. Limited specifically to
+    HTTPS URLs.
+  </summary>
+</histogram>
+
 <histogram name="SiteEngagementService.EngagementScoreBucket" units="%">
   <owner>calamity@chromium.org</owner>
   <summary>
@@ -50121,6 +50220,9 @@
 </histogram>
 
 <histogram name="Sync.FirstSyncDelayByBackup" units="ms">
+  <obsolete>
+    Backup logic has been removed since 02/2016.
+  </obsolete>
   <owner>haitaol@chromium.org</owner>
   <summary>First sync delay casued by backing up user data.</summary>
 </histogram>
@@ -51266,6 +51368,15 @@
   </summary>
 </histogram>
 
+<histogram name="Tab.LostTabAgeWhenSwitchedToForeground" units="ms">
+  <owner>pkotwicz@chromium.org</owner>
+  <summary>
+    [Android] When a tab that was opened in the background (e.g. via &quot;Open
+    link in new tab&quot;) is evicted prior to the first time that it is shown,
+    we record the tab's age at the time that the tab is shown.
+  </summary>
+</histogram>
+
 <histogram name="Tab.NewTab" enum="NewTabType">
   <owner>lliabraa@chromium.org</owner>
   <owner>beaudoin@chromium.org</owner>
@@ -58338,6 +58449,22 @@
   <int value="16" label="kCodecAC3"/>
 </enum>
 
+<enum name="AudioDevicePropertyResult" type="int">
+  <int value="0" label="Other"/>
+  <int value="1" label="Device has changed"/>
+  <int value="2" label="IO stopped abnormally"/>
+  <int value="3" label="Hog mode"/>
+  <int value="4" label="Bufer frame size"/>
+  <int value="5" label="Buffer frame size range"/>
+  <int value="6" label="Stream configuration"/>
+  <int value="7" label="Actual sample rate"/>
+  <int value="8" label="Nominal sample rate"/>
+  <int value="9" label="Device is running somewhere"/>
+  <int value="10" label="Device is running"/>
+  <int value="11" label="Device is alive"/>
+  <int value="12" label="Stream physical format"/>
+</enum>
+
 <enum name="AudioFramesPerBuffer" type="int">
   <int value="0" label="k160"/>
   <int value="1" label="k320"/>
@@ -58923,6 +59050,7 @@
   <int value="110" label="WSH_SEND_BLOB_DURING_BLOB_SEND"/>
   <int value="111" label="WSH_SEND_FRAME_DURING_BLOB_SEND"/>
   <int value="112" label="RFH_UNEXPECTED_LOAD_START"/>
+  <int value="113" label="NMF_INVALID_ARGUMENT"/>
 </enum>
 
 <enum name="BadMessageReasonExtensions" type="int">
@@ -64131,6 +64259,7 @@
   <int value="392" label="DISPLAY_SOURCE_ON_SINKS_UPDATED"/>
   <int value="393" label="INPUT_IME_ON_COMPOSITION_BOUNDS_CHANGED"/>
   <int value="394" label="INPUT_METHOD_PRIVATE_ON_IME_MENU_ACTIVATION_CHANGED"/>
+  <int value="395" label="INPUT_METHOD_PRIVATE_ON_IME_MENU_LIST_CHANGED"/>
 </enum>
 
 <enum name="ExtensionFileWriteResult" type="int">
@@ -67153,6 +67282,12 @@
   <int value="1241" label="MediaStreamOnEnded"/>
   <int value="1242" label="DocumentCreateEventInputEvent"/>
   <int value="1243" label="WebAnimationHyphenatedProperty"/>
+  <int value="1244"
+      label="FormControlsCollectionReturnsRadioNodeListForFieldSet"/>
+  <int value="1245" label="ApplicationCacheManifestSelectInsecureOrigin"/>
+  <int value="1246" label="ApplicationCacheManifestSelectSecureOrigin"/>
+  <int value="1247" label="ApplicationCacheAPIInsecureOrigin"/>
+  <int value="1248" label="ApplicationCacheAPISecureOrigin"/>
 </enum>
 
 <enum name="FetchRequestMode" type="int">
@@ -71282,6 +71417,7 @@
   <int value="-1497338981" label="disable-accelerated-overflow-scroll"/>
   <int value="-1490298774" label="enable-captive-portal-bypass-proxy-option"/>
   <int value="-1482685863" label="enable-request-tablet-site"/>
+  <int value="-1467332609" label="tab-management-experiment-type-anise"/>
   <int value="-1460462432" label="disable-media-source"/>
   <int value="-1440152291" label="disable-gesture-typing"/>
   <int value="-1433719718" label="enable-webrtc-stun-origin"/>
@@ -71436,6 +71572,7 @@
   <int value="-340622848" label="disable-javascript-harmony-shipping"/>
   <int value="-340255045" label="allow-nacl-socket-api"/>
   <int value="-328361990" label="enable-experimental-extension-apis"/>
+  <int value="-322827131" label="tab-management-experiment-type-basil"/>
   <int value="-320820051" label="enable-zero-copy"/>
   <int value="-314910380" label="disable-distance-field-text"/>
   <int value="-311148335" label="v8-pac-mojo-out-of-process"/>
@@ -71563,6 +71700,7 @@
   <int value="773919225" label="disable-office-editing-component-extension"/>
   <int value="779086132" label="enable-data-reduction-proxy-alt"/>
   <int value="782167080" label="enable-new-qp-input-view"/>
+  <int value="807734471" label="tab-management-experiment-type-disabled"/>
   <int value="811374216" label="disable-new-bookmark-apps"/>
   <int value="820650704" label="disable-ntp-popular-sites"/>
   <int value="821192723" label="show-fps-counter"/>
@@ -71611,6 +71749,7 @@
   <int value="1105439588" label="enable-swipe-selection"/>
   <int value="1107543566" label="enable-one-copy"/>
   <int value="1108663108" label="disable-device-discovery-notifications"/>
+  <int value="1113365156" label="tab-management-experiment-type-chive"/>
   <int value="1114629582" label="enable-floating-virtual-keyboard"/>
   <int value="1118109174" label="enable-launcher-search-provider-api"/>
   <int value="1129888794" label="ash-touch-hud"/>
@@ -71745,6 +71884,7 @@
   <int value="1993258379" label="enable-icon-ntp"/>
   <int value="2000091128" label="enable-touch-hover"/>
   <int value="2004829262" label="enable-webgl-draft-extensions"/>
+  <int value="2005614493" label="tab-management-experiment-type-dill"/>
   <int value="2037756154" label="enable-impl-side-painting"/>
   <int value="2059322877" label="new-avatar-menu"/>
   <int value="2071461362" label="disable-credit-card-scan"/>
@@ -72720,6 +72860,13 @@
   <int value="39" label="SmoothStream"/>
 </enum>
 
+<enum name="MediaControlsShowReason" type="int">
+  <int value="0" label="Attribute"/>
+  <int value="1" label="Fullscreen"/>
+  <int value="2" label="No scripts allowed"/>
+  <int value="3" label="Not shown"/>
+</enum>
+
 <enum name="MediaElementAutoPlay" type="int">
   <int value="0" label="Media element with autoplay seen"/>
   <int value="1"
@@ -82525,6 +82672,7 @@
   <int value="1" label="No device"/>
   <int value="2" label="No service"/>
   <int value="3" label="Not found"/>
+  <int value="4" label="Blacklisted"/>
 </enum>
 
 <enum name="WebBluetoothGetPrimaryServiceOutcome" type="int">
@@ -86675,6 +86823,7 @@
   <affected-histogram name="PageLoad.AbortTiming.Other"/>
   <affected-histogram name="PageLoad.AbortTiming.Reload"/>
   <affected-histogram name="PageLoad.AbortTiming.Stop"/>
+  <affected-histogram name="PageLoad.AbortTiming.UnknownNavigation"/>
   <affected-histogram name="PageLoad.Timing2.NavigationToFirstBackground"/>
 </histogram_suffixes>
 
diff --git a/tools/metrics/rappor/rappor.xml b/tools/metrics/rappor/rappor.xml
index 2d3a2f26..4de1937 100644
--- a/tools/metrics/rappor/rappor.xml
+++ b/tools/metrics/rappor/rappor.xml
@@ -1004,6 +1004,25 @@
   </summary>
 </rappor-metric>
 
+<rappor-metric name="PowerfulFeatureUse.Host.ApplicationCacheAPI.Insecure"
+    type="ETLD_PLUS_ONE">
+  <owner>jww@chromium.org</owner>
+  <summary>
+    The host of the URL that uses a the Application Cache programmatic API from
+    an insecure origin.
+  </summary>
+</rappor-metric>
+
+<rappor-metric
+    name="PowerfulFeatureUse.Host.ApplicationCacheManifestSelect.Insecure"
+    type="ETLD_PLUS_ONE">
+  <owner>jww@chromium.org</owner>
+  <summary>
+    The host of the URL that uses an Application Cache manifest from an insecure
+    origin.
+  </summary>
+</rappor-metric>
+
 <rappor-metric name="PowerfulFeatureUse.Host.DeviceMotion.Insecure"
     type="ETLD_PLUS_ONE">
   <owner>jww@chromium.org</owner>
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py
index 76f8e7d8..a712349 100644
--- a/tools/perf/benchmarks/blink_perf.py
+++ b/tools/perf/benchmarks/blink_perf.py
@@ -202,6 +202,7 @@
     return CreateStorySetFromPath(path, SKIPPED_FILE)
 
 
+@benchmark.Disabled('win')  # http://crbug.com/588819
 class BlinkPerfEvents(perf_benchmark.PerfBenchmark):
   tag = 'events'
   test = _BlinkPerfMeasurement
diff --git a/tools/perf/docs/perf_regression_sheriffing.md b/tools/perf/docs/perf_regression_sheriffing.md
index 3b998d0..7c95cd02 100644
--- a/tools/perf/docs/perf_regression_sheriffing.md
+++ b/tools/perf/docs/perf_regression_sheriffing.md
@@ -72,6 +72,13 @@
 with the CL author. If the bisects failed to update the bug with results, please
 file a bug on it (see [feedback](#feedback) links below).
 
+Also during your shift, please spend any spare time driving down bugs from the
+[regression backlog](http://go/triage-backlog). Treat these bugs as you would
+your own - investigate the regressions, find out what the next step should be,
+and then move the bug along. As the backlog only contains bugs that haven't been
+modified in some time, you should be able to end your shift with an empty
+backlog.
+
 After your shift, please try to follow up on the bugs you filed weekly. Kick off
 new bisects if the previous ones failed, and if the bisect picks a likely
 culprit follow up to ensure the CL author addresses the problem. If you are
diff --git a/tools/valgrind/drmemory/suppressions.txt b/tools/valgrind/drmemory/suppressions.txt
index c5e6d403..14e4005a 100644
--- a/tools/valgrind/drmemory/suppressions.txt
+++ b/tools/valgrind/drmemory/suppressions.txt
@@ -789,7 +789,7 @@
 *!IPC::internal::HandleAttachmentWin::HandleAttachmentWin
 
 HANDLE LEAK
-name=bug_586668
+name=bug_586668_a
 system call NtDuplicateObject
 KERNELBASE.dll!DuplicateHandle
 KERNEL32.dll!DuplicateHandle
@@ -799,6 +799,17 @@
 mojo_system_impl.dll!mojo::edk::Channel::OnReadComplete
 
 HANDLE LEAK
+name=bug_586668_b
+system call NtDuplicateObject
+KERNELBASE.dll!DuplicateHandle
+KERNEL32.dll!DuplicateHandle
+base.dll!base::SharedMemory::DuplicateHandle
+mojo_system_impl.dll!mojo::edk::PlatformSharedBuffer::DuplicatePlatformHandle
+mojo_system_impl.dll!mojo::edk::SharedBufferDispatcher::EndSerialize
+mojo_system_impl.dll!mojo::edk::MessagePipeDispatcher::WriteMessage
+mojo_system_impl.dll!mojo::edk::Core::WriteMessage
+
+HANDLE LEAK
 name=bug_586996_b
 system call NtDuplicateObject
 KERNELBASE.dll!DuplicateHandle
diff --git a/tools/valgrind/gtest_exclude/content_browsertests.gtest-drmemory_win32.txt b/tools/valgrind/gtest_exclude/content_browsertests.gtest-drmemory_win32.txt
index 1ced8cb..a4eb170 100644
--- a/tools/valgrind/gtest_exclude/content_browsertests.gtest-drmemory_win32.txt
+++ b/tools/valgrind/gtest_exclude/content_browsertests.gtest-drmemory_win32.txt
@@ -64,3 +64,6 @@
 
 # https://crbug.com/505714
 NaClBrowserTestGLibc.PPAPICore
+
+# https://crbug.com/589174
+WebContentsImplBrowserTest.SetTitleOnUnload
diff --git a/tools/valgrind/gtest_exclude/unit_tests.gtest-memcheck.txt b/tools/valgrind/gtest_exclude/unit_tests.gtest-memcheck.txt
index ece10da..482109a 100644
--- a/tools/valgrind/gtest_exclude/unit_tests.gtest-memcheck.txt
+++ b/tools/valgrind/gtest_exclude/unit_tests.gtest-memcheck.txt
@@ -38,6 +38,3 @@
 DesktopMediaListAshTest.*
 ExtensionTestMessageListenerUnittest.*
 SigninErrorNotifierTest.*
-
-# Hangs: https://crbug.com/582372
-CombinedDesktopMediaListTest.*
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index 574ffab9..79c135d 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -106,8 +106,31 @@
   g_unique_id_win_map.Get().erase(unique_id);
 }
 
+base::LazyInstance<base::ObserverList<IAccessible2UsageObserver>>
+    g_iaccessible2_usage_observer_list = LAZY_INSTANCE_INITIALIZER;
+
 }  // namespace
 
+//
+// IAccessible2UsageObserver
+//
+
+IAccessible2UsageObserver::IAccessible2UsageObserver() {
+}
+
+IAccessible2UsageObserver::~IAccessible2UsageObserver() {
+}
+
+// static
+base::ObserverList<IAccessible2UsageObserver>&
+    GetIAccessible2UsageObserverList() {
+  return g_iaccessible2_usage_observer_list.Get();
+}
+
+//
+// AXPlatformNode::Create
+//
+
 // static
 AXPlatformNode* AXPlatformNode::Create(AXPlatformNodeDelegate* delegate) {
   // Make sure ATL is initialized in this module.
@@ -129,6 +152,10 @@
   return ax_platform_node.get();
 }
 
+//
+// AXPlatformNodeWin
+//
+
 AXPlatformNodeWin::AXPlatformNodeWin()
     : unique_id_win_(GetNextNegativeUniqueIdForWinAccessibility(this)) {
 }
@@ -876,6 +903,13 @@
 STDMETHODIMP AXPlatformNodeWin::QueryService(
     REFGUID guidService, REFIID riid, void** object) {
   COM_OBJECT_VALIDATE_1_ARG(object);
+
+  if (riid == IID_IAccessible2) {
+    FOR_EACH_OBSERVER(IAccessible2UsageObserver,
+                      GetIAccessible2UsageObserverList(),
+                      OnIAccessible2Used());
+  }
+
   if (guidService == IID_IAccessible ||
       guidService == IID_IAccessible2 ||
       guidService == IID_IAccessible2_2 ||
diff --git a/ui/accessibility/platform/ax_platform_node_win.h b/ui/accessibility/platform/ax_platform_node_win.h
index 5d264211..3979272 100644
--- a/ui/accessibility/platform/ax_platform_node_win.h
+++ b/ui/accessibility/platform/ax_platform_node_win.h
@@ -9,11 +9,29 @@
 #include <atlcom.h>
 #include <oleacc.h>
 
+#include "base/observer_list.h"
 #include "third_party/iaccessible2/ia2_api_all.h"
+#include "ui/accessibility/ax_export.h"
+#include "ui/accessibility/ax_text_utils.h"
 #include "ui/accessibility/platform/ax_platform_node_base.h"
 
 namespace ui {
 
+// A simple interface for a class that wants to be notified when IAccessible2
+// is used by a client, a strong indication that full accessibility support
+// should be enabled.
+class AX_EXPORT IAccessible2UsageObserver {
+ public:
+  IAccessible2UsageObserver();
+  virtual ~IAccessible2UsageObserver();
+  virtual void OnIAccessible2Used() = 0;
+};
+
+// Get an observer list that allows modules across the codebase to
+// listen to when usage of IAccessible2 is detected.
+extern AX_EXPORT base::ObserverList<IAccessible2UsageObserver>&
+    GetIAccessible2UsageObserverList();
+
 class __declspec(uuid("26f5641a-246d-457b-a96d-07f3fae6acf2"))
 AXPlatformNodeWin
 : public CComObjectRootEx<CComMultiThreadModel>,
diff --git a/ui/android/java/src/org/chromium/ui/base/DeviceFormFactor.java b/ui/android/java/src/org/chromium/ui/base/DeviceFormFactor.java
index da99957f..4b472c0 100644
--- a/ui/android/java/src/org/chromium/ui/base/DeviceFormFactor.java
+++ b/ui/android/java/src/org/chromium/ui/base/DeviceFormFactor.java
@@ -5,6 +5,7 @@
 package org.chromium.ui.base;
 
 import android.content.Context;
+import android.util.DisplayMetrics;
 
 import org.chromium.base.annotations.CalledByNative;
 
@@ -16,24 +17,49 @@
     /**
      * The minimum width that would classify the device as a tablet or a large tablet.
      */
-    private static final int MINIMUM_TABLET_WIDTH_DP = 600;
+    public static final int MINIMUM_TABLET_WIDTH_DP = 600;
     private static final int MINIMUM_LARGE_TABLET_WIDTH_DP = 720;
 
+    private static Boolean sIsTablet = null;
+    private static Boolean sIsLargeTablet = null;
+
     /**
      * @param context Android's context.
-     * @return        Whether the app should treat the device as a tablet for layout.
+     * @return        Whether the app should treat the device as a tablet for layout. This method
+     *                does not depend on the current window size and is not affected by
+     *                multi-window. It is dependent only on the device's size.
      */
     @CalledByNative
     public static boolean isTablet(Context context) {
-        int minimumScreenWidthDp = context.getResources().getConfiguration().smallestScreenWidthDp;
-        return minimumScreenWidthDp >= MINIMUM_TABLET_WIDTH_DP;
+        if (sIsTablet == null) {
+            sIsTablet = getSmallestDeviceWidthDp(context.getResources().getDisplayMetrics())
+                    >= MINIMUM_TABLET_WIDTH_DP;
+        }
+        return sIsTablet;
     }
 
     /**
-     * @return True if the current screen's minimum dimension is larger than 720dp.
+     * @param context Android's context.
+     * @return True if the current device's minimum dimension is larger than 720dp. This method
+     *                does not depend on the current window size and is not affected by
+     *                multi-window.
      */
     public static boolean isLargeTablet(Context context) {
-        int minimumScreenWidthDp = context.getResources().getConfiguration().smallestScreenWidthDp;
-        return minimumScreenWidthDp >= MINIMUM_LARGE_TABLET_WIDTH_DP;
+        if (sIsLargeTablet == null) {
+            sIsLargeTablet = getSmallestDeviceWidthDp(context.getResources().getDisplayMetrics())
+                    >= MINIMUM_LARGE_TABLET_WIDTH_DP;
+        }
+        return sIsLargeTablet;
+    }
+
+    /**
+     * Calculates the minimum device width in dp.
+     * @param metrics The {@link DisplayMetrics} to use for calculating device size.
+     * @return The smaller of device width and height in dp.
+     */
+    public static int getSmallestDeviceWidthDp(DisplayMetrics metrics) {
+        int smallestDeviceWidthDp = Math.round(Math.min(metrics.heightPixels / metrics.density,
+                metrics.widthPixels / metrics.density));
+        return smallestDeviceWidthDp;
     }
 }
diff --git a/ui/android/java/strings/android_ui_strings.grd b/ui/android/java/strings/android_ui_strings.grd
index 1eee8497..1ce51bc3 100644
--- a/ui/android/java/strings/android_ui_strings.grd
+++ b/ui/android/java/strings/android_ui_strings.grd
@@ -234,11 +234,6 @@
       <message name="IDS_AUTOFILL_KEYBOARD_ACCESSORY_CONTENT_DESCRIPTION" desc="The text announced by the screen reader when the autofill suggestions are shown.">
         Suggestions available
       </message>
-      
-      <!-- Herb strings -->
-      <message name="IDS_CACHE_NATIVE_FLAGS_REQUIRES_RESTART" desc="Toast telling the user that flags may not take effect until a restart." translateable="false">
-        Cached flags may not take effect until the browser is restarted again.
-      </message>
     </messages>
   </release>
 </grit>
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index 6a8f5ea..fd925a0 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -2,10 +2,12 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/buildflag_header.gni")
 import("//build/config/compiler/compiler.gni")
 import("//build/config/sanitizers/sanitizers.gni")
 import("//build/config/ui.gni")
 import("//testing/test.gni")
+import("//ui/base/ui_features.gni")
 import("//ui/ozone/ozone.gni")
 
 if (is_android) {
@@ -43,6 +45,11 @@
   configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 }
 
+buildflag_header("ui_features") {
+  header = "ui_features.h"
+  flags = [ "ENABLE_HIDPI=$enable_hidpi" ]
+}
+
 component("base") {
   output_name = "ui_base"
 
@@ -130,6 +137,7 @@
     "cursor/cursor_android.cc",
     "cursor/cursor_loader.h",
     "cursor/cursor_win.cc",
+    "default_style.h",
     "default_theme_provider_mac.mm",
     "device_form_factor.h",
     "device_form_factor_android.cc",
@@ -344,6 +352,7 @@
   defines = [ "UI_BASE_IMPLEMENTATION" ]
 
   public_deps = [
+    ":ui_features",
     "//base",
     "//skia",
     "//ui/events:events_base",
@@ -626,8 +635,8 @@
       "test/scoped_fake_nswindow_focus.mm",
       "test/scoped_fake_nswindow_fullscreen.h",
       "test/scoped_fake_nswindow_fullscreen.mm",
-      "test/scoped_preferred_scroller_style_legacy_mac.h",
-      "test/scoped_preferred_scroller_style_legacy_mac.mm",
+      "test/scoped_preferred_scroller_style_mac.h",
+      "test/scoped_preferred_scroller_style_mac.mm",
       "test/test_clipboard.cc",
       "test/test_clipboard.h",
       "test/windowed_nsnotification_observer.h",
diff --git a/ui/base/cocoa/controls/blue_label_button.mm b/ui/base/cocoa/controls/blue_label_button.mm
index 9d9b580..37ecc8da 100644
--- a/ui/base/cocoa/controls/blue_label_button.mm
+++ b/ui/base/cocoa/controls/blue_label_button.mm
@@ -29,6 +29,8 @@
 const SkColor kOuterRingColor = SkColorSetRGB(0x2b, 0x67, 0xce);
 const SkColor kPressOuterRingColor = SkColorSetRGB(0x23, 0x52, 0xa2);
 
+const int kFontSizeDelta = ui::ResourceBundle::kSmallFontDelta;
+
 @interface BlueLabelButtonCell : NSButtonCell
 
 + (NSAttributedString*)generateAttributedString:(NSString*)buttonText;
@@ -54,8 +56,7 @@
 
 + (NSAttributedString*)generateAttributedString:(NSString*)buttonText {
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  NSFont* buttonFont = rb.GetFontList(ui::ResourceBundle::SmallFont).
-      GetPrimaryFont().GetNativeFont();
+  NSFont* buttonFont = rb.GetFontWithDelta(kFontSizeDelta).GetNativeFont();
   base::scoped_nsobject<NSMutableParagraphStyle> buttonTextParagraphStyle(
       [[NSMutableParagraphStyle alloc] init]);
   [buttonTextParagraphStyle setAlignment:NSCenterTextAlignment];
diff --git a/ui/base/cocoa/menu_controller_unittest.mm b/ui/base/cocoa/menu_controller_unittest.mm
index 5bda6b6..57a32be 100644
--- a/ui/base/cocoa/menu_controller_unittest.mm
+++ b/ui/base/cocoa/menu_controller_unittest.mm
@@ -271,8 +271,9 @@
 // Tests that items which have a font set actually use that font.
 TEST_F(MenuControllerTest, LabelFontList) {
   Delegate delegate;
-  const gfx::FontList& bold = ResourceBundle::GetSharedInstance().GetFontList(
-      ResourceBundle::BoldFont);
+  const gfx::FontList& bold =
+      ResourceBundle::GetSharedInstance().GetFontListWithDelta(0,
+                                                               gfx::Font::BOLD);
   FontListMenuModel model(&delegate, &bold, 0);
   model.AddItem(1, ASCIIToUTF16("one"));
   model.AddItem(2, ASCIIToUTF16("two"));
diff --git a/ui/base/default_style.h b/ui/base/default_style.h
new file mode 100644
index 0000000..49790af2
--- /dev/null
+++ b/ui/base/default_style.h
@@ -0,0 +1,40 @@
+// Copyright 2016 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 UI_BASE_DEFAULT_STYLE_H_
+#define UI_BASE_DEFAULT_STYLE_H_
+
+#include "build/build_config.h"
+
+// This file contains the constants that provide the default style for UI
+// controls and dialogs.
+
+namespace ui {
+
+// Default font size delta for messages in dialogs. Note that on Windows, the
+// "base" font size is determined by consulting the system for the font used in
+// native MessageBox dialogs. On Mac, it is [NSFont systemFontSize]. Linux
+// consults the default font description for a GTK Widget context. On ChromeOS,
+// ui::ResourceBundle provides a description via IDS_UI_FONT_FAMILY_CROS.
+const int kMessageFontSizeDelta = 0;
+
+// Default font size delta for dialog buttons, textfields, and labels.
+#if defined(OS_MACOSX)
+// Cocoa dialogs prefer [NSFont smallSystemFontSize] for labels (typically 11pt
+// vs 13pt).
+const int kLabelFontSizeDelta = -2;
+#else
+const int kLabelFontSizeDelta = 0;
+#endif
+
+// Font size delta for dialog titles.
+#if defined(OS_MACOSX)
+const int kTitleFontSizeDelta = 0;
+#else
+const int kTitleFontSizeDelta = 3;
+#endif
+
+}  // namespace ui
+
+#endif  // UI_BASE_DEFAULT_STYLE_H_
diff --git a/ui/base/dragdrop/os_exchange_data_provider_aura.cc b/ui/base/dragdrop/os_exchange_data_provider_aura.cc
index 9cd070a..009c3ee 100644
--- a/ui/base/dragdrop/os_exchange_data_provider_aura.cc
+++ b/ui/base/dragdrop/os_exchange_data_provider_aura.cc
@@ -6,7 +6,6 @@
 
 #include "base/logging.h"
 #include "base/strings/utf_string_conversions.h"
-#include "net/base/net_util.h"
 #include "ui/base/clipboard/clipboard.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
 #include "ui/base/dragdrop/file_info.h"
diff --git a/ui/base/ime/chromeos/input_method_manager.h b/ui/base/ime/chromeos/input_method_manager.h
index 32d24d6..4b1be80 100644
--- a/ui/base/ime/chromeos/input_method_manager.h
+++ b/ui/base/ime/chromeos/input_method_manager.h
@@ -77,6 +77,9 @@
 
     // Called when the IME menu is activated or deactivated.
     virtual void ImeMenuActivationChanged(bool is_active) = 0;
+    // Called when the current input method or the list of active input method
+    // IDs is changed.
+    virtual void ImeMenuListChanged() = 0;
 
     DISALLOW_ASSIGN(ImeMenuObserver);
   };
diff --git a/ui/base/resource/resource_bundle.cc b/ui/base/resource/resource_bundle.cc
index 536b9fc..8afa15b 100644
--- a/ui/base/resource/resource_bundle.cc
+++ b/ui/base/resource/resource_bundle.cc
@@ -32,6 +32,7 @@
 #include "ui/base/resource/data_pack.h"
 #include "ui/base/ui_base_paths.h"
 #include "ui/base/ui_base_switches.h"
+#include "ui/base/ui_features.h"
 #include "ui/gfx/codec/jpeg_codec.h"
 #include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/geometry/safe_integer_conversions.h"
@@ -62,11 +63,6 @@
 
 namespace {
 
-// Font sizes relative to base font.
-const int kSmallFontSizeDelta = -1;
-const int kMediumFontSizeDelta = 3;
-const int kLargeFontSizeDelta = 8;
-
 // PNG-related constants.
 const unsigned char kPngMagic[8] = { 0x89, 'P', 'N', 'G', 13, 10, 26, 10 };
 const size_t kPngChunkMetadataSize = 12;  // length, type, crc32
@@ -535,29 +531,72 @@
   return msg;
 }
 
-const gfx::FontList& ResourceBundle::GetFontList(FontStyle style) {
-  {
-    base::AutoLock lock_scope(*images_and_fonts_lock_);
-    LoadFontsIfNecessary();
-  }
-  switch (style) {
-    case BoldFont:
-      return *bold_font_list_;
+const gfx::FontList& ResourceBundle::GetFontListWithDelta(
+    int size_delta,
+    gfx::Font::FontStyle style) {
+  base::AutoLock lock_scope(*images_and_fonts_lock_);
+
+  typedef std::pair<int, gfx::Font::FontStyle> Key;
+  const Key styled_key(size_delta, style);
+
+  auto found = font_cache_.find(styled_key);
+  if (found != font_cache_.end())
+    return found->second;
+
+  const Key base_key(0, gfx::Font::NORMAL);
+  gfx::FontList& base = font_cache_[base_key];
+  if (styled_key == base_key)
+    return base;
+
+  // Fonts of a given style are derived from the unstyled font of the same size.
+  // Cache the unstyled font by first inserting a default-constructed font list.
+  // Then, derive it for the initial insertion, or use the iterator that points
+  // to the existing entry that the insertion collided with.
+  const Key sized_key(size_delta, gfx::Font::NORMAL);
+  auto sized = font_cache_.insert(std::make_pair(sized_key, gfx::FontList()));
+  if (sized.second)
+    sized.first->second = base.DeriveWithSizeDelta(size_delta);
+  if (styled_key == sized_key)
+    return sized.first->second;
+
+  auto styled = font_cache_.insert(std::make_pair(styled_key, gfx::FontList()));
+  DCHECK(styled.second);  // Otherwise font_cache_.find(..) would have found it.
+  styled.first->second = sized.first->second.DeriveWithStyle(
+      sized.first->second.GetFontStyle() | style);
+  return styled.first->second;
+}
+
+const gfx::Font& ResourceBundle::GetFontWithDelta(int size_delta,
+                                                  gfx::Font::FontStyle style) {
+  return GetFontListWithDelta(size_delta, style).GetPrimaryFont();
+}
+
+const gfx::FontList& ResourceBundle::GetFontList(FontStyle legacy_style) {
+  gfx::Font::FontStyle font_style = gfx::Font::NORMAL;
+  if (legacy_style == BoldFont || legacy_style == SmallBoldFont ||
+      legacy_style == MediumBoldFont || legacy_style == LargeBoldFont)
+    font_style = gfx::Font::BOLD;
+
+  int size_delta = 0;
+  switch (legacy_style) {
     case SmallFont:
-      return *small_font_list_;
-    case MediumFont:
-      return *medium_font_list_;
     case SmallBoldFont:
-      return *small_bold_font_list_;
+      size_delta = kSmallFontDelta;
+      break;
+    case MediumFont:
     case MediumBoldFont:
-      return *medium_bold_font_list_;
+      size_delta = kMediumFontDelta;
+      break;
     case LargeFont:
-      return *large_font_list_;
     case LargeBoldFont:
-      return *large_bold_font_list_;
-    default:
-      return *base_font_list_;
+      size_delta = kLargeFontDelta;
+      break;
+    case BaseFont:
+    case BoldFont:
+      break;
   }
+
+  return GetFontListWithDelta(size_delta, font_style);
 }
 
 const gfx::Font& ResourceBundle::GetFont(FontStyle style) {
@@ -567,8 +606,7 @@
 void ResourceBundle::ReloadFonts() {
   base::AutoLock lock_scope(*images_and_fonts_lock_);
   InitDefaultFontList();
-  base_font_list_.reset();
-  LoadFontsIfNecessary();
+  font_cache_.clear();
 }
 
 ScaleFactor ResourceBundle::GetMaxScaleFactor() const {
@@ -637,7 +675,7 @@
 #elif defined(OS_CHROMEOS)
   // TODO(oshima): Include 200P only if the device support 200P
   supported_scale_factors.push_back(SCALE_FACTOR_200P);
-#elif defined(OS_LINUX) && defined(ENABLE_HIDPI)
+#elif defined(OS_LINUX) && BUILDFLAG(ENABLE_HIDPI)
   supported_scale_factors.push_back(SCALE_FACTOR_200P);
 #elif defined(OS_WIN)
   bool default_to_100P = true;
@@ -745,34 +783,6 @@
 #endif
 }
 
-void ResourceBundle::LoadFontsIfNecessary() {
-  images_and_fonts_lock_->AssertAcquired();
-  if (base_font_list_)
-    return;
-
-  base_font_list_.reset(new gfx::FontList());
-  bold_font_list_.reset(new gfx::FontList(base_font_list_->DeriveWithStyle(
-      base_font_list_->GetFontStyle() | gfx::Font::BOLD)));
-
-  small_font_list_.reset(new gfx::FontList(
-      base_font_list_->DeriveWithSizeDelta(kSmallFontSizeDelta)));
-  small_bold_font_list_.reset(
-      new gfx::FontList(small_font_list_->DeriveWithStyle(
-          small_font_list_->GetFontStyle() | gfx::Font::BOLD)));
-
-  medium_font_list_.reset(new gfx::FontList(
-      base_font_list_->DeriveWithSizeDelta(kMediumFontSizeDelta)));
-  medium_bold_font_list_.reset(
-      new gfx::FontList(medium_font_list_->DeriveWithStyle(
-          medium_font_list_->GetFontStyle() | gfx::Font::BOLD)));
-
-  large_font_list_.reset(new gfx::FontList(
-      base_font_list_->DeriveWithSizeDelta(kLargeFontSizeDelta)));
-  large_bold_font_list_.reset(
-      new gfx::FontList(large_font_list_->DeriveWithStyle(
-          large_font_list_->GetFontStyle() | gfx::Font::BOLD)));
-}
-
 bool ResourceBundle::LoadBitmap(const ResourceHandle& data_handle,
                                 int resource_id,
                                 SkBitmap* bitmap,
diff --git a/ui/base/resource/resource_bundle.h b/ui/base/resource/resource_bundle.h
index 5a3cc5a4..1382aeb 100644
--- a/ui/base/resource/resource_bundle.h
+++ b/ui/base/resource/resource_bundle.h
@@ -43,12 +43,16 @@
 // such as theme graphics. Every resource is loaded only once.
 class UI_BASE_EXPORT ResourceBundle {
  public:
-  // An enumeration of the various font styles used throughout Chrome.
-  // The following holds true for the font sizes:
-  // Small <= SmallBold <= Base <= Bold <= Medium <= MediumBold <= Large.
+  // Legacy font size deltas. Consider these to be magic numbers. New code
+  // should declare their own size delta constant using an identifier that
+  // imparts some semantic meaning.
+  static const int kSmallFontDelta = -1;
+  static const int kMediumFontDelta = 3;
+  static const int kLargeFontDelta = 8;
+
+  // Legacy font style mappings. TODO(tapted): Phase these out in favour of
+  // client code providing their own constant with the desired font size delta.
   enum FontStyle {
-    // NOTE: depending upon the locale, using one of the *BoldFont below
-    // may *not* actually result in a bold font.
     SmallFont,
     SmallBoldFont,
     BaseFont,
@@ -238,10 +242,19 @@
   // string if the message_id is not found.
   base::string16 GetLocalizedString(int message_id);
 
-  // Returns the font list for the specified style.
-  const gfx::FontList& GetFontList(FontStyle style);
+  // Returns a font list derived from the platform-specific "Base" font list.
+  // The result is always cached and exists for the lifetime of the process.
+  const gfx::FontList& GetFontListWithDelta(
+      int size_delta,
+      gfx::Font::FontStyle style = gfx::Font::NORMAL);
 
-  // Returns the font for the specified style.
+  // Returns the primary font from the FontList given by GetFontListWithDelta().
+  const gfx::Font& GetFontWithDelta(
+      int size_delta,
+      gfx::Font::FontStyle style = gfx::Font::NORMAL);
+
+  // Deprecated. Returns fonts using hard-coded size deltas implied by |style|.
+  const gfx::FontList& GetFontList(FontStyle style);
   const gfx::Font& GetFont(FontStyle style);
 
   // Resets and reloads the cached fonts.  This is useful when the fonts of the
@@ -341,10 +354,6 @@
   // Initializes the font description of default gfx::FontList.
   void InitDefaultFontList();
 
-  // Initializes all the gfx::FontList members if they haven't yet been
-  // initialized.
-  void LoadFontsIfNecessary();
-
   // Fills the |bitmap| given the data file to look in and the |resource_id|.
   // Returns false if the resource does not exist.
   //
@@ -411,17 +420,11 @@
 
   gfx::Image empty_image_;
 
-  // The various font lists used. Cached to avoid repeated GDI
-  // creation/destruction.
-  scoped_ptr<gfx::FontList> base_font_list_;
-  scoped_ptr<gfx::FontList> bold_font_list_;
-  scoped_ptr<gfx::FontList> small_font_list_;
-  scoped_ptr<gfx::FontList> small_bold_font_list_;
-  scoped_ptr<gfx::FontList> medium_font_list_;
-  scoped_ptr<gfx::FontList> medium_bold_font_list_;
-  scoped_ptr<gfx::FontList> large_font_list_;
-  scoped_ptr<gfx::FontList> large_bold_font_list_;
-  scoped_ptr<gfx::FontList> web_font_list_;
+  // The various font lists used, as a map from a signed size delta from the
+  // platform base font size, plus style, to the FontList. Cached to avoid
+  // repeated GDI creation/destruction and font derivation.
+  // Must be accessed only while holding |images_and_fonts_lock_|.
+  std::map<std::pair<int, gfx::Font::FontStyle>, gfx::FontList> font_cache_;
 
   base::FilePath overridden_pak_path_;
 
diff --git a/ui/base/test/scoped_preferred_scroller_style_legacy_mac.h b/ui/base/test/scoped_preferred_scroller_style_legacy_mac.h
deleted file mode 100644
index 99b0028d..0000000
--- a/ui/base/test/scoped_preferred_scroller_style_legacy_mac.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2016 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 UI_BASE_TEST_SCOPED_PREFERRED_SCROLLER_STYLE_LEGACY_MAC_H_
-#define UI_BASE_TEST_SCOPED_PREFERRED_SCROLLER_STYLE_LEGACY_MAC_H_
-
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-
-namespace base {
-namespace mac {
-class ScopedObjCClassSwizzler;
-}
-}
-
-namespace ui {
-namespace test {
-
-// Overrides system setting for scrollbar style with NSScrollerStyleLegacy,
-// which means "always show scrollbars".
-class ScopedPreferredScrollerStyleLegacy {
- public:
-  ScopedPreferredScrollerStyleLegacy();
-  ~ScopedPreferredScrollerStyleLegacy();
-
- private:
-  scoped_ptr<base::mac::ScopedObjCClassSwizzler> swizzler_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScopedPreferredScrollerStyleLegacy);
-};
-
-}  // namespace test
-}  // namespace ui
-
-#endif  // UI_BASE_TEST_SCOPED_PREFERRED_SCROLLER_STYLE_LEGACY_MAC_H_
diff --git a/ui/base/test/scoped_preferred_scroller_style_legacy_mac.mm b/ui/base/test/scoped_preferred_scroller_style_legacy_mac.mm
deleted file mode 100644
index 82e9a5b..0000000
--- a/ui/base/test/scoped_preferred_scroller_style_legacy_mac.mm
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2016 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 "ui/base/test/scoped_preferred_scroller_style_legacy_mac.h"
-
-#import "base/mac/sdk_forward_declarations.h"
-#import "base/mac/scoped_objc_class_swizzler.h"
-
-using base::mac::ScopedObjCClassSwizzler;
-
-namespace {
-
-void NotifyStyleChanged() {
-  [[NSNotificationCenter defaultCenter]
-      postNotificationName:NSPreferredScrollerStyleDidChangeNotification
-                    object:nil];
-}
-
-}  // namespace
-
-// Donates a testing implementation of +[NSScroller preferredScrollerStyle].
-@interface FakeNSScrollerPreferredStyleDonor : NSObject
-@end
-
-@implementation FakeNSScrollerPreferredStyleDonor
-
-+ (NSInteger)preferredScrollerStyle {
-  return NSScrollerStyleLegacy;
-}
-
-@end
-
-namespace ui {
-namespace test {
-
-ScopedPreferredScrollerStyleLegacy::ScopedPreferredScrollerStyleLegacy() {
-  if (![NSScroller respondsToSelector:@selector(preferredScrollerStyle)])
-    return;
-
-  NSInteger previous_style = [NSScroller preferredScrollerStyle];
-
-  swizzler_.reset(
-      new ScopedObjCClassSwizzler([NSScroller class],
-                                  [FakeNSScrollerPreferredStyleDonor class],
-                                  @selector(preferredScrollerStyle)));
-
-  if (previous_style != NSScrollerStyleLegacy)
-    NotifyStyleChanged();
-}
-
-ScopedPreferredScrollerStyleLegacy::~ScopedPreferredScrollerStyleLegacy() {
-  if (!swizzler_)
-    return;  // Handle 10.6, which wouldn't have swizzled anything.
-
-  swizzler_.reset();
-
-  if ([NSScroller preferredScrollerStyle] != NSScrollerStyleLegacy)
-    NotifyStyleChanged();
-}
-
-}  // namespace test
-}  // namespace ui
diff --git a/ui/base/test/scoped_preferred_scroller_style_mac.h b/ui/base/test/scoped_preferred_scroller_style_mac.h
new file mode 100644
index 0000000..9e56130d
--- /dev/null
+++ b/ui/base/test/scoped_preferred_scroller_style_mac.h
@@ -0,0 +1,40 @@
+// Copyright 2016 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 UI_BASE_TEST_SCOPED_PREFERRED_SCROLLER_STYLE_LEGACY_MAC_H_
+#define UI_BASE_TEST_SCOPED_PREFERRED_SCROLLER_STYLE_LEGACY_MAC_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+namespace mac {
+class ScopedObjCClassSwizzler;
+}
+}
+
+namespace ui {
+namespace test {
+
+// Overrides system setting for scrollbar style with NSScrollerOverlay if we
+// want the scrollbar to overlay. Otherwise, override with
+// NSScrollerStyleLegacy which means "always show scrollbars".
+class ScopedPreferredScrollerStyle {
+ public:
+  explicit ScopedPreferredScrollerStyle(bool overlay);
+  ~ScopedPreferredScrollerStyle();
+
+ private:
+  scoped_ptr<base::mac::ScopedObjCClassSwizzler> swizzler_;
+
+  // True if the scrollbar style should overlay.
+  bool overlay_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedPreferredScrollerStyle);
+};
+
+}  // namespace test
+}  // namespace ui
+
+#endif  // UI_BASE_TEST_SCOPED_PREFERRED_SCROLLER_STYLE_LEGACY_MAC_H_
diff --git a/ui/base/test/scoped_preferred_scroller_style_mac.mm b/ui/base/test/scoped_preferred_scroller_style_mac.mm
new file mode 100644
index 0000000..8a94cc6
--- /dev/null
+++ b/ui/base/test/scoped_preferred_scroller_style_mac.mm
@@ -0,0 +1,83 @@
+// Copyright 2016 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 "ui/base/test/scoped_preferred_scroller_style_mac.h"
+
+#import "base/mac/sdk_forward_declarations.h"
+#import "base/mac/scoped_objc_class_swizzler.h"
+
+using base::mac::ScopedObjCClassSwizzler;
+
+namespace {
+
+void NotifyStyleChanged() {
+  [[NSNotificationCenter defaultCenter]
+      postNotificationName:NSPreferredScrollerStyleDidChangeNotification
+                    object:nil];
+}
+
+NSScrollerStyle GetScrollerStyle(bool overlay) {
+  return overlay ? NSScrollerStyleOverlay : NSScrollerStyleLegacy;
+}
+
+}  // namespace
+
+// Donates a testing implementation of +[NSScroller preferredScrollerStyle] by
+// returning NSScrollerStyleLegacy.
+@interface FakeNSScrollerPreferredStyleLegacyDonor : NSObject
+@end
+
+@implementation FakeNSScrollerPreferredStyleLegacyDonor
+
++ (NSInteger)preferredScrollerStyle {
+  return NSScrollerStyleLegacy;
+}
+
+@end
+
+// Donates a testing implementation of +[NSScroller preferredScrollerStyle] by
+// returning NSScrollerStyleOverlay.
+@interface FakeNSScrollerPreferredStyleOverlayDonor : NSObject
+@end
+
+@implementation FakeNSScrollerPreferredStyleOverlayDonor
+
++ (NSInteger)preferredScrollerStyle {
+  return NSScrollerStyleOverlay;
+}
+
+@end
+
+namespace ui {
+namespace test {
+
+ScopedPreferredScrollerStyle::ScopedPreferredScrollerStyle(bool overlay)
+    : overlay_(overlay) {
+  if (![NSScroller respondsToSelector:@selector(preferredScrollerStyle)])
+    return;
+
+  NSInteger previous_style = [NSScroller preferredScrollerStyle];
+  Class style_class = overlay_
+                          ? [FakeNSScrollerPreferredStyleOverlayDonor class]
+                          : [FakeNSScrollerPreferredStyleLegacyDonor class];
+
+  swizzler_.reset(new ScopedObjCClassSwizzler(
+      [NSScroller class], style_class, @selector(preferredScrollerStyle)));
+
+  if (previous_style != GetScrollerStyle(overlay_))
+    NotifyStyleChanged();
+}
+
+ScopedPreferredScrollerStyle::~ScopedPreferredScrollerStyle() {
+  if (!swizzler_)
+    return;  // Handle 10.6, which wouldn't have swizzled anything.
+
+  swizzler_.reset();
+
+  if ([NSScroller preferredScrollerStyle] != GetScrollerStyle(overlay_))
+    NotifyStyleChanged();
+}
+
+}  // namespace test
+}  // namespace ui
diff --git a/ui/base/ui_base.gyp b/ui/base/ui_base.gyp
index d092bc15..80f28d45 100644
--- a/ui/base/ui_base.gyp
+++ b/ui/base/ui_base.gyp
@@ -41,12 +41,23 @@
         }],
     ],
     },
+    { # GN version: //ui/base:ui_features
+      'target_name': 'ui_features',
+      'includes': [ '../../build/buildflag_header.gypi' ],
+      'variables': {
+        'buildflag_header_path': 'ui/base/ui_features.h',
+        'buildflag_flags': [
+          'ENABLE_HIDPI=<(enable_hidpi)',
+        ],
+      },
+    },
     {
       # GN version: //ui/base
       'target_name': 'ui_base',
       'type': '<(component)',
       'dependencies': [
         'ui_data_pack',
+        'ui_features',
         '../../base/base.gyp:base',
         '../../base/base.gyp:base_i18n',
         '../../base/base.gyp:base_static',
@@ -198,6 +209,7 @@
         'default_theme_provider.cc',
         'default_theme_provider.h',
         'default_theme_provider_mac.mm',
+        'default_style.h',
         'device_form_factor.h',
         'device_form_factor_android.cc',
         'device_form_factor_android.h',
@@ -727,8 +739,8 @@
             'test/scoped_fake_nswindow_focus.mm',
             'test/scoped_fake_nswindow_fullscreen.h',
             'test/scoped_fake_nswindow_fullscreen.mm',
-            'test/scoped_preferred_scroller_style_legacy_mac.h',
-            'test/scoped_preferred_scroller_style_legacy_mac.mm',
+            'test/scoped_preferred_scroller_style_mac.h',
+            'test/scoped_preferred_scroller_style_mac.mm',
             'test/windowed_nsnotification_observer.h',
             'test/windowed_nsnotification_observer.mm',
           ],
diff --git a/ui/base/ui_features.gni b/ui/base/ui_features.gni
new file mode 100644
index 0000000..724c4d4
--- /dev/null
+++ b/ui/base/ui_features.gni
@@ -0,0 +1,5 @@
+# Copyright 2016 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.
+
+enable_hidpi = is_mac || is_win || is_linux
diff --git a/ui/events/blink/input_handler_proxy.cc b/ui/events/blink/input_handler_proxy.cc
index 2a191b8..187c9ac8 100644
--- a/ui/events/blink/input_handler_proxy.cc
+++ b/ui/events/blink/input_handler_proxy.cc
@@ -597,10 +597,18 @@
   } else if (smooth_scroll_enabled_ &&
              gesture_event.data.scrollBegin.deltaHintUnits ==
                  blink::WebGestureEvent::ScrollUnits::Pixels) {
-    gfx::Vector2dF scroll_delta(-gesture_event.data.scrollBegin.deltaXHint,
-                                -gesture_event.data.scrollBegin.deltaYHint);
-    scroll_status = input_handler_->ScrollAnimated(
-        gfx::Point(gesture_event.x, gesture_event.y), scroll_delta);
+    // Generate a scroll begin/end combination to determine if
+    // this can actually be handled by the impl thread or not. But
+    // don't generate any scroll yet; GestureScrollUpdate will generate
+    // the scroll animation.
+    scroll_status = input_handler_->ScrollBegin(
+        &scroll_state, cc::InputHandler::ANIMATED_WHEEL);
+    if (scroll_status.thread == cc::InputHandler::SCROLL_ON_IMPL_THREAD) {
+      cc::ScrollStateData scroll_state_end_data;
+      scroll_state_end_data.is_ending = true;
+      cc::ScrollState scroll_state_end(scroll_state_end_data);
+      input_handler_->ScrollEnd(&scroll_state_end);
+    }
   } else {
     scroll_status =
         input_handler_->ScrollBegin(&scroll_state, cc::InputHandler::GESTURE);
diff --git a/ui/events/blink/input_handler_proxy_unittest.cc b/ui/events/blink/input_handler_proxy_unittest.cc
index 08358efb..6723a31 100644
--- a/ui/events/blink/input_handler_proxy_unittest.cc
+++ b/ui/events/blink/input_handler_proxy_unittest.cc
@@ -639,8 +639,9 @@
   gesture_.type = WebInputEvent::GestureScrollBegin;
   gesture_.data.scrollBegin.deltaHintUnits =
       WebGestureEvent::ScrollUnits::Pixels;
-  EXPECT_CALL(mock_input_handler_, ScrollAnimated(::testing::_, ::testing::_))
+  EXPECT_CALL(mock_input_handler_, ScrollBegin(::testing::_, ::testing::_))
       .WillOnce(testing::Return(kImplThreadScrollState));
+  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_));
   EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(gesture_));
 
   gesture_.type = WebInputEvent::GestureScrollUpdate;
diff --git a/ui/events/event.cc b/ui/events/event.cc
index 6e1228c8..2ff9ffd 100644
--- a/ui/events/event.cc
+++ b/ui/events/event.cc
@@ -155,6 +155,11 @@
         new GestureEvent(static_cast<const GestureEvent&>(event)));
   }
 
+  if (event.IsPointerEvent()) {
+    return make_scoped_ptr(
+        new PointerEvent(static_cast<const PointerEvent&>(event)));
+  }
+
   if (event.IsScrollEvent()) {
     return make_scoped_ptr(
         new ScrollEvent(static_cast<const ScrollEvent&>(event)));
@@ -178,6 +183,36 @@
   return static_cast<const GestureEvent*>(this);
 }
 
+MouseEvent* Event::AsMouseEvent() {
+  CHECK(IsMouseEvent());
+  return static_cast<MouseEvent*>(this);
+}
+
+const MouseEvent* Event::AsMouseEvent() const {
+  CHECK(IsMouseEvent());
+  return static_cast<const MouseEvent*>(this);
+}
+
+PointerEvent* Event::AsPointerEvent() {
+  CHECK(IsPointerEvent());
+  return static_cast<PointerEvent*>(this);
+}
+
+const PointerEvent* Event::AsPointerEvent() const {
+  CHECK(IsPointerEvent());
+  return static_cast<const PointerEvent*>(this);
+}
+
+TouchEvent* Event::AsTouchEvent() {
+  CHECK(IsTouchEvent());
+  return static_cast<TouchEvent*>(this);
+}
+
+const TouchEvent* Event::AsTouchEvent() const {
+  CHECK(IsTouchEvent());
+  return static_cast<const TouchEvent*>(this);
+}
+
 bool Event::HasNativeEvent() const {
   base::NativeEvent null_event;
   std::memset(&null_event, 0, sizeof(null_event));
@@ -644,6 +679,11 @@
 ////////////////////////////////////////////////////////////////////////////////
 // PointerEvent
 
+PointerEvent::PointerEvent(const PointerEvent& pointer_event)
+    : LocatedEvent(pointer_event),
+      pointer_id_(pointer_event.pointer_id()),
+      details_(pointer_event.pointer_details()) {}
+
 PointerEvent::PointerEvent(const MouseEvent& mouse_event)
     : LocatedEvent(mouse_event),
       pointer_id_(kMousePointerId),
diff --git a/ui/events/event.h b/ui/events/event.h
index 90ea9d9..e11ac73 100644
--- a/ui/events/event.h
+++ b/ui/events/event.h
@@ -29,6 +29,9 @@
 
 namespace ui {
 class EventTarget;
+class MouseEvent;
+class PointerEvent;
+class TouchEvent;
 enum class DomCode;
 
 class EVENTS_EXPORT Event {
@@ -198,7 +201,7 @@
 
   bool IsLocatedEvent() const {
     return IsMouseEvent() || IsScrollEvent() || IsTouchEvent() ||
-           IsGestureEvent();
+           IsGestureEvent() || IsPointerEvent();
   }
 
   // Convenience methods to cast |this| to a GestureEvent. IsGestureEvent()
@@ -206,6 +209,21 @@
   GestureEvent* AsGestureEvent();
   const GestureEvent* AsGestureEvent() const;
 
+  // Convenience methods to cast |this| to a MouseEvent. IsMouseEvent()
+  // must be true as a precondition to calling these methods.
+  MouseEvent* AsMouseEvent();
+  const MouseEvent* AsMouseEvent() const;
+
+  // Convenience methods to cast |this| to a PointerEvent. IsPointerEvent()
+  // must be true as a precondition to calling these methods.
+  PointerEvent* AsPointerEvent();
+  const PointerEvent* AsPointerEvent() const;
+
+  // Convenience methods to cast |this| to a TouchEvent. IsTouchEvent()
+  // must be true as a precondition to calling these methods.
+  TouchEvent* AsTouchEvent();
+  const TouchEvent* AsTouchEvent() const;
+
   // Returns true if the event has a valid |native_event_|.
   bool HasNativeEvent() const;
 
@@ -648,6 +666,7 @@
  public:
   static const int32_t kMousePointerId;
 
+  explicit PointerEvent(const PointerEvent& pointer_event);
   explicit PointerEvent(const MouseEvent& mouse_event);
   explicit PointerEvent(const TouchEvent& touch_event);
 
diff --git a/ui/events/event_unittest.cc b/ui/events/event_unittest.cc
index 7d55063..2090055 100644
--- a/ui/events/event_unittest.cc
+++ b/ui/events/event_unittest.cc
@@ -802,4 +802,36 @@
             pointer_event_from_mouse.pointer_details());
 }
 
+TEST(EventTest, PointerEventClone) {
+  {
+    ui::PointerEvent ptr_event(
+        ui::TouchEvent(ET_TOUCH_PRESSED, gfx::Point(0, 0), 0, 0,
+                       ui::EventTimeForNow(), 10.0f, 5.0f, 0.0f, 15.0f));
+    scoped_ptr<ui::Event> clone(ui::Event::Clone(ptr_event));
+    EXPECT_TRUE(clone->IsPointerEvent());
+    ui::PointerEvent* clone_as_ptr = clone->AsPointerEvent();
+
+    EXPECT_EQ(ptr_event.type(), clone_as_ptr->type());
+    EXPECT_EQ(ptr_event.pointer_id(), clone_as_ptr->pointer_id());
+    EXPECT_EQ(ptr_event.pointer_details(), clone_as_ptr->pointer_details());
+    EXPECT_EQ(ptr_event.location(), clone_as_ptr->location());
+    EXPECT_EQ(ptr_event.root_location(), clone_as_ptr->root_location());
+  }
+
+  {
+    ui::PointerEvent ptr_event(
+        ui::MouseEvent(ET_MOUSE_PRESSED, gfx::Point(0, 0), gfx::Point(0, 0),
+                       ui::EventTimeForNow(), 0, 0));
+    scoped_ptr<ui::Event> clone(ui::Event::Clone(ptr_event));
+    EXPECT_TRUE(clone->IsPointerEvent());
+    ui::PointerEvent* clone_as_ptr = clone->AsPointerEvent();
+
+    EXPECT_EQ(ptr_event.type(), clone_as_ptr->type());
+    EXPECT_EQ(ptr_event.pointer_id(), clone_as_ptr->pointer_id());
+    EXPECT_EQ(ptr_event.pointer_details(), clone_as_ptr->pointer_details());
+    EXPECT_EQ(ptr_event.location(), clone_as_ptr->location());
+    EXPECT_EQ(ptr_event.root_location(), clone_as_ptr->root_location());
+  }
+}
+
 }  // namespace ui
diff --git a/ui/events/keycodes/keyboard_code_conversion_mac.mm b/ui/events/keycodes/keyboard_code_conversion_mac.mm
index 8eb5749..9c9f72d 100644
--- a/ui/events/keycodes/keyboard_code_conversion_mac.mm
+++ b/ui/events/keycodes/keyboard_code_conversion_mac.mm
@@ -9,6 +9,8 @@
 #import <Carbon/Carbon.h>
 
 #include "base/logging.h"
+#include "base/mac/mac_logging.h"
+#include "base/mac/scoped_cftyperef.h"
 #include "base/macros.h"
 #include "ui/events/keycodes/dom/keycode_converter.h"
 
@@ -439,6 +441,7 @@
 
 DomKey DomKeyFromKeyCode(unsigned short keyCode) {
   switch (keyCode) {
+    case kVK_ANSI_KeypadEnter:
     case kVK_Return:
       return DomKey::ENTER;
     case kVK_Tab:
@@ -535,11 +538,6 @@
 
 DomKey DomKeyFromCharCode(unichar char_code) {
   switch (char_code) {
-    case 0x03:
-      return DomKey::ENTER;  // Numpad Enter
-    // Mac maps backspace to forward delete unicode.
-    case 0x7f:
-      return DomKey::BACKSPACE;
     case NSUpArrowFunctionKey:
       return DomKey::ARROW_UP;
     case NSDownArrowFunctionKey:
@@ -635,6 +633,54 @@
   }
 }
 
+UniChar MacKeycodeAndModifiersToCharacter(unsigned short mac_keycode,
+                                          int modifiers) {
+  // Convert NSEvent modifiers to format UCKeyTranslate accepts. See docs
+  // on UCKeyTranslate for more info.
+  int unicode_modifiers = 0;
+  if (modifiers & NSShiftKeyMask)
+    unicode_modifiers |= shiftKey;
+  if (modifiers & NSAlphaShiftKeyMask)
+    unicode_modifiers |= alphaLock;
+  // if (modifiers & NSControlKeyMask)
+  //   unicode_modifiers |= controlKey;
+  if (modifiers & NSAlternateKeyMask)
+    unicode_modifiers |= optionKey;
+  // if (modifiers & NSCommandKeyMask)
+  //   unicode_modifiers |= cmdKey;
+  UInt32 modifier_key_state = (unicode_modifiers >> 8) & 0xFF;
+
+  base::ScopedCFTypeRef<TISInputSourceRef> input_source_copy(
+      TISCopyCurrentKeyboardLayoutInputSource());
+  CFDataRef layout_data = static_cast<CFDataRef>(TISGetInputSourceProperty(
+      input_source_copy, kTISPropertyUnicodeKeyLayoutData));
+  const UCKeyboardLayout* layout =
+      reinterpret_cast<const UCKeyboardLayout*>(CFDataGetBytePtr(layout_data));
+
+  UInt32 dead_key_state = 0;
+  UniCharCount char_count = 0;
+  // According Apple's doc UCKeyTranslate::maxStringLength maybe up to 255 but
+  // would actually be rare to get more than 4.
+  UniChar unicode_string[4];
+  OSStatus status =
+      UCKeyTranslate(layout, static_cast<UInt16>(mac_keycode), kUCKeyActionDown,
+                     modifier_key_state, LMGetKbdLast(), 0, &dead_key_state,
+                     arraysize(unicode_string), &char_count, unicode_string);
+
+  OSSTATUS_DCHECK(status == noErr, status);
+  if (dead_key_state != 0) {
+    // A dead key, injecting space to get the diacritic in an isolated form.
+    status = UCKeyTranslate(layout, static_cast<UInt16>(kVK_Space),
+                            kUCKeyActionDown, 0, LMGetKbdLast(), 0,
+                            &dead_key_state, arraysize(unicode_string),
+                            &char_count, unicode_string);
+    OSSTATUS_DCHECK(status == noErr, status);
+  }
+
+  // TODO(chongz): Handle multiple character case. Should be rare.
+  return unicode_string[0];
+}
+
 }  // namespace
 
 int MacKeyCodeForWindowsKeyCode(KeyboardCode keycode,
@@ -742,12 +788,38 @@
 
 DomKey DomKeyFromNSEvent(NSEvent* event) {
   // Apply the lookup based on the character first since that has the
-  // Keyboard layout and modifers already applied; whereas the keyCode
+  // Keyboard layout and modifiers already applied; whereas the keyCode
   // doesn't.
   if ([event type] == NSKeyDown || [event type] == NSKeyUp) {
+    // Have to use [event characters] to handle dead key state.
     NSString* characters = [event characters];
-    if ([characters length] > 0)
-      return DomKeyFromCharCode([characters characterAtIndex:0]);
+    if ([characters length] > 0) {
+      // An invalid dead key combination will produce two characters, according
+      // to spec DomKey should be the last character.
+      // e.g. On French keyboard [+a will produce "^q", DomKey should be 'q'.
+      unichar dom_key_char =
+          [characters characterAtIndex:[characters length] - 1];
+      const bool is_ctrl_down = ([event modifierFlags] & NSControlKeyMask) &&
+                                !([event modifierFlags] & NSAlternateKeyMask);
+      const bool is_command_down = [event modifierFlags] & NSCommandKeyMask;
+      // On Mac Blink won't insert ASCII character if either Ctrl or Command, or
+      // both, are down.
+      // See EditingBehavior::shouldInsertCharacter()
+      if (std::iscntrl(dom_key_char) ||
+          (dom_key_char < 0x80 && (is_ctrl_down || is_command_down))) {
+        // According to spec if the key combination produces a non-printable
+        // character, the key value should be the character without modifiers
+        // except Shift and AltGr.
+        // See https://w3c.github.io/uievents/#keys-guidelines
+        const int kAllowedModifiersMask =
+            NSShiftKeyMask | NSAlphaShiftKeyMask | NSAlternateKeyMask;
+        // MacKeycodeAndModifiersToCharacter() is efficient (around 6E-4 ms).
+        dom_key_char = MacKeycodeAndModifiersToCharacter(
+            [event keyCode], [event modifierFlags] & kAllowedModifiersMask);
+      }
+      if (!std::iscntrl(dom_key_char))
+        return DomKeyFromCharCode(dom_key_char);
+    }
   }
   return DomKeyFromKeyCode([event keyCode]);
 }
diff --git a/ui/file_manager/file_manager/foreground/js/file_tasks.js b/ui/file_manager/file_manager/foreground/js/file_tasks.js
index efa27d01..a1c2566 100644
--- a/ui/file_manager/file_manager/foreground/js/file_tasks.js
+++ b/ui/file_manager/file_manager/foreground/js/file_tasks.js
@@ -554,12 +554,16 @@
  * @private
  */
 FileTasks.prototype.checkAvailability_ = function(callback) {
-  var areAll = function(props, name) {
-    var isOne = function(e) {
+  var areAll = function(entries, props, name) {
+    // TODO(cmihail): Make files in directories available offline.
+    // See http://crbug.com/569767.
+    var okEntriesNum = 0;
+    for (var i = 0; i < entries.length; i++) {
       // If got no properties, we safely assume that item is available.
-      return !e || e[name];
-    };
-    return props.filter(isOne).length === props.length;
+      if (props[i] && (props[i][name] || entries[i].isDirectory))
+        okEntriesNum++;
+    }
+    return okEntriesNum === props.length;
   };
 
   var containsDriveEntries =
@@ -583,7 +587,7 @@
   if (isDriveOffline) {
     this.metadataModel_.get(this.entries_, ['availableOffline', 'hosted']).then(
         function(props) {
-          if (areAll(props, 'availableOffline')) {
+          if (areAll(this.entries_, props, 'availableOffline')) {
             callback();
             return;
           }
@@ -611,7 +615,7 @@
   if (isOnMetered) {
     this.metadataModel_.get(this.entries_, ['availableWhenMetered', 'size'])
         .then(function(props) {
-          if (areAll(props, 'availableWhenMetered')) {
+          if (areAll(this.entries_, props, 'availableWhenMetered')) {
             callback();
             return;
           }
diff --git a/ui/file_manager/file_manager/foreground/js/task_controller.js b/ui/file_manager/file_manager/foreground/js/task_controller.js
index c38c41c..e011fa0 100644
--- a/ui/file_manager/file_manager/foreground/js/task_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/task_controller.js
@@ -263,7 +263,7 @@
   // Caller of update context menu task items.
   // FileSelectionHandler.EventType.CHANGE
   if (this.dialogType_ === DialogType.FULL_PAGE &&
-      selection.directoryCount === 0 && selection.fileCount > 0) {
+      (selection.directoryCount > 0 || selection.fileCount > 0)) {
     // Show disabled items for position calculation of the menu. They will be
     // overridden in this.updateFileSelectionAsync().
     this.updateContextMenuTaskItems_(
@@ -281,7 +281,7 @@
 TaskController.prototype.onSelectionChangeThrottled_ = function() {
   var selection = this.selectionHandler_.selection;
   if (this.dialogType_ === DialogType.FULL_PAGE &&
-      selection.directoryCount === 0 && selection.fileCount > 0) {
+      (selection.directoryCount > 0 || selection.fileCount > 0)) {
     this.getFileTasks()
         .then(function(tasks) {
           tasks.display(this.ui_.taskMenuButton);
diff --git a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
index 3cd331ef..75bcaf3 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
@@ -24,8 +24,17 @@
     var item = this.items[i];
     if (!item.entry)
       continue;
-    if (util.isSameEntry(item.entry, entry))
+    if (util.isSameEntry(item.entry, entry)) {
+      // The Drive root volume item "Google Drive" and its child "My Drive" have
+      // the same entry. When we look for a tree item of Drive's root directory,
+      // "My Drive" should be returned, as we use "Google Drive" for grouping
+      // "My Drive", "Shared with me", "Recent", and "Offine".
+      // Therefore, we have to skip "Google Drive" here.
+      if (item instanceof DriveVolumeItem)
+        return item.getItemByEntry(entry);
+
       return item;
+    }
     if (util.isDescendantEntry(item.entry, entry))
       return item.getItemByEntry(entry);
   }
diff --git a/ui/gfx/animation/multi_animation.h b/ui/gfx/animation/multi_animation.h
index fd28e38..a74656989 100644
--- a/ui/gfx/animation/multi_animation.h
+++ b/ui/gfx/animation/multi_animation.h
@@ -33,11 +33,12 @@
   // for 200ms with a % between .25 and .75 use the following three values: 200,
   // 100, 400.
   struct Part {
-    Part() : time_ms(0), start_time_ms(0), end_time_ms(0), type(Tween::ZERO) {}
-    Part(int time_ms, Tween::Type type)
+    Part() : Part(0, Tween::ZERO) {}
+    Part(int time_ms, Tween::Type type) : Part(time_ms, 0, time_ms, type) {}
+    Part(int time_ms, int start_time_ms, int end_time_ms, Tween::Type type)
         : time_ms(time_ms),
-          start_time_ms(0),
-          end_time_ms(time_ms),
+          start_time_ms(start_time_ms),
+          end_time_ms(end_time_ms),
           type(type) {}
 
     int time_ms;
diff --git a/ui/gfx/animation/multi_animation_unittest.cc b/ui/gfx/animation/multi_animation_unittest.cc
index b8a11fda..f8bff9a0f 100644
--- a/ui/gfx/animation/multi_animation_unittest.cc
+++ b/ui/gfx/animation/multi_animation_unittest.cc
@@ -40,9 +40,7 @@
 TEST(MultiAnimationTest, DifferingStartAndEnd) {
   // Create a MultiAnimation with two parts.
   MultiAnimation::Parts parts;
-  parts.push_back(MultiAnimation::Part(200, Tween::LINEAR));
-  parts[0].start_time_ms = 100;
-  parts[0].end_time_ms = 400;
+  parts.push_back(MultiAnimation::Part(200, 100, 400, Tween::LINEAR));
 
   MultiAnimation animation(parts, MultiAnimation::GetDefaultTimerInterval());
   AnimationContainerElement* as_element =
diff --git a/ui/gfx/canvas.cc b/ui/gfx/canvas.cc
index 874c328c1..80483eb 100644
--- a/ui/gfx/canvas.cc
+++ b/ui/gfx/canvas.cc
@@ -10,6 +10,7 @@
 #include "base/i18n/rtl.h"
 #include "base/logging.h"
 #include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkPath.h"
 #include "third_party/skia/include/effects/SkGradientShader.h"
 #include "ui/gfx/font_list.h"
 #include "ui/gfx/geometry/rect.h"
@@ -477,12 +478,30 @@
                           int dest_y,
                           int w,
                           int h) {
-  if (!IntersectsClipRectInt(dest_x, dest_y, w, h))
+  SkRect dest_rect = { SkIntToScalar(dest_x),
+                       SkIntToScalar(dest_y),
+                       SkIntToScalar(dest_x + w),
+                       SkIntToScalar(dest_y + h) };
+  if (!IntersectsClipRect(dest_rect))
     return;
 
+  SkPaint paint;
+  if (InitSkPaintForTiling(image, src_x, src_y, tile_scale_x, tile_scale_y,
+                           dest_x, dest_y, &paint))
+    canvas_->drawRect(dest_rect, paint);
+}
+
+bool Canvas::InitSkPaintForTiling(const ImageSkia& image,
+                                  int src_x,
+                                  int src_y,
+                                  float tile_scale_x,
+                                  float tile_scale_y,
+                                  int dest_x,
+                                  int dest_y,
+                                  SkPaint* paint) {
   const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_);
   if (image_rep.is_null())
-    return;
+    return false;
 
   SkMatrix shader_scale;
   shader_scale.setScale(SkFloatToScalar(tile_scale_x),
@@ -490,36 +509,20 @@
   shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y));
   shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y));
 
-  skia::RefPtr<SkShader> shader = CreateImageRepShader(
-      image_rep,
-      SkShader::kRepeat_TileMode,
-      shader_scale);
-
-  SkPaint paint;
-  paint.setShader(shader.get());
-  paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
-
-  SkRect dest_rect = { SkIntToScalar(dest_x),
-                       SkIntToScalar(dest_y),
-                       SkIntToScalar(dest_x + w),
-                       SkIntToScalar(dest_y + h) };
-  canvas_->drawRect(dest_rect, paint);
+  // setShader() takes ownership of the created shader.
+  paint->setShader(CreateImageRepShader(image_rep, SkShader::kRepeat_TileMode,
+                                        shader_scale).get());
+  paint->setXfermodeMode(SkXfermode::kSrcOver_Mode);
+  return true;
 }
 
 void Canvas::Transform(const gfx::Transform& transform) {
   canvas_->concat(transform.matrix());
 }
 
-bool Canvas::IntersectsClipRectInt(int x, int y, int w, int h) {
+bool Canvas::IntersectsClipRect(const SkRect& rect) {
   SkRect clip;
-  return canvas_->getClipBounds(&clip) &&
-      clip.intersect(SkIntToScalar(x), SkIntToScalar(y), SkIntToScalar(x + w),
-                     SkIntToScalar(y + h));
-}
-
-bool Canvas::IntersectsClipRect(const Rect& rect) {
-  return IntersectsClipRectInt(rect.x(), rect.y(),
-                               rect.width(), rect.height());
+  return canvas_->getClipBounds(&clip) && clip.intersects(rect);
 }
 
 void Canvas::DrawImageIntHelper(const ImageSkiaRep& image_rep,
@@ -541,16 +544,15 @@
     return;
   }
 
-  if (!IntersectsClipRectInt(dest_x, dest_y, dest_w, dest_h))
-    return;
-
-  float user_scale_x = static_cast<float>(dest_w) / src_w;
-  float user_scale_y = static_cast<float>(dest_h) / src_h;
-
   SkRect dest_rect = { SkIntToScalar(dest_x),
                        SkIntToScalar(dest_y),
                        SkIntToScalar(dest_x + dest_w),
                        SkIntToScalar(dest_y + dest_h) };
+  if (!IntersectsClipRect(dest_rect))
+    return;
+
+  float user_scale_x = static_cast<float>(dest_w) / src_w;
+  float user_scale_y = static_cast<float>(dest_h) / src_h;
 
   // Make a bitmap shader that contains the bitmap we want to draw. This is
   // basically what SkCanvas.drawBitmap does internally, but it gives us
diff --git a/ui/gfx/canvas.h b/ui/gfx/canvas.h
index 6233af3..367aa8a7 100644
--- a/ui/gfx/canvas.h
+++ b/ui/gfx/canvas.h
@@ -399,6 +399,18 @@
                     int w,
                     int h);
 
+  // Helper for TileImageInt().  Initializes |paint| for tiling |image| with the
+  // given parameters.  Returns false if the provided image does not have a
+  // representation for the current scale.
+  bool InitSkPaintForTiling(const ImageSkia& image,
+                            int src_x,
+                            int src_y,
+                            float tile_scale_x,
+                            float tile_scale_y,
+                            int dest_x,
+                            int dest_y,
+                            SkPaint* paint);
+
   // Apply transformation on the canvas.
   void Transform(const Transform& transform);
 
@@ -413,9 +425,8 @@
   float image_scale() const { return image_scale_; }
 
  private:
-  // Test whether the provided rectangle intersects the current clip rect.
-  bool IntersectsClipRectInt(int x, int y, int w, int h);
-  bool IntersectsClipRect(const Rect& rect);
+  // Tests whether the provided rectangle intersects the current clip rect.
+  bool IntersectsClipRect(const SkRect& rect);
 
   // Helper for the DrawImageInt functions declared above. The
   // |remove_image_scale| parameter indicates if the scale of the |image_rep|
diff --git a/ui/gfx/canvas_skia.cc b/ui/gfx/canvas_skia.cc
index 8f45fce..d20f92fe 100644
--- a/ui/gfx/canvas_skia.cc
+++ b/ui/gfx/canvas_skia.cc
@@ -21,6 +21,7 @@
 #include "ui/gfx/range/range.h"
 #include "ui/gfx/render_text.h"
 #include "ui/gfx/shadow_value.h"
+#include "ui/gfx/skia_util.h"
 #include "ui/gfx/text_elider.h"
 #include "ui/gfx/text_utils.h"
 
@@ -187,7 +188,7 @@
                                        int line_height,
                                        int flags,
                                        const ShadowValues& shadows) {
-  if (!IntersectsClipRect(text_bounds))
+  if (!IntersectsClipRect(RectToSkRect(text_bounds)))
     return;
 
   Rect clip_rect(text_bounds);
diff --git a/ui/gfx/render_text_unittest.cc b/ui/gfx/render_text_unittest.cc
index cea1786..d07c8f5 100644
--- a/ui/gfx/render_text_unittest.cc
+++ b/ui/gfx/render_text_unittest.cc
@@ -3048,27 +3048,36 @@
                                     kCanvasSize.height());
     {
 #if !defined(OS_CHROMEOS)
+      int top_test_height = kTestSize;
+#if defined(OS_WIN)
+      // Windows 8+ draws 1 pixel above the display rect.
+      if (base::win::GetVersion() >= base::win::VERSION_WIN8)
+        top_test_height = kTestSize - 1;
+#endif // OS_WIN
       // TODO(dschuyler): On ChromeOS text draws above the GetStringSize rect.
       SCOPED_TRACE("TextDoesntClip Top Side");
       rect_buffer.EnsureSolidRect(SK_ColorWHITE, 0, 0, kCanvasSize.width(),
-                                  kTestSize);
-#endif
+                                  top_test_height);
+#endif // !OS_CHROMEOS
     }
     {
+      int bottom_test_y = kTestSize + string_size.height();
+      int bottom_test_height = kTestSize;
+#if defined(OS_WIN)
+      // Windows 8+ draws 1 pixel below the display rect.
+      if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
+        bottom_test_y = kTestSize + string_size.height() + 1;
+        bottom_test_height = kTestSize - 1;
+      }
+#endif // OS_WIN
       SCOPED_TRACE("TextDoesntClip Bottom Side");
-      rect_buffer.EnsureSolidRect(SK_ColorWHITE, 0,
-                                  kTestSize + string_size.height(),
-                                  kCanvasSize.width(), kTestSize);
+      rect_buffer.EnsureSolidRect(SK_ColorWHITE, 0, bottom_test_y,
+                                  kCanvasSize.width(), bottom_test_height);
     }
     {
       SCOPED_TRACE("TextDoesntClip Left Side");
-#if defined(OS_WIN)
-      // TODO(dschuyler): On Windows XP the Unicode test draws to the left edge
-      // as if it is ignoring the SetDisplayRect shift by kTestSize.  This
-      // appears to be a preexisting issue that wasn't revealed by the prior
-      // unit tests.
-#elif defined(OS_MACOSX) || defined(OS_CHROMEOS)
-      // TODO(dschuyler): On Windows (non-XP), Chrome OS and Mac smoothing draws
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
+      // TODO(dschuyler): On Windows, Chrome OS and Mac smoothing draws to the
       // left of text.  This appears to be a preexisting issue that wasn't
       // revealed by the prior unit tests.
       rect_buffer.EnsureSolidRect(SK_ColorWHITE, 0, kTestSize, kTestSize - 1,
diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn
index a1c148d7..9d92df5 100644
--- a/ui/gl/BUILD.gn
+++ b/ui/gl/BUILD.gn
@@ -267,10 +267,7 @@
       "gl_implementation_ozone.cc",
       "gl_surface_ozone.cc",
     ]
-    deps += [
-      "//ui/ozone",
-      "//ui/ozone:ozone_base",
-    ]
+    deps += [ "//ui/ozone" ]
   }
 }
 
diff --git a/ui/gl/gl_context_osmesa.cc b/ui/gl/gl_context_osmesa.cc
index ee0f757..dd04b232 100644
--- a/ui/gl/gl_context_osmesa.cc
+++ b/ui/gl/gl_context_osmesa.cc
@@ -26,8 +26,18 @@
   OSMesaContext share_handle = static_cast<OSMesaContext>(
       share_group() ? share_group()->GetHandle() : nullptr);
 
-  GLuint format = compatible_surface->GetFormat();
-  DCHECK_NE(format, (unsigned)0);
+  GLuint format = 0;
+  switch (compatible_surface->GetFormat()) {
+    case GLSurface::SURFACE_OSMESA_BGRA:
+      format = OSMESA_BGRA;
+      break;
+    case GLSurface::SURFACE_OSMESA_RGBA:
+      format = OSMESA_RGBA;
+      break;
+    default:
+      NOTREACHED();
+      return false;
+  }
   context_ = OSMesaCreateContextExt(format,
                                     0,  // depth bits
                                     0,  // stencil bits
diff --git a/ui/gl/gl_image_io_surface.mm b/ui/gl/gl_image_io_surface.mm
index 3059333..536ce6c 100644
--- a/ui/gl/gl_image_io_surface.mm
+++ b/ui/gl/gl_image_io_surface.mm
@@ -16,6 +16,7 @@
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context.h"
 #include "ui/gl/gl_helper.h"
+#include "ui/gl/gl_version_info.h"
 #include "ui/gl/scoped_binders.h"
 
 // Note that this must be included after gl_bindings.h to avoid conflicts.
@@ -68,7 +69,7 @@
 
 bool ValidInternalFormat(unsigned internalformat) {
   switch (internalformat) {
-    case GL_RED:
+    case GL_R8:
     case GL_BGRA_EXT:
     case GL_RGB:
     case GL_RGB_YCBCR_420V_CHROMIUM:
@@ -107,7 +108,9 @@
 GLenum TextureFormat(BufferFormat format) {
   switch (format) {
     case BufferFormat::R_8:
-      return GL_RED;
+      return gfx::GLContext::GetCurrent()->GetVersionInfo()->IsES3Capable()
+                 ? GL_R8
+                 : GL_RED;
     case BufferFormat::BGRA_8888:
     case BufferFormat::RGBA_8888:
       return GL_RGBA;
diff --git a/ui/gl/gl_image_memory.cc b/ui/gl/gl_image_memory.cc
index a29a388..cabc6a09 100644
--- a/ui/gl/gl_image_memory.cc
+++ b/ui/gl/gl_image_memory.cc
@@ -26,7 +26,7 @@
     case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
     case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
     case GL_ETC1_RGB8_OES:
-    case GL_RED:
+    case GL_R8:
     case GL_RGB:
     case GL_RGBA:
     case GL_BGRA_EXT:
@@ -99,7 +99,9 @@
     case BufferFormat::ETC1:
       return GL_ETC1_RGB8_OES;
     case BufferFormat::R_8:
-      return GL_RED;
+      return gfx::GLContext::GetCurrent()->GetVersionInfo()->IsES3Capable()
+                 ? GL_R8
+                 : GL_RED;
     case BufferFormat::RGBA_4444:
     case BufferFormat::RGBA_8888:
       return GL_RGBA;
@@ -125,10 +127,11 @@
       return GL_RGBA;
     case BufferFormat::BGRX_8888:
       return GL_BGRA_EXT;
+    case BufferFormat::R_8:
+      return GL_RED;
     case BufferFormat::RGBA_4444:
     case BufferFormat::RGBA_8888:
     case BufferFormat::BGRA_8888:
-    case BufferFormat::R_8:
     case BufferFormat::ATC:
     case BufferFormat::ATCIA:
     case BufferFormat::DXT1:
diff --git a/ui/gl/gl_mock.cc b/ui/gl/gl_mock.cc
index 3b83579..785376f 100644
--- a/ui/gl/gl_mock.cc
+++ b/ui/gl/gl_mock.cc
@@ -6,6 +6,17 @@
 
 namespace gfx {
 
+namespace {
+
+// This is called mainly to prevent the compiler combining the code of mock
+// functions with identical contents, so that their function pointers will be
+// different.
+void MakeFunctionUnique(const char* func_name) {
+  VLOG(2) << "Calling mock " << func_name;
+}
+
+}  // namespace anonymous
+
 MockGLInterface::MockGLInterface() {
 }
 
@@ -18,4 +29,13 @@
   interface_ = gl_interface;
 }
 
+void GL_BINDING_CALL MockGLInterface::Mock_glTexSubImage3DNoData(
+    GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
+    GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type) {
+  MakeFunctionUnique("glTexSubImage3DNoData");
+  interface_->TexSubImage3DNoData(
+      target, level, xoffset, yoffset, zoffset, width, height, depth,
+      format, type);
+}
+
 }  // namespace gfx
diff --git a/ui/gl/gl_mock.h b/ui/gl/gl_mock.h
index 2a375e67..1ef09fab 100644
--- a/ui/gl/gl_mock.h
+++ b/ui/gl/gl_mock.h
@@ -42,19 +42,40 @@
       const void* /*data*/) {
     NOTREACHED();
   }
+
   void TexSubImage3D(
-      GLenum /*target*/, GLint /*level*/, GLint /*xoffset*/, GLint /*yoffset*/,
-      GLint /*zoffset*/, GLsizei /*width*/, GLsizei /*height*/,
-      GLsizei /*depth*/, GLenum /*format*/, GLenum /*type*/,
-      const void* /*pixels*/) {
-    NOTREACHED();
+      GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
+      GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
+      const void* pixels) {
+    if (pixels == nullptr) {
+      TexSubImage3DNoData(target, level, xoffset, yoffset, zoffset,
+                          width, height, depth, format, type);
+    } else {
+      NOTREACHED();
+    }
   }
 
+  MOCK_METHOD10(TexSubImage3DNoData,
+                void(GLenum target,
+                     GLint level,
+                     GLint xoffset,
+                     GLint yoffset,
+                     GLint zoffset,
+                     GLsizei width,
+                     GLsizei height,
+                     GLsizei depth,
+                     GLenum format,
+                     GLenum type));
+
  private:
   static MockGLInterface* interface_;
 
   // Static mock functions that invoke the member functions of interface_.
   #include "gl_bindings_autogen_mock.h"
+
+  static void GL_BINDING_CALL Mock_glTexSubImage3DNoData(
+      GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
+      GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type);
 };
 
 }  // namespace gfx
diff --git a/ui/gl/gl_surface.cc b/ui/gl/gl_surface.cc
index 2fccf87..da08315 100644
--- a/ui/gl/gl_surface.cc
+++ b/ui/gl/gl_surface.cc
@@ -190,9 +190,9 @@
   return NULL;
 }
 
-unsigned GLSurface::GetFormat() {
+GLSurface::Format GLSurface::GetFormat() {
   NOTIMPLEMENTED();
-  return 0;
+  return SURFACE_DEFAULT;
 }
 
 VSyncProvider* GLSurface::GetVSyncProvider() {
@@ -373,7 +373,7 @@
   return surface_->GetConfig();
 }
 
-unsigned GLSurfaceAdapter::GetFormat() {
+GLSurface::Format GLSurfaceAdapter::GetFormat() {
   return surface_->GetFormat();
 }
 
diff --git a/ui/gl/gl_surface.h b/ui/gl/gl_surface.h
index 3b08ebc..ffac1cf 100644
--- a/ui/gl/gl_surface.h
+++ b/ui/gl/gl_surface.h
@@ -38,8 +38,10 @@
 
   // Minimum bit depth of surface.
   enum Format {
-    SURFACE_ARGB8888 = 1, // 32 bits
-    SURFACE_RGB565 = 2,  // 16 bits
+    SURFACE_ARGB8888,
+    SURFACE_RGB565,
+    SURFACE_OSMESA_BGRA,
+    SURFACE_OSMESA_RGBA,
     SURFACE_DEFAULT = SURFACE_ARGB8888
   };
 
@@ -152,7 +154,7 @@
   virtual void* GetConfig();
 
   // Get the GL pixel format of the surface, if available.
-  virtual unsigned GetFormat();
+  virtual GLSurface::Format GetFormat();
 
   // Get access to a helper providing time of recent refresh and period
   // of screen refresh. If unavailable, returns NULL.
@@ -211,12 +213,7 @@
 
   // Create a GL surface used for offscreen rendering.
   static scoped_refptr<GLSurface> CreateOffscreenGLSurface(
-      const gfx::Size& size) {
-    return CreateOffscreenGLSurface(size, SURFACE_DEFAULT);
-  }
-
-  static scoped_refptr<GLSurface> CreateOffscreenGLSurface(
-      const gfx::Size& size, GLSurface::Format format);
+      const gfx::Size& size);
 
   static GLSurface* GetCurrent();
 
@@ -279,7 +276,7 @@
   void* GetShareHandle() override;
   void* GetDisplay() override;
   void* GetConfig() override;
-  unsigned GetFormat() override;
+  GLSurface::Format GetFormat() override;
   VSyncProvider* GetVSyncProvider() override;
   bool ScheduleOverlayPlane(int z_order,
                             OverlayTransform transform,
diff --git a/ui/gl/gl_surface_android.cc b/ui/gl/gl_surface_android.cc
index 05a92ee..1486ec45 100644
--- a/ui/gl/gl_surface_android.cc
+++ b/ui/gl/gl_surface_android.cc
@@ -54,14 +54,13 @@
 
 // static
 scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface(
-    const gfx::Size& size,
-    GLSurface::Format format) {
+    const gfx::Size& size) {
   CHECK_NE(kGLImplementationNone, GetGLImplementation());
   switch (GetGLImplementation()) {
     case kGLImplementationOSMesaGL: {
       scoped_refptr<GLSurface> surface(
-          new GLSurfaceOSMesa(OSMesaSurfaceFormatBGRA, size));
-      if (!surface->Initialize(format))
+          new GLSurfaceOSMesa(SURFACE_OSMESA_BGRA, size));
+      if (!surface->Initialize())
         return NULL;
 
       return surface;
@@ -75,7 +74,7 @@
         surface = new PbufferGLSurfaceEGL(size);
       }
 
-      if (!surface->Initialize(format))
+      if (!surface->Initialize())
         return NULL;
       return surface;
     }
diff --git a/ui/gl/gl_surface_egl.cc b/ui/gl/gl_surface_egl.cc
index 081ffa5..8c3ed9fa 100644
--- a/ui/gl/gl_surface_egl.cc
+++ b/ui/gl/gl_surface_egl.cc
@@ -16,6 +16,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/sys_info.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "ui/gfx/geometry/rect.h"
@@ -436,8 +437,7 @@
 }
 
 GLSurfaceEGL::GLSurfaceEGL() :
-    config_(nullptr),
-    format_(SURFACE_DEFAULT) {}
+    config_(nullptr) {}
 
 bool GLSurfaceEGL::InitializeOneOff() {
   static bool initialized = false;
@@ -619,10 +619,6 @@
 #endif
 }
 
-bool NativeViewGLSurfaceEGL::Initialize() {
-  return Initialize(SURFACE_DEFAULT);
-}
-
 bool NativeViewGLSurfaceEGL::Initialize(GLSurface::Format format) {
   format_ = format;
   return Initialize(nullptr);
@@ -935,6 +931,19 @@
     size_.SetSize(1, 1);
 }
 
+bool PbufferGLSurfaceEGL::Initialize() {
+  GLSurface::Format format = SURFACE_DEFAULT;
+#if defined(OS_ANDROID)
+  // This is to allow context virtualization which requires on- and offscreen
+  // to use a compatible config. We expect the client to request RGB565
+  // onscreen surface also for this to work (with the exception of
+  // fullscreen video).
+  if (base::SysInfo::IsLowEndDevice())
+    format = SURFACE_RGB565;
+#endif
+  return Initialize(format);
+}
+
 bool PbufferGLSurfaceEGL::Initialize(GLSurface::Format format) {
   EGLSurface old_surface = surface_;
   format_ = format;
diff --git a/ui/gl/gl_surface_egl.h b/ui/gl/gl_surface_egl.h
index 25085f4..9eb3d416 100644
--- a/ui/gl/gl_surface_egl.h
+++ b/ui/gl/gl_surface_egl.h
@@ -84,7 +84,7 @@
   explicit NativeViewGLSurfaceEGL(EGLNativeWindowType window);
 
   // Implement GLSurface.
-  bool Initialize() override;
+  using GLSurfaceEGL::Initialize;
   bool Initialize(GLSurface::Format format) override;
   void Destroy() override;
   bool Resize(const gfx::Size& size,
@@ -157,6 +157,7 @@
   explicit PbufferGLSurfaceEGL(const gfx::Size& size);
 
   // Implement GLSurface.
+  bool Initialize() override;
   bool Initialize(GLSurface::Format format) override;
   void Destroy() override;
   bool IsOffscreen() override;
diff --git a/ui/gl/gl_surface_mac.cc b/ui/gl/gl_surface_mac.cc
index 36a26e8..7e7d5c9b 100644
--- a/ui/gl/gl_surface_mac.cc
+++ b/ui/gl/gl_surface_mac.cc
@@ -133,14 +133,13 @@
 }
 
 scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface(
-    const gfx::Size& size,
-    GLSurface::Format format) {
+    const gfx::Size& size) {
   TRACE_EVENT0("gpu", "GLSurface::CreateOffscreenGLSurface");
   switch (GetGLImplementation()) {
     case kGLImplementationOSMesaGL: {
       scoped_refptr<GLSurface> surface(
-          new GLSurfaceOSMesa(OSMesaSurfaceFormatRGBA, size));
-      if (!surface->Initialize(format))
+          new GLSurfaceOSMesa(SURFACE_OSMESA_RGBA, size));
+      if (!surface->Initialize())
         return NULL;
 
       return surface;
@@ -149,7 +148,7 @@
     case kGLImplementationDesktopGLCoreProfile:
     case kGLImplementationAppleGL: {
       scoped_refptr<GLSurface> surface(new NoOpGLSurface(size));
-      if (!surface->Initialize(format))
+      if (!surface->Initialize())
         return NULL;
 
       return surface;
diff --git a/ui/gl/gl_surface_osmesa.cc b/ui/gl/gl_surface_osmesa.cc
index 7825942f..e39f9bd 100644
--- a/ui/gl/gl_surface_osmesa.cc
+++ b/ui/gl/gl_surface_osmesa.cc
@@ -15,17 +15,10 @@
 
 namespace gfx {
 
-GLSurfaceOSMesa::GLSurfaceOSMesa(OSMesaSurfaceFormat format,
+GLSurfaceOSMesa::GLSurfaceOSMesa(GLSurface::Format format,
                                  const gfx::Size& size)
-    : size_(size) {
-  switch (format) {
-    case OSMesaSurfaceFormatBGRA:
-      format_ = OSMESA_BGRA;
-      break;
-    case OSMesaSurfaceFormatRGBA:
-      format_ = OSMESA_RGBA;
-      break;
-  }
+    : size_(size),
+      format_(format) {
   // Implementations of OSMesa surface do not support having a 0 size. In such
   // cases use a (1, 1) surface.
   if (size_.GetArea() == 0)
@@ -102,7 +95,7 @@
   return buffer_.get();
 }
 
-unsigned GLSurfaceOSMesa::GetFormat() {
+GLSurface::Format GLSurfaceOSMesa::GetFormat() {
   return format_;
 }
 
@@ -117,7 +110,7 @@
 }
 
 GLSurfaceOSMesaHeadless::GLSurfaceOSMesaHeadless()
-    : GLSurfaceOSMesa(OSMesaSurfaceFormatBGRA, gfx::Size(1, 1)) {
+    : GLSurfaceOSMesa(SURFACE_OSMESA_BGRA, gfx::Size(1, 1)) {
 }
 
 GLSurfaceOSMesaHeadless::~GLSurfaceOSMesaHeadless() { Destroy(); }
diff --git a/ui/gl/gl_surface_osmesa.h b/ui/gl/gl_surface_osmesa.h
index 6c317ea..d46a55c3 100644
--- a/ui/gl/gl_surface_osmesa.h
+++ b/ui/gl/gl_surface_osmesa.h
@@ -14,14 +14,12 @@
 
 namespace gfx {
 
-enum OSMesaSurfaceFormat { OSMesaSurfaceFormatBGRA, OSMesaSurfaceFormatRGBA };
-
 // A surface that the Mesa software renderer draws to. This is actually just a
 // buffer in system memory. GetHandle returns a pointer to the buffer. These
 // surfaces can be resized and resizing preserves the contents.
 class GL_EXPORT GLSurfaceOSMesa : public GLSurface {
  public:
-  GLSurfaceOSMesa(OSMesaSurfaceFormat format, const gfx::Size& size);
+  GLSurfaceOSMesa(GLSurface::Format format, const gfx::Size& size);
 
   // Implement GLSurface.
   bool Initialize(GLSurface::Format format) override;
@@ -33,14 +31,14 @@
   gfx::SwapResult SwapBuffers() override;
   gfx::Size GetSize() override;
   void* GetHandle() override;
-  unsigned GetFormat() override;
+  GLSurface::Format GetFormat() override;
 
  protected:
   ~GLSurfaceOSMesa() override;
 
  private:
-  unsigned format_;
   gfx::Size size_;
+  GLSurface::Format format_;
   scoped_ptr<int32_t[]> buffer_;
 
   DISALLOW_COPY_AND_ASSIGN(GLSurfaceOSMesa);
diff --git a/ui/gl/gl_surface_ozone.cc b/ui/gl/gl_surface_ozone.cc
index 7bc2ed7..2ca519d 100644
--- a/ui/gl/gl_surface_ozone.cc
+++ b/ui/gl/gl_surface_ozone.cc
@@ -724,12 +724,12 @@
 
 // static
 scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface(
-    const gfx::Size& size, GLSurface::Format format) {
+    const gfx::Size& size) {
   switch (GetGLImplementation()) {
     case kGLImplementationOSMesaGL: {
       scoped_refptr<GLSurface> surface(
-          new GLSurfaceOSMesa(OSMesaSurfaceFormatBGRA, size));
-      if (!surface->Initialize(format))
+          new GLSurfaceOSMesa(SURFACE_OSMESA_BGRA, size));
+      if (!surface->Initialize())
         return nullptr;
 
       return surface;
@@ -743,7 +743,7 @@
         surface = new PbufferGLSurfaceEGL(size);
       }
 
-      if (!surface->Initialize(format))
+      if (!surface->Initialize())
         return nullptr;
       return surface;
     }
diff --git a/ui/gl/gl_surface_win.cc b/ui/gl/gl_surface_win.cc
index abff8df1..9ac1f38a 100644
--- a/ui/gl/gl_surface_win.cc
+++ b/ui/gl/gl_surface_win.cc
@@ -83,7 +83,7 @@
 
 NativeViewGLSurfaceOSMesa::NativeViewGLSurfaceOSMesa(
     gfx::AcceleratedWidget window)
-    : GLSurfaceOSMesa(OSMesaSurfaceFormatRGBA, gfx::Size(1, 1)),
+    : GLSurfaceOSMesa(SURFACE_OSMESA_RGBA, gfx::Size(1, 1)),
       window_(window),
       device_context_(NULL) {
   DCHECK(window);
@@ -233,27 +233,27 @@
 }
 
 scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface(
-    const gfx::Size& size, GLSurface::Format format) {
+    const gfx::Size& size) {
   TRACE_EVENT0("gpu", "GLSurface::CreateOffscreenGLSurface");
   switch (GetGLImplementation()) {
     case kGLImplementationOSMesaGL: {
       scoped_refptr<GLSurface> surface(
-          new GLSurfaceOSMesa(OSMesaSurfaceFormatRGBA, size));
-      if (!surface->Initialize(format))
+          new GLSurfaceOSMesa(SURFACE_OSMESA_RGBA, size));
+      if (!surface->Initialize())
         return NULL;
 
       return surface;
     }
     case kGLImplementationEGLGLES2: {
       scoped_refptr<GLSurface> surface(new PbufferGLSurfaceEGL(size));
-      if (!surface->Initialize(format))
+      if (!surface->Initialize())
         return NULL;
 
       return surface;
     }
     case kGLImplementationDesktopGL: {
       scoped_refptr<GLSurface> surface(new PbufferGLSurfaceWGL(size));
-      if (!surface->Initialize(format))
+      if (!surface->Initialize())
         return NULL;
 
       return surface;
diff --git a/ui/gl/gl_surface_x11.cc b/ui/gl/gl_surface_x11.cc
index a012b16..4e36e2e 100644
--- a/ui/gl/gl_surface_x11.cc
+++ b/ui/gl/gl_surface_x11.cc
@@ -84,7 +84,7 @@
 
 NativeViewGLSurfaceOSMesa::NativeViewGLSurfaceOSMesa(
     gfx::AcceleratedWidget window)
-    : GLSurfaceOSMesa(OSMesaSurfaceFormatBGRA, gfx::Size(1, 1)),
+    : GLSurfaceOSMesa(SURFACE_OSMESA_BGRA, gfx::Size(1, 1)),
       xdisplay_(gfx::GetXDisplay()),
       window_graphics_context_(0),
       window_(window),
@@ -303,13 +303,13 @@
 }
 
 scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface(
-    const gfx::Size& size, GLSurface::Format format) {
+    const gfx::Size& size) {
   TRACE_EVENT0("gpu", "GLSurface::CreateOffscreenGLSurface");
   switch (GetGLImplementation()) {
     case kGLImplementationOSMesaGL: {
       scoped_refptr<GLSurface> surface(
-          new GLSurfaceOSMesa(OSMesaSurfaceFormatRGBA, size));
-      if (!surface->Initialize(format))
+          new GLSurfaceOSMesa(SURFACE_OSMESA_RGBA, size));
+      if (!surface->Initialize())
         return NULL;
 
       return surface;
@@ -317,14 +317,14 @@
     case kGLImplementationDesktopGL: {
       scoped_refptr<GLSurface> surface(
           new UnmappedNativeViewGLSurfaceGLX(size));
-      if (!surface->Initialize(format))
+      if (!surface->Initialize())
         return NULL;
 
       return surface;
     }
     case kGLImplementationEGLGLES2: {
       scoped_refptr<GLSurface> surface(new PbufferGLSurfaceEGL(size));
-      if (!surface->Initialize(format))
+      if (!surface->Initialize())
         return NULL;
 
       return surface;
diff --git a/ui/login/display_manager.js b/ui/login/display_manager.js
index a945bfef..b8c6b1d 100644
--- a/ui/login/display_manager.js
+++ b/ui/login/display_manager.js
@@ -31,6 +31,8 @@
 /** @const */ var SCREEN_TERMS_OF_SERVICE = 'terms-of-service';
 /** @const */ var SCREEN_WRONG_HWID = 'wrong-hwid';
 /** @const */ var SCREEN_DEVICE_DISABLED = 'device-disabled';
+/** @const */ var SCREEN_UNRECOVERABLE_CRYPTOHOME_ERROR =
+    'unrecoverable-cryptohome-error';
 
 /* Accelerator identifiers. Must be kept in sync with webui_login_view.cc. */
 /** @const */ var ACCELERATOR_CANCEL = 'cancel';
diff --git a/ui/login/screen_container.css b/ui/login/screen_container.css
index 97a824b..2017e70d1 100644
--- a/ui/login/screen_container.css
+++ b/ui/login/screen_container.css
@@ -70,7 +70,8 @@
 #oobe.terms-of-service #inner-container,
 #oobe.update #inner-container,
 #oobe.user-image #inner-container,
-#oobe.wrong-hwid #inner-container {
+#oobe.wrong-hwid #inner-container,
+#oobe.unrecoverable-cryptohome-error #inner-container {
   background: white;
   box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.3),
               0 4px 23px 5px rgba(0, 0, 0, 0.2),
@@ -147,7 +148,8 @@
 #supervised-user-creation-dot,
 #terms-of-service-dot,
 #tpm-error-message-dot,
-#wrong-hwid-dot {
+#wrong-hwid-dot,
+#unrecoverable-cryptohome-error-dot {
   display: none;
 }
 
diff --git a/ui/native_theme/native_theme_mac.h b/ui/native_theme/native_theme_mac.h
index 7970a58..ca9ac071 100644
--- a/ui/native_theme/native_theme_mac.h
+++ b/ui/native_theme/native_theme_mac.h
@@ -20,18 +20,6 @@
   SkColor GetSystemColor(ColorId color_id) const override;
 
   // Overridden from NativeThemeBase:
-  void PaintScrollbarTrack(SkCanvas* canvas,
-                           Part part,
-                           State state,
-                           const ScrollbarTrackExtraParams& extra_params,
-                           const gfx::Rect& rect) const override;
-  void PaintScrollbarThumb(SkCanvas* sk_canvas,
-                           Part part,
-                           State state,
-                           const gfx::Rect& rect) const override;
-  void PaintScrollbarCorner(SkCanvas* canvas,
-                            State state,
-                            const gfx::Rect& rect) const override;
   void PaintMenuPopupBackground(
       SkCanvas* canvas,
       const gfx::Size& size,
diff --git a/ui/native_theme/native_theme_mac.mm b/ui/native_theme/native_theme_mac.mm
index 43eb1296..e81c60c 100644
--- a/ui/native_theme/native_theme_mac.mm
+++ b/ui/native_theme/native_theme_mac.mm
@@ -19,20 +19,6 @@
 
 namespace {
 
-const SkColor kScrollerTrackGradientColors[] = {
-    SkColorSetRGB(0xEF, 0xEF, 0xEF),
-    SkColorSetRGB(0xF9, 0xF9, 0xF9),
-    SkColorSetRGB(0xFD, 0xFD, 0xFD),
-    SkColorSetRGB(0xF6, 0xF6, 0xF6) };
-const SkColor kScrollerTrackInnerBorderColor = SkColorSetRGB(0xE4, 0xE4, 0xE4);
-const SkColor kScrollerTrackOuterBorderColor = SkColorSetRGB(0xEF, 0xEF, 0xEF);
-const SkColor kScrollerThumbColor = SkColorSetARGB(0x38, 0, 0, 0);
-const SkColor kScrollerThumbHoverColor = SkColorSetARGB(0x80, 0, 0, 0);
-const int kScrollerTrackBorderWidth = 1;
-
-// The amount the thumb is inset from both the ends and the sides of the track.
-const int kScrollerThumbInset = 3;
-
 // Values calculated by reading pixels and solving simultaneous equations
 // derived from "A over B" alpha compositing. Steps: Sample the semi-transparent
 // pixel over two backgrounds; P1, P2 over backgrounds B1, B2. Use the color
@@ -240,131 +226,6 @@
   }
 }
 
-void NativeThemeMac::PaintScrollbarTrack(
-    SkCanvas* canvas,
-    Part part,
-    State state,
-    const ScrollbarTrackExtraParams& extra_params,
-    const gfx::Rect& rect) const {
-  // Emulate the non-overlay scroller style from OSX 10.7 and later.
-  SkPoint gradient_bounds[2];
-  if (part == kScrollbarVerticalTrack) {
-    gradient_bounds[0].set(rect.x(), rect.y());
-    gradient_bounds[1].set(rect.right(), rect.y());
-  } else {
-    DCHECK_EQ(part, kScrollbarHorizontalTrack);
-    gradient_bounds[0].set(rect.x(), rect.y());
-    gradient_bounds[1].set(rect.x(), rect.bottom());
-  }
-  skia::RefPtr<SkShader> shader = skia::AdoptRef(
-      SkGradientShader::CreateLinear(gradient_bounds,
-                                     kScrollerTrackGradientColors,
-                                     NULL,
-                                     arraysize(kScrollerTrackGradientColors),
-                                     SkShader::kClamp_TileMode));
-  SkPaint gradient;
-  gradient.setShader(shader.get());
-
-  SkIRect track_rect = gfx::RectToSkIRect(rect);
-  canvas->drawIRect(track_rect, gradient);
-
-  // Draw inner and outer line borders.
-  if (part == kScrollbarVerticalTrack) {
-    SkPaint paint;
-    paint.setColor(kScrollerTrackInnerBorderColor);
-    canvas->drawRectCoords(track_rect.left(),
-                           track_rect.top(),
-                           track_rect.left() + kScrollerTrackBorderWidth,
-                           track_rect.bottom(),
-                           paint);
-    paint.setColor(kScrollerTrackOuterBorderColor);
-    canvas->drawRectCoords(track_rect.right() - kScrollerTrackBorderWidth,
-                           track_rect.top(),
-                           track_rect.right(),
-                           track_rect.bottom(),
-                           paint);
-  } else {
-    SkPaint paint;
-    paint.setColor(kScrollerTrackInnerBorderColor);
-    canvas->drawRectCoords(track_rect.left(),
-                           track_rect.top(),
-                           track_rect.right(),
-                           track_rect.top() + kScrollerTrackBorderWidth,
-                           paint);
-    paint.setColor(kScrollerTrackOuterBorderColor);
-    canvas->drawRectCoords(track_rect.left(),
-                           track_rect.bottom() - kScrollerTrackBorderWidth,
-                           track_rect.right(),
-                           track_rect.bottom(),
-                           paint);
-  }
-}
-
-void NativeThemeMac::PaintScrollbarThumb(SkCanvas* canvas,
-                                         Part part,
-                                         State state,
-                                         const gfx::Rect& rect) const {
-  gfx::Rect thumb_rect(rect);
-  switch (part) {
-    case kScrollbarHorizontalThumb:
-      thumb_rect.Inset(0, kScrollerTrackBorderWidth, 0, 0);
-      break;
-    case kScrollbarVerticalThumb:
-      thumb_rect.Inset(kScrollerTrackBorderWidth, 0, 0, 0);
-      break;
-    default:
-      NOTREACHED();
-      break;
-  }
-
-  thumb_rect.Inset(kScrollerThumbInset, kScrollerThumbInset);
-
-  SkPaint paint;
-  paint.setAntiAlias(true);
-  paint.setColor(state == kHovered ? thumb_active_color_
-                                   : thumb_inactive_color_);
-  const SkScalar radius = std::min(rect.width(), rect.height());
-  canvas->drawRoundRect(gfx::RectToSkRect(thumb_rect), radius, radius, paint);
-}
-
-void NativeThemeMac::PaintScrollbarCorner(SkCanvas* canvas,
-                                          State state,
-                                          const gfx::Rect& rect) const {
-  DCHECK_GT(rect.width(), 0);
-  DCHECK_GT(rect.height(), 0);
-
-  // Draw radial gradient from top-left corner.
-  skia::RefPtr<SkShader> shader = skia::AdoptRef(
-      SkGradientShader::CreateRadial(SkPoint::Make(rect.x(), rect.y()),
-                                     rect.width(),
-                                     kScrollerTrackGradientColors,
-                                     NULL,
-                                     arraysize(kScrollerTrackGradientColors),
-                                     SkShader::kClamp_TileMode));
-  SkPaint gradient;
-  gradient.setStyle(SkPaint::kFill_Style);
-  gradient.setAntiAlias(true);
-  gradient.setShader(shader.get());
-  canvas->drawRect(gfx::RectToSkRect(rect), gradient);
-
-  // Draw inner border corner point.
-  canvas->drawPoint(rect.x(), rect.y(), kScrollerTrackInnerBorderColor);
-
-  // Draw outer borders.
-  SkPaint paint;
-  paint.setColor(kScrollerTrackOuterBorderColor);
-  canvas->drawRectCoords(rect.right() - kScrollerTrackBorderWidth,
-                         rect.y(),
-                         rect.right(),
-                         rect.bottom(),
-                         paint);
-  canvas->drawRectCoords(rect.x(),
-                         rect.bottom() - kScrollerTrackBorderWidth,
-                         rect.right(),
-                         rect.bottom(),
-                         paint);
-}
-
 void NativeThemeMac::PaintMenuPopupBackground(
     SkCanvas* canvas,
     const gfx::Size& size,
@@ -406,10 +267,6 @@
 }
 
 NativeThemeMac::NativeThemeMac() {
-  set_scrollbar_button_length(0);
-  SetScrollbarColors(kScrollerThumbColor,
-                     kScrollerThumbHoverColor,
-                     kScrollerTrackGradientColors[0]);
 }
 
 NativeThemeMac::~NativeThemeMac() {
diff --git a/ui/ozone/BUILD.gn b/ui/ozone/BUILD.gn
index 4d13863..09a32e7 100644
--- a/ui/ozone/BUILD.gn
+++ b/ui/ozone/BUILD.gn
@@ -8,6 +8,8 @@
 
 assert(use_ozone)
 
+visibility = [ ":*" ]
+
 # The list of platforms that will be built.
 ozone_platforms = []
 
@@ -103,6 +105,15 @@
     "//ui/gfx/geometry",
     "//ui/gfx/ipc",
   ]
+
+  visibility += [
+    # Everyone should depend on //ui/ozone instead except a handful of
+    # things that would otherwise create a cycle.
+    "//ui/base",
+    "//ui/events/ozone/*",
+    "//ui/ozone/platform/*",
+    "//ui/ozone/common/*",
+  ]
 }
 
 source_set("platform") {
@@ -112,16 +123,19 @@
     "platform_selection.cc",
     "platform_selection.h",
     "public/client_native_pixmap_factory.cc",
-    "public/client_native_pixmap_factory.h",
     "public/ozone_gpu_test_helper.cc",
-    "public/ozone_gpu_test_helper.h",
     "public/ozone_platform.cc",
-    "public/ozone_platform.h",
     constructor_list_cc_file,
     platform_list_cc_file,
     platform_list_h_file,
   ]
 
+  public = [
+    "public/client_native_pixmap_factory.h",
+    "public/ozone_gpu_test_helper.h",
+    "public/ozone_platform.h",
+  ]
+
   defines = [ "OZONE_IMPLEMENTATION" ]
 
   public_deps = [
@@ -148,6 +162,9 @@
 
   # Platforms are always linked into //ui/ozone and can include our headers.
   allow_circular_includes_from = ozone_platform_deps
+
+  # This is used for platform tests.
+  visibility += [ "//ui/ozone/platform/*" ]
 }
 
 component("ozone") {
@@ -172,6 +189,8 @@
         "--output_txt=" + rebase_path(platform_list_txt_file, root_build_dir),
         "--default=$ozone_platform",
       ] + ozone_platforms
+
+  visibility += [ "//media:*" ]
 }
 
 # GYP version: ui/ozone/ozone.gyp:generate_constructor_list
diff --git a/ui/ozone/common/BUILD.gn b/ui/ozone/common/BUILD.gn
index 5fca52d4..0f88278 100644
--- a/ui/ozone/common/BUILD.gn
+++ b/ui/ozone/common/BUILD.gn
@@ -30,4 +30,6 @@
   public_deps = [
     "//ui/ozone:ozone_base",
   ]
+
+  visibility = [ "//ui/ozone/platform/*" ]
 }
diff --git a/ui/ozone/demo/BUILD.gn b/ui/ozone/demo/BUILD.gn
index 70b2ded5..c05bb92 100644
--- a/ui/ozone/demo/BUILD.gn
+++ b/ui/ozone/demo/BUILD.gn
@@ -33,7 +33,6 @@
     "//ui/gfx/geometry",
     "//ui/gl",
     "//ui/ozone",
-    "//ui/ozone:ozone_base",
     "//ui/platform_window",
   ]
 }
diff --git a/ui/ozone/platform/caca/BUILD.gn b/ui/ozone/platform/caca/BUILD.gn
index 32a3892..be3fbb9d 100644
--- a/ui/ozone/platform/caca/BUILD.gn
+++ b/ui/ozone/platform/caca/BUILD.gn
@@ -4,6 +4,8 @@
 
 import("//build/config/linux/pkg_config.gni")
 
+visibility = [ "//ui/ozone/*" ]
+
 source_set("caca") {
   sources = [
     "caca_event_source.cc",
diff --git a/ui/ozone/platform/cast/BUILD.gn b/ui/ozone/platform/cast/BUILD.gn
index 0365def..0a548e44 100644
--- a/ui/ozone/platform/cast/BUILD.gn
+++ b/ui/ozone/platform/cast/BUILD.gn
@@ -5,6 +5,11 @@
 import("//build/config/chromecast_build.gni")
 import("//ui/ozone/ozone.gni")
 
+visibility = [
+  "//ui/ozone/*",
+  "//chromecast/*",
+]
+
 # GYP version: cast.gypi:ozone_platform_cast
 # TODO(slan): gn check needs deps on ozone and media to pass. Correct this.
 source_set("cast") {
diff --git a/ui/ozone/platform/drm/BUILD.gn b/ui/ozone/platform/drm/BUILD.gn
index 391e5362..a9be8cd 100644
--- a/ui/ozone/platform/drm/BUILD.gn
+++ b/ui/ozone/platform/drm/BUILD.gn
@@ -10,6 +10,8 @@
   use_drm_atomic = false
 }
 
+visibility = [ "//ui/ozone/*" ]
+
 pkg_config("libdrm") {
   packages = [ "libdrm" ]
 }
diff --git a/ui/ozone/platform/drm/common/scoped_drm_types.h b/ui/ozone/platform/drm/common/scoped_drm_types.h
index 2fa16df6..a56f661 100644
--- a/ui/ozone/platform/drm/common/scoped_drm_types.h
+++ b/ui/ozone/platform/drm/common/scoped_drm_types.h
@@ -6,7 +6,6 @@
 #define UI_OZONE_PLATFORM_DRM_COMMON_SCOPED_DRM_TYPES_H_
 
 #include "base/memory/scoped_ptr.h"
-#include "ui/ozone/ozone_export.h"
 
 typedef struct _drmModeConnector drmModeConnector;
 typedef struct _drmModeCrtc drmModeCrtc;
@@ -22,39 +21,39 @@
 
 namespace ui {
 
-struct OZONE_EXPORT DrmResourcesDeleter {
+struct DrmResourcesDeleter {
   void operator()(drmModeRes* resources) const;
 };
-struct OZONE_EXPORT DrmConnectorDeleter {
+struct DrmConnectorDeleter {
   void operator()(drmModeConnector* connector) const;
 };
-struct OZONE_EXPORT DrmCrtcDeleter {
+struct DrmCrtcDeleter {
   void operator()(drmModeCrtc* crtc) const;
 };
-struct OZONE_EXPORT DrmEncoderDeleter {
+struct DrmEncoderDeleter {
   void operator()(drmModeEncoder* encoder) const;
 };
-struct OZONE_EXPORT DrmObjectPropertiesDeleter {
+struct DrmObjectPropertiesDeleter {
   void operator()(drmModeObjectProperties* properties) const;
 };
-struct OZONE_EXPORT DrmPlaneDeleter {
+struct DrmPlaneDeleter {
   void operator()(drmModePlane* plane) const;
 };
-struct OZONE_EXPORT DrmPlaneResDeleter {
+struct DrmPlaneResDeleter {
   void operator()(drmModePlaneRes* plane_res) const;
 };
-struct OZONE_EXPORT DrmPropertyDeleter {
+struct DrmPropertyDeleter {
   void operator()(drmModePropertyRes* property) const;
 };
 #if defined(USE_DRM_ATOMIC)
-struct OZONE_EXPORT DrmAtomicReqDeleter {
+struct DrmAtomicReqDeleter {
   void operator()(drmModeAtomicReq* property) const;
 };
 #endif  // defined(USE_DRM_ATOMIC)
-struct OZONE_EXPORT DrmPropertyBlobDeleter {
+struct DrmPropertyBlobDeleter {
   void operator()(drmModePropertyBlobRes* property) const;
 };
-struct OZONE_EXPORT DrmFramebufferDeleter {
+struct DrmFramebufferDeleter {
   void operator()(drmModeFB* framebuffer) const;
 };
 
diff --git a/ui/ozone/platform/drm/gpu/crtc_controller.h b/ui/ozone/platform/drm/gpu/crtc_controller.h
index 0740ee9..f332ce5 100644
--- a/ui/ozone/platform/drm/gpu/crtc_controller.h
+++ b/ui/ozone/platform/drm/gpu/crtc_controller.h
@@ -13,7 +13,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "ui/gfx/swap_result.h"
-#include "ui/ozone/ozone_export.h"
 #include "ui/ozone/platform/drm/common/scoped_drm_types.h"
 #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h"
 #include "ui/ozone/platform/drm/gpu/overlay_plane.h"
@@ -28,8 +27,7 @@
 // One CRTC can be paired up with one or more connectors. The simplest
 // configuration represents one CRTC driving one monitor, while pairing up a
 // CRTC with multiple connectors results in hardware mirroring.
-class OZONE_EXPORT CrtcController
-    : public base::SupportsWeakPtr<CrtcController> {
+class CrtcController : public base::SupportsWeakPtr<CrtcController> {
  public:
   CrtcController(const scoped_refptr<DrmDevice>& drm,
                  uint32_t crtc,
diff --git a/ui/ozone/platform/drm/gpu/drm_buffer.h b/ui/ozone/platform/drm/gpu/drm_buffer.h
index 61d553e..13868e34 100644
--- a/ui/ozone/platform/drm/gpu/drm_buffer.h
+++ b/ui/ozone/platform/drm/gpu/drm_buffer.h
@@ -11,7 +11,6 @@
 #include "base/macros.h"
 #include "skia/ext/refptr.h"
 #include "third_party/skia/include/core/SkSurface.h"
-#include "ui/ozone/ozone_export.h"
 #include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
 
 namespace ui {
@@ -21,7 +20,7 @@
 // Wrapper for a DRM allocated buffer. Keeps track of the native properties of
 // the buffer and wraps the pixel memory into a SkSurface which can be used to
 // draw into using Skia.
-class OZONE_EXPORT DrmBuffer : public ScanoutBuffer {
+class DrmBuffer : public ScanoutBuffer {
  public:
   DrmBuffer(const scoped_refptr<DrmDevice>& drm);
 
diff --git a/ui/ozone/platform/drm/gpu/drm_device.h b/ui/ozone/platform/drm/gpu/drm_device.h
index 3d4e8186..a53d311 100644
--- a/ui/ozone/platform/drm/gpu/drm_device.h
+++ b/ui/ozone/platform/drm/gpu/drm_device.h
@@ -18,7 +18,6 @@
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/overlay_transform.h"
-#include "ui/ozone/ozone_export.h"
 #include "ui/ozone/platform/drm/common/scoped_drm_types.h"
 #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h"
 
@@ -39,7 +38,7 @@
 // Wraps DRM calls into a nice interface. Used to provide different
 // implementations of the DRM calls. For the actual implementation the DRM API
 // would be called. In unit tests this interface would be stubbed.
-class OZONE_EXPORT DrmDevice : public base::RefCountedThreadSafe<DrmDevice> {
+class DrmDevice : public base::RefCountedThreadSafe<DrmDevice> {
  public:
   typedef base::Callback<void(unsigned int /* frame */,
                               unsigned int /* seconds */,
diff --git a/ui/ozone/platform/drm/gpu/drm_device_manager.h b/ui/ozone/platform/drm/gpu/drm_device_manager.h
index d415aad1..e3190d4 100644
--- a/ui/ozone/platform/drm/gpu/drm_device_manager.h
+++ b/ui/ozone/platform/drm/gpu/drm_device_manager.h
@@ -12,7 +12,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "ui/gfx/native_widget_types.h"
-#include "ui/ozone/ozone_export.h"
 
 namespace base {
 class FilePath;
@@ -28,7 +27,7 @@
 
 // Tracks the mapping between widgets and the DRM devices used to allocate
 // buffers for the window represented by the widget.
-class OZONE_EXPORT DrmDeviceManager {
+class DrmDeviceManager {
  public:
   DrmDeviceManager(scoped_ptr<DrmDeviceGenerator> drm_device_generator);
   ~DrmDeviceManager();
diff --git a/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc b/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc
index f39d5f6a..0530301 100644
--- a/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc
+++ b/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc
@@ -157,16 +157,16 @@
   window_->SetController(nullptr);
   std::vector<ui::OverlayCheck_Params> validated_params =
       overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList());
-  EXPECT_EQ(false, validated_params.front().is_overlay_candidate);
-  EXPECT_EQ(false, validated_params.back().is_overlay_candidate);
+  EXPECT_FALSE(validated_params.front().is_overlay_candidate);
+  EXPECT_FALSE(validated_params.back().is_overlay_candidate);
   window_->SetController(controller);
 }
 
 TEST_F(DrmOverlayValidatorTest, DontPromoteMoreLayersThanAvailablePlanes) {
   std::vector<ui::OverlayCheck_Params> validated_params =
       overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList());
-  EXPECT_EQ(true, validated_params.front().is_overlay_candidate);
-  EXPECT_EQ(false, validated_params.back().is_overlay_candidate);
+  EXPECT_TRUE(validated_params.front().is_overlay_candidate);
+  EXPECT_FALSE(validated_params.back().is_overlay_candidate);
 }
 
 TEST_F(DrmOverlayValidatorTest, DontCollapseOverlayToPrimaryInFullScreen) {
@@ -179,8 +179,8 @@
       overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList());
   // Second candidate should be marked as Invalid as we have only one plane
   // per CRTC.
-  EXPECT_EQ(true, validated_params.front().is_overlay_candidate);
-  EXPECT_EQ(false, validated_params.back().is_overlay_candidate);
+  EXPECT_TRUE(validated_params.front().is_overlay_candidate);
+  EXPECT_FALSE(validated_params.back().is_overlay_candidate);
 }
 
 TEST_F(DrmOverlayValidatorTest, ClearCacheOnReset) {
@@ -288,7 +288,7 @@
       overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList());
 
   for (const auto& param : validated_params)
-    EXPECT_EQ(true, param.is_overlay_candidate);
+    EXPECT_TRUE(param.is_overlay_candidate);
 
   EXPECT_EQ(5, plane_manager_->plane_count());
 
@@ -323,7 +323,7 @@
             plane_list.back().buffer->GetFramebufferPixelFormat());
   EXPECT_EQ(3, plane_manager_->plane_count());
   for (const auto& param : validated_params)
-    EXPECT_EQ(true, param.is_overlay_candidate);
+    EXPECT_TRUE(param.is_overlay_candidate);
 }
 
 TEST_F(DrmOverlayValidatorTest, RejectYUVBuffersIfNotSupported) {
@@ -349,7 +349,7 @@
   validated_params = overlay_validator_->TestPageFlip(validated_params,
                                                       ui::OverlayPlaneList());
 
-  EXPECT_EQ(false, validated_params.back().is_overlay_candidate);
+  EXPECT_FALSE(validated_params.back().is_overlay_candidate);
 }
 
 TEST_F(DrmOverlayValidatorTest,
@@ -389,7 +389,7 @@
   validated_params = overlay_validator_->TestPageFlip(validated_params,
                                                       ui::OverlayPlaneList());
 
-  EXPECT_EQ(true, validated_params.back().is_overlay_candidate);
+  EXPECT_TRUE(validated_params.back().is_overlay_candidate);
 
   // Both controllers have Overlay which support DRM_FORMAT_UYVY, hence this
   // should be picked as the optimal format.
@@ -408,7 +408,7 @@
 
   validated_params = overlay_validator_->TestPageFlip(validated_params,
                                                       ui::OverlayPlaneList());
-  EXPECT_EQ(false, validated_params.back().is_overlay_candidate);
+  EXPECT_FALSE(validated_params.back().is_overlay_candidate);
 
   // Check case where we dont have support for packed formats in primary
   // display.
@@ -419,7 +419,7 @@
 
   validated_params = overlay_validator_->TestPageFlip(validated_params,
                                                       ui::OverlayPlaneList());
-  EXPECT_EQ(false, validated_params.back().is_overlay_candidate);
+  EXPECT_FALSE(validated_params.back().is_overlay_candidate);
   controller->RemoveCrtc(drm_, kSecondaryCrtc);
 }
 
@@ -458,7 +458,7 @@
   std::vector<ui::OverlayCheck_Params> validated_params =
       overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList());
 
-  EXPECT_EQ(true, validated_params.back().is_overlay_candidate);
+  EXPECT_TRUE(validated_params.back().is_overlay_candidate);
   // Both controllers have Overlay which support DRM_FORMAT_UYVY, hence this
   // should be picked as the optimal format.
   ui::OverlayPlaneList plane_list =
@@ -476,7 +476,7 @@
 
   validated_params =
       overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList());
-  EXPECT_EQ(true, validated_params.back().is_overlay_candidate);
+  EXPECT_TRUE(validated_params.back().is_overlay_candidate);
 
   plane_list = overlay_validator_->PrepareBuffersForPageFlip(plane_list_);
   EXPECT_EQ(DRM_FORMAT_XRGB8888,
@@ -491,7 +491,7 @@
 
   validated_params =
       overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList());
-  EXPECT_EQ(true, validated_params.back().is_overlay_candidate);
+  EXPECT_TRUE(validated_params.back().is_overlay_candidate);
 
   plane_list = overlay_validator_->PrepareBuffersForPageFlip(plane_list_);
   EXPECT_EQ(DRM_FORMAT_XRGB8888,
diff --git a/ui/ozone/platform/drm/gpu/drm_window.h b/ui/ozone/platform/drm/gpu/drm_window.h
index f5dad7c..59407a5 100644
--- a/ui/ozone/platform/drm/gpu/drm_window.h
+++ b/ui/ozone/platform/drm/gpu/drm_window.h
@@ -14,7 +14,6 @@
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gfx/swap_result.h"
 #include "ui/gfx/vsync_provider.h"
-#include "ui/ozone/ozone_export.h"
 #include "ui/ozone/platform/drm/gpu/overlay_plane.h"
 #include "ui/ozone/platform/drm/gpu/page_flip_request.h"
 #include "ui/ozone/public/surface_ozone_egl.h"
@@ -46,7 +45,7 @@
 //
 // If there's no display whose bounds match the window's, the window is
 // disconnected and its contents will not be visible to the user.
-class OZONE_EXPORT DrmWindow {
+class DrmWindow {
  public:
   DrmWindow(gfx::AcceleratedWidget widget,
             DrmDeviceManager* device_manager,
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_controller.h b/ui/ozone/platform/drm/gpu/hardware_display_controller.h
index 2207452..8ec577d 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_controller.h
+++ b/ui/ozone/platform/drm/gpu/hardware_display_controller.h
@@ -18,7 +18,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "ui/gfx/swap_result.h"
-#include "ui/ozone/ozone_export.h"
 #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h"
 #include "ui/ozone/platform/drm/gpu/overlay_plane.h"
 
@@ -86,7 +85,7 @@
 // only a subset of connectors can be active independently, showing different
 // framebuffers. Though, in this case, it would be possible to have all
 // connectors active if some use the same CRTC to mirror the display.
-class OZONE_EXPORT HardwareDisplayController {
+class HardwareDisplayController {
   typedef base::Callback<void(gfx::SwapResult)> PageFlipCallback;
 
  public:
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane.h b/ui/ozone/platform/drm/gpu/hardware_display_plane.h
index 798d2f36..729df45 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_plane.h
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane.h
@@ -11,7 +11,6 @@
 #include <vector>
 
 #include "base/macros.h"
-#include "ui/ozone/ozone_export.h"
 #include "ui/ozone/platform/drm/common/scoped_drm_types.h"
 
 namespace gfx {
@@ -22,7 +21,7 @@
 
 class DrmDevice;
 
-class OZONE_EXPORT HardwareDisplayPlane {
+class HardwareDisplayPlane {
  public:
   enum Type { kDummy, kPrimary, kOverlay, kCursor };
 
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
index e9b04ec0..2a4fee2 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h
@@ -12,7 +12,6 @@
 
 #include "base/macros.h"
 #include "base/memory/scoped_vector.h"
-#include "ui/ozone/ozone_export.h"
 #include "ui/ozone/platform/drm/common/scoped_drm_types.h"
 #include "ui/ozone/platform/drm/gpu/hardware_display_plane.h"
 #include "ui/ozone/platform/drm/gpu/overlay_plane.h"
@@ -28,7 +27,7 @@
 
 // This contains the list of planes controlled by one HDC on a given DRM fd.
 // It is owned by the HDC and filled by the CrtcController.
-struct OZONE_EXPORT HardwareDisplayPlaneList {
+struct HardwareDisplayPlaneList {
   HardwareDisplayPlaneList();
   ~HardwareDisplayPlaneList();
 
@@ -67,7 +66,7 @@
 #endif  // defined(USE_DRM_ATOMIC)
 };
 
-class OZONE_EXPORT HardwareDisplayPlaneManager {
+class HardwareDisplayPlaneManager {
  public:
   HardwareDisplayPlaneManager();
   virtual ~HardwareDisplayPlaneManager();
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h
index 3fc911c..d9512eb 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_atomic.h
@@ -8,13 +8,11 @@
 #include <stdint.h>
 
 #include "base/macros.h"
-#include "ui/ozone/ozone_export.h"
 #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h"
 
 namespace ui {
 
-class OZONE_EXPORT HardwareDisplayPlaneManagerAtomic
-    : public HardwareDisplayPlaneManager {
+class HardwareDisplayPlaneManagerAtomic : public HardwareDisplayPlaneManager {
  public:
   HardwareDisplayPlaneManagerAtomic();
   ~HardwareDisplayPlaneManagerAtomic() override;
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h
index c716187e..56c55766 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h
+++ b/ui/ozone/platform/drm/gpu/hardware_display_plane_manager_legacy.h
@@ -8,13 +8,11 @@
 #include <stdint.h>
 
 #include "base/macros.h"
-#include "ui/ozone/ozone_export.h"
 #include "ui/ozone/platform/drm/gpu/hardware_display_plane_manager.h"
 
 namespace ui {
 
-class OZONE_EXPORT HardwareDisplayPlaneManagerLegacy
-    : public HardwareDisplayPlaneManager {
+class HardwareDisplayPlaneManagerLegacy : public HardwareDisplayPlaneManager {
  public:
   HardwareDisplayPlaneManagerLegacy();
   ~HardwareDisplayPlaneManagerLegacy() override;
diff --git a/ui/ozone/platform/drm/gpu/overlay_plane.h b/ui/ozone/platform/drm/gpu/overlay_plane.h
index 1666e07..f3d1f777b 100644
--- a/ui/ozone/platform/drm/gpu/overlay_plane.h
+++ b/ui/ozone/platform/drm/gpu/overlay_plane.h
@@ -12,7 +12,6 @@
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/overlay_transform.h"
-#include "ui/ozone/ozone_export.h"
 
 namespace ui {
 
@@ -21,7 +20,7 @@
 struct OverlayPlane;
 typedef std::vector<OverlayPlane> OverlayPlaneList;
 
-struct OZONE_EXPORT OverlayPlane {
+struct OverlayPlane {
   // Simpler constructor for the primary plane.
   explicit OverlayPlane(const scoped_refptr<ScanoutBuffer>& buffer);
 
diff --git a/ui/ozone/platform/drm/gpu/screen_manager.h b/ui/ozone/platform/drm/gpu/screen_manager.h
index aae384b6..59f81d2 100644
--- a/ui/ozone/platform/drm/gpu/screen_manager.h
+++ b/ui/ozone/platform/drm/gpu/screen_manager.h
@@ -12,7 +12,6 @@
 #include "base/memory/scoped_vector.h"
 #include "base/observer_list.h"
 #include "ui/gfx/native_widget_types.h"
-#include "ui/ozone/ozone_export.h"
 #include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
 
 typedef struct _drmModeModeInfo drmModeModeInfo;
@@ -30,7 +29,7 @@
 class ScanoutBufferGenerator;
 
 // Responsible for keeping track of active displays and configuring them.
-class OZONE_EXPORT ScreenManager {
+class ScreenManager {
  public:
   ScreenManager(ScanoutBufferGenerator* surface_generator);
   virtual ~ScreenManager();
diff --git a/ui/ozone/platform/egltest/BUILD.gn b/ui/ozone/platform/egltest/BUILD.gn
index a2dcc293..77b1566c 100644
--- a/ui/ozone/platform/egltest/BUILD.gn
+++ b/ui/ozone/platform/egltest/BUILD.gn
@@ -5,6 +5,8 @@
 import("//tools/generate_library_loader/generate_library_loader.gni")
 import("//ui/ozone/ozone.gni")
 
+visibility = [ "//ui/ozone/*" ]
+
 source_set("egltest") {
   sources = [
     "client_native_pixmap_factory_egltest.cc",
@@ -71,5 +73,7 @@
     deps = [
       "//build/config/sanitizers:deps",
     ]
+
+    visibility += [ "//chromecast/*" ]
   }
 }
diff --git a/ui/ozone/platform/headless/BUILD.gn b/ui/ozone/platform/headless/BUILD.gn
index b65b5241..4a4fdb3 100644
--- a/ui/ozone/platform/headless/BUILD.gn
+++ b/ui/ozone/platform/headless/BUILD.gn
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+visibility = [ "//ui/ozone/*" ]
+
 source_set("headless") {
   sources = [
     "client_native_pixmap_factory_headless.cc",
diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn
index 81e1385..8f72aef 100644
--- a/ui/ozone/platform/wayland/BUILD.gn
+++ b/ui/ozone/platform/wayland/BUILD.gn
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+visibility = [ "//ui/ozone/*" ]
+
 source_set("wayland") {
   sources = [
     "client_native_pixmap_factory_wayland.cc",
diff --git a/ui/ozone/platform/x11/BUILD.gn b/ui/ozone/platform/x11/BUILD.gn
index 22f26ee..31185ddb 100644
--- a/ui/ozone/platform/x11/BUILD.gn
+++ b/ui/ozone/platform/x11/BUILD.gn
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+visibility = [ "//ui/ozone/*" ]
+
 source_set("x11") {
   sources = [
     "client_native_pixmap_factory_x11.cc",
diff --git a/ui/platform_window/win/win_window.cc b/ui/platform_window/win/win_window.cc
index 802f2d79..1282b091 100644
--- a/ui/platform_window/win/win_window.cc
+++ b/ui/platform_window/win/win_window.cc
@@ -74,9 +74,11 @@
       GetWindowLong(hwnd(), GWL_STYLE),
       GetWindowLong(hwnd(), GWL_EXSTYLE),
       bounds);
+  unsigned int flags = SWP_NOREPOSITION;
+  if (!::IsWindowVisible(hwnd()))
+    flags |= SWP_NOACTIVATE;
   SetWindowPos(hwnd(), NULL, window_bounds.x(), window_bounds.y(),
-               window_bounds.width(), window_bounds.height(),
-               SWP_NOREPOSITION);
+               window_bounds.width(), window_bounds.height(), flags);
 }
 
 gfx::Rect WinWindow::GetBounds() {
diff --git a/ui/views/animation/button_ink_drop_delegate.cc b/ui/views/animation/button_ink_drop_delegate.cc
index 44a24ad..5b753c2 100644
--- a/ui/views/animation/button_ink_drop_delegate.cc
+++ b/ui/views/animation/button_ink_drop_delegate.cc
@@ -25,20 +25,6 @@
 ButtonInkDropDelegate::~ButtonInkDropDelegate() {
 }
 
-void ButtonInkDropDelegate::SetInkDropSize(int large_size,
-                                           int large_corner_radius,
-                                           int small_size,
-                                           int small_corner_radius) {
-  ink_drop_animation_controller_->SetInkDropSize(
-      gfx::Size(large_size, large_size), large_corner_radius,
-      gfx::Size(small_size, small_size), small_corner_radius);
-}
-
-void ButtonInkDropDelegate::OnLayout() {
-  ink_drop_animation_controller_->SetInkDropCenter(
-      ink_drop_host_->CalculateInkDropCenter());
-}
-
 void ButtonInkDropDelegate::OnAction(InkDropState state) {
   ink_drop_animation_controller_->AnimateToState(state);
 }
@@ -53,8 +39,10 @@
 void ButtonInkDropDelegate::OnMouseEvent(ui::MouseEvent* event) {
   switch (event->type()) {
     case ui::ET_MOUSE_ENTERED:
+      SetHovered(true);
+      break;
     case ui::ET_MOUSE_EXITED:
-      SetHovered(ink_drop_host_->ShouldShowInkDropHover());
+      SetHovered(false);
       break;
     default:
       return;
diff --git a/ui/views/animation/button_ink_drop_delegate.h b/ui/views/animation/button_ink_drop_delegate.h
index dc4ecdce..9b8637c3 100644
--- a/ui/views/animation/button_ink_drop_delegate.h
+++ b/ui/views/animation/button_ink_drop_delegate.h
@@ -29,11 +29,6 @@
   ~ButtonInkDropDelegate() override;
 
   // InkDropDelegate:
-  void SetInkDropSize(int large_size,
-                      int large_corner_radius,
-                      int small_size,
-                      int small_corner_radius) override;
-  void OnLayout() override;
   void OnAction(InkDropState state) override;
   void SetHovered(bool is_hovered) override;
 
diff --git a/ui/views/animation/ink_drop_animation_controller.h b/ui/views/animation/ink_drop_animation_controller.h
index 082a8bc..2d71307 100644
--- a/ui/views/animation/ink_drop_animation_controller.h
+++ b/ui/views/animation/ink_drop_animation_controller.h
@@ -40,20 +40,6 @@
   // Enables or disables the hover state.
   virtual void SetHovered(bool is_hovered) = 0;
 
-  // Returns true if the hover state is enabled.
-  virtual bool IsHovered() const = 0;
-
-  virtual gfx::Size GetInkDropLargeSize() const = 0;
-
-  // Sets the different sizes of the ink drop.
-  virtual void SetInkDropSize(const gfx::Size& large_size,
-                              int large_corner_radius,
-                              const gfx::Size& small_size,
-                              int small_corner_radius) = 0;
-
-  // Sets the |center_point| of the ink drop relative to its parent Layer.
-  virtual void SetInkDropCenter(const gfx::Point& center_point) = 0;
-
  protected:
   InkDropAnimationController() {}
 
diff --git a/ui/views/animation/ink_drop_animation_controller_factory.cc b/ui/views/animation/ink_drop_animation_controller_factory.cc
index 377d996c..9a9c8ed 100644
--- a/ui/views/animation/ink_drop_animation_controller_factory.cc
+++ b/ui/views/animation/ink_drop_animation_controller_factory.cc
@@ -29,24 +29,12 @@
   bool IsVisible() const override;
   void AnimateToState(InkDropState state) override;
   void SetHovered(bool is_hovered) override;
-  bool IsHovered() const override;
-  gfx::Size GetInkDropLargeSize() const override;
-  void SetInkDropSize(const gfx::Size& large_size,
-                      int large_corner_radius,
-                      const gfx::Size& small_size,
-                      int small_corner_radius) override;
-  void SetInkDropCenter(const gfx::Point& center_point) override;
 
  private:
-  // Tracks whether the ink drop is hovered or not. This is used to ensure that
-  // this behaves like all other InkDropAnimationController implementations.
-  bool is_hovered_;
-
   DISALLOW_COPY_AND_ASSIGN(InkDropAnimationControllerStub);
 };
 
-InkDropAnimationControllerStub::InkDropAnimationControllerStub()
-    : is_hovered_(false) {}
+InkDropAnimationControllerStub::InkDropAnimationControllerStub() {}
 
 InkDropAnimationControllerStub::~InkDropAnimationControllerStub() {}
 
@@ -58,28 +46,9 @@
   return false;
 }
 
-void InkDropAnimationControllerStub::AnimateToState(InkDropState state) {
-}
+void InkDropAnimationControllerStub::AnimateToState(InkDropState state) {}
 
-void InkDropAnimationControllerStub::SetHovered(bool is_hovered) {
-  is_hovered_ = is_hovered;
-}
-
-bool InkDropAnimationControllerStub::IsHovered() const {
-  return is_hovered_;
-}
-
-gfx::Size InkDropAnimationControllerStub::GetInkDropLargeSize() const {
-  return gfx::Size();
-}
-
-void InkDropAnimationControllerStub::SetInkDropSize(const gfx::Size& large_size,
-                                                    int large_corner_radius,
-                                                    const gfx::Size& small_size,
-                                                    int small_corner_radius) {}
-
-void InkDropAnimationControllerStub::SetInkDropCenter(
-    const gfx::Point& center_point) {}
+void InkDropAnimationControllerStub::SetHovered(bool is_hovered) {}
 
 }  // namespace
 
diff --git a/ui/views/animation/ink_drop_animation_controller_factory_unittest.cc b/ui/views/animation/ink_drop_animation_controller_factory_unittest.cc
index c94f78f..5991eb0 100644
--- a/ui/views/animation/ink_drop_animation_controller_factory_unittest.cc
+++ b/ui/views/animation/ink_drop_animation_controller_factory_unittest.cc
@@ -58,8 +58,6 @@
       InkDropAnimationControllerFactory::CreateInkDropAnimationController(
           &test_ink_drop_host_)
           .release());
-  ink_drop_animation_controller_->SetInkDropSize(gfx::Size(10, 10), 4,
-                                                 gfx::Size(8, 8), 2);
 
   zero_duration_mode_.reset(new ui::ScopedAnimationDurationScaleMode(
       ui::ScopedAnimationDurationScaleMode::ZERO_DURATION));
@@ -110,13 +108,6 @@
             ink_drop_animation_controller_->GetTargetInkDropState());
 }
 
-TEST_P(InkDropAnimationControllerFactoryTest, HoveredStateAfterAnimateToState) {
-  ink_drop_animation_controller_->SetHovered(true);
-  ink_drop_animation_controller_->AnimateToState(InkDropState::ACTION_PENDING);
-
-  EXPECT_TRUE(ink_drop_animation_controller_->IsHovered());
-}
-
 TEST_P(InkDropAnimationControllerFactoryTest, TypicalQuickAction) {
   ink_drop_animation_controller_->AnimateToState(InkDropState::ACTION_PENDING);
   ink_drop_animation_controller_->AnimateToState(InkDropState::QUICK_ACTION);
diff --git a/ui/views/animation/ink_drop_animation_controller_impl.cc b/ui/views/animation/ink_drop_animation_controller_impl.cc
index a8c8cf4e..23bf9f25 100644
--- a/ui/views/animation/ink_drop_animation_controller_impl.cc
+++ b/ui/views/animation/ink_drop_animation_controller_impl.cc
@@ -53,10 +53,7 @@
 InkDropAnimationControllerImpl::InkDropAnimationControllerImpl(
     InkDropHost* ink_drop_host)
     : ink_drop_host_(ink_drop_host),
-      ink_drop_large_corner_radius_(0),
-      ink_drop_small_corner_radius_(0),
       root_layer_(new ui::Layer(ui::LAYER_NOT_DRAWN)),
-      is_hovered_(false),
       can_destroy_after_hidden_animation_(true),
       hover_after_animation_timer_(nullptr) {
   root_layer_->set_name("InkDropAnimationControllerImpl:RootLayer");
@@ -107,7 +104,6 @@
 }
 
 void InkDropAnimationControllerImpl::SetHovered(bool is_hovered) {
-  is_hovered_ = is_hovered;
   SetHoveredInternal(is_hovered,
                      is_hovered ? base::TimeDelta::FromMilliseconds(
                                       kHoverFadeInFromUserInputDurationInMs)
@@ -115,50 +111,10 @@
                                       kHoverFadeOutFromUserInputDurationInMs));
 }
 
-bool InkDropAnimationControllerImpl::IsHovered() const {
-  return is_hovered_;
-}
-
-gfx::Size InkDropAnimationControllerImpl::GetInkDropLargeSize() const {
-  return ink_drop_large_size_;
-}
-
-void InkDropAnimationControllerImpl::SetInkDropSize(const gfx::Size& large_size,
-                                                    int large_corner_radius,
-                                                    const gfx::Size& small_size,
-                                                    int small_corner_radius) {
-  // TODO(bruthig): Fix the ink drop animations to work for non-square sizes.
-  DCHECK_EQ(large_size.width(), large_size.height())
-      << "The ink drop animation does not currently support non-square sizes.";
-  DCHECK_EQ(small_size.width(), small_size.height())
-      << "The ink drop animation does not currently support non-square sizes.";
-  ink_drop_large_size_ = large_size;
-  ink_drop_large_corner_radius_ = large_corner_radius;
-  ink_drop_small_size_ = small_size;
-  ink_drop_small_corner_radius_ = small_corner_radius;
-
-  DestroyInkDropAnimation();
-  DestroyInkDropHover();
-}
-
-void InkDropAnimationControllerImpl::SetInkDropCenter(
-    const gfx::Point& center_point) {
-  ink_drop_center_ = center_point;
-  if (ink_drop_animation_)
-    ink_drop_animation_->SetCenterPoint(ink_drop_center_);
-  if (hover_)
-    hover_->SetCenterPoint(ink_drop_center_);
-}
-
 void InkDropAnimationControllerImpl::CreateInkDropAnimation() {
   DestroyInkDropAnimation();
-
-  ink_drop_animation_.reset(new SquareInkDropAnimation(
-      ink_drop_large_size_, ink_drop_large_corner_radius_, ink_drop_small_size_,
-      ink_drop_small_corner_radius_));
-
+  ink_drop_animation_ = ink_drop_host_->CreateInkDropAnimation();
   ink_drop_animation_->AddObserver(this);
-  ink_drop_animation_->SetCenterPoint(ink_drop_center_);
   root_layer_->Add(ink_drop_animation_->GetRootLayer());
 }
 
@@ -173,9 +129,9 @@
 void InkDropAnimationControllerImpl::CreateInkDropHover() {
   DestroyInkDropHover();
 
-  hover_.reset(
-      new InkDropHover(ink_drop_small_size_, ink_drop_small_corner_radius_));
-  hover_->SetCenterPoint(ink_drop_center_);
+  hover_ = ink_drop_host_->CreateInkDropHover();
+  if (!hover_)
+    return;
   root_layer_->Add(hover_->layer());
 }
 
@@ -221,9 +177,8 @@
     return;
 
   if (is_hovered) {
-    if (!hover_)
-      CreateInkDropHover();
-    if (!IsVisible())
+    CreateInkDropHover();
+    if (hover_ && !IsVisible())
       hover_->FadeIn(animation_duration);
   } else {
     hover_->FadeOut(animation_duration);
@@ -249,9 +204,8 @@
 }
 
 void InkDropAnimationControllerImpl::HoverAfterAnimationTimerFired() {
-  SetHoveredInternal(ink_drop_host_->ShouldShowInkDropHover(),
-                     base::TimeDelta::FromMilliseconds(
-                         kHoverFadeInAfterAnimationDurationInMs));
+  SetHoveredInternal(true, base::TimeDelta::FromMilliseconds(
+                               kHoverFadeInAfterAnimationDurationInMs));
   hover_after_animation_timer_.reset();
 }
 
diff --git a/ui/views/animation/ink_drop_animation_controller_impl.h b/ui/views/animation/ink_drop_animation_controller_impl.h
index 07d138d..3c7cf243e 100644
--- a/ui/views/animation/ink_drop_animation_controller_impl.h
+++ b/ui/views/animation/ink_drop_animation_controller_impl.h
@@ -38,13 +38,6 @@
   bool IsVisible() const override;
   void AnimateToState(InkDropState ink_drop_state) override;
   void SetHovered(bool is_hovered) override;
-  bool IsHovered() const override;
-  gfx::Size GetInkDropLargeSize() const override;
-  void SetInkDropSize(const gfx::Size& large_size,
-                      int large_corner_radius,
-                      const gfx::Size& small_size,
-                      int small_corner_radius) override;
-  void SetInkDropCenter(const gfx::Point& center_point) override;
 
  private:
   friend class InkDropAnimationControllerFactoryTest;
@@ -93,21 +86,6 @@
   // hover should be shown or not.
   InkDropHost* ink_drop_host_;
 
-  // Cached size for the ink drop's large size animations.
-  gfx::Size ink_drop_large_size_;
-
-  // Cached corner radius for the ink drop's large size animations.
-  int ink_drop_large_corner_radius_;
-
-  // Cached size for the ink drop's small size animations.
-  gfx::Size ink_drop_small_size_;
-
-  // Cached corner radius for the ink drop's small size animations.
-  int ink_drop_small_corner_radius_;
-
-  // Cached center point for the ink drop.
-  gfx::Point ink_drop_center_;
-
   // The root Layer that parents the InkDropAnimation layers and the
   // InkDropHover layers. The |root_layer_| is the one that is added and removed
   // from the InkDropHost.
@@ -116,9 +94,6 @@
   // The current InkDropHover. Lazily created using CreateInkDropHover();
   scoped_ptr<InkDropHover> hover_;
 
-  // The logical hover state of |this|.
-  bool is_hovered_;
-
   // The current InkDropAnimation. Created on demand using
   // CreateInkDropAnimation().
   scoped_ptr<InkDropAnimation> ink_drop_animation_;
diff --git a/ui/views/animation/ink_drop_animation_controller_impl_unittest.cc b/ui/views/animation/ink_drop_animation_controller_impl_unittest.cc
index 1f0862cb..a32ba606 100644
--- a/ui/views/animation/ink_drop_animation_controller_impl_unittest.cc
+++ b/ui/views/animation/ink_drop_animation_controller_impl_unittest.cc
@@ -26,6 +26,10 @@
     return ink_drop_animation_controller_.IsHoverFadingInOrVisible();
   }
 
+  const InkDropHover* hover() const {
+    return ink_drop_animation_controller_.hover_.get();
+  }
+
   // The test target.
   InkDropAnimationControllerImpl ink_drop_animation_controller_;
 
@@ -54,16 +58,6 @@
 
 InkDropAnimationControllerImplTest::~InkDropAnimationControllerImplTest() {}
 
-TEST_F(InkDropAnimationControllerImplTest, SetHoveredIsHovered) {
-  ink_drop_host_.set_should_show_hover(true);
-
-  ink_drop_animation_controller_.SetHovered(true);
-  EXPECT_TRUE(ink_drop_animation_controller_.IsHovered());
-
-  ink_drop_animation_controller_.SetHovered(false);
-  EXPECT_FALSE(ink_drop_animation_controller_.IsHovered());
-}
-
 TEST_F(InkDropAnimationControllerImplTest, SetHoveredIsFadingInOrVisible) {
   ink_drop_host_.set_should_show_hover(true);
 
@@ -109,4 +103,15 @@
   EXPECT_FALSE(is_hover_fading_in_or_visible());
 }
 
+// Verifies that there is not a crash when setting hovered state and the host
+// returns null for the hover.
+TEST_F(InkDropAnimationControllerImplTest,
+       SetHoveredFalseWorksWhenNoInkDropHoverExists) {
+  ink_drop_host_.set_should_show_hover(false);
+  ink_drop_animation_controller_.SetHovered(true);
+  EXPECT_FALSE(hover());
+  ink_drop_animation_controller_.SetHovered(false);
+  EXPECT_FALSE(hover());
+}
+
 }  // namespace views
diff --git a/ui/views/animation/ink_drop_delegate.h b/ui/views/animation/ink_drop_delegate.h
index 0bf265a..99b1e82c 100644
--- a/ui/views/animation/ink_drop_delegate.h
+++ b/ui/views/animation/ink_drop_delegate.h
@@ -23,19 +23,6 @@
   InkDropDelegate() {}
   virtual ~InkDropDelegate() {}
 
-  // Sets sizes for the animation layers that are squares with |large_size| and
-  // |small_size| being the length of each side. When painting rounded squares
-  // |large_corner_radius| and |small_corner_radius| are specifying the
-  // corner radius.
-  virtual void SetInkDropSize(int large_size,
-                              int large_corner_radius,
-                              int small_size,
-                              int small_corner_radius) = 0;
-
-  // Called when the bounds or layout of the View changes necessitating change
-  // in positioning of ink ripple layers.
-  virtual void OnLayout() = 0;
-
   // Called when ink ripple state changes.
   // TODO(bruthig): Replace the InkDropState parameter with an InkDropAction
   // enum.  The InkDropAction enum should be a subset of the InkDropState values
diff --git a/ui/views/animation/ink_drop_host.h b/ui/views/animation/ink_drop_host.h
index ab9f165..570f271 100644
--- a/ui/views/animation/ink_drop_host.h
+++ b/ui/views/animation/ink_drop_host.h
@@ -6,6 +6,7 @@
 #define UI_VIEWS_ANIMATION_INK_DROP_HOST_H_
 
 #include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/views/views_export.h"
 
@@ -15,6 +16,9 @@
 
 namespace views {
 
+class InkDropAnimation;
+class InkDropHover;
+
 // Used by the InkDropAnimationController to add and remove the ink drop layers
 // from a host's layer tree. Typically the ink drop layer is added to a View's
 // layer but it can also be added to a View's ancestor layer.
@@ -33,11 +37,11 @@
   // Removes |ink_drop_layer| from the layer tree.
   virtual void RemoveInkDropLayer(ui::Layer* ink_drop_layer) = 0;
 
-  // Returns the Point where the ink drop should be centered.
-  virtual gfx::Point CalculateInkDropCenter() const = 0;
+  // Creates and returns the effect used for press.
+  virtual scoped_ptr<InkDropAnimation> CreateInkDropAnimation() const = 0;
 
-  // Returns true if the InkDropHover should be shown.
-  virtual bool ShouldShowInkDropHover() const = 0;
+  // Creates and returns the effect used for hover.
+  virtual scoped_ptr<InkDropHover> CreateInkDropHover() const = 0;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(InkDropHost);
diff --git a/ui/views/animation/ink_drop_host_view.cc b/ui/views/animation/ink_drop_host_view.cc
new file mode 100644
index 0000000..d19978c
--- /dev/null
+++ b/ui/views/animation/ink_drop_host_view.cc
@@ -0,0 +1,57 @@
+// Copyright 2016 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 "ui/views/animation/ink_drop_host_view.h"
+
+#include "ui/views/animation/ink_drop_hover.h"
+#include "ui/views/animation/square_ink_drop_animation.h"
+
+namespace views {
+
+// Default sizes for ink drop effects.
+const int kInkDropLargeSize = 32;
+const int kInkDropLargeCornerRadius = 4;
+const int kInkDropSmallSize = 24;
+const int kInkDropSmallCornerRadius = 2;
+
+InkDropHostView::InkDropHostView() {}
+
+InkDropHostView::~InkDropHostView() {}
+
+void InkDropHostView::AddInkDropLayer(ui::Layer* ink_drop_layer) {
+  SetPaintToLayer(true);
+  SetFillsBoundsOpaquely(false);
+  layer()->Add(ink_drop_layer);
+  layer()->StackAtBottom(ink_drop_layer);
+}
+
+void InkDropHostView::RemoveInkDropLayer(ui::Layer* ink_drop_layer) {
+  layer()->Remove(ink_drop_layer);
+  SetFillsBoundsOpaquely(true);
+  SetPaintToLayer(false);
+}
+
+scoped_ptr<InkDropAnimation> InkDropHostView::CreateInkDropAnimation() const {
+  scoped_ptr<InkDropAnimation> animation(new SquareInkDropAnimation(
+      gfx::Size(kInkDropLargeSize, kInkDropLargeSize),
+      kInkDropLargeCornerRadius,
+      gfx::Size(kInkDropSmallSize, kInkDropSmallSize),
+      kInkDropSmallCornerRadius));
+  animation->SetCenterPoint(GetInkDropCenter());
+  return animation;
+}
+
+scoped_ptr<InkDropHover> InkDropHostView::CreateInkDropHover() const {
+  scoped_ptr<InkDropHover> hover(
+      new InkDropHover(gfx::Size(kInkDropSmallSize, kInkDropSmallSize),
+                       kInkDropSmallCornerRadius));
+  hover->SetCenterPoint(GetInkDropCenter());
+  return hover;
+}
+
+gfx::Point InkDropHostView::GetInkDropCenter() const {
+  return GetLocalBounds().CenterPoint();
+}
+
+}  // namespace views
diff --git a/ui/views/animation/ink_drop_host_view.h b/ui/views/animation/ink_drop_host_view.h
new file mode 100644
index 0000000..c77a39f0
--- /dev/null
+++ b/ui/views/animation/ink_drop_host_view.h
@@ -0,0 +1,39 @@
+// Copyright 2016 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 UI_VIEWS_ANIMATION_INK_DROP_HOST_VIEW_H_
+#define UI_VIEWS_ANIMATION_INK_DROP_HOST_VIEW_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/views/animation/ink_drop_host.h"
+#include "ui/views/view.h"
+
+namespace views {
+
+class InkDropAnimation;
+class InkDropHover;
+
+// A view that provides InkDropHost functionality.
+class VIEWS_EXPORT InkDropHostView : public views::View, public InkDropHost {
+ public:
+  InkDropHostView();
+  ~InkDropHostView() override;
+
+  // Overridden from views::InkDropHost:
+  void AddInkDropLayer(ui::Layer* ink_drop_layer) override;
+  void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override;
+  scoped_ptr<InkDropAnimation> CreateInkDropAnimation() const override;
+  scoped_ptr<InkDropHover> CreateInkDropHover() const override;
+
+ protected:
+  // Overrideable methods to allow views to provide minor tweaks to the default
+  // ink drop.
+  virtual gfx::Point GetInkDropCenter() const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(InkDropHostView);
+};
+}
+
+#endif  // UI_VIEWS_ANIMATION_INK_DROP_HOST_VIEW_H_
diff --git a/ui/views/animation/test/test_ink_drop_host.cc b/ui/views/animation/test/test_ink_drop_host.cc
index 3b46616..c8572f3d 100644
--- a/ui/views/animation/test/test_ink_drop_host.cc
+++ b/ui/views/animation/test/test_ink_drop_host.cc
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "ui/gfx/geometry/size.h"
+#include "ui/views/animation/ink_drop_hover.h"
+#include "ui/views/animation/square_ink_drop_animation.h"
 #include "ui/views/animation/test/test_ink_drop_host.h"
 
 namespace views {
@@ -19,12 +22,15 @@
   --num_ink_drop_layers_;
 }
 
-gfx::Point TestInkDropHost::CalculateInkDropCenter() const {
-  return gfx::Point();
+scoped_ptr<InkDropAnimation> TestInkDropHost::CreateInkDropAnimation() const {
+  gfx::Size size(10, 10);
+  return make_scoped_ptr(new SquareInkDropAnimation(size, 5, size, 5));
 }
 
-bool TestInkDropHost::ShouldShowInkDropHover() const {
-  return should_show_hover_;
+scoped_ptr<InkDropHover> TestInkDropHost::CreateInkDropHover() const {
+  return should_show_hover_
+             ? make_scoped_ptr(new InkDropHover(gfx::Size(10, 10), 4))
+             : nullptr;
 }
 
 }  // namespace views
diff --git a/ui/views/animation/test/test_ink_drop_host.h b/ui/views/animation/test/test_ink_drop_host.h
index 9192a116..139ffec 100644
--- a/ui/views/animation/test/test_ink_drop_host.h
+++ b/ui/views/animation/test/test_ink_drop_host.h
@@ -26,8 +26,8 @@
   // TestInkDropHost:
   void AddInkDropLayer(ui::Layer* ink_drop_layer) override;
   void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override;
-  gfx::Point CalculateInkDropCenter() const override;
-  bool ShouldShowInkDropHover() const override;
+  scoped_ptr<InkDropAnimation> CreateInkDropAnimation() const override;
+  scoped_ptr<InkDropHover> CreateInkDropHover() const override;
 
  private:
   int num_ink_drop_layers_;
diff --git a/ui/views/bubble/bubble_delegate.cc b/ui/views/bubble/bubble_delegate.cc
index 5e30b98..a18c0888 100644
--- a/ui/views/bubble/bubble_delegate.cc
+++ b/ui/views/bubble/bubble_delegate.cc
@@ -6,6 +6,7 @@
 
 #include "build/build_config.h"
 #include "ui/accessibility/ax_view_state.h"
+#include "ui/base/default_style.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/geometry/rect.h"
@@ -301,10 +302,9 @@
 
 const gfx::FontList& BubbleDelegateView::GetTitleFontList() const {
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  return rb.GetFontList(ui::ResourceBundle::MediumFont);
+  return rb.GetFontListWithDelta(ui::kTitleFontSizeDelta);
 }
 
-
 void BubbleDelegateView::UpdateColorsFromTheme(const ui::NativeTheme* theme) {
   if (!color_explicitly_set_)
     color_ = theme->GetSystemColor(ui::NativeTheme::kColorId_BubbleBackground);
diff --git a/ui/views/bubble/bubble_frame_view.cc b/ui/views/bubble/bubble_frame_view.cc
index c102835..64bf37c5 100644
--- a/ui/views/bubble/bubble_frame_view.cc
+++ b/ui/views/bubble/bubble_frame_view.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "build/build_config.h"
+#include "ui/base/default_style.h"
 #include "ui/base/hit_test.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -84,7 +85,7 @@
 
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
   title_ = new Label(base::string16(),
-                     rb.GetFontList(ui::ResourceBundle::MediumFont));
+                     rb.GetFontListWithDelta(ui::kTitleFontSizeDelta));
   title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   title_->set_collapse_when_hidden(true);
   title_->SetVisible(false);
diff --git a/ui/views/cocoa/views_scrollbar_bridge.h b/ui/views/cocoa/views_scrollbar_bridge.h
new file mode 100644
index 0000000..eb070a1
--- /dev/null
+++ b/ui/views/cocoa/views_scrollbar_bridge.h
@@ -0,0 +1,40 @@
+// Copyright 2016 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 UI_VIEWS_COCOA_VIEWS_SCROLLBAR_BRIDGE_DELEGATE_H_
+#define UI_VIEWS_COCOA_VIEWS_SCROLLBAR_BRIDGE_DELEGATE_H_
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/mac/scoped_nsobject.h"
+#include "ui/views/views_export.h"
+
+// The delegate set to ViewsScrollbarBridge.
+class ViewsScrollbarBridgeDelegate {
+ public:
+  // Invoked by ViewsScrollbarBridge when the system informs the process that
+  // the preferred scroller style has changed
+  virtual void OnScrollerStyleChanged() = 0;
+};
+
+// A bridge to NSScroller managed by NativeCocoaScrollbar. Serves as a helper
+// class to bridge NSScroller notifications and functions to CocoaScrollbar.
+@interface ViewsScrollbarBridge : NSObject {
+ @private
+  ViewsScrollbarBridgeDelegate* delegate_;  // Weak. Owns this.
+}
+
+// Initializes with the given delegate and registers for notifications on
+// scroller style changes.
+- (id)initWithDelegate:(ViewsScrollbarBridgeDelegate*)delegate;
+
+// Sets |delegate_| to nullptr.
+-(void)clearDelegate;
+
+// Returns the style of scrollers that OSX is using.
++ (NSScrollerStyle)getPreferredScrollerStyle;
+
+@end
+
+#endif
\ No newline at end of file
diff --git a/ui/views/cocoa/views_scrollbar_bridge.mm b/ui/views/cocoa/views_scrollbar_bridge.mm
new file mode 100644
index 0000000..94527be
--- /dev/null
+++ b/ui/views/cocoa/views_scrollbar_bridge.mm
@@ -0,0 +1,54 @@
+// Copyright 2016 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 "ui/views/cocoa/views_scrollbar_bridge.h"
+
+#include "base/mac/mac_util.h"
+#import "base/mac/sdk_forward_declarations.h"
+
+@interface ViewsScrollbarBridge ()
+
+// Called when we receive a NSPreferredScrollerStyleDidChangeNotification.
+- (void)onScrollerStyleChanged:(NSNotification*)notification;
+
+@end
+
+@implementation ViewsScrollbarBridge
+
+- (id)initWithDelegate:(ViewsScrollbarBridgeDelegate*)delegate {
+  if ((self = [super init])) {
+    delegate_ = delegate;
+    [[NSNotificationCenter defaultCenter]
+        addObserver:self
+           selector:@selector(onScrollerStyleChanged:)
+               name:NSPreferredScrollerStyleDidChangeNotification
+             object:nil];
+  }
+  return self;
+}
+
+- (void)dealloc {
+  DCHECK(!delegate_);
+  [super dealloc];
+}
+
+- (void)clearDelegate {
+  delegate_ = nullptr;
+  [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)onScrollerStyleChanged:(NSNotification*)notification {
+  if (delegate_)
+    delegate_->OnScrollerStyleChanged();
+}
+
++ (NSScrollerStyle)getPreferredScrollerStyle {
+  if (![NSScroller respondsToSelector:@selector(preferredScrollerStyle)]) {
+    DCHECK(base::mac::IsOSSnowLeopard());
+    return NSScrollerStyleLegacy;
+  }
+  return [NSScroller preferredScrollerStyle];
+}
+
+@end
\ No newline at end of file
diff --git a/ui/views/controls/button/button.h b/ui/views/controls/button/button.h
index 0f1160b1..dab4870 100644
--- a/ui/views/controls/button/button.h
+++ b/ui/views/controls/button/button.h
@@ -7,7 +7,7 @@
 
 #include "base/macros.h"
 #include "ui/native_theme/native_theme.h"
-#include "ui/views/view.h"
+#include "ui/views/animation/ink_drop_host_view.h"
 
 namespace views {
 
@@ -26,7 +26,7 @@
 
 // A View representing a button. Depending on the specific type, the button
 // could be implemented by a native control or custom rendered.
-class VIEWS_EXPORT Button : public View {
+class VIEWS_EXPORT Button : public InkDropHostView {
  public:
   ~Button() override;
 
diff --git a/ui/views/controls/button/custom_button.cc b/ui/views/controls/button/custom_button.cc
index 8caea1d..7c46462 100644
--- a/ui/views/controls/button/custom_button.cc
+++ b/ui/views/controls/button/custom_button.cc
@@ -11,6 +11,7 @@
 #include "ui/gfx/animation/throb_animation.h"
 #include "ui/gfx/screen.h"
 #include "ui/views/animation/ink_drop_delegate.h"
+#include "ui/views/animation/ink_drop_hover.h"
 #include "ui/views/controls/button/blue_button.h"
 #include "ui/views/controls/button/checkbox.h"
 #include "ui/views/controls/button/image_button.h"
@@ -116,12 +117,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // CustomButton, View overrides:
 
-void CustomButton::Layout() {
-  Button::Layout();
-  if (ink_drop_delegate_)
-    ink_drop_delegate_->OnLayout();
-}
-
 void CustomButton::OnEnabledChanged() {
   // TODO(bruthig): Is there any reason we are not calling
   // Button::OnEnabledChanged() here?
@@ -132,7 +127,9 @@
     SetState(ShouldEnterHoveredState() ? STATE_HOVERED : STATE_NORMAL);
   else
     SetState(STATE_DISABLED);
-  UpdateInkDropHoverState();
+
+  if (ink_drop_delegate_)
+    ink_drop_delegate_->SetHovered(ShouldShowInkDropHover());
 }
 
 const char* CustomButton::GetClassName() const {
@@ -329,6 +326,10 @@
   SetState(visible && ShouldEnterHoveredState() ? STATE_HOVERED : STATE_NORMAL);
 }
 
+scoped_ptr<InkDropHover> CustomButton::CreateInkDropHover() const {
+  return ShouldShowInkDropHover() ? Button::CreateInkDropHover() : nullptr;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // CustomButton, gfx::AnimationDelegate implementation:
 
@@ -337,30 +338,6 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// CustomButton, views::InkDropHost implementation:
-
-void CustomButton::AddInkDropLayer(ui::Layer* ink_drop_layer) {
-  SetPaintToLayer(true);
-  SetFillsBoundsOpaquely(false);
-  layer()->Add(ink_drop_layer);
-  layer()->StackAtBottom(ink_drop_layer);
-}
-
-void CustomButton::RemoveInkDropLayer(ui::Layer* ink_drop_layer) {
-  layer()->Remove(ink_drop_layer);
-  SetFillsBoundsOpaquely(true);
-  SetPaintToLayer(false);
-}
-
-gfx::Point CustomButton::CalculateInkDropCenter() const {
-  return GetLocalBounds().CenterPoint();
-}
-
-bool CustomButton::ShouldShowInkDropHover() const {
-  return enabled() && IsMouseHovered() && !InDrag();
-}
-
-////////////////////////////////////////////////////////////////////////////////
 // CustomButton, protected:
 
 CustomButton::CustomButton(ButtonListener* listener)
@@ -416,20 +393,9 @@
   return check_mouse_position && IsMouseHovered();
 }
 
-void CustomButton::UpdateInkDropHoverState() {
-  if (ink_drop_delegate_)
-    ink_drop_delegate_->SetHovered(ShouldShowInkDropHover());
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // CustomButton, View overrides (protected):
 
-void CustomButton::OnBoundsChanged(const gfx::Rect& previous_bounds) {
-  Button::OnBoundsChanged(previous_bounds);
-  if (ink_drop_delegate_)
-    ink_drop_delegate_->OnLayout();
-}
-
 void CustomButton::ViewHierarchyChanged(
     const ViewHierarchyChangedDetails& details) {
   if (!details.is_add && state_ != STATE_DISABLED)
@@ -453,4 +419,8 @@
   Button::OnClickCanceled(event);
 }
 
+bool CustomButton::ShouldShowInkDropHover() const {
+  return enabled() && IsMouseHovered() && !InDrag();
+}
+
 }  // namespace views
diff --git a/ui/views/controls/button/custom_button.h b/ui/views/controls/button/custom_button.h
index 4513466..36661c1 100644
--- a/ui/views/controls/button/custom_button.h
+++ b/ui/views/controls/button/custom_button.h
@@ -10,7 +10,6 @@
 #include "ui/events/event_constants.h"
 #include "ui/gfx/animation/animation_delegate.h"
 #include "ui/gfx/animation/throb_animation.h"
-#include "ui/views/animation/ink_drop_host.h"
 #include "ui/views/animation/ink_drop_state.h"
 #include "ui/views/controls/button/button.h"
 
@@ -22,9 +21,7 @@
 // Note that this type of button is not focusable by default and will not be
 // part of the focus chain.  Call SetFocusable(true) to make it part of the
 // focus chain.
-class VIEWS_EXPORT CustomButton : public Button,
-                                  public gfx::AnimationDelegate,
-                                  public views::InkDropHost {
+class VIEWS_EXPORT CustomButton : public Button, public gfx::AnimationDelegate {
  public:
   // An enum describing the events on which a button should notify its listener.
   enum NotifyAction {
@@ -79,7 +76,6 @@
   bool IsHotTracked() const;
 
   // Overridden from View:
-  void Layout() override;
   void OnEnabledChanged() override;
   const char* GetClassName() const override;
   bool OnMousePressed(const ui::MouseEvent& event) override;
@@ -99,16 +95,11 @@
   void OnDragDone() override;
   void GetAccessibleState(ui::AXViewState* state) override;
   void VisibilityChanged(View* starting_from, bool is_visible) override;
+  scoped_ptr<InkDropHover> CreateInkDropHover() const override;
 
   // Overridden from gfx::AnimationDelegate:
   void AnimationProgressed(const gfx::Animation* animation) override;
 
-  // Overridden from views::InkDropHost:
-  void AddInkDropLayer(ui::Layer* ink_drop_layer) override;
-  void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override;
-  gfx::Point CalculateInkDropCenter() const override;
-  bool ShouldShowInkDropHover() const override;
-
  protected:
   // Construct the Button with a Listener. See comment for Button's ctor.
   explicit CustomButton(ButtonListener* listener);
@@ -138,16 +129,12 @@
   // state). This does not take into account enabled state.
   bool ShouldEnterHoveredState();
 
-  // Updates the |ink_drop_delegate_|'s hover state.
-  void UpdateInkDropHoverState();
-
   InkDropDelegate* ink_drop_delegate() const { return ink_drop_delegate_; }
   void set_ink_drop_delegate(InkDropDelegate* ink_drop_delegate) {
     ink_drop_delegate_ = ink_drop_delegate;
   }
 
   // Overridden from View:
-  void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
   void ViewHierarchyChanged(
       const ViewHierarchyChangedDetails& details) override;
   void OnBlur() override;
@@ -161,6 +148,8 @@
   }
 
  private:
+  bool ShouldShowInkDropHover() const;
+
   ButtonState state_;
 
   gfx::ThrobAnimation hover_animation_;
diff --git a/ui/views/controls/button/custom_button_unittest.cc b/ui/views/controls/button/custom_button_unittest.cc
index d4f172e7..13d54c6d 100644
--- a/ui/views/controls/button/custom_button_unittest.cc
+++ b/ui/views/controls/button/custom_button_unittest.cc
@@ -13,6 +13,7 @@
 #include "ui/gfx/screen.h"
 #include "ui/views/animation/ink_drop_delegate.h"
 #include "ui/views/animation/ink_drop_host.h"
+#include "ui/views/animation/test/test_ink_drop_host.h"
 #include "ui/views/controls/button/checkbox.h"
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/button/label_button.h"
@@ -71,17 +72,10 @@
                       bool* ink_hidden)
       : ink_drop_host_(ink_drop_host),
         ink_shown_(ink_shown),
-        ink_hidden_(ink_hidden) {
-    ink_drop_host_->AddInkDropLayer(nullptr);
-  }
+        ink_hidden_(ink_hidden) {}
   ~TestInkDropDelegate() override {}
 
   // InkDropDelegate:
-  void SetInkDropSize(int large_size,
-                      int large_corner_radius,
-                      int small_size,
-                      int small_corner_radius) override {}
-  void OnLayout() override {}
   void OnAction(InkDropState state) override {
     switch (state) {
       case InkDropState::ACTION_PENDING:
@@ -120,11 +114,6 @@
   }
   ~TestButtonWithInkDrop() override {}
 
-  // views::InkDropHost:
-  void AddInkDropLayer(ui::Layer* ink_drop_layer) override {}
-  void RemoveInkDropLayer(ui::Layer* ink_drop_layer) override {}
-  gfx::Point CalculateInkDropCenter() const override { return gfx::Point(); }
-
  private:
   scoped_ptr<views::InkDropDelegate> ink_drop_delegate_;
 
diff --git a/ui/views/controls/combobox/combobox.cc b/ui/views/controls/combobox/combobox.cc
index 22512ea9..270bdd5 100644
--- a/ui/views/controls/combobox/combobox.cc
+++ b/ui/views/controls/combobox/combobox.cc
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "build/build_config.h"
 #include "ui/accessibility/ax_view_state.h"
+#include "ui/base/default_style.h"
 #include "ui/base/ime/input_method.h"
 #include "ui/base/models/combobox_model.h"
 #include "ui/base/models/combobox_model_observer.h"
@@ -391,7 +392,7 @@
 // static
 const gfx::FontList& Combobox::GetFontList() {
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  return rb.GetFontList(ui::ResourceBundle::BaseFont);
+  return rb.GetFontListWithDelta(ui::kLabelFontSizeDelta);
 }
 
 void Combobox::SetStyle(Style style) {
diff --git a/ui/views/controls/glow_hover_controller.cc b/ui/views/controls/glow_hover_controller.cc
index 9a5fa0bc..ef08308 100644
--- a/ui/views/controls/glow_hover_controller.cc
+++ b/ui/views/controls/glow_hover_controller.cc
@@ -9,8 +9,8 @@
 namespace views {
 
 // Amount to scale the opacity.
-static const double kTrackOpacityScale = 0.25;
-static const double kHighlightOpacityScale = 1.0;
+static const double kSubtleOpacityScale = 0.45;
+static const double kPronouncedOpacityScale = 1.0;
 
 // How long the hover state takes.
 static const int kTrackHoverDurationMs = 400;
@@ -18,7 +18,7 @@
 GlowHoverController::GlowHoverController(views::View* view)
     : view_(view),
       animation_(this),
-      opacity_scale_(kTrackOpacityScale) {
+      opacity_scale_(kSubtleOpacityScale) {
   animation_.set_delegate(this);
 }
 
@@ -39,13 +39,13 @@
 void GlowHoverController::Show(Style style) {
   switch (style) {
     case SUBTLE:
-      opacity_scale_ = kTrackOpacityScale;
+      opacity_scale_ = kSubtleOpacityScale;
       animation_.SetSlideDuration(kTrackHoverDurationMs);
       animation_.SetTweenType(gfx::Tween::EASE_OUT);
       animation_.Show();
       break;
     case PRONOUNCED:
-      opacity_scale_ = kHighlightOpacityScale;
+      opacity_scale_ = kPronouncedOpacityScale;
       // Force the end state to show immediately.
       animation_.Show();
       animation_.End();
@@ -69,8 +69,8 @@
 }
 
 SkAlpha GlowHoverController::GetAlpha() const {
-  return static_cast<SkAlpha>(gfx::ToFlooredInt(
-      0.5 + animation_.CurrentValueBetween(0., 255 * opacity_scale_)));
+  return static_cast<SkAlpha>(animation_.CurrentValueBetween(
+      0, gfx::ToRoundedInt(255 * opacity_scale_)));
 }
 
 bool GlowHoverController::ShouldDraw() const {
diff --git a/ui/views/controls/label.cc b/ui/views/controls/label.cc
index 99137e6e..66ce8b6 100644
--- a/ui/views/controls/label.cc
+++ b/ui/views/controls/label.cc
@@ -18,6 +18,8 @@
 #include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/accessibility/ax_view_state.h"
+#include "ui/base/default_style.h"
+#include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/geometry/insets.h"
@@ -25,17 +27,23 @@
 #include "ui/native_theme/native_theme.h"
 
 namespace views {
+namespace {
+
+const gfx::FontList& GetDefaultFontList() {
+  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+  return rb.GetFontListWithDelta(ui::kLabelFontSizeDelta);
+}
+
+}  // namespace
 
 // static
 const char Label::kViewClassName[] = "Label";
 const int Label::kFocusBorderPadding = 1;
 
-Label::Label() {
-  Init(base::string16(), gfx::FontList());
+Label::Label() : Label(base::string16()) {
 }
 
-Label::Label(const base::string16& text) {
-  Init(text, gfx::FontList());
+Label::Label(const base::string16& text) : Label(text, GetDefaultFontList()) {
 }
 
 Label::Label(const base::string16& text, const gfx::FontList& font_list) {
diff --git a/ui/views/controls/scroll_view.cc b/ui/views/controls/scroll_view.cc
index 6902a8a..a3e1e97 100644
--- a/ui/views/controls/scroll_view.cc
+++ b/ui/views/controls/scroll_view.cc
@@ -10,7 +10,7 @@
 #include "ui/gfx/canvas.h"
 #include "ui/native_theme/native_theme.h"
 #include "ui/views/border.h"
-#include "ui/views/controls/scrollbar/native_scroll_bar.h"
+#include "ui/views/style/platform_style.h"
 #include "ui/views/widget/root_view.h"
 
 namespace views {
@@ -124,8 +124,8 @@
       contents_viewport_(new Viewport()),
       header_(NULL),
       header_viewport_(new Viewport()),
-      horiz_sb_(new NativeScrollBar(true)),
-      vert_sb_(new NativeScrollBar(false)),
+      horiz_sb_(PlatformStyle::CreateScrollBar(true).release()),
+      vert_sb_(PlatformStyle::CreateScrollBar(false).release()),
       corner_view_(new ScrollCornerView()),
       min_height_(-1),
       max_height_(-1),
@@ -300,11 +300,15 @@
     should_layout_contents = true;
   }
 
+  int height_offset = horiz_sb_required ?
+      horiz_sb_->GetContentOverlapSize() : 0;
+  int width_offset = vert_sb_required ?
+      vert_sb_->GetContentOverlapSize() : 0;
+
   if (horiz_sb_required) {
-    int height_offset = horiz_sb_->GetContentOverlapSize();
     horiz_sb_->SetBounds(contents_x,
                          viewport_bounds.bottom() - height_offset,
-                         viewport_bounds.right() - contents_x,
+                         viewport_bounds.right() - contents_x - width_offset,
                          horiz_sb_height + height_offset);
   }
   if (vert_sb_required) {
@@ -312,7 +316,7 @@
     vert_sb_->SetBounds(viewport_bounds.right() - width_offset,
                         contents_y,
                         vert_sb_width + width_offset,
-                        viewport_bounds.bottom() - contents_y);
+                        viewport_bounds.bottom() - contents_y - height_offset);
   }
   if (corner_view_required) {
     // Show the resize corner.
diff --git a/ui/views/controls/scroll_view_unittest.cc b/ui/views/controls/scroll_view_unittest.cc
index 180560ef..011f65d 100644
--- a/ui/views/controls/scroll_view_unittest.cc
+++ b/ui/views/controls/scroll_view_unittest.cc
@@ -10,6 +10,10 @@
 #include "ui/views/controls/scrollbar/overlay_scroll_bar.h"
 #include "ui/views/test/test_views.h"
 
+#if defined(OS_MACOSX)
+#include "ui/base/test/scoped_preferred_scroller_style_mac.h"
+#endif
+
 namespace views {
 
 namespace {
@@ -18,6 +22,8 @@
 const int kMinHeight = 50;
 const int kMaxHeight = 100;
 
+enum ScrollBarOrientation { HORIZONTAL, VERTICAL };
+
 // View implementation that allows setting the preferred size.
 class CustomView : public View {
  public:
@@ -47,6 +53,20 @@
   DISALLOW_COPY_AND_ASSIGN(CustomView);
 };
 
+void CheckScrollbarVisibility(const ScrollView& scroll_view,
+                              ScrollBarOrientation orientation,
+                              bool should_be_visible) {
+  const ScrollBar* scrollbar = orientation == HORIZONTAL
+                                   ? scroll_view.horizontal_scroll_bar()
+                                   : scroll_view.vertical_scroll_bar();
+  if (should_be_visible) {
+    ASSERT_TRUE(scrollbar);
+    EXPECT_TRUE(scrollbar->visible());
+  } else {
+    EXPECT_TRUE(!scrollbar || !scrollbar->visible());
+  }
+}
+
 }  // namespace
 
 // Verifies the viewport is sized to fit the available space.
@@ -60,7 +80,12 @@
 }
 
 // Verifies the scrollbars are added as necessary.
+// If on Mac, test the non-overlay scrollbars.
 TEST(ScrollViewTest, ScrollBars) {
+#if defined(OS_MACOSX)
+  ui::test::ScopedPreferredScrollerStyle scroller_style_override(false);
+#endif
+
   ScrollView scroll_view;
   View* contents = new View;
   scroll_view.SetContents(contents);
@@ -71,6 +96,8 @@
   scroll_view.Layout();
   EXPECT_EQ(100 - scroll_view.GetScrollBarWidth(), contents->parent()->width());
   EXPECT_EQ(100, contents->parent()->height());
+  CheckScrollbarVisibility(scroll_view, VERTICAL, true);
+  CheckScrollbarVisibility(scroll_view, HORIZONTAL, false);
   EXPECT_TRUE(!scroll_view.horizontal_scroll_bar() ||
               !scroll_view.horizontal_scroll_bar()->visible());
   ASSERT_TRUE(scroll_view.vertical_scroll_bar() != NULL);
@@ -82,10 +109,8 @@
   EXPECT_EQ(100, contents->parent()->width());
   EXPECT_EQ(100 - scroll_view.GetScrollBarHeight(),
             contents->parent()->height());
-  ASSERT_TRUE(scroll_view.horizontal_scroll_bar() != NULL);
-  EXPECT_TRUE(scroll_view.horizontal_scroll_bar()->visible());
-  EXPECT_TRUE(!scroll_view.vertical_scroll_bar() ||
-              !scroll_view.vertical_scroll_bar()->visible());
+  CheckScrollbarVisibility(scroll_view, VERTICAL, false);
+  CheckScrollbarVisibility(scroll_view, HORIZONTAL, true);
 
   // Both horizontal and vertical.
   contents->SetBounds(0, 0, 300, 400);
@@ -93,10 +118,8 @@
   EXPECT_EQ(100 - scroll_view.GetScrollBarWidth(), contents->parent()->width());
   EXPECT_EQ(100 - scroll_view.GetScrollBarHeight(),
             contents->parent()->height());
-  ASSERT_TRUE(scroll_view.horizontal_scroll_bar() != NULL);
-  EXPECT_TRUE(scroll_view.horizontal_scroll_bar()->visible());
-  ASSERT_TRUE(scroll_view.vertical_scroll_bar() != NULL);
-  EXPECT_TRUE(scroll_view.vertical_scroll_bar()->visible());
+  CheckScrollbarVisibility(scroll_view, VERTICAL, true);
+  CheckScrollbarVisibility(scroll_view, HORIZONTAL, true);
 
   // Add a border, test vertical scrollbar.
   const int kTopPadding = 1;
@@ -449,4 +472,63 @@
   EXPECT_TRUE(corner_view->visible());
 }
 
+#if defined(OS_MACOSX)
+// Tests the overlay scrollbars on Mac. Ensure that they show up properly and
+// do not overlap each other.
+TEST(ScrollViewTest, CocoaOverlayScrollBars) {
+  scoped_ptr<ui::test::ScopedPreferredScrollerStyle> scroller_style_override;
+  scroller_style_override.reset(
+      new ui::test::ScopedPreferredScrollerStyle(true));
+  ScrollView scroll_view;
+  View* contents = new View;
+  scroll_view.SetContents(contents);
+  scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100));
+
+  // Size the contents such that vertical scrollbar is needed.
+  // Since it is overlaid, the ViewPort size should match the ScrollView.
+  contents->SetBounds(0, 0, 50, 400);
+  scroll_view.Layout();
+  EXPECT_EQ(100, contents->parent()->width());
+  EXPECT_EQ(100, contents->parent()->height());
+  EXPECT_EQ(0, scroll_view.GetScrollBarWidth());
+  CheckScrollbarVisibility(scroll_view, VERTICAL, true);
+  CheckScrollbarVisibility(scroll_view, HORIZONTAL, false);
+
+  // Size the contents such that horizontal scrollbar is needed.
+  contents->SetBounds(0, 0, 400, 50);
+  scroll_view.Layout();
+  EXPECT_EQ(100, contents->parent()->width());
+  EXPECT_EQ(100, contents->parent()->height());
+  EXPECT_EQ(0, scroll_view.GetScrollBarHeight());
+  CheckScrollbarVisibility(scroll_view, VERTICAL, false);
+  CheckScrollbarVisibility(scroll_view, HORIZONTAL, true);
+
+  // Both horizontal and vertical scrollbars.
+  contents->SetBounds(0, 0, 300, 400);
+  scroll_view.Layout();
+  EXPECT_EQ(100, contents->parent()->width());
+  EXPECT_EQ(100, contents->parent()->height());
+  EXPECT_EQ(0, scroll_view.GetScrollBarWidth());
+  EXPECT_EQ(0, scroll_view.GetScrollBarHeight());
+  CheckScrollbarVisibility(scroll_view, VERTICAL, true);
+  CheckScrollbarVisibility(scroll_view, HORIZONTAL, true);
+
+  // Make sure the horizontal and vertical scrollbars don't overlap each other.
+  gfx::Rect vert_bounds = scroll_view.vertical_scroll_bar()->bounds();
+  gfx::Rect horiz_bounds = scroll_view.horizontal_scroll_bar()->bounds();
+  EXPECT_EQ(vert_bounds.x(), horiz_bounds.right());
+  EXPECT_EQ(horiz_bounds.y(), vert_bounds.bottom());
+
+  // Switch to the non-overlay style and check that the ViewPort is now sized
+  // to be smaller, and ScrollbarWidth and ScrollbarHeight are non-zero.
+  scroller_style_override.reset(
+      new ui::test::ScopedPreferredScrollerStyle(false));
+  EXPECT_EQ(100 - scroll_view.GetScrollBarWidth(), contents->parent()->width());
+  EXPECT_EQ(100 - scroll_view.GetScrollBarHeight(),
+            contents->parent()->height());
+  EXPECT_NE(0, scroll_view.GetScrollBarWidth());
+  EXPECT_NE(0, scroll_view.GetScrollBarHeight());
+}
+#endif
+
 }  // namespace views
diff --git a/ui/views/controls/scrollbar/cocoa_scroll_bar.h b/ui/views/controls/scrollbar/cocoa_scroll_bar.h
new file mode 100644
index 0000000..d3c9ba5f
--- /dev/null
+++ b/ui/views/controls/scrollbar/cocoa_scroll_bar.h
@@ -0,0 +1,70 @@
+// Copyright 2016 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 UI_VIEWS_CONTROLS_SCROLLBAR_COCOA_SCROLL_BAR_H_
+#define UI_VIEWS_CONTROLS_SCROLLBAR_COCOA_SCROLL_BAR_H_
+
+#include "base/macros.h"
+#import "base/mac/scoped_nsobject.h"
+#import "ui/views/cocoa/views_scrollbar_bridge.h"
+#include "ui/views/controls/scrollbar/base_scroll_bar.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+
+// The transparent scrollbar for Mac which overlays its contents.
+class VIEWS_EXPORT CocoaScrollBar : public BaseScrollBar,
+                                    public ViewsScrollbarBridgeDelegate {
+ public:
+  explicit CocoaScrollBar(bool horizontal);
+  ~CocoaScrollBar() override;
+
+  // Called by CocoaScrollBarThumb when the mouse enters or exits the view.
+  void OnMouseEnteredScrollbarThumb(const ui::MouseEvent& event);
+
+  // ScrollDelegate:
+  bool OnScroll(float dx, float dy) override;
+
+  // ViewsScrollbarBridgeDelegate:
+  void OnScrollerStyleChanged() override;
+
+  // Returns the scroller style.
+  NSScrollerStyle GetScrollerStyle() const { return scroller_style_; }
+
+ protected:
+  // BaseScrollBar:
+  gfx::Rect GetTrackBounds() const override;
+
+  // ScrollBar:
+  int GetLayoutSize() const override;
+  int GetContentOverlapSize() const override;
+
+  // View:
+  void Layout() override;
+  gfx::Size GetPreferredSize() const override;
+  void OnPaint(gfx::Canvas* canvas) override;
+
+ private:
+  // Methods to change the visibility of the scrollbar.
+  void ShowScrollbar();
+  void HideScrollbar();
+
+  // Scroller style the scrollbar is using.
+  NSScrollerStyle scroller_style_;
+
+  // Timer that will start the scrollbar's hiding animation when it reaches 0.
+  base::Timer hide_scrollbar_timer_;
+
+  // True when the scrolltrack should be drawn.
+  bool has_scrolltrack_;
+
+  // The bridge for NSScroller.
+  base::scoped_nsobject<ViewsScrollbarBridge> bridge_;
+
+  DISALLOW_COPY_AND_ASSIGN(CocoaScrollBar);
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_CONTROLS_SCROLLBAR_COCOA_SCROLL_BAR_H_
diff --git a/ui/views/controls/scrollbar/cocoa_scroll_bar.mm b/ui/views/controls/scrollbar/cocoa_scroll_bar.mm
new file mode 100644
index 0000000..7f8bae81
--- /dev/null
+++ b/ui/views/controls/scrollbar/cocoa_scroll_bar.mm
@@ -0,0 +1,301 @@
+// Copyright 2016 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 "ui/views/controls/scrollbar/cocoa_scroll_bar.h"
+
+#import "base/mac/sdk_forward_declarations.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/effects/SkGradientShader.h"
+#include "ui/compositor/layer.h"
+#include "ui/compositor/layer_animator.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/gfx/canvas.h"
+#include "ui/views/controls/scrollbar/base_scroll_bar_thumb.h"
+
+namespace views {
+
+namespace {
+
+// The length of the fade animation.
+const int kFadeDurationMs = 240;
+
+// How long we should wait before hiding the scrollbar.
+const int kScrollbarHideTimeoutMs = 500;
+
+// The width of the scrollbar.
+const int kScrollbarWidth = 15;
+
+// The width of the scrollbar thumb.
+const int kScrollbarThumbWidth = 10;
+
+// The width of the scroller track border.
+const int kScrollerTrackBorderWidth = 1;
+
+// The amount the thumb is inset from both the ends and the sides of the track.
+const int kScrollbarThumbInset = 3;
+
+// Scrollbar thumb colors.
+const SkColor kScrollerDefaultThumbColor = SkColorSetARGB(0x38, 0, 0, 0);
+const SkColor kScrollerHoverThumbColor = SkColorSetARGB(0x80, 0, 0, 0);
+
+// Scroller track colors.
+// TODO(spqchan): Add an alpha channel for the overlay-style scroll track.
+const SkColor kScrollerTrackGradientColors[] = {
+    SkColorSetRGB(0xEF, 0xEF, 0xEF), SkColorSetRGB(0xF9, 0xF9, 0xF9),
+    SkColorSetRGB(0xFD, 0xFD, 0xFD), SkColorSetRGB(0xF6, 0xF6, 0xF6)};
+const SkColor kScrollerTrackInnerBorderColor = SkColorSetRGB(0xE4, 0xE4, 0xE4);
+const SkColor kScrollerTrackOuterBorderColor = SkColorSetRGB(0xEF, 0xEF, 0xEF);
+
+//////////////////////////////////////////////////////////////////
+// CocoaScrollBarThumb
+
+class CocoaScrollBarThumb : public BaseScrollBarThumb {
+ public:
+  explicit CocoaScrollBarThumb(CocoaScrollBar* scroll_bar);
+  ~CocoaScrollBarThumb() override;
+
+  // Returns true if the thumb is in hover or pressed state.
+  bool IsStateHoverOrPressed();
+
+ protected:
+  // View:
+  gfx::Size GetPreferredSize() const override;
+  void OnPaint(gfx::Canvas* canvas) override;
+  void OnMouseEntered(const ui::MouseEvent& event) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CocoaScrollBarThumb);
+};
+
+CocoaScrollBarThumb::CocoaScrollBarThumb(CocoaScrollBar* scroll_bar)
+    : BaseScrollBarThumb(scroll_bar) {
+  DCHECK(scroll_bar);
+
+  // This is necessary, otherwise the thumb will be rendered below the views if
+  // those views paint to their own layers.
+  SetPaintToLayer(true);
+  SetFillsBoundsOpaquely(false);
+}
+
+CocoaScrollBarThumb::~CocoaScrollBarThumb() {}
+
+bool CocoaScrollBarThumb::IsStateHoverOrPressed() {
+  CustomButton::ButtonState state = GetState();
+  return state == CustomButton::STATE_HOVERED ||
+         state == CustomButton::STATE_PRESSED;
+}
+
+gfx::Size CocoaScrollBarThumb::GetPreferredSize() const {
+  return gfx::Size(kScrollbarThumbWidth, kScrollbarThumbWidth);
+}
+
+void CocoaScrollBarThumb::OnPaint(gfx::Canvas* canvas) {
+  CocoaScrollBar* scrollbar = static_cast<CocoaScrollBar*>(scroll_bar());
+  DCHECK(scrollbar);
+
+  SkColor thumb_color = kScrollerDefaultThumbColor;
+  if (scrollbar->GetScrollerStyle() == NSScrollerStyleOverlay ||
+      IsStateHoverOrPressed()) {
+    thumb_color = kScrollerHoverThumbColor;
+  }
+
+  gfx::Rect local_bounds(GetLocalBounds());
+  SkPaint paint;
+  paint.setAntiAlias(true);
+  paint.setStyle(SkPaint::kFill_Style);
+  paint.setColor(thumb_color);
+  const SkScalar radius = std::min(local_bounds.width(), local_bounds.height());
+  canvas->DrawRoundRect(local_bounds, radius, paint);
+}
+
+void CocoaScrollBarThumb::OnMouseEntered(const ui::MouseEvent& event) {
+  BaseScrollBarThumb::OnMouseEntered(event);
+  CocoaScrollBar* scrollbar = static_cast<CocoaScrollBar*>(scroll_bar());
+  scrollbar->OnMouseEnteredScrollbarThumb(event);
+}
+
+}  // namespace
+
+//////////////////////////////////////////////////////////////////
+// CocoaScrollBar class
+
+CocoaScrollBar::CocoaScrollBar(bool horizontal)
+    : BaseScrollBar(horizontal, new CocoaScrollBarThumb(this)),
+      hide_scrollbar_timer_(
+          FROM_HERE,
+          base::TimeDelta::FromMilliseconds(kScrollbarHideTimeoutMs),
+          base::Bind(&CocoaScrollBar::HideScrollbar, base::Unretained(this)),
+          false) {
+  bridge_.reset([[ViewsScrollbarBridge alloc] initWithDelegate:this]);
+
+  scroller_style_ = [ViewsScrollbarBridge getPreferredScrollerStyle];
+
+  SetPaintToLayer(true);
+  has_scrolltrack_ = scroller_style_ == NSScrollerStyleLegacy;
+  layer()->SetOpacity(scroller_style_ == NSScrollerStyleOverlay ? 0.0 : 1.0);
+}
+
+CocoaScrollBar::~CocoaScrollBar() {
+  [bridge_ clearDelegate];
+}
+
+//////////////////////////////////////////////////////////////////
+// CocoaScrollBar, BaseScrollBar:
+
+gfx::Rect CocoaScrollBar::GetTrackBounds() const {
+  gfx::Rect local_bounds(GetLocalBounds());
+  local_bounds.Inset(kScrollbarThumbInset, kScrollbarThumbInset);
+
+  gfx::Size track_size = local_bounds.size();
+  track_size.SetToMax(GetThumb()->size());
+  local_bounds.set_size(track_size);
+  return local_bounds;
+}
+
+//////////////////////////////////////////////////////////////////
+// CocoaScrollBar, ScrollBar:
+
+int CocoaScrollBar::GetLayoutSize() const {
+  return scroller_style_ == NSScrollerStyleOverlay ? 0 : kScrollbarWidth;
+}
+
+int CocoaScrollBar::GetContentOverlapSize() const {
+  return scroller_style_ == NSScrollerStyleLegacy ? 0 : kScrollbarWidth;
+}
+
+//////////////////////////////////////////////////////////////////
+// CocoaScrollBar::Views:
+
+void CocoaScrollBar::Layout() {
+  GetThumb()->SetBoundsRect(GetTrackBounds());
+}
+
+gfx::Size CocoaScrollBar::GetPreferredSize() const {
+  return gfx::Size();
+}
+
+void CocoaScrollBar::OnPaint(gfx::Canvas* canvas) {
+  if (!has_scrolltrack_)
+    return;
+
+  // Paint the scrollbar track background.
+  gfx::Rect track_rect = GetLocalBounds();
+
+  SkPoint gradient_bounds[2];
+  if (IsHorizontal()) {
+    gradient_bounds[0].set(track_rect.x(), track_rect.y());
+    gradient_bounds[1].set(track_rect.x(), track_rect.bottom());
+  } else {
+    gradient_bounds[0].set(track_rect.x(), track_rect.y());
+    gradient_bounds[1].set(track_rect.right(), track_rect.y());
+  }
+  skia::RefPtr<SkShader> shader = skia::AdoptRef(SkGradientShader::CreateLinear(
+      gradient_bounds, kScrollerTrackGradientColors, nullptr,
+      arraysize(kScrollerTrackGradientColors), SkShader::kClamp_TileMode));
+  SkPaint gradient;
+  gradient.setShader(shader.get());
+  canvas->DrawRect(track_rect, gradient);
+
+  // Draw the inner border: top if horizontal, left if vertical.
+  SkPaint paint;
+  paint.setColor(kScrollerTrackInnerBorderColor);
+  gfx::Rect inner_border(track_rect);
+  if (IsHorizontal())
+    inner_border.set_height(kScrollerTrackBorderWidth);
+  else
+    inner_border.set_width(kScrollerTrackBorderWidth);
+  canvas->DrawRect(inner_border, paint);
+
+  // Draw the outer border: bottom if horizontal, right if veritcal.
+  paint.setColor(kScrollerTrackOuterBorderColor);
+  gfx::Rect outer_border(inner_border);
+  if (IsHorizontal())
+    outer_border.set_y(track_rect.bottom());
+  else
+    outer_border.set_x(track_rect.right());
+  canvas->DrawRect(outer_border, paint);
+}
+
+void CocoaScrollBar::OnMouseEnteredScrollbarThumb(const ui::MouseEvent& event) {
+  if (scroller_style_ != NSScrollerStyleOverlay)
+    return;
+
+  // If the scrollbar thumb has not compeletely faded away, then reshow it when
+  // the mouse enters the scrollbar thumb.
+  if (layer()->opacity())
+    ShowScrollbar();
+
+  hide_scrollbar_timer_.Reset();
+}
+
+//////////////////////////////////////////////////////////////////
+// CocoaScrollBar::ScrollDelegate:
+
+bool CocoaScrollBar::OnScroll(float dx, float dy) {
+  bool did_scroll = BaseScrollBar::OnScroll(dx, dy);
+  if (did_scroll && scroller_style_ == NSScrollerStyleOverlay) {
+    ShowScrollbar();
+    hide_scrollbar_timer_.Reset();
+  }
+  return did_scroll;
+}
+
+//////////////////////////////////////////////////////////////////
+// CocoaScrollBar::ViewsScrollbarBridge:
+
+void CocoaScrollBar::OnScrollerStyleChanged() {
+  NSScrollerStyle scroller_style =
+      [ViewsScrollbarBridge getPreferredScrollerStyle];
+  if (scroller_style_ == scroller_style)
+    return;
+
+  scroller_style_ = scroller_style;
+
+  // Ensure that the ScrollView updates the scrollbar's layout.
+  if (parent())
+    parent()->Layout();
+
+  if (scroller_style_ == NSScrollerStyleOverlay) {
+    // Hide the scrollbar, but don't fade out.
+    layer()->SetOpacity(0.0);
+  } else {
+    ShowScrollbar();
+  }
+}
+
+//////////////////////////////////////////////////////////////////
+// CocoaScrollBar, private:
+
+void CocoaScrollBar::HideScrollbar() {
+  DCHECK_EQ(scroller_style_, NSScrollerStyleOverlay);
+
+  // If the thumb is in a hover or pressed state, we don't want the scrollbar
+  // to disappear. As such, we should reset the timer.
+  CocoaScrollBarThumb* thumb = static_cast<CocoaScrollBarThumb*>(GetThumb());
+  if (thumb->IsStateHoverOrPressed()) {
+    hide_scrollbar_timer_.Reset();
+    return;
+  }
+
+  ui::ScopedLayerAnimationSettings animation(layer()->GetAnimator());
+  animation.SetTransitionDuration(
+      base::TimeDelta::FromMilliseconds(kFadeDurationMs));
+  layer()->SetOpacity(0.0);
+}
+
+void CocoaScrollBar::ShowScrollbar() {
+  // Updates the scrolltrack and repaint it, if necessary.
+  CocoaScrollBarThumb* thumb = static_cast<CocoaScrollBarThumb*>(GetThumb());
+  bool has_scrolltrack = scroller_style_ == NSScrollerStyleLegacy ||
+                         thumb->IsStateHoverOrPressed();
+  if (has_scrolltrack_ != has_scrolltrack) {
+    has_scrolltrack_ = has_scrolltrack;
+    SchedulePaint();
+  }
+
+  layer()->SetOpacity(1.0);
+  hide_scrollbar_timer_.Stop();
+}
+
+}  // namespace views
diff --git a/ui/views/controls/tabbed_pane/tabbed_pane.cc b/ui/views/controls/tabbed_pane/tabbed_pane.cc
index eb15ac9..5579bb0 100644
--- a/ui/views/controls/tabbed_pane/tabbed_pane.cc
+++ b/ui/views/controls/tabbed_pane/tabbed_pane.cc
@@ -9,6 +9,7 @@
 #include "third_party/skia/include/core/SkPaint.h"
 #include "third_party/skia/include/core/SkPath.h"
 #include "ui/accessibility/ax_view_state.h"
+#include "ui/base/default_style.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/events/keycodes/keyboard_codes.h"
 #include "ui/gfx/canvas.h"
@@ -27,6 +28,10 @@
 const SkColor kTabBorderColor = SkColorSetRGB(0xC8, 0xC8, 0xC8);
 const SkScalar kTabBorderThickness = 1.0f;
 
+const gfx::Font::FontStyle kHoverStyle = gfx::Font::NORMAL;
+const gfx::Font::FontStyle kActiveStyle = gfx::Font::BOLD;
+const gfx::Font::FontStyle kInactiveStyle = gfx::Font::NORMAL;
+
 }  // namespace
 
 namespace views {
@@ -102,9 +107,11 @@
 
 Tab::Tab(TabbedPane* tabbed_pane, const base::string16& title, View* contents)
     : tabbed_pane_(tabbed_pane),
-      title_(new Label(title,
-                       ui::ResourceBundle::GetSharedInstance().GetFontList(
-                           ui::ResourceBundle::BoldFont))),
+      title_(new Label(
+          title,
+          ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta(
+              ui::kLabelFontSizeDelta,
+              kActiveStyle))),
       tab_state_(TAB_ACTIVE),
       contents_(contents) {
   // Calculate this now while the font list is guaranteed to be bold.
@@ -182,15 +189,18 @@
   switch (tab_state) {
     case TAB_INACTIVE:
       title_->SetEnabledColor(kTabTitleColor_Inactive);
-      title_->SetFontList(rb.GetFontList(ui::ResourceBundle::BaseFont));
+      title_->SetFontList(
+          rb.GetFontListWithDelta(ui::kLabelFontSizeDelta, kInactiveStyle));
       break;
     case TAB_ACTIVE:
       title_->SetEnabledColor(kTabTitleColor_Active);
-      title_->SetFontList(rb.GetFontList(ui::ResourceBundle::BoldFont));
+      title_->SetFontList(
+          rb.GetFontListWithDelta(ui::kLabelFontSizeDelta, kActiveStyle));
       break;
     case TAB_HOVERED:
       title_->SetEnabledColor(kTabTitleColor_Hovered);
-      title_->SetFontList(rb.GetFontList(ui::ResourceBundle::BaseFont));
+      title_->SetFontList(
+          rb.GetFontListWithDelta(ui::kLabelFontSizeDelta, kHoverStyle));
       break;
   }
   SchedulePaint();
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index 101f385..74d18b7 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -12,9 +12,11 @@
 #include "ui/accessibility/ax_view_state.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
 #include "ui/base/cursor/cursor.h"
+#include "ui/base/default_style.h"
 #include "ui/base/dragdrop/drag_drop_types.h"
 #include "ui/base/dragdrop/drag_utils.h"
 #include "ui/base/ime/input_method.h"
+#include "ui/base/resource/resource_bundle.h"
 #include "ui/base/touch/selection_bound.h"
 #include "ui/base/ui_base_switches_util.h"
 #include "ui/compositor/canvas_painter.h"
@@ -239,6 +241,11 @@
 }
 #endif
 
+const gfx::FontList& GetDefaultFontList() {
+  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+  return rb.GetFontListWithDelta(ui::kLabelFontSizeDelta);
+}
+
 }  // namespace
 
 // static
@@ -284,6 +291,7 @@
       weak_ptr_factory_(this) {
   set_context_menu_controller(this);
   set_drag_controller(this);
+  GetRenderText()->SetFontList(GetDefaultFontList());
   SetBorder(scoped_ptr<Border>(new FocusableBorder()));
   SetFocusable(true);
 
diff --git a/ui/views/mus/DEPS b/ui/views/mus/DEPS
index f51da41a..a6ef8809 100644
--- a/ui/views/mus/DEPS
+++ b/ui/views/mus/DEPS
@@ -26,6 +26,5 @@
 specific_include_rules = {
   "platform_test_helper_mus.cc": [
     "+mojo/shell/background",
-    "+mojo/shell/runner/host/command_line_switch.h",
   ],
 }
diff --git a/ui/views/mus/platform_test_helper_mus.cc b/ui/views/mus/platform_test_helper_mus.cc
index 9f1d481..bc99b4b 100644
--- a/ui/views/mus/platform_test_helper_mus.cc
+++ b/ui/views/mus/platform_test_helper_mus.cc
@@ -8,7 +8,6 @@
 #include "mojo/shell/background/background_shell.h"
 #include "mojo/shell/public/cpp/shell_client.h"
 #include "mojo/shell/public/cpp/shell_connection.h"
-#include "mojo/shell/runner/host/command_line_switch.h"
 #include "ui/views/mus/window_manager_connection.h"
 #include "url/gurl.h"
 
@@ -31,7 +30,7 @@
     base::CommandLine::ForCurrentProcess()->AppendSwitch("use-new-edk");
 
     background_shell_.reset(new mojo::shell::BackgroundShell);
-    background_shell_->Init(std::vector<mojo::shell::CommandLineSwitch>());
+    background_shell_->Init(nullptr);
     shell_client_.reset(new DefaultShellClient);
     shell_connection_.reset(new mojo::ShellConnection(
         shell_client_.get(),
diff --git a/ui/views/style/platform_style.cc b/ui/views/style/platform_style.cc
index 6d636b6..cef44cd 100644
--- a/ui/views/style/platform_style.cc
+++ b/ui/views/style/platform_style.cc
@@ -8,6 +8,7 @@
 #include "ui/base/material_design/material_design_controller.h"
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/button/label_button_border.h"
+#include "ui/views/controls/scrollbar/native_scroll_bar.h"
 
 namespace views {
 
@@ -25,6 +26,12 @@
       Button::STYLE_TEXTBUTTON));
   return border;
 }
+
+// static
+scoped_ptr<ScrollBar> PlatformStyle::CreateScrollBar(bool is_horizontal) {
+  return make_scoped_ptr(new NativeScrollBar(is_horizontal));
+}
+
 #endif
 
 #if !defined(OS_LINUX) || defined(OS_CHROMEOS)
diff --git a/ui/views/style/platform_style.h b/ui/views/style/platform_style.h
index e56fe0e..1f7b9a2 100644
--- a/ui/views/style/platform_style.h
+++ b/ui/views/style/platform_style.h
@@ -14,6 +14,7 @@
 class Border;
 class LabelButton;
 class LabelButtonBorder;
+class ScrollBar;
 
 // Cross-platform API for providing platform-specific styling for toolkit-views.
 class PlatformStyle {
@@ -26,6 +27,9 @@
   // Applies the current system theme to the default border created by |button|.
   static scoped_ptr<Border> CreateThemedLabelButtonBorder(LabelButton* button);
 
+  // Creates the default scrollbar for the given orientation.
+  static scoped_ptr<ScrollBar> CreateScrollBar(bool is_horizontal);
+
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformStyle);
 };
diff --git a/ui/views/style/platform_style_mac.cc b/ui/views/style/platform_style_mac.mm
similarity index 76%
rename from ui/views/style/platform_style_mac.cc
rename to ui/views/style/platform_style_mac.mm
index f1038d87..44254ea 100644
--- a/ui/views/style/platform_style_mac.cc
+++ b/ui/views/style/platform_style_mac.mm
@@ -6,6 +6,7 @@
 
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/button/label_button_border.h"
+#import "ui/views/controls/scrollbar/cocoa_scroll_bar.h"
 #include "ui/views/style/mac/dialog_button_border_mac.h"
 
 namespace views {
@@ -19,4 +20,9 @@
   return make_scoped_ptr(new LabelButtonAssetBorder(style));
 }
 
+// static
+scoped_ptr<ScrollBar> PlatformStyle::CreateScrollBar(bool is_horizontal) {
+  return make_scoped_ptr(new CocoaScrollBar(is_horizontal));
+}
+
 }  // namespace views
diff --git a/ui/views/view.h b/ui/views/view.h
index a5ef00d..86bed2a 100644
--- a/ui/views/view.h
+++ b/ui/views/view.h
@@ -31,6 +31,7 @@
 #include "ui/events/event.h"
 #include "ui/events/event_target.h"
 #include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/vector2d.h"
 #include "ui/gfx/native_widget_types.h"
diff --git a/ui/views/views.gyp b/ui/views/views.gyp
index f067521..14d92ce4 100644
--- a/ui/views/views.gyp
+++ b/ui/views/views.gyp
@@ -27,6 +27,8 @@
       'animation/ink_drop_animation_observer.h',
       'animation/ink_drop_delegate.h',
       'animation/ink_drop_host.h',
+      'animation/ink_drop_host_view.cc',
+      'animation/ink_drop_host_view.h',
       'animation/ink_drop_hover.cc',
       'animation/ink_drop_hover.h',
       'animation/ink_drop_painted_layer_delegates.cc',
@@ -63,6 +65,8 @@
       'cocoa/tooltip_manager_mac.mm',
       'cocoa/views_nswindow_delegate.h',
       'cocoa/views_nswindow_delegate.mm',
+      'cocoa/views_scrollbar_bridge.h',
+      'cocoa/views_scrollbar_bridge.mm',
       'cocoa/widget_owner_nswindow_adapter.h',
       'cocoa/widget_owner_nswindow_adapter.mm',
       'color_chooser/color_chooser_listener.h',
@@ -174,6 +178,8 @@
       'controls/scrollbar/base_scroll_bar_button.h',
       'controls/scrollbar/base_scroll_bar_thumb.cc',
       'controls/scrollbar/base_scroll_bar_thumb.h',
+      'controls/scrollbar/cocoa_scroll_bar.h',
+      'controls/scrollbar/cocoa_scroll_bar.mm',
       'controls/scrollbar/native_scroll_bar.cc',
       'controls/scrollbar/native_scroll_bar.h',
       'controls/scrollbar/native_scroll_bar_views.cc',
@@ -282,7 +288,7 @@
       'style/mac/dialog_button_border_mac.h',
       'style/platform_style.cc',
       'style/platform_style.h',
-      'style/platform_style_mac.cc',
+      'style/platform_style_mac.mm',
       'view.cc',
       'view.h',
       'view_constants.cc',
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc
index 84fa83e..77bd8802 100644
--- a/ui/views/widget/widget.cc
+++ b/ui/views/widget/widget.cc
@@ -10,6 +10,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/trace_event/trace_event.h"
 #include "ui/base/cursor/cursor.h"
+#include "ui/base/default_style.h"
 #include "ui/base/default_theme_provider.h"
 #include "ui/base/hit_test.h"
 #include "ui/base/ime/input_method.h"
@@ -274,14 +275,16 @@
 
 // static
 int Widget::GetLocalizedContentsWidth(int col_resource_id) {
-  return ui::GetLocalizedContentsWidthForFont(col_resource_id,
-      ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont));
+  return ui::GetLocalizedContentsWidthForFont(
+      col_resource_id, ResourceBundle::GetSharedInstance().GetFontWithDelta(
+                           ui::kMessageFontSizeDelta));
 }
 
 // static
 int Widget::GetLocalizedContentsHeight(int row_resource_id) {
-  return ui::GetLocalizedContentsHeightForFont(row_resource_id,
-      ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont));
+  return ui::GetLocalizedContentsHeightForFont(
+      row_resource_id, ResourceBundle::GetSharedInstance().GetFontWithDelta(
+                           ui::kMessageFontSizeDelta));
 }
 
 // static
diff --git a/ui/views/widget/widget_interactive_uitest.cc b/ui/views/widget/widget_interactive_uitest.cc
index 61431a6a..50a5763 100644
--- a/ui/views/widget/widget_interactive_uitest.cc
+++ b/ui/views/widget/widget_interactive_uitest.cc
@@ -654,6 +654,7 @@
   }
 
   widget->Show();
+  widget->GetNativeWindow()->GetHost()->Show();
   const HWND hwnd = HWNDForWidget(widget);
   EXPECT_TRUE(::IsWindow(hwnd));
   EXPECT_TRUE(::IsWindowEnabled(hwnd));
@@ -740,6 +741,69 @@
   EXPECT_EQ(true, widget1.active());
   EXPECT_EQ(false, widget2.active());
 }
+
+// On Windows if we create a fullscreen window on a thread, then it affects the
+// way other windows on the thread interact with the taskbar. To workaround
+// this we reduce the bounds of a fullscreen window by 1px when it loses
+// activation. This test verifies the same.
+TEST_F(WidgetTestInteractive, FullscreenBoundsReducedOnActivationLoss) {
+  Widget widget1;
+  Widget::InitParams params =
+      CreateParams(Widget::InitParams::TYPE_WINDOW);
+  params.native_widget = new DesktopNativeWidgetAura(&widget1);
+  params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  widget1.Init(params);
+  widget1.SetBounds(gfx::Rect(0, 0, 200, 200));
+  widget1.Show();
+
+  widget1.Activate();
+  RunPendingMessages();
+  EXPECT_EQ(::GetActiveWindow(),
+            widget1.GetNativeWindow()->GetHost()->GetAcceleratedWidget());
+
+  widget1.SetFullscreen(true);
+  EXPECT_TRUE(widget1.IsFullscreen());
+  // Ensure that the StopIgnoringPosChanges task in HWNDMessageHandler runs.
+  // This task is queued when a widget becomes fullscreen.
+  RunPendingMessages();
+  EXPECT_EQ(::GetActiveWindow(),
+            widget1.GetNativeWindow()->GetHost()->GetAcceleratedWidget());
+  gfx::Rect fullscreen_bounds = widget1.GetWindowBoundsInScreen();
+
+  Widget widget2;
+  params.native_widget = new DesktopNativeWidgetAura(&widget2);
+  params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  widget2.Init(params);
+  widget2.SetBounds(gfx::Rect(0, 0, 200, 200));
+  widget2.Show();
+
+  widget2.Activate();
+  RunPendingMessages();
+  EXPECT_EQ(::GetActiveWindow(),
+            widget2.GetNativeWindow()->GetHost()->GetAcceleratedWidget());
+
+  gfx::Rect fullscreen_bounds_after_activation_loss =
+      widget1.GetWindowBoundsInScreen();
+
+  // After deactivation loss the bounds of the fullscreen widget should be
+  // reduced by 1px.
+  EXPECT_EQ(fullscreen_bounds.height() -
+            fullscreen_bounds_after_activation_loss.height(), 1);
+
+  widget1.Activate();
+  RunPendingMessages();
+  EXPECT_EQ(::GetActiveWindow(),
+            widget1.GetNativeWindow()->GetHost()->GetAcceleratedWidget());
+
+  gfx::Rect fullscreen_bounds_after_activate =
+      widget1.GetWindowBoundsInScreen();
+
+  // After activation the bounds of the fullscreen widget should be restored.
+  EXPECT_EQ(fullscreen_bounds, fullscreen_bounds_after_activate);
+
+  widget1.CloseNow();
+  widget2.CloseNow();
+}
 #endif  // defined(OS_WIN)
 
 #if !defined(OS_CHROMEOS)
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
index f632827..1b693f8 100644
--- a/ui/views/win/hwnd_message_handler.cc
+++ b/ui/views/win/hwnd_message_handler.cc
@@ -333,6 +333,7 @@
       dwm_transition_desired_(false),
       sent_window_size_changing_(false),
       left_button_down_on_caption_(false),
+      background_fullscreen_hack_(false),
       autohide_factory_(this),
       weak_factory_(this) {}
 
@@ -525,25 +526,8 @@
 
 void HWNDMessageHandler::SetBounds(const gfx::Rect& bounds_in_pixels,
                                    bool force_size_changed) {
-  LONG style = GetWindowLong(hwnd(), GWL_STYLE);
-  if (style & WS_MAXIMIZE)
-    SetWindowLong(hwnd(), GWL_STYLE, style & ~WS_MAXIMIZE);
-
-  gfx::Size old_size = GetClientAreaBounds().size();
-  SetWindowPos(hwnd(), NULL, bounds_in_pixels.x(), bounds_in_pixels.y(),
-               bounds_in_pixels.width(), bounds_in_pixels.height(),
-               SWP_NOACTIVATE | SWP_NOZORDER);
-
-  // If HWND size is not changed, we will not receive standard size change
-  // notifications. If |force_size_changed| is |true|, we should pretend size is
-  // changed.
-  if (old_size == bounds_in_pixels.size() && force_size_changed) {
-    delegate_->HandleClientSizeChanged(GetClientAreaBounds().size());
-    ResetWindowRegion(false, true);
-  }
-
-  if (direct_manipulation_helper_)
-    direct_manipulation_helper_->SetBounds(bounds_in_pixels);
+  background_fullscreen_hack_ = false;
+  SetBoundsInternal(bounds_in_pixels, force_size_changed);
 }
 
 void HWNDMessageHandler::SetSize(const gfx::Size& size) {
@@ -844,6 +828,7 @@
 }
 
 void HWNDMessageHandler::SetFullscreen(bool fullscreen) {
+  background_fullscreen_hack_ = false;
   fullscreen_handler()->SetFullscreen(fullscreen);
   // If we are out of fullscreen and there was a pending DWM transition for the
   // window, then go ahead and do it now.
@@ -929,7 +914,8 @@
   }
 
   if (message == WM_ACTIVATE && IsTopLevelWindow(window))
-    PostProcessActivateMessage(LOWORD(w_param), !!HIWORD(w_param));
+    PostProcessActivateMessage(LOWORD(w_param), !!HIWORD(w_param),
+                               reinterpret_cast<HWND>(l_param));
   return result;
 }
 
@@ -1027,12 +1013,51 @@
   }
 }
 
-void HWNDMessageHandler::PostProcessActivateMessage(int activation_state,
-                                                    bool minimized) {
+void HWNDMessageHandler::PostProcessActivateMessage(
+    int activation_state,
+    bool minimized,
+    HWND window_gaining_or_losing_activation) {
   DCHECK(IsTopLevelWindow(hwnd()));
   const bool active = activation_state != WA_INACTIVE && !minimized;
   if (delegate_->CanActivate())
     delegate_->HandleActivationChanged(active);
+
+  if (!::IsWindow(window_gaining_or_losing_activation))
+    window_gaining_or_losing_activation = ::GetForegroundWindow();
+
+  // If the window losing activation is a fullscreen window, we reduce the size
+  // of the window by 1px. i.e. Not fullscreen. This is to work around an
+  // apparent bug in the Windows taskbar where in it tracks fullscreen state on
+  // a per thread basis. This causes it not be a topmost window when any
+  // maximized window on a thread which has a fullscreen window is active. This
+  // affects the way these windows interact with the taskbar, they obscure it
+  // when maximized, autohide does not work correctly, etc.
+  // By reducing the size of the fullscreen window by 1px, we ensure that the
+  // taskbar no longer treats the window and in turn the thread as a fullscreen
+  // thread. This in turn ensures that maximized windows on the same thread
+  /// don't obscure the taskbar, etc.
+  if (!active) {
+    if (fullscreen_handler_->fullscreen() &&
+        ::IsWindow(window_gaining_or_losing_activation)) {
+      // Reduce the bounds of the window by 1px to ensure that Windows does
+      // not treat this like a fullscreen window.
+      MONITORINFO monitor_info = {sizeof(monitor_info)};
+      GetMonitorInfo(MonitorFromWindow(hwnd(), MONITOR_DEFAULTTOPRIMARY),
+                      &monitor_info);
+      gfx::Rect shrunk_rect(monitor_info.rcMonitor);
+      shrunk_rect.set_height(shrunk_rect.height() - 1);
+      background_fullscreen_hack_ = true;
+      SetBoundsInternal(shrunk_rect, false);
+    }
+  } else if (background_fullscreen_hack_) {
+    // Restore the bounds of the window to fullscreen.
+    DCHECK(fullscreen_handler_->fullscreen());
+    background_fullscreen_hack_ = false;
+    MONITORINFO monitor_info = {sizeof(monitor_info)};
+    GetMonitorInfo(MonitorFromWindow(hwnd(), MONITOR_DEFAULTTOPRIMARY),
+                   &monitor_info);
+    SetBoundsInternal(gfx::Rect(monitor_info.rcMonitor), false);
+  }
 }
 
 void HWNDMessageHandler::RestoreEnabledIfNecessary() {
@@ -1078,6 +1103,9 @@
 }
 
 void HWNDMessageHandler::ClientAreaSizeChanged() {
+  // Ignore size changes due to fullscreen windows losing activation.
+  if (background_fullscreen_hack_)
+    return;
   gfx::Size s = GetClientAreaBounds().size();
   delegate_->HandleClientSizeChanged(s);
 }
@@ -2165,9 +2193,17 @@
         GetMonitorAndRects(window_rect, &monitor, &monitor_rect, &work_area)) {
       bool work_area_changed = (monitor_rect == last_monitor_rect_) &&
                                (work_area != last_work_area_);
+      // If the size of a background fullscreen window changes again, then we
+      // should reset the |background_fullscreen_hack_| flag.
+      if (background_fullscreen_hack_ &&
+          (!(window_pos->flags & SWP_NOSIZE) &&
+            (monitor_rect.height() - window_pos->cy != 1))) {
+          background_fullscreen_hack_ = false;
+      }
       if (monitor && (monitor == last_monitor_) &&
           ((fullscreen_handler_->fullscreen() &&
-            !fullscreen_handler_->metro_snap()) ||
+            !fullscreen_handler_->metro_snap() &&
+            !background_fullscreen_hack_) ||
             work_area_changed)) {
         // A rect for the monitor we're on changed.  Normally Windows notifies
         // us about this (and thus we're reaching here due to the SetWindowPos()
@@ -2575,5 +2611,29 @@
   return handled;
 }
 
+void HWNDMessageHandler::SetBoundsInternal(const gfx::Rect& bounds_in_pixels,
+                                           bool force_size_changed) {
+  LONG style = GetWindowLong(hwnd(), GWL_STYLE);
+  if (style & WS_MAXIMIZE)
+    SetWindowLong(hwnd(), GWL_STYLE, style & ~WS_MAXIMIZE);
+
+  gfx::Size old_size = GetClientAreaBounds().size();
+  SetWindowPos(hwnd(), NULL, bounds_in_pixels.x(), bounds_in_pixels.y(),
+               bounds_in_pixels.width(), bounds_in_pixels.height(),
+               SWP_NOACTIVATE | SWP_NOZORDER);
+
+  // If HWND size is not changed, we will not receive standard size change
+  // notifications. If |force_size_changed| is |true|, we should pretend size is
+  // changed.
+  if (old_size == bounds_in_pixels.size() && force_size_changed &&
+      !background_fullscreen_hack_) {
+    delegate_->HandleClientSizeChanged(GetClientAreaBounds().size());
+    ResetWindowRegion(false, true);
+  }
+
+  if (direct_manipulation_helper_)
+    direct_manipulation_helper_->SetBounds(bounds_in_pixels);
+}
+
 
 }  // namespace views
diff --git a/ui/views/win/hwnd_message_handler.h b/ui/views/win/hwnd_message_handler.h
index 4b7ab41..3f7b752 100644
--- a/ui/views/win/hwnd_message_handler.h
+++ b/ui/views/win/hwnd_message_handler.h
@@ -255,7 +255,10 @@
 
   // Called after the WM_ACTIVATE message has been processed by the default
   // windows procedure.
-  void PostProcessActivateMessage(int activation_state, bool minimized);
+  void PostProcessActivateMessage(
+      int activation_state,
+      bool minimized,
+      HWND window_gaining_or_losing_activation);
 
   // Enables disabled owner windows that may have been disabled due to this
   // window's modality.
@@ -502,6 +505,11 @@
                                   WPARAM w_param,
                                   LPARAM l_param);
 
+  // Helper function for setting the bounds of the HWND. For more information
+  // please refer to the SetBounds() function.
+  void SetBoundsInternal(const gfx::Rect& bounds_in_pixels,
+                         bool force_size_changed);
+
   HWNDMessageHandlerDelegate* delegate_;
 
   scoped_ptr<FullscreenHandler> fullscreen_handler_;
@@ -632,6 +640,10 @@
   // Defaults to false.
   bool left_button_down_on_caption_;
 
+  // Set to true if the window is a background fullscreen window, i.e a
+  // fullscreen window which lost activation. Defaults to false.
+  bool background_fullscreen_hack_;
+
   // The WeakPtrFactories below must occur last in the class definition so they
   // get destroyed last.
 
diff --git a/ui/views/window/dialog_client_view.cc b/ui/views/window/dialog_client_view.cc
index f6567a2..5f069ef 100644
--- a/ui/views/window/dialog_client_view.cc
+++ b/ui/views/window/dialog_client_view.cc
@@ -58,25 +58,24 @@
       cancel_button_(NULL),
       extra_view_(NULL),
       footnote_view_(NULL),
-      notified_delegate_(false) {
-}
+      delegate_allowed_close_(false) {}
 
 DialogClientView::~DialogClientView() {
 }
 
 void DialogClientView::AcceptWindow() {
-  // Only notify the delegate once. See |notified_delegate_|'s comment.
-  if (!notified_delegate_ && GetDialogDelegate()->Accept(false)) {
-    notified_delegate_ = true;
-    Close();
+  // Only notify the delegate once. See |delegate_allowed_close_|'s comment.
+  if (!delegate_allowed_close_ && GetDialogDelegate()->Accept(false)) {
+    delegate_allowed_close_ = true;
+    GetWidget()->Close();
   }
 }
 
 void DialogClientView::CancelWindow() {
-  // Only notify the delegate once. See |notified_delegate_|'s comment.
-  if (!notified_delegate_ && GetDialogDelegate()->Cancel()) {
-    notified_delegate_ = true;
-    Close();
+  // Only notify the delegate once. See |delegate_allowed_close_|'s comment.
+  if (!delegate_allowed_close_ && GetDialogDelegate()->Cancel()) {
+    delegate_allowed_close_ = true;
+    GetWidget()->Close();
   }
 }
 
@@ -122,17 +121,11 @@
 // DialogClientView, ClientView overrides:
 
 bool DialogClientView::CanClose() {
-  if (notified_delegate_)
-    return true;
-
-  // The dialog is closing but no Accept or Cancel action has been performed
-  // before: it's a Close action.
-  if (GetDialogDelegate()->Close()) {
-    notified_delegate_ = true;
-    GetDialogDelegate()->OnClosed();
-    return true;
-  }
-  return false;
+  // If the dialog is closing but no Accept or Cancel action has been performed
+  // before, it's a Close action.
+  if (!delegate_allowed_close_)
+    delegate_allowed_close_ = GetDialogDelegate()->Close();
+  return delegate_allowed_close_;
 }
 
 DialogClientView* DialogClientView::AsDialogClientView() {
@@ -239,7 +232,7 @@
 
 bool DialogClientView::AcceleratorPressed(const ui::Accelerator& accelerator) {
   DCHECK_EQ(accelerator.key_code(), ui::VKEY_ESCAPE);
-  Close();
+  GetWidget()->Close();
   return true;
 }
 
@@ -300,7 +293,7 @@
       cancel_button_(NULL),
       extra_view_(NULL),
       footnote_view_(NULL),
-      notified_delegate_(false) {}
+      delegate_allowed_close_(false) {}
 
 DialogDelegate* DialogClientView::GetDialogDelegate() const {
   return GetWidget()->widget_delegate()->AsDialogDelegate();
@@ -381,10 +374,7 @@
                   kButtonVEdgeMarginNew, kButtonHEdgeMarginNew);
 }
 
-void DialogClientView::Close() {
-  GetWidget()->Close();
-  GetDialogDelegate()->OnClosed();
-}
+
 
 void DialogClientView::SetupFocusChain() {
   // Create a vector of child views in the order of intended focus.
diff --git a/ui/views/window/dialog_client_view.h b/ui/views/window/dialog_client_view.h
index 32f6a617..8f4e0fc 100644
--- a/ui/views/window/dialog_client_view.h
+++ b/ui/views/window/dialog_client_view.h
@@ -93,9 +93,6 @@
   // Returns the insets for the buttons and extra view.
   gfx::Insets GetButtonRowInsets() const;
 
-  // Closes the widget.
-  void Close();
-
   // Sets up the focus chain for the child views. This is required since the
   // delegate may choose to add/remove views at any time.
   void SetupFocusChain();
@@ -111,10 +108,10 @@
   View* footnote_view_;
 
   // True if we've notified the delegate the window is closing and the delegate
-  // allosed the close. In some situations it's possible to get two closes (see
+  // allowed the close. In some situations it's possible to get two closes (see
   // http://crbug.com/71940). This is used to avoid notifying the delegate
   // twice, which can have bad consequences.
-  bool notified_delegate_;
+  bool delegate_allowed_close_;
 
   DISALLOW_COPY_AND_ASSIGN(DialogClientView);
 };
diff --git a/ui/views/window/dialog_delegate.h b/ui/views/window/dialog_delegate.h
index dc9f89a..68b1f20 100644
--- a/ui/views/window/dialog_delegate.h
+++ b/ui/views/window/dialog_delegate.h
@@ -109,9 +109,6 @@
   // Returns whether this particular dialog should use the new dialog style.
   virtual bool UseNewStyleForThisDialog() const;
 
-  // Called when the window has been closed.
-  virtual void OnClosed() {}
-
   // A helper for accessing the DialogClientView object contained by this
   // delegate's Window.
   const DialogClientView* GetDialogClientView() const;