diff --git a/BUILD.gn b/BUILD.gn
index 8dee958a..d27481923 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -157,6 +157,7 @@
 
   if (!is_ios) {
     deps += [
+      "//media:media_unittests",
       "//mojo",
       "//mojo/common:mojo_common_unittests",
       "//mojo/edk/system:mojo_system_unittests",
@@ -185,7 +186,6 @@
       "//gpu:gpu_unittests",
       "//gpu/ipc/service:gpu_ipc_service_unittests",
       "//ipc:ipc_tests",
-      "//media:media_unittests",
       "//media/capture:capture_unittests",
       "//media/cast:cast_unittests",
       "//media/midi:midi_unittests",
diff --git a/DEPS b/DEPS
index 2cf6c5a..2f391397 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,11 @@
   # 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': '0aa492d0f47d7becbd87c582a61591bdf2d17fa7',
+  'skia_revision': '968af43f721cd949ba3005f8e5f3c03c6c978a74',
   # 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': 'b906454a392b00c0e0550e71542466d697a0e7fc',
+  'v8_revision': '1bf2e10ddb194d4c2871a87a4732613419de892d',
   # 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.
@@ -64,7 +64,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': 'fe1c8e61668079b873922acb1e56d0ea55a3c375',
+  'pdfium_revision': '7d0af80637afbc673e4bc9a34bcb556afdf3434d',
   # 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.
@@ -72,7 +72,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': '14308731e5446a73ac2258688a9688b524483cb6',
+  'boringssl_revision': '0e4a448ab8aa66a38593f68d19fa0a2e340833e4',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling google-toolbox-for-mac
   # and whatever else without interference from each other.
@@ -96,7 +96,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '26f2e66be57ee956fec3f6535edd60fec853e58e',
+  'catapult_revision': 'a4770ef4862143806989e8bd52585053ec20dabf',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -157,7 +157,7 @@
     Var('chromium_git') + '/external/github.com/google/googletest.git' + '@' + '42bc671f47b122fad36db5eccbc06868afdf7862',
 
   'src/third_party/icu':
-    Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'b971435d43d012e9c49ef5e99c0c3047640d53be',
+    Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '1fec0c83e9ad7f5a075ae0b50af9a3889f54be0e',
 
   'src/third_party/hunspell_dictionaries':
     Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + 'dc6e7c25bf47cbfb466e0701fd2728b4a12e79d5',
diff --git a/WATCHLISTS b/WATCHLISTS
index 4be220ea..0fc7ff9 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -894,7 +894,7 @@
                   '|chrome/android/javatests/src/org/chromium/chrome/browser/payments'\
                   '|chrome/browser/payments'\
                   '|chrome/browser/ui/views/payments'\
-                  '|chrome/test/data/payments'\
+                  '|components/payments/test/data'\
                   '|components/payments'\
                   '|content/browser/payments'\
                   '|content/test/data/payments'\
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index 8ebf6ab..41ebffb 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -522,6 +522,8 @@
     "browser/aw_safe_browsing_resource_throttle.h",
     "browser/aw_safe_browsing_ui_manager.cc",
     "browser/aw_safe_browsing_ui_manager.h",
+    "browser/aw_safe_browsing_whitelist_manager.cc",
+    "browser/aw_safe_browsing_whitelist_manager.h",
     "browser/aw_settings.cc",
     "browser/aw_settings.h",
     "browser/aw_ssl_host_state_delegate.cc",
@@ -711,6 +713,7 @@
     "//components/spellcheck:build_features",
     "//components/supervised_user_error_page",
     "//components/supervised_user_error_page:gin",
+    "//components/url_matcher",
     "//components/version_info",
     "//components/visitedlink/browser",
     "//components/visitedlink/renderer",
diff --git a/android_webview/browser/aw_browser_context.cc b/android_webview/browser/aw_browser_context.cc
index ea499630..dc4ee73b 100644
--- a/android_webview/browser/aw_browser_context.cc
+++ b/android_webview/browser/aw_browser_context.cc
@@ -12,6 +12,7 @@
 #include "android_webview/browser/aw_permission_manager.h"
 #include "android_webview/browser/aw_quota_manager_bridge.h"
 #include "android_webview/browser/aw_resource_context.h"
+#include "android_webview/browser/aw_safe_browsing_whitelist_manager.h"
 #include "android_webview/browser/net/aw_url_request_context_getter.h"
 #include "android_webview/common/aw_content_client.h"
 #include "base/base_paths_android.h"
@@ -107,6 +108,18 @@
                                          base::Bind(OverrideBlacklistForURL));
 }
 
+std::unique_ptr<AwSafeBrowsingWhitelistManager>
+CreateSafeBrowsingWhitelistManager() {
+  // Should not be called until the end of PreMainMessageLoopRun,
+  scoped_refptr<base::SequencedTaskRunner> background_task_runner =
+      base::CreateSequencedTaskRunnerWithTraits(
+          {base::MayBlock(), base::TaskPriority::BACKGROUND});
+  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner =
+      BrowserThread::GetTaskRunnerForThread(BrowserThread::IO);
+  return base::MakeUnique<AwSafeBrowsingWhitelistManager>(
+      background_task_runner, io_task_runner);
+}
+
 }  // namespace
 
 // Delete the legacy cache dir (in the app data dir) in 10 seconds after init.
@@ -208,6 +221,7 @@
   safe_browsing_trigger_manager_ =
       base::MakeUnique<safe_browsing::TriggerManager>(
           safe_browsing_ui_manager_.get());
+  safe_browsing_whitelist_manager_ = CreateSafeBrowsingWhitelistManager();
 }
 
 void AwBrowserContext::OnWebRestrictionsAuthorityChanged() {
@@ -377,7 +391,7 @@
   return web_restriction_provider_.get();
 }
 
-AwSafeBrowsingUIManager* AwBrowserContext::GetSafeBrowsingUIManager() {
+AwSafeBrowsingUIManager* AwBrowserContext::GetSafeBrowsingUIManager() const {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   return safe_browsing_ui_manager_.get();
 }
@@ -401,6 +415,12 @@
   return safe_browsing_trigger_manager_.get();
 }
 
+AwSafeBrowsingWhitelistManager*
+AwBrowserContext::GetSafeBrowsingWhitelistManager() const {
+  // Should not be called until the end of PreMainMessageLoopRun,
+  return safe_browsing_whitelist_manager_.get();
+}
+
 void AwBrowserContext::RebuildTable(
     const scoped_refptr<URLEnumerator>& enumerator) {
   // Android WebView rebuilds from WebChromeClient.getVisitedHistory. The client
diff --git a/android_webview/browser/aw_browser_context.h b/android_webview/browser/aw_browser_context.h
index b2c89e47..c44733ab 100644
--- a/android_webview/browser/aw_browser_context.h
+++ b/android_webview/browser/aw_browser_context.h
@@ -50,6 +50,7 @@
 
 class AwFormDatabaseService;
 class AwQuotaManagerBridge;
+class AwSafeBrowsingWhitelistManager;
 class AwURLRequestContextGetter;
 
 namespace prefs {
@@ -119,9 +120,10 @@
   // visitedlink::VisitedLinkDelegate implementation.
   void RebuildTable(const scoped_refptr<URLEnumerator>& enumerator) override;
 
-  AwSafeBrowsingUIManager* GetSafeBrowsingUIManager();
+  AwSafeBrowsingUIManager* GetSafeBrowsingUIManager() const;
   safe_browsing::RemoteSafeBrowsingDatabaseManager* GetSafeBrowsingDBManager();
   safe_browsing::TriggerManager* GetSafeBrowsingTriggerManager() const;
+  AwSafeBrowsingWhitelistManager* GetSafeBrowsingWhitelistManager() const;
 
  private:
   void InitUserPrefService();
@@ -160,6 +162,9 @@
       safe_browsing_db_manager_;
   bool safe_browsing_db_manager_started_ = false;
 
+  std::unique_ptr<AwSafeBrowsingWhitelistManager>
+      safe_browsing_whitelist_manager_;
+
   DISALLOW_COPY_AND_ASSIGN(AwBrowserContext);
 };
 
diff --git a/android_webview/browser/aw_contents_statics.cc b/android_webview/browser/aw_contents_statics.cc
index 72090592..91482bbd 100644
--- a/android_webview/browser/aw_contents_statics.cc
+++ b/android_webview/browser/aw_contents_statics.cc
@@ -8,8 +8,10 @@
 #include "android_webview/browser/aw_browser_context.h"
 #include "android_webview/browser/aw_contents_io_thread_client.h"
 #include "android_webview/browser/aw_safe_browsing_config_helper.h"
+#include "android_webview/browser/aw_safe_browsing_whitelist_manager.h"
 #include "android_webview/browser/net/aw_url_request_context_getter.h"
 #include "android_webview/common/aw_version_info_values.h"
+#include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
 #include "base/android/scoped_java_ref.h"
 #include "base/callback.h"
@@ -78,15 +80,27 @@
 }
 
 // static
-jboolean GetSafeBrowsingEnabled(JNIEnv* env, const JavaParamRef<jclass>&) {
-  return AwSafeBrowsingConfigHelper::GetSafeBrowsingEnabled();
+jboolean GetSafeBrowsingEnabledByManifest(JNIEnv* env,
+                                          const JavaParamRef<jclass>&) {
+  return AwSafeBrowsingConfigHelper::GetSafeBrowsingEnabledByManifest();
 }
 
 // static
-void SetSafeBrowsingEnabled(JNIEnv* env,
-                            const JavaParamRef<jclass>&,
-                            jboolean enable) {
-  AwSafeBrowsingConfigHelper::SetSafeBrowsingEnabled(enable);
+void SetSafeBrowsingEnabledByManifest(JNIEnv* env,
+                                      const JavaParamRef<jclass>&,
+                                      jboolean enable) {
+  AwSafeBrowsingConfigHelper::SetSafeBrowsingEnabledByManifest(enable);
+}
+
+// static
+void SetSafeBrowsingWhiteList(JNIEnv* env,
+                              const JavaParamRef<jclass>&,
+                              const JavaParamRef<jobjectArray>& jrules) {
+  std::vector<std::string> rules;
+  base::android::AppendJavaStringArrayToStringVector(env, jrules, &rules);
+  AwSafeBrowsingWhitelistManager* whitelist_manager =
+      AwBrowserContext::GetDefault()->GetSafeBrowsingWhitelistManager();
+  whitelist_manager->SetWhitelistOnUIThread(std::move(rules));
 }
 
 // static
diff --git a/android_webview/browser/aw_safe_browsing_config_helper.cc b/android_webview/browser/aw_safe_browsing_config_helper.cc
index 58f6f2df..8908f7b 100644
--- a/android_webview/browser/aw_safe_browsing_config_helper.cc
+++ b/android_webview/browser/aw_safe_browsing_config_helper.cc
@@ -9,24 +9,26 @@
 #include "base/synchronization/lock.h"
 
 namespace {
-// g_safebrowsing_enabled can be set and read from different threads.
-base::LazyInstance<base::Lock>::Leaky g_safebrowsing_enabled_lock =
+// g_safebrowsing_enabled_by_manifest can be set and read from different
+// threads.
+base::LazyInstance<base::Lock>::Leaky g_safebrowsing_enabled_by_manifest_lock =
     LAZY_INSTANCE_INITIALIZER;
-bool g_safebrowsing_enabled = false;
+bool g_safebrowsing_enabled_by_manifest = false;
 }  // namespace
 
 namespace android_webview {
 
 // static
-void AwSafeBrowsingConfigHelper::SetSafeBrowsingEnabled(bool enabled) {
-  base::AutoLock lock(g_safebrowsing_enabled_lock.Get());
-  g_safebrowsing_enabled = enabled;
+void AwSafeBrowsingConfigHelper::SetSafeBrowsingEnabledByManifest(
+    bool enabled) {
+  base::AutoLock lock(g_safebrowsing_enabled_by_manifest_lock.Get());
+  g_safebrowsing_enabled_by_manifest = enabled;
 }
 
 // static
-bool AwSafeBrowsingConfigHelper::GetSafeBrowsingEnabled() {
-  base::AutoLock lock(g_safebrowsing_enabled_lock.Get());
-  return g_safebrowsing_enabled;
+bool AwSafeBrowsingConfigHelper::GetSafeBrowsingEnabledByManifest() {
+  base::AutoLock lock(g_safebrowsing_enabled_by_manifest_lock.Get());
+  return g_safebrowsing_enabled_by_manifest;
 }
 
 }  // namespace android_webview
diff --git a/android_webview/browser/aw_safe_browsing_config_helper.h b/android_webview/browser/aw_safe_browsing_config_helper.h
index 5b96b37..a448c0e 100644
--- a/android_webview/browser/aw_safe_browsing_config_helper.h
+++ b/android_webview/browser/aw_safe_browsing_config_helper.h
@@ -11,8 +11,8 @@
 
 class AwSafeBrowsingConfigHelper {
  public:
-  static bool GetSafeBrowsingEnabled();
-  static void SetSafeBrowsingEnabled(bool enabled);
+  static bool GetSafeBrowsingEnabledByManifest();
+  static void SetSafeBrowsingEnabledByManifest(bool enabled);
 
  private:
   AwSafeBrowsingConfigHelper();
diff --git a/android_webview/browser/aw_safe_browsing_resource_throttle.cc b/android_webview/browser/aw_safe_browsing_resource_throttle.cc
index 1f54c40..df901c4 100644
--- a/android_webview/browser/aw_safe_browsing_resource_throttle.cc
+++ b/android_webview/browser/aw_safe_browsing_resource_throttle.cc
@@ -6,6 +6,7 @@
 
 #include "android_webview/browser/aw_contents_client_bridge.h"
 #include "android_webview/browser/aw_safe_browsing_ui_manager.h"
+#include "android_webview/browser/aw_safe_browsing_whitelist_manager.h"
 #include "base/macros.h"
 #include "components/safe_browsing/base_resource_throttle.h"
 #include "components/safe_browsing_db/database_manager.h"
@@ -28,10 +29,12 @@
     net::URLRequest* request,
     content::ResourceType resource_type,
     scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> database_manager,
-    scoped_refptr<AwSafeBrowsingUIManager> ui_manager) {
+    scoped_refptr<AwSafeBrowsingUIManager> ui_manager,
+    AwSafeBrowsingWhitelistManager* whitelist_manager) {
   if (database_manager->IsSupported()) {
     return new AwSafeBrowsingResourceThrottle(request, resource_type,
-                                              database_manager, ui_manager);
+                                              database_manager, ui_manager,
+                                              whitelist_manager);
   }
   return nullptr;
 }
@@ -40,7 +43,8 @@
     net::URLRequest* request,
     content::ResourceType resource_type,
     scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> database_manager,
-    scoped_refptr<AwSafeBrowsingUIManager> ui_manager)
+    scoped_refptr<AwSafeBrowsingUIManager> ui_manager,
+    AwSafeBrowsingWhitelistManager* whitelist_manager)
     : safe_browsing::BaseResourceThrottle(
           request,
           resource_type,
@@ -49,10 +53,18 @@
                safe_browsing::SB_THREAT_TYPE_URL_PHISHING}),
           database_manager,
           ui_manager),
-      request_(request) {}
+      request_(request),
+      whitelist_manager_(whitelist_manager) {}
 
 AwSafeBrowsingResourceThrottle::~AwSafeBrowsingResourceThrottle() {}
 
+bool AwSafeBrowsingResourceThrottle::CheckUrl(const GURL& gurl) {
+  if (whitelist_manager_->IsURLWhitelisted(gurl)) {
+    return true;
+  }
+  return BaseResourceThrottle::CheckUrl(gurl);
+}
+
 void AwSafeBrowsingResourceThrottle::StartDisplayingBlockingPageHelper(
     security_interstitials::UnsafeResource resource) {
   content::BrowserThread::PostTask(
diff --git a/android_webview/browser/aw_safe_browsing_resource_throttle.h b/android_webview/browser/aw_safe_browsing_resource_throttle.h
index ed3bceb..8ec14aac 100644
--- a/android_webview/browser/aw_safe_browsing_resource_throttle.h
+++ b/android_webview/browser/aw_safe_browsing_resource_throttle.h
@@ -22,6 +22,8 @@
 
 namespace android_webview {
 
+class AwSafeBrowsingWhitelistManager;
+
 class AwSafeBrowsingResourceThrottle
     : public safe_browsing::BaseResourceThrottle {
  public:
@@ -32,6 +34,8 @@
     BACK_TO_SAFETY,
   };
 
+  static const void* kUserDataKey;
+
   // Will construct an AwSafeBrowsingResourceThrottle if GMS exists on device
   // and supports safebrowsing.
   static AwSafeBrowsingResourceThrottle* MaybeCreate(
@@ -39,9 +43,11 @@
       content::ResourceType resource_type,
       scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
           database_manager,
-      scoped_refptr<AwSafeBrowsingUIManager> ui_manager);
+      scoped_refptr<AwSafeBrowsingUIManager> ui_manager,
+      AwSafeBrowsingWhitelistManager* whitelist_manager);
 
-  static const void* kUserDataKey;
+ protected:
+  bool CheckUrl(const GURL& url) override;
 
  private:
   AwSafeBrowsingResourceThrottle(
@@ -49,7 +55,8 @@
       content::ResourceType resource_type,
       scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
           database_manager,
-      scoped_refptr<AwSafeBrowsingUIManager> ui_manager);
+      scoped_refptr<AwSafeBrowsingUIManager> ui_manager,
+      AwSafeBrowsingWhitelistManager* whitelist_manager);
 
   ~AwSafeBrowsingResourceThrottle() override;
 
@@ -77,6 +84,8 @@
 
   net::URLRequest* request_;
 
+  AwSafeBrowsingWhitelistManager* whitelist_manager_;
+
   DISALLOW_COPY_AND_ASSIGN(AwSafeBrowsingResourceThrottle);
 };
 
diff --git a/android_webview/browser/aw_safe_browsing_whitelist_manager.cc b/android_webview/browser/aw_safe_browsing_whitelist_manager.cc
new file mode 100644
index 0000000..d4c5fa09
--- /dev/null
+++ b/android_webview/browser/aw_safe_browsing_whitelist_manager.cc
@@ -0,0 +1,227 @@
+// Copyright 2017 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/aw_safe_browsing_whitelist_manager.h"
+
+#include <map>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/sequenced_task_runner.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/task_runner_util.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "net/base/url_util.h"
+#include "url/url_util.h"
+
+namespace android_webview {
+
+// This is a simple trie structure designed for handling host/domain matches
+// for Safebrowsing whitelisting. For the match rules, see the class header.
+//
+// It is easy to visualize the trie edges as hostname components of a url in
+// reverse order. For example a whitelist of google.com will have a tree
+// tree structure as below.
+//                       root
+//                         | com
+//                       Node1
+//                google/    \ example
+//                   Node2   Node3
+//
+// Normally, a search in the tree should end in a leaf node for a positive
+// match. For example in the tree above com.google and com.example are matches.
+// However, the whitelisting also allows matching subdomains if there is a
+// leading dot,  for example, see ."google.com" and a.google.com below:
+//                       root
+//                         | com
+//                       Node1
+//                         | google
+//                       Node2
+//                         | a
+//                       Node3
+// Here, both Node2 and Node3 are valid terminal nodes to terminate a match.
+// The boolean is_terminal indicates whether a node can successfully terminate
+// a search (aka. whether this rule was entered to the whitelist) and
+// match_prefix indicate if this should match exactly, or just do a prefix
+// match.
+
+// The structure is optimized such that if a node already allows a prefix
+// match, then there is no need for it to have children, or if it has children
+// these children are removed.
+struct TrieNode {
+  std::map<std::string, std::unique_ptr<TrieNode>> children;
+  bool match_prefix = false;
+  bool is_terminal = false;
+};
+
+namespace {
+
+void InsertRuleToTrie(const std::vector<base::StringPiece>& components,
+                      TrieNode* root,
+                      bool match_prefix) {
+  TrieNode* node = root;
+  for (auto hostcomp = components.rbegin(); hostcomp != components.rend();
+       ++hostcomp) {
+    DCHECK(!node->match_prefix);
+    std::string component = hostcomp->as_string();
+    auto child_node = node->children.find(component);
+    if (child_node == node->children.end()) {
+      std::unique_ptr<TrieNode> temp = base::MakeUnique<TrieNode>();
+      TrieNode* current = temp.get();
+      node->children.emplace(component, std::move(temp));
+      node = current;
+    } else {
+      node = child_node->second.get();
+      // Optimization. No need to add new nodes as this node matches prefixes.
+      DCHECK(node);
+      if (node->match_prefix)
+        return;
+    }
+  }
+  DCHECK(node != root);
+  // Optimization. If match_prefix is true, remove all nodes originating
+  // from that node.
+  if (match_prefix) {
+    node->match_prefix = true;
+    node->children.clear();
+  }
+  node->is_terminal = true;
+}
+
+std::vector<base::StringPiece> SplitHost(const GURL& url) {
+  std::vector<base::StringPiece> components;
+  if (url.HostIsIPAddress()) {
+    components.push_back(url.host_piece());
+  } else {
+    components =
+        base::SplitStringPiece(url.host_piece(), ".", base::KEEP_WHITESPACE,
+                               base::SPLIT_WANT_NONEMPTY);
+  }
+  DCHECK(components.size() > 0);
+  return components;
+}
+
+// Rule is a UTF-8 wide string.
+bool AddRuleToWhitelist(base::StringPiece rule, TrieNode* root) {
+  if (rule.empty()) {
+    return false;
+  }
+  // Leading dot means to do an exact match.
+  bool started_with_dot = false;
+  if (rule.front() == '.') {
+    rule.remove_prefix(1);  // Strip it for the rest of the handling.
+    started_with_dot = true;
+  }
+  // With the dot removed |rule| should look like a hostname.
+  GURL test_url("http://" + rule.as_string());
+  if (!test_url.is_valid()) {
+    return false;
+  }
+
+  bool has_path = test_url.has_path() && test_url.path() != "/";
+  // Verify that it is a hostname.
+  if (!test_url.has_host() || has_path || test_url.has_port() ||
+      test_url.has_query() || test_url.has_password() ||
+      test_url.has_username() || test_url.has_ref()) {
+    return false;
+  }
+
+  bool match_prefix = false;
+  if (test_url.HostIsIPAddress()) {
+    // leading dots are not allowed for IP addresses. IP addresses are always
+    // exact match.
+    if (started_with_dot) {
+      return false;
+    }
+    match_prefix = false;
+  } else {
+    match_prefix = !started_with_dot;
+  }
+  InsertRuleToTrie(SplitHost(test_url), root, match_prefix);
+  return true;
+}
+
+void AddRules(const std::vector<std::string>& rules, TrieNode* root) {
+  for (auto rule : rules) {
+    if (!AddRuleToWhitelist(rule, root)) {
+      LOG(ERROR) << " Dropping invalid whitelist rule " << rule;
+    }
+  }
+}
+
+bool IsWhitelisted(const GURL& url, const TrieNode* node) {
+  std::vector<base::StringPiece> components = SplitHost(url);
+  for (auto component = components.rbegin(); component != components.rend();
+       ++component) {
+    if (node->match_prefix) {
+      return true;
+    }
+    auto child_node = node->children.find(component->as_string());
+    if (child_node == node->children.end()) {
+      return false;
+    } else {
+      node = child_node->second.get();
+      DCHECK(node);
+    }
+  }
+  // DCHECK optimization. A match_prefix node should have no children.
+  DCHECK(!node->match_prefix || node->children.empty());
+  // If trie search finished in a terminal node, host is found in trie. The
+  // root node is not a terminal node.
+  return node->is_terminal;
+}
+
+}  // namespace
+
+AwSafeBrowsingWhitelistManager::AwSafeBrowsingWhitelistManager(
+    const scoped_refptr<base::SequencedTaskRunner>& background_task_runner,
+    const scoped_refptr<base::SequencedTaskRunner>& io_task_runner)
+    : background_task_runner_(background_task_runner),
+      io_task_runner_(io_task_runner),
+      ui_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+      whitelist_(base::MakeUnique<TrieNode>()) {}
+
+AwSafeBrowsingWhitelistManager::~AwSafeBrowsingWhitelistManager() {}
+
+void AwSafeBrowsingWhitelistManager::SetWhitelist(
+    std::unique_ptr<TrieNode> whitelist) {
+  DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+  whitelist_ = std::move(whitelist);
+}
+
+// A task that builds the whitelist on a background thread.
+void AwSafeBrowsingWhitelistManager::BuildWhitelist(
+    const std::vector<std::string>& rules) {
+  DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
+
+  std::unique_ptr<TrieNode> whitelist(base::MakeUnique<TrieNode>());
+  AddRules(rules, whitelist.get());
+  DCHECK(!whitelist->is_terminal);
+  DCHECK(!whitelist->match_prefix);
+  // use base::Unretained as AwSafeBrowsingWhitelistManager is a singleton and
+  // not cleaned.
+  io_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&AwSafeBrowsingWhitelistManager::SetWhitelist,
+                 base::Unretained(this), base::Passed(std::move(whitelist))));
+}
+
+void AwSafeBrowsingWhitelistManager::SetWhitelistOnUIThread(
+    std::vector<std::string>&& rules) {
+  DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
+  // use base::Unretained as AwSafeBrowsingWhitelistManager is a singleton and
+  // not cleaned.
+  background_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&AwSafeBrowsingWhitelistManager::BuildWhitelist,
+                 base::Unretained(this), base::Passed(std::move(rules))));
+}
+
+bool AwSafeBrowsingWhitelistManager::IsURLWhitelisted(const GURL& url) const {
+  DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+  return IsWhitelisted(url, whitelist_.get());
+}
+
+}  // namespace android_webview
diff --git a/android_webview/browser/aw_safe_browsing_whitelist_manager.h b/android_webview/browser/aw_safe_browsing_whitelist_manager.h
new file mode 100644
index 0000000..ade2354
--- /dev/null
+++ b/android_webview/browser/aw_safe_browsing_whitelist_manager.h
@@ -0,0 +1,87 @@
+// Copyright 2017 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_AW_SAFE_BROWSING_WHITELIST_MANAGER_H_
+#define ANDROID_WEBVIEW_BROWSER_AW_SAFE_BROWSING_WHITELIST_MANAGER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
+#include "url/gurl.h"
+
+namespace base {
+class SequencedTaskRunner;
+}  // namespace base
+
+namespace android_webview {
+struct TrieNode;
+
+// This class tracks the whitelisting policies for Safebrowsing. The class
+// interacts with UI thread, where the whitelist is set, and then checks
+// for the URLs in IO thread. The whitelisted entries are not checked for
+// Safebrowsing.
+//
+// The class must be constructed on the UI thread.
+//
+// Update whitelist tasks from the UI thread are post to the IO thread.
+//
+// Encoding and the whitelisting rules:
+//    The whitelist is set in Java and plumbed to native through JNI, making
+//  them UTF-8 encoded wide strings.
+//
+// Each rule should take one of these:
+//    HOSTNAME
+//   .HOSTNAME
+//   IPV4_LITERAL
+//   IPV6_LITERAL_WITH_BRACKETS
+//
+// All other rules, including wildcards, are invalid.
+//
+// The hostname with a leading dot means an exact match, otherwise subdomains
+// are also matched. This particular rule is similar to admiministration
+// blacklist policy format:
+//      https://www.chromium.org/administrators/url-blacklist-filter-format
+//
+// The expected number of entries on the list should be 100s at most, however
+// the size is not enforced here. The list size can be enforced at
+// Java level if necessary.
+//
+class AwSafeBrowsingWhitelistManager {
+ public:
+  // Must be constructed on the UI thread.
+  // |background_task_runner| is used to build the filter list in a background
+  // thread.
+  // |io_task_runner| must be backed by the IO thread.
+  AwSafeBrowsingWhitelistManager(
+      const scoped_refptr<base::SequencedTaskRunner>& background_task_runner,
+      const scoped_refptr<base::SequencedTaskRunner>& io_task_runner);
+  virtual ~AwSafeBrowsingWhitelistManager();
+
+  // Returns true if |url| is whitelisted by the current whitelist. Must be
+  // called from the IO thread.
+  bool IsURLWhitelisted(const GURL& url) const;
+
+  // Replace the current host whitelist with a new one.
+  void SetWhitelistOnUIThread(std::vector<std::string>&& rules);
+
+ private:
+  // Builds whitelist on background thread.
+  void BuildWhitelist(const std::vector<std::string>& rules);
+  // Replaces the current whitelist. Must be called on the IO thread.
+  void SetWhitelist(std::unique_ptr<TrieNode> whitelist);
+
+  scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
+  scoped_refptr<base::SequencedTaskRunner> io_task_runner_;
+  scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
+
+  std::unique_ptr<TrieNode> whitelist_;
+
+  DISALLOW_COPY_AND_ASSIGN(AwSafeBrowsingWhitelistManager);
+};
+
+}  // namespace android_webview
+
+#endif  // ANDROID_WEBVIEW_BROWSER_AW_SAFE_BROWSING_WHITELIST_MANAGER_H_
diff --git a/android_webview/browser/aw_safe_browsing_whitelist_manager_unittest.cc b/android_webview/browser/aw_safe_browsing_whitelist_manager_unittest.cc
new file mode 100644
index 0000000..fa1663c
--- /dev/null
+++ b/android_webview/browser/aw_safe_browsing_whitelist_manager_unittest.cc
@@ -0,0 +1,455 @@
+// Copyright 2017 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/aw_safe_browsing_whitelist_manager.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace android_webview {
+
+class AwSafeBrowsingWhitelistManagerTest : public testing::Test {
+ protected:
+  AwSafeBrowsingWhitelistManagerTest() {}
+
+  void SetUp() override {
+    wm_.reset(new AwSafeBrowsingWhitelistManager(
+        base::ThreadTaskRunnerHandle::Get(),
+        base::ThreadTaskRunnerHandle::Get()));
+  }
+
+  void TearDown() override { wm_.reset(); }
+
+  base::MessageLoopForIO loop_;
+  std::unique_ptr<AwSafeBrowsingWhitelistManager> wm_;
+};
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest, WsSchemeCanBeWhitelisted) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("google.com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("ws://google.com")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("wss://google.com")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest, HttpSchemeCanBeWhitelisted) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("google.com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://google.com")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("https://google.com")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://google.com:80")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://google.com:123")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://google.com:443")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest, WsSchemeCanBeWhitelistedExactMatch) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back(".google.com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("ws://google.com")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("wss://google.com")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("ws://google.com:80")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("ws://google.com:123")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("ws://google.com:443")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest, ExactMatchWorks) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back(".google.com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://google.com")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("https://google.com")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("ws://google.com")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("wss://google.com")));
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("ws://a.google.com")));
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("wss://a.google.com")));
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("ws://com")));
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("wss://oogle.com")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest, SchemeInWhitelistIsInvalid) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("http://google.com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://google.com")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest,
+       NonStandardSchemeInWhitelistIsInvalid) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("data:google.com");
+  whitelist.push_back("mailto:google.com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://google.com")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest, PortInWhitelistIsInvalid) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("www.google.com:123");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://www.google.com")));
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://www.google.com:123")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest, PathInWhitelistIsInvalid) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("www.google.com/123");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://www.google.com/123")));
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://www.google.com")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest, PathQueryAndReferenceWorks) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("google.com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://google.com/a")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://google.com/a/b")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://google.com?test=1")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://google.com/a#a100")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest, TrailingDotInRuleWorks) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("google.com.");
+  whitelist.push_back("example.com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://google.com")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://example.com.")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest, DomainNameEmbeddedInPathIsIgnored) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("google.com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://example.com/google.com")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://google.com")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest, URLsWithEmbeddedUserNamePassword) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("google.com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://user1:pass@google.com")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest,
+       PathQueryAndReferenceWorksWithLeadingDot) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back(".google.com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://google.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://google.com/a")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://google.com/a/b")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://google.com?test=1")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://google.com/a#a100")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest,
+       SubdomainsAreAllowedWhenNoLeadingDots) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("google.com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://google.com")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://a.google.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://b.a.google.com/")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest,
+       SubdomainsAreNotAllowedWhenLeadingDots) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back(".google.com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://google.com")));
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://a.google.com/")));
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://b.a.google.com/")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest, WildCardNotAccepted) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("*");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://a.google.com/")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest,
+       MatchSubdomainsInMultipleWhitelists) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("a.google.com");
+  whitelist.push_back(".google.com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://a.google.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://b.a.google.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://google.com/")));
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://b.google.com/")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest, TestLeadingDotInGURL) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("a.google.com");
+  whitelist.push_back(".google.com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://.a.google.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://.b.a.google.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://.google.com/")));
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://.b.google.com/")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest, VerifyTLDsAreNotSpecial) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back(".com");
+  whitelist.push_back("co");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://a.google.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://b.a.google.co/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://com/")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest, VerifyRandomWildcardsAreIgnored) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("*.com");
+  whitelist.push_back("*co");
+  whitelist.push_back("b.a.*.co");
+  whitelist.push_back("b.*.*.co");
+  whitelist.push_back("b.*");
+  whitelist.push_back("c*");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://a.google.com/")));
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://b.a.google.co/")));
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://com/")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest, VerifyPrefixOrSuffixOfDomains) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("google.com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://ogle.com/")));
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://agoogle.com/")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest, VerifyIPV4CanBeWhitelisted) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("google.com");
+  whitelist.push_back("192.168.1.1");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://google.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://192.168.1.1/")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest, VerifyIPV4IsNotSegmented) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("192.168.1.1");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://192.168.1.1/")));
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://1.192.168.1.1/")));
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://192.168.1.0/")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest, VerifyLeadingDotInIPV4IsNotValid) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back(".192.168.1.1");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://192.168.1.1/")));
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://1.192.168.1.1/")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest, VerifyMultipleIPV4Works) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("192.168.1.1");
+  whitelist.push_back("192.168.1.2");
+  whitelist.push_back("194.168.1.1");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://192.168.1.1/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://192.168.1.2/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://194.168.1.1/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("https://194.168.1.1/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://194.168.1.1:443/")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest, VerifyIPV6CanBeWhitelisted) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("[10:20:30:40:50:60:70:80]");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://[10:20:30:40:50:60:70:80]")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest,
+       VerifyIPV6CannotBeWhitelistedIfBroken) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("[10:20:30:40:50:60:]");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://[10:20:30:40:50:60:70:80]")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest,
+       VerifyIPV6WithZerosCanBeWhitelisted) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("[20:0:0:0:0:0:0:0]");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://[20:0:0:0:0:0:0:0]")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest, VerifyCapitalizationDoesNotMatter) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("A.goOGle.Com");
+  whitelist.push_back(".GOOGLE.COM");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://a.google.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://b.a.google.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://google.com/")));
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://b.google.com/")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest,
+       VerifyWhitelistingWorksWhenDomainSuffixesMatch1) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("com");
+  whitelist.push_back("example.com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://a.google.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://example.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://a.example.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://com/")));
+}
+
+// Same as verifyWhitelistingWorksWhenDomainSuffixesMatch1 but order reversed.
+TEST_F(AwSafeBrowsingWhitelistManagerTest,
+       VerifyWhitelistingWorksWhenDomainSuffixesMatch2) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("example.com");
+  whitelist.push_back("com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://a.google.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://example.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://a.example.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://com/")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest,
+       VerifyWhitelistingWorksWhenDomainSuffixesMatchWithLeadingDots1) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back(".com");
+  whitelist.push_back("example.com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://a.google.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://example.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://a.example.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://com/")));
+}
+
+// Same as VerifyWhitelistingWorksWhenDomainSuffixesMatchWithLeadingDots2
+// but order reversed.
+TEST_F(AwSafeBrowsingWhitelistManagerTest,
+       VerifyWhitelistingWorksWhenDomainSuffixesMatchWithLeadingDots2) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("example.com");
+  whitelist.push_back(".com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://a.google.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://example.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://a.example.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://com/")));
+}
+
+// Verify that a more general rule won't be rendered useless by a rule that
+// more closely matches. For example if "com" is a rule to whitelist all com
+// subdomains, a later rule for .example.com should not make a.example.com a
+// no match.
+TEST_F(AwSafeBrowsingWhitelistManagerTest,
+       VerifyAnExactMatchRuleCanBeOverwrittenByAMoreGeneralNonExactMatchRule) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("com");
+  whitelist.push_back(".example.com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://a.example.com/")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest,
+       VerifySubdomainMatchWinsIfRuleIsEnteredWithAndWithoutSubdomainMatch) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("example.com");
+  whitelist.push_back(".example.com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://a.example.com/")));
+
+  whitelist = std::vector<std::string>();
+  whitelist.push_back(".example.com");
+  whitelist.push_back("example.com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://a.example.com/")));
+}
+
+TEST_F(AwSafeBrowsingWhitelistManagerTest,
+       VerifyOrderOfRuleEntryDoesNotChangeExpectations) {
+  std::vector<std::string> whitelist;
+  whitelist.push_back("b.example.com");
+  whitelist.push_back(".example.com");
+  whitelist.push_back("example.com");
+  whitelist.push_back("a.example.com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://a.example.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://b.example.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://example.com/")));
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://com/")));
+
+  whitelist = std::vector<std::string>();
+  whitelist.push_back("a.example.com");
+  whitelist.push_back("example.com");
+  whitelist.push_back(".example.com");
+  whitelist.push_back("b.example.com");
+  wm_->SetWhitelistOnUIThread(std::move(whitelist));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://a.example.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://b.example.com/")));
+  EXPECT_TRUE(wm_->IsURLWhitelisted(GURL("http://example.com/")));
+  EXPECT_FALSE(wm_->IsURLWhitelisted(GURL("http://com/")));
+}
+
+}  // namespace android_webview
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 be4af71..66a3a2d 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
@@ -301,7 +301,8 @@
         AwSafeBrowsingResourceThrottle::MaybeCreate(
             request, resource_type,
             AwBrowserContext::GetDefault()->GetSafeBrowsingDBManager(),
-            AwBrowserContext::GetDefault()->GetSafeBrowsingUIManager());
+            AwBrowserContext::GetDefault()->GetSafeBrowsingUIManager(),
+            AwBrowserContext::GetDefault()->GetSafeBrowsingWhitelistManager());
     if (throttle == nullptr) {
       // Should not happen
       DLOG(WARNING) << "Failed creating safebrowsing throttle";
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java b/android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java
index c144833f..16c5d07 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java
@@ -89,12 +89,26 @@
     }
 
     // Can be called from any thread.
-    public static boolean getSafeBrowsingEnabled() {
-        return nativeGetSafeBrowsingEnabled();
+    public static boolean getSafeBrowsingEnabledByManifest() {
+        return nativeGetSafeBrowsingEnabledByManifest();
     }
 
+    public static void setSafeBrowsingEnabledByManifest(boolean enable) {
+        nativeSetSafeBrowsingEnabledByManifest(enable);
+    }
+
+    // TODO(ntfschr): remove this when downstream no longer depends on it
+    public static boolean getSafeBrowsingEnabled() {
+        return getSafeBrowsingEnabledByManifest();
+    }
+
+    // TODO(ntfschr): remove this when downstream no longer depends on it
     public static void setSafeBrowsingEnabled(boolean enable) {
-        nativeSetSafeBrowsingEnabled(enable);
+        setSafeBrowsingEnabledByManifest(enable);
+    }
+
+    public static void setSafeBrowsingWhiteList(String[] urls) {
+        nativeSetSafeBrowsingWhiteList(urls);
     }
 
     @SuppressWarnings("unchecked")
@@ -157,8 +171,9 @@
     private static native String nativeGetProductVersion();
     private static native void nativeSetServiceWorkerIoThreadClient(
             AwContentsIoThreadClient ioThreadClient, AwBrowserContext browserContext);
-    private static native boolean nativeGetSafeBrowsingEnabled();
-    private static native void nativeSetSafeBrowsingEnabled(boolean enable);
+    private static native boolean nativeGetSafeBrowsingEnabledByManifest();
+    private static native void nativeSetSafeBrowsingEnabledByManifest(boolean enable);
+    private static native void nativeSetSafeBrowsingWhiteList(String[] urls);
     private static native void nativeSetCheckClearTextPermitted(boolean permitted);
     private static native String nativeFindAddress(String addr);
 }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwSafeBrowsingConfigHelper.java b/android_webview/java/src/org/chromium/android_webview/AwSafeBrowsingConfigHelper.java
index 1177fea..8ecb6b9 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwSafeBrowsingConfigHelper.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwSafeBrowsingConfigHelper.java
@@ -21,14 +21,16 @@
 
     private static final String OPT_IN_META_DATA_STR = "android.webkit.WebView.EnableSafeBrowsing";
 
+    private static boolean sSafeBrowsingUserOptIn;
+
     public static void maybeInitSafeBrowsingFromSettings(final Context appContext) {
-        if (CommandLine.getInstance().hasSwitch(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
-                || appHasOptedIn(appContext)) {
-            // Assume safebrowsing on by default initially. If GMS is available, we later use
-            // isVerifyAppsEnabled() to check if "Scan device for security threats" has been checked
-            // by the user.
-            AwContentsStatics.setSafeBrowsingEnabled(true);
-        }
+        AwContentsStatics.setSafeBrowsingEnabledByManifest(
+                CommandLine.getInstance().hasSwitch(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
+                || appHasOptedIn(appContext));
+        // Assume safebrowsing on by default initially. If GMS is available, we later use
+        // isVerifyAppsEnabled() to check if "Scan device for security threats" has been checked by
+        // the user.
+        setSafeBrowsingUserOptIn(true);
     }
 
     private static boolean appHasOptedIn(Context appContext) {
@@ -49,6 +51,15 @@
         }
     }
 
+    // Can be called from any thread.
+    public static boolean getSafeBrowsingUserOptIn() {
+        return sSafeBrowsingUserOptIn;
+    }
+
+    public static void setSafeBrowsingUserOptIn(boolean optin) {
+        sSafeBrowsingUserOptIn = optin;
+    }
+
     // Not meant to be instantiated.
     private AwSafeBrowsingConfigHelper() {}
 }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwSettings.java b/android_webview/java/src/org/chromium/android_webview/AwSettings.java
index 9b9a1f36..242a1f9b 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwSettings.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwSettings.java
@@ -92,7 +92,7 @@
     // Although this bit is stored on AwSettings it is actually controlled via the CookieManager.
     private boolean mAcceptThirdPartyCookies;
 
-    // if null, default to AwContentsStatics.getSafeBrowsingEnabled()
+    // if null, default to AwContentsStatics.getSafeBrowsingEnabledByManifest()
     private Boolean mSafeBrowsingEnabled;
 
     private final boolean mSupportLegacyQuirks;
@@ -357,8 +357,9 @@
      */
     public boolean getSafeBrowsingEnabled() {
         synchronized (mAwSettingsLock) {
+            if (!AwSafeBrowsingConfigHelper.getSafeBrowsingUserOptIn()) return false;
             if (mSafeBrowsingEnabled == null) {
-                return AwContentsStatics.getSafeBrowsingEnabled();
+                return AwContentsStatics.getSafeBrowsingEnabledByManifest();
             }
             return mSafeBrowsingEnabled;
         }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java
index 9721eda..cd1f1b2 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/SafeBrowsingTest.java
@@ -8,6 +8,7 @@
 import android.content.SharedPreferences;
 import android.graphics.Bitmap;
 import android.graphics.Color;
+import android.net.Uri;
 import android.support.test.filters.SmallTest;
 import android.view.ViewGroup;
 import android.webkit.ValueCallback;
@@ -19,6 +20,8 @@
 import org.chromium.android_webview.AwContents.NativeDrawGLFunctorFactory;
 import org.chromium.android_webview.AwContentsClient;
 import org.chromium.android_webview.AwContentsClient.AwWebResourceRequest;
+import org.chromium.android_webview.AwContentsStatics;
+import org.chromium.android_webview.AwSafeBrowsingConfigHelper;
 import org.chromium.android_webview.AwSafeBrowsingConversionHelper;
 import org.chromium.android_webview.AwSafeBrowsingResponse;
 import org.chromium.android_webview.AwSettings;
@@ -262,7 +265,6 @@
     public void setUp() throws Exception {
         super.setUp();
         mContentsClient = new SafeBrowsingContentsClient();
-
         mContainerView = createAwTestContainerViewOnMainSync(
                 mContentsClient, false, new SafeBrowsingDependencyFactory());
         mAwContents = (MockAwContents) mContainerView.getAwContents();
@@ -437,6 +439,24 @@
     @SmallTest
     @Feature({"AndroidWebView"})
     @CommandLineFlags.Add(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
+    public void testSafeBrowsingWhitelistedUnsafePagesDontShowInterstitial() throws Throwable {
+        loadGreenPage();
+        final String responseUrl = mTestServer.getURL(MALWARE_HTML_PATH);
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                String host = Uri.parse(responseUrl).getHost();
+                String[] s = new String[] {host};
+                AwContentsStatics.setSafeBrowsingWhiteList(s);
+            }
+        });
+        loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), responseUrl);
+        assertTargetPageHasLoaded(MALWARE_PAGE_BACKGROUND_COLOR);
+    }
+
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    @CommandLineFlags.Add(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
     public void testSafeBrowsingShowsInterstitialForMainFrame() throws Throwable {
         loadGreenPage();
         loadPathAndWaitForInterstitial(MALWARE_HTML_PATH);
@@ -742,4 +762,26 @@
         assertEquals(AwSafeBrowsingConversionHelper.SAFE_BROWSING_THREAT_MALWARE,
                 mContentsClient.getLastThreatType());
     }
+
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    @CommandLineFlags.Add(AwSwitches.WEBVIEW_ENABLE_SAFEBROWSING_SUPPORT)
+    public void testSafeBrowsingUserOptOutOverridesManifest() throws Throwable {
+        AwSafeBrowsingConfigHelper.setSafeBrowsingUserOptIn(false);
+        loadGreenPage();
+        final String responseUrl = mTestServer.getURL(MALWARE_HTML_PATH);
+        loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), responseUrl);
+        assertTargetPageHasLoaded(MALWARE_PAGE_BACKGROUND_COLOR);
+    }
+
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    public void testSafeBrowsingUserOptOutOverridesPerWebView() throws Throwable {
+        AwSafeBrowsingConfigHelper.setSafeBrowsingUserOptIn(false);
+        getAwSettingsOnUiThread(mAwContents).setSafeBrowsingEnabled(true);
+        loadGreenPage();
+        final String responseUrl = mTestServer.getURL(MALWARE_HTML_PATH);
+        loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), responseUrl);
+        assertTargetPageHasLoaded(MALWARE_PAGE_BACKGROUND_COLOR);
+    }
 }
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn
index b660f60..4b87ec42 100644
--- a/android_webview/test/BUILD.gn
+++ b/android_webview/test/BUILD.gn
@@ -258,6 +258,7 @@
     "../browser/aw_form_database_service_unittest.cc",
     "../browser/aw_media_url_interceptor_unittest.cc",
     "../browser/aw_permission_manager_unittest.cc",
+    "../browser/aw_safe_browsing_whitelist_manager_unittest.cc",
     "../browser/aw_static_cookie_policy_unittest.cc",
     "../browser/browser_view_renderer_unittest.cc",
     "../browser/command_line_helper_unittest.cc",
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 36adbfb1..b720b02 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -558,6 +558,8 @@
     "system/tray_accessibility.h",
     "system/tray_caps_lock.cc",
     "system/tray_caps_lock.h",
+    "system/tray_drag_controller.cc",
+    "system/tray_drag_controller.h",
     "system/tray_tracing.cc",
     "system/tray_tracing.h",
     "system/update/tray_update.cc",
@@ -681,8 +683,6 @@
     "wm/overview/cleanup_animation_observer.cc",
     "wm/overview/cleanup_animation_observer.h",
     "wm/overview/overview_animation_type.h",
-    "wm/overview/overview_window_drag_controller.cc",
-    "wm/overview/overview_window_drag_controller.h",
     "wm/overview/scoped_overview_animation_settings.cc",
     "wm/overview/scoped_overview_animation_settings.h",
     "wm/overview/scoped_transform_overview_window.cc",
@@ -1019,8 +1019,8 @@
 
   deps = [
     ":ash",
+    ":test_support_without_content",
     "//ash/public/cpp:ash_public_cpp",
-    "//ash/test:test_support_without_content",
     "//base",
     "//base:i18n",
     "//components/user_manager",
@@ -1055,8 +1055,8 @@
   deps = [
     ":ash_shell_lib",
     ":ash_with_content",
+    ":test_support_without_content",
     "//ash/public/cpp:ash_public_cpp",
-    "//ash/test:test_support_without_content",
     "//base:i18n",
     "//chrome:packed_resources",
     "//chromeos",
@@ -1098,8 +1098,8 @@
   deps = [
     ":ash",
     ":ash_with_content",
+    ":test_support_with_content",
     "//ash/public/cpp:ash_public_cpp",
-    "//ash/test:test_support_with_content",
     "//base",
     "//base/test:test_support",
     "//chromeos",
@@ -1291,12 +1291,12 @@
     "wm/workspace_controller_unittest.cc",
   ]
   deps = [
+    ":test_support_without_content",
     "//ash",
     "//ash/mus:lib",
     "//ash/public/cpp:ash_public_cpp",
     "//ash/public/cpp:unit_tests",
     "//ash/resources/vector_icons",
-    "//ash/test:test_support_without_content",
     "//base",
     "//base/test:test_support",
     "//chromeos",
@@ -1329,7 +1329,7 @@
     "//ui/wm/public",
   ]
   public_deps = [
-    "//ash/test:test_support_without_content",
+    ":test_support_without_content",
   ]
 
   if (use_ozone) {
@@ -1450,12 +1450,12 @@
   deps = [
     ":ash",
     ":common_unittests",
+    ":test_support_without_content",
     "//ash/autoclick/common:autoclick",
     "//ash/public/cpp:ash_public_cpp",
     "//ash/resources",
     "//ash/resources/vector_icons",
     "//ash/strings",
-    "//ash/test:test_support_without_content",
     "//ash/touch_hud",
     "//base",
     "//base/test:test_support",
@@ -1535,8 +1535,8 @@
   ]
 
   deps = [
+    ":test_support_without_content",
     "//ash/public/cpp:ash_public_cpp",
-    "//ash/test:test_support_without_content",
     "//base/test:test_support",
     "//cc:test_support",
     "//cc/base",
@@ -1574,3 +1574,210 @@
     "//ash/resources:ash_test_resources_200_percent",
   ]
 }
+
+static_library("test_support_without_content") {
+  testonly = true
+  sources = [
+    "test/ash_test_environment_default.cc",
+  ]
+
+  public_deps = [
+    ":test_support_common",
+  ]
+
+  deps = [
+    "//base",
+    "//base/test:test_support",
+    "//skia",
+  ]
+}
+
+static_library("test_support_with_content") {
+  testonly = true
+  sources = [
+    "test/ash_test_environment_content.cc",
+    "test/ash_test_environment_content.h",
+    "test/content/test_shell_content_state.cc",
+    "test/content/test_shell_content_state.h",
+  ]
+  configs += [ "//build/config:precompiled_headers" ]
+
+  public_deps = [
+    ":test_support_common",
+    "//ash:ash_with_content",
+    "//content/public/browser",
+    "//content/test:test_support",
+    "//skia",
+  ]
+}
+
+# Internal target consumed by |test_support_with_content| and
+# |test_support_without_content|. This target contains all the test support
+# files, with the exception of an implementation of AshTestEnvironment.
+# Consumers of ash should use one of |test_support_with_content| or
+# |test_support_without_content|.
+static_library("test_support_common") {
+  testonly = true
+  visibility = [ ":*" ]
+  sources = [
+    "app_list/test_app_list_view_presenter_impl.cc",
+    "app_list/test_app_list_view_presenter_impl.h",
+    "display/display_configuration_controller_test_api.cc",
+    "display/display_configuration_controller_test_api.h",
+    "display/mirror_window_test_api.cc",
+    "display/mirror_window_test_api.h",
+    "display/screen_orientation_controller_test_api.cc",
+    "display/screen_orientation_controller_test_api.h",
+    "keyboard/test_keyboard_ui.cc",
+    "keyboard/test_keyboard_ui.h",
+    "laser/laser_pointer_controller_test_api.cc",
+    "laser/laser_pointer_controller_test_api.h",
+    "laser/laser_pointer_points_test_api.cc",
+    "laser/laser_pointer_points_test_api.h",
+    "metrics/task_switch_time_tracker_test_api.cc",
+    "metrics/task_switch_time_tracker_test_api.h",
+    "metrics/user_metrics_recorder_test_api.cc",
+    "metrics/user_metrics_recorder_test_api.h",
+
+    # TODO(jamescook): Consider adding a //ash/public/cpp:test_support target.
+    "public/cpp/immersive/immersive_fullscreen_controller_test_api.cc",
+    "public/cpp/immersive/immersive_fullscreen_controller_test_api.h",
+    "rotator/screen_rotation_animator_test_api.cc",
+    "rotator/screen_rotation_animator_test_api.h",
+    "session/test_session_controller_client.cc",
+    "session/test_session_controller_client.h",
+    "shelf/overflow_bubble_view_test_api.cc",
+    "shelf/overflow_bubble_view_test_api.h",
+    "shelf/overflow_button_test_api.cc",
+    "shelf/overflow_button_test_api.h",
+    "shelf/shelf_button_pressed_metric_tracker_test_api.cc",
+    "shelf/shelf_button_pressed_metric_tracker_test_api.h",
+    "shelf/shelf_view_test_api.cc",
+    "shelf/shelf_view_test_api.h",
+    "shell/toplevel_window.cc",
+    "shell/toplevel_window.h",
+    "shell_test_api.cc",
+    "shell_test_api.h",
+    "system/cast/tray_cast_test_api.cc",
+    "system/cast/tray_cast_test_api.h",
+    "system/palette/test_palette_delegate.cc",
+    "system/palette/test_palette_delegate.h",
+    "system/status_area_widget_test_helper.cc",
+    "system/status_area_widget_test_helper.h",
+    "system/tray/system_tray_test_api.h",
+    "system/tray/test_system_tray_item.cc",
+    "system/tray/test_system_tray_item.h",
+    "test/ash_test_base.cc",
+    "test/ash_test_base.h",
+    "test/ash_test_environment.h",
+    "test/ash_test_helper.cc",
+    "test/ash_test_helper.h",
+    "test/ash_test_views_delegate.cc",
+    "test/ash_test_views_delegate.h",
+
+    # TODO(jamescook): Rename to TestChildModalWindow and move to //ash/wm
+    "test/child_modal_window.cc",
+    "test/child_modal_window.h",
+
+    # TODO(jamescook): Create //ash/accessibility for this and other code.
+    "test/test_accessibility_delegate.cc",
+    "test/test_accessibility_delegate.h",
+    "test/ui_controls_factory_ash.cc",
+    "test/ui_controls_factory_ash.h",
+    "test_screenshot_delegate.cc",
+    "test_screenshot_delegate.h",
+    "test_shell_delegate.cc",
+    "test_shell_delegate.h",
+    "wallpaper/test_wallpaper_delegate.cc",
+    "wallpaper/test_wallpaper_delegate.h",
+    "wallpaper/wallpaper_controller_test_api.cc",
+    "wallpaper/wallpaper_controller_test_api.h",
+    "wm/cursor_manager_test_api.cc",
+    "wm/cursor_manager_test_api.h",
+    "wm/lock_state_controller_test_api.cc",
+    "wm/lock_state_controller_test_api.h",
+    "wm/test_activation_delegate.cc",
+    "wm/test_activation_delegate.h",
+    "wm/test_overlay_delegate.cc",
+    "wm/test_overlay_delegate.h",
+    "wm/test_session_state_animator.cc",
+    "wm/test_session_state_animator.h",
+    "wm/workspace/workspace_event_handler_test_helper.cc",
+    "wm/workspace/workspace_event_handler_test_helper.h",
+    "wm/workspace_controller_test_api.cc",
+    "wm/workspace_controller_test_api.h",
+  ]
+  configs += [ "//build/config:precompiled_headers" ]
+
+  public_deps = [
+    "//ash",
+    "//testing/gtest",
+    "//third_party/WebKit/public:blink_headers",
+    "//ui/display:display_manager_test_api",
+  ]
+  deps = [
+    "//ash",
+    "//ash/mus:lib",
+    "//ash/public/cpp:ash_public_cpp",
+    "//ash/resources",
+    "//base",
+    "//base:i18n",
+    "//base/test:test_support",
+    "//chromeos",
+    "//components/prefs:test_support",
+    "//components/signin/core/account_id",
+    "//components/user_manager:user_manager",
+    "//device/bluetooth",
+    "//services/ui/public/cpp/input_devices",
+    "//services/ui/public/interfaces",
+    "//skia",
+    "//testing/gtest",
+    "//ui/accessibility",
+    "//ui/app_list:test_support",
+    "//ui/app_list/presenter",
+    "//ui/app_list/presenter:test_support",
+    "//ui/aura",
+    "//ui/aura:test_support",
+    "//ui/base:test_support",
+    "//ui/compositor:test_support",
+    "//ui/display",
+    "//ui/display/types",
+    "//ui/events:events_base",
+    "//ui/events:test_support",
+    "//ui/events/devices",
+    "//ui/gl",
+    "//ui/gl:test_support",
+    "//ui/keyboard",
+    "//ui/message_center",
+    "//ui/views",
+    "//ui/views:test_support",
+    "//ui/wm",
+    "//ui/wm/public",
+  ]
+
+  if (use_x11) {
+    deps += [ "//ui/gfx/x" ]
+  }
+}
+
+static_library("interactive_ui_test_support") {
+  testonly = true
+  configs += [ "//build/config:precompiled_headers" ]
+  public_deps = [
+    ":test_support_without_content",
+    "//ash",
+  ]
+  sources = [
+    "test/ash_interactive_ui_test_base.cc",
+    "test/ash_interactive_ui_test_base.h",
+  ]
+  deps = [
+    ":test_support_with_content",
+    "//base",
+    "//skia",
+    "//testing/gtest",
+    "//ui/aura",
+    "//ui/base",
+    "//ui/gl:test_support",
+  ]
+}
diff --git a/ash/README.md b/ash/README.md
index d32a76c..556766a0 100644
--- a/ash/README.md
+++ b/ash/README.md
@@ -18,6 +18,10 @@
 from AshTestBase. This is often needed to test code that depends on ash::Shell
 and the controllers it owns.
 
+Test support code (TestFooDelegate, FooControllerTestApi, etc.) lives in the
+same directory as the class under test (e.g. //ash/foo rather than //ash/test).
+Test code uses namespace ash; there is no special "test" namespace.
+
 Mus+ash
 ----------
 Ash is transitioning to use the mus window server and gpu process, found in
diff --git a/ash/accelerators/accelerator_controller.cc b/ash/accelerators/accelerator_controller.cc
index 438bedbe..c762d18 100644
--- a/ash/accelerators/accelerator_controller.cc
+++ b/ash/accelerators/accelerator_controller.cc
@@ -380,7 +380,7 @@
     WebNotificationTray* notification_tray =
         status_area_widget->web_notification_tray();
     if (notification_tray->visible())
-      notification_tray->ShowMessageCenterBubble();
+      notification_tray->ShowBubble();
   }
 }
 
@@ -512,8 +512,8 @@
   if (status_area_widget) {
     ImeMenuTray* ime_menu_tray = status_area_widget->ime_menu_tray();
     if (ime_menu_tray && ime_menu_tray->visible() &&
-        !ime_menu_tray->IsImeMenuBubbleShown()) {
-      ime_menu_tray->ShowImeMenuBubble();
+        !ime_menu_tray->GetBubbleView()) {
+      ime_menu_tray->ShowBubble();
     }
   }
 }
@@ -572,7 +572,7 @@
   Shelf::ForWindow(Shell::GetRootWindowForNewWindows())
       ->GetStatusAreaWidget()
       ->palette_tray()
-      ->ShowPalette();
+      ->ShowBubble();
 }
 
 bool CanHandleShowStylusTools() {
@@ -590,6 +590,9 @@
   } else if (accelerator.IsCmdDown() && accelerator.key_code() == ui::VKEY_A) {
     base::RecordAction(
         base::UserMetricsAction("VoiceInteraction.Started.Search_A"));
+  } else if (accelerator.key_code() == ui::VKEY_ASSISTANT) {
+    base::RecordAction(
+        base::UserMetricsAction("VoiceInteraction.Started.Assistant"));
   }
   Shell::Get()->app_list()->StartVoiceInteractionSession();
 }
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc
index 5f7e460..e37a3bc 100644
--- a/ash/accelerators/accelerator_controller_unittest.cc
+++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -19,11 +19,11 @@
 #include "ash/system/keyboard_brightness_control_delegate.h"
 #include "ash/system/tray/system_tray_delegate.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/lock_state_controller_test_api.h"
-#include "ash/test/test_screenshot_delegate.h"
-#include "ash/test/test_session_state_animator.h"
+#include "ash/test_screenshot_delegate.h"
 #include "ash/wm/lock_state_controller.h"
+#include "ash/wm/lock_state_controller_test_api.h"
 #include "ash/wm/panels/panel_layout_manager.h"
+#include "ash/wm/test_session_state_animator.h"
 #include "ash/wm/window_positioning_utils.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
diff --git a/ash/accelerators/accelerator_filter_unittest.cc b/ash/accelerators/accelerator_filter_unittest.cc
index 4adaefa..782080f 100644
--- a/ash/accelerators/accelerator_filter_unittest.cc
+++ b/ash/accelerators/accelerator_filter_unittest.cc
@@ -14,7 +14,7 @@
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/ash_test_helper.h"
-#include "ash/test/test_screenshot_delegate.h"
+#include "ash/test_screenshot_delegate.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/ash/accelerators/accelerator_interactive_uitest_chromeos.cc b/ash/accelerators/accelerator_interactive_uitest_chromeos.cc
index f0d7ba6..d38ccb6 100644
--- a/ash/accelerators/accelerator_interactive_uitest_chromeos.cc
+++ b/ash/accelerators/accelerator_interactive_uitest_chromeos.cc
@@ -10,7 +10,7 @@
 #include "ash/system/tray/system_tray_delegate.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "ash/test/ash_interactive_ui_test_base.h"
-#include "ash/test/test_screenshot_delegate.h"
+#include "ash/test_screenshot_delegate.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "base/run_loop.h"
diff --git a/ash/app_list/app_list_presenter_delegate_unittest.cc b/ash/app_list/app_list_presenter_delegate_unittest.cc
index 0ec12afd..47931f8 100644
--- a/ash/app_list/app_list_presenter_delegate_unittest.cc
+++ b/ash/app_list/app_list_presenter_delegate_unittest.cc
@@ -4,6 +4,7 @@
 
 #include <memory>
 
+#include "ash/app_list/test_app_list_view_presenter_impl.h"
 #include "ash/ash_switches.h"
 #include "ash/public/cpp/config.h"
 #include "ash/public/cpp/shelf_types.h"
@@ -13,7 +14,6 @@
 #include "ash/shell.h"
 #include "ash/shell_port.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/test_app_list_view_presenter_impl.h"
 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/wm/window_util.h"
 #include "base/command_line.h"
diff --git a/ash/test/test_app_list_view_presenter_impl.cc b/ash/app_list/test_app_list_view_presenter_impl.cc
similarity index 91%
rename from ash/test/test_app_list_view_presenter_impl.cc
rename to ash/app_list/test_app_list_view_presenter_impl.cc
index 4692af7..5437ed9 100644
--- a/ash/test/test_app_list_view_presenter_impl.cc
+++ b/ash/app_list/test_app_list_view_presenter_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 "ash/test/test_app_list_view_presenter_impl.h"
+#include "ash/app_list/test_app_list_view_presenter_impl.h"
 
 #include "ash/app_list/app_list_presenter_delegate_factory.h"
 #include "base/memory/ptr_util.h"
diff --git a/ash/test/test_app_list_view_presenter_impl.h b/ash/app_list/test_app_list_view_presenter_impl.h
similarity index 79%
rename from ash/test/test_app_list_view_presenter_impl.h
rename to ash/app_list/test_app_list_view_presenter_impl.h
index b1b3a3c..58046ee 100644
--- a/ash/test/test_app_list_view_presenter_impl.h
+++ b/ash/app_list/test_app_list_view_presenter_impl.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 ASH_TEST_TEST_APP_LIST_VIEW_PRESENTER_IMPL_H_
-#define ASH_TEST_TEST_APP_LIST_VIEW_PRESENTER_IMPL_H_
+#ifndef ASH_APP_LIST_TEST_APP_LIST_VIEW_PRESENTER_IMPL_H_
+#define ASH_APP_LIST_TEST_APP_LIST_VIEW_PRESENTER_IMPL_H_
 
 #include "ash/ash_export.h"
 #include "base/macros.h"
@@ -24,4 +24,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_TEST_APP_LIST_VIEW_PRESENTER_IMPL_H_
+#endif  // ASH_APP_LIST_TEST_APP_LIST_VIEW_PRESENTER_IMPL_H_
diff --git a/ash/content/display/screen_orientation_controller_chromeos_unittest.cc b/ash/content/display/screen_orientation_controller_chromeos_unittest.cc
index a66527f..1d4c5ef 100644
--- a/ash/content/display/screen_orientation_controller_chromeos_unittest.cc
+++ b/ash/content/display/screen_orientation_controller_chromeos_unittest.cc
@@ -10,6 +10,7 @@
 #include "ash/ash_switches.h"
 #include "ash/content/shell_content_state.h"
 #include "ash/display/screen_orientation_controller_chromeos.h"
+#include "ash/display/screen_orientation_controller_test_api.h"
 #include "ash/public/cpp/app_types.h"
 #include "ash/shell.h"
 #include "ash/system/screen_layout_observer.h"
@@ -17,8 +18,7 @@
 #include "ash/test/ash_test_environment_content.h"
 #include "ash/test/ash_test_helper.h"
 #include "ash/test/content/test_shell_content_state.h"
-#include "ash/test/screen_orientation_controller_test_api.h"
-#include "ash/test/test_shell_delegate.h"
+#include "ash/test_shell_delegate.h"
 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/wm/window_state.h"
 #include "base/command_line.h"
diff --git a/ash/display/DEPS b/ash/display/DEPS
index 66bd25d..5ca4b3a5 100644
--- a/ash/display/DEPS
+++ b/ash/display/DEPS
@@ -6,7 +6,7 @@
   "display_color_manager_chromeos.cc": [
     "+third_party/qcms/src/qcms.h",
   ],
-  "screen_orientation_controller_chromeos.h": [
+  "screen_orientation_controller_(chromeos|test_api)\.h": [
     "+third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h",
   ],
 }
diff --git a/ash/test/display_configuration_controller_test_api.cc b/ash/display/display_configuration_controller_test_api.cc
similarity index 91%
rename from ash/test/display_configuration_controller_test_api.cc
rename to ash/display/display_configuration_controller_test_api.cc
index 3035afe..8764ae0 100644
--- a/ash/test/display_configuration_controller_test_api.cc
+++ b/ash/display/display_configuration_controller_test_api.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 "ash/test/display_configuration_controller_test_api.h"
+#include "ash/display/display_configuration_controller_test_api.h"
 
 #include "ash/display/display_configuration_controller.h"
 
diff --git a/ash/test/display_configuration_controller_test_api.h b/ash/display/display_configuration_controller_test_api.h
similarity index 81%
rename from ash/test/display_configuration_controller_test_api.h
rename to ash/display/display_configuration_controller_test_api.h
index c0f5628..0738b50 100644
--- a/ash/test/display_configuration_controller_test_api.h
+++ b/ash/display/display_configuration_controller_test_api.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 ASH_TEST_DISPLAY_CONFIGURATION_CONTROLLER_TEST_API_H_
-#define ASH_TEST_DISPLAY_CONFIGURATION_CONTROLLER_TEST_API_H_
+#ifndef ASH_DISPLAY_DISPLAY_CONFIGURATION_CONTROLLER_TEST_API_H_
+#define ASH_DISPLAY_DISPLAY_CONFIGURATION_CONTROLLER_TEST_API_H_
 
 #include <stdint.h>
 
@@ -32,4 +32,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_DISPLAY_CONFIGURATION_CONTROLLER_TEST_API_H_
+#endif  // ASH_DISPLAY_DISPLAY_CONFIGURATION_CONTROLLER_TEST_API_H_
diff --git a/ash/display/display_configuration_controller_unittest.cc b/ash/display/display_configuration_controller_unittest.cc
index fb49736..b491db751 100644
--- a/ash/display/display_configuration_controller_unittest.cc
+++ b/ash/display/display_configuration_controller_unittest.cc
@@ -5,11 +5,11 @@
 #include "ash/display/display_configuration_controller.h"
 
 #include "ash/ash_switches.h"
+#include "ash/display/display_configuration_controller_test_api.h"
 #include "ash/public/cpp/config.h"
 #include "ash/rotator/screen_rotation_animator.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/display_configuration_controller_test_api.h"
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "ui/display/manager/display_manager.h"
diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc
index 45c7d49..c9bba9f 100644
--- a/ash/display/display_manager_unittest.cc
+++ b/ash/display/display_manager_unittest.cc
@@ -9,15 +9,15 @@
 #include "ash/display/display_configuration_controller.h"
 #include "ash/display/display_util.h"
 #include "ash/display/mirror_window_controller.h"
+#include "ash/display/mirror_window_test_api.h"
 #include "ash/display/screen_orientation_controller_chromeos.h"
+#include "ash/display/screen_orientation_controller_test_api.h"
 #include "ash/display/window_tree_host_manager.h"
 #include "ash/public/cpp/app_types.h"
 #include "ash/screen_util.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/mirror_window_test_api.h"
-#include "ash/test/screen_orientation_controller_test_api.h"
 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
diff --git a/ash/display/mirror_window_controller_unittest.cc b/ash/display/mirror_window_controller_unittest.cc
index cbd1747..b556071 100644
--- a/ash/display/mirror_window_controller_unittest.cc
+++ b/ash/display/mirror_window_controller_unittest.cc
@@ -4,11 +4,11 @@
 
 #include "ash/display/mirror_window_controller.h"
 
+#include "ash/display/mirror_window_test_api.h"
 #include "ash/display/window_tree_host_manager.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/cursor_manager_test_api.h"
-#include "ash/test/mirror_window_test_api.h"
+#include "ash/wm/cursor_manager_test_api.h"
 #include "base/command_line.h"
 #include "base/strings/stringprintf.h"
 #include "ui/aura/env.h"
diff --git a/ash/test/mirror_window_test_api.cc b/ash/display/mirror_window_test_api.cc
similarity index 97%
rename from ash/test/mirror_window_test_api.cc
rename to ash/display/mirror_window_test_api.cc
index dbae7ef9..982b88e 100644
--- a/ash/test/mirror_window_test_api.cc
+++ b/ash/display/mirror_window_test_api.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 "ash/test/mirror_window_test_api.h"
+#include "ash/display/mirror_window_test_api.h"
 
 #include "ash/display/cursor_window_controller.h"
 #include "ash/display/mirror_window_controller.h"
diff --git a/ash/test/mirror_window_test_api.h b/ash/display/mirror_window_test_api.h
similarity index 86%
rename from ash/test/mirror_window_test_api.h
rename to ash/display/mirror_window_test_api.h
index a9a0d23b..ed951c8 100644
--- a/ash/test/mirror_window_test_api.h
+++ b/ash/display/mirror_window_test_api.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_TEST_MIRROR_WINDOW_TEST_API_H_
-#define ASH_TEST_MIRROR_WINDOW_TEST_API_H_
+#ifndef ASH_DISPLAY_MIRROR_WINDOW_TEST_API_H_
+#define ASH_DISPLAY_MIRROR_WINDOW_TEST_API_H_
 
 #include "base/macros.h"
 
 namespace aura {
 class Window;
 class WindowTreeHost;
-}
+}  // namespace aura
 
 namespace gfx {
 class Point;
@@ -48,4 +48,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_MIRROR_WINDOW_TEST_API_H_
+#endif  // ASH_DISPLAY_MIRROR_WINDOW_TEST_API_H_
diff --git a/ash/display/mouse_cursor_event_filter_unittest.cc b/ash/display/mouse_cursor_event_filter_unittest.cc
index 83566d50..1e3eeb54 100644
--- a/ash/display/mouse_cursor_event_filter_unittest.cc
+++ b/ash/display/mouse_cursor_event_filter_unittest.cc
@@ -6,7 +6,7 @@
 
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/cursor_manager_test_api.h"
+#include "ash/wm/cursor_manager_test_api.h"
 #include "ui/aura/env.h"
 #include "ui/display/display_layout.h"
 #include "ui/display/manager/display_manager.h"
diff --git a/ash/display/root_window_transformers_unittest.cc b/ash/display/root_window_transformers_unittest.cc
index e841a807..301845fa 100644
--- a/ash/display/root_window_transformers_unittest.cc
+++ b/ash/display/root_window_transformers_unittest.cc
@@ -7,14 +7,14 @@
 #include <memory>
 
 #include "ash/display/display_util.h"
+#include "ash/display/mirror_window_test_api.h"
 #include "ash/host/root_window_transformer.h"
 #include "ash/magnifier/magnification_controller.h"
 #include "ash/screen_util.h"
 #include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/cursor_manager_test_api.h"
-#include "ash/test/mirror_window_test_api.h"
+#include "ash/wm/cursor_manager_test_api.h"
 #include "base/synchronization/waitable_event.h"
 #include "ui/aura/env.h"
 #include "ui/aura/window_event_dispatcher.h"
diff --git a/ash/test/screen_orientation_controller_test_api.cc b/ash/display/screen_orientation_controller_test_api.cc
similarity index 93%
rename from ash/test/screen_orientation_controller_test_api.cc
rename to ash/display/screen_orientation_controller_test_api.cc
index a4a8ef1..78a1f4e 100644
--- a/ash/test/screen_orientation_controller_test_api.cc
+++ b/ash/display/screen_orientation_controller_test_api.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 "ash/test/screen_orientation_controller_test_api.h"
+#include "ash/display/screen_orientation_controller_test_api.h"
 
 #include "ash/display/screen_orientation_controller_chromeos.h"
 
diff --git a/ash/test/screen_orientation_controller_test_api.h b/ash/display/screen_orientation_controller_test_api.h
similarity index 83%
rename from ash/test/screen_orientation_controller_test_api.h
rename to ash/display/screen_orientation_controller_test_api.h
index d6bab86..7eae2a8 100644
--- a/ash/test/screen_orientation_controller_test_api.h
+++ b/ash/display/screen_orientation_controller_test_api.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 ASH_TEST_SCREEN_ORIENTATION_CONTROLLER_TEST_API_H_
-#define ASH_TEST_SCREEN_ORIENTATION_CONTROLLER_TEST_API_H_
+#ifndef ASH_DISPLAY_SCREEN_ORIENTATION_CONTROLLER_TEST_API_H_
+#define ASH_DISPLAY_SCREEN_ORIENTATION_CONTROLLER_TEST_API_H_
 
 #include "base/macros.h"
 #include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h"
@@ -34,4 +34,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_SCREEN_ORIENTATION_CONTROLLER_TEST_API_H_
+#endif  // ASH_DISPLAY_SCREEN_ORIENTATION_CONTROLLER_TEST_API_H_
diff --git a/ash/display/screen_position_controller_unittest.cc b/ash/display/screen_position_controller_unittest.cc
index d3b4e33..312b567 100644
--- a/ash/display/screen_position_controller_unittest.cc
+++ b/ash/display/screen_position_controller_unittest.cc
@@ -9,8 +9,8 @@
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/screen_util.h"
 #include "ash/shell.h"
+#include "ash/shell_test_api.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/shell_test_api.h"
 #include "ui/aura/env.h"
 #include "ui/aura/test/test_window_delegate.h"
 #include "ui/aura/window_tracker.h"
diff --git a/ash/display/window_tree_host_manager_unittest.cc b/ash/display/window_tree_host_manager_unittest.cc
index 3bac9692..3bdfc34d 100644
--- a/ash/display/window_tree_host_manager_unittest.cc
+++ b/ash/display/window_tree_host_manager_unittest.cc
@@ -13,8 +13,8 @@
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/ash_test_helper.h"
-#include "ash/test/cursor_manager_test_api.h"
-#include "ash/test/test_shell_delegate.h"
+#include "ash/test_shell_delegate.h"
+#include "ash/wm/cursor_manager_test_api.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/wm_event.h"
 #include "base/command_line.h"
diff --git a/ash/test/test_keyboard_ui.cc b/ash/keyboard/test_keyboard_ui.cc
similarity index 96%
rename from ash/test/test_keyboard_ui.cc
rename to ash/keyboard/test_keyboard_ui.cc
index 375a9b16..69669bf 100644
--- a/ash/test/test_keyboard_ui.cc
+++ b/ash/keyboard/test_keyboard_ui.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 "ash/test/test_keyboard_ui.h"
+#include "ash/keyboard/test_keyboard_ui.h"
 
 #include "ash/shell.h"
 #include "ash/wm/window_util.h"
diff --git a/ash/test/test_keyboard_ui.h b/ash/keyboard/test_keyboard_ui.h
similarity index 89%
rename from ash/test/test_keyboard_ui.h
rename to ash/keyboard/test_keyboard_ui.h
index aab17d0..4cd2db6 100644
--- a/ash/test/test_keyboard_ui.h
+++ b/ash/keyboard/test_keyboard_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 ASH_TEST_TEST_KEYBOARD_UI_H_
-#define ASH_TEST_TEST_KEYBOARD_UI_H_
+#ifndef ASH_KEYBOARD_TEST_KEYBOARD_UI_H_
+#define ASH_KEYBOARD_TEST_KEYBOARD_UI_H_
 
 #include <memory>
 
@@ -41,4 +41,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_TEST_KEYBOARD_UI_H_
+#endif  // ASH_KEYBOARD_TEST_KEYBOARD_UI_H_
diff --git a/ash/test/task_switch_time_tracker_test_api.cc b/ash/metrics/task_switch_time_tracker_test_api.cc
similarity index 93%
rename from ash/test/task_switch_time_tracker_test_api.cc
rename to ash/metrics/task_switch_time_tracker_test_api.cc
index 7ba1238..c26ec6a 100644
--- a/ash/test/task_switch_time_tracker_test_api.cc
+++ b/ash/metrics/task_switch_time_tracker_test_api.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 "ash/test/task_switch_time_tracker_test_api.h"
+#include "ash/metrics/task_switch_time_tracker_test_api.h"
 
 #include "ash/metrics/task_switch_time_tracker.h"
 #include "base/test/simple_test_tick_clock.h"
diff --git a/ash/test/task_switch_time_tracker_test_api.h b/ash/metrics/task_switch_time_tracker_test_api.h
similarity index 87%
rename from ash/test/task_switch_time_tracker_test_api.h
rename to ash/metrics/task_switch_time_tracker_test_api.h
index 62156fbc..7468ac6 100644
--- a/ash/test/task_switch_time_tracker_test_api.h
+++ b/ash/metrics/task_switch_time_tracker_test_api.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 ASH_TEST_TASK_SWITCH_TIME_TRACKER_TEST_API_H_
-#define ASH_TEST_TASK_SWITCH_TIME_TRACKER_TEST_API_H_
+#ifndef ASH_METRICS_TASK_SWITCH_TIME_TRACKER_TEST_API_H_
+#define ASH_METRICS_TASK_SWITCH_TIME_TRACKER_TEST_API_H_
 
 #include <memory>
 #include <string>
@@ -48,4 +48,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_TASK_SWITCH_TIME_TRACKER_TEST_API_H_
+#endif  // ASH_METRICS_TASK_SWITCH_TIME_TRACKER_TEST_API_H_
diff --git a/ash/metrics/task_switch_time_tracker_unittest.cc b/ash/metrics/task_switch_time_tracker_unittest.cc
index 9b6c909..857dfd8 100644
--- a/ash/metrics/task_switch_time_tracker_unittest.cc
+++ b/ash/metrics/task_switch_time_tracker_unittest.cc
@@ -6,7 +6,7 @@
 
 #include <string>
 
-#include "ash/test/task_switch_time_tracker_test_api.h"
+#include "ash/metrics/task_switch_time_tracker_test_api.h"
 #include "base/test/histogram_tester.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/ash/test/user_metrics_recorder_test_api.cc b/ash/metrics/user_metrics_recorder_test_api.cc
similarity index 91%
rename from ash/test/user_metrics_recorder_test_api.cc
rename to ash/metrics/user_metrics_recorder_test_api.cc
index 2bdd6f2c..cc38422 100644
--- a/ash/test/user_metrics_recorder_test_api.cc
+++ b/ash/metrics/user_metrics_recorder_test_api.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 "ash/test/user_metrics_recorder_test_api.h"
+#include "ash/metrics/user_metrics_recorder_test_api.h"
 
 namespace ash {
 
diff --git a/ash/test/user_metrics_recorder_test_api.h b/ash/metrics/user_metrics_recorder_test_api.h
similarity index 83%
rename from ash/test/user_metrics_recorder_test_api.h
rename to ash/metrics/user_metrics_recorder_test_api.h
index acaa2ca7..0e1111b7 100644
--- a/ash/test/user_metrics_recorder_test_api.h
+++ b/ash/metrics/user_metrics_recorder_test_api.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 ASH_TEST_USER_METRICS_RECORDER_TEST_API_H_
-#define ASH_TEST_USER_METRICS_RECORDER_TEST_API_H_
+#ifndef ASH_METRICS_USER_METRICS_RECORDER_TEST_API_H_
+#define ASH_METRICS_USER_METRICS_RECORDER_TEST_API_H_
 
 #include "ash/metrics/user_metrics_recorder.h"
 #include "base/macros.h"
@@ -31,4 +31,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_USER_METRICS_RECORDER_TEST_API_H_
+#endif  // ASH_METRICS_USER_METRICS_RECORDER_TEST_API_H_
diff --git a/ash/metrics/user_metrics_recorder_unittest.cc b/ash/metrics/user_metrics_recorder_unittest.cc
index c67d5364..3d3f86c 100644
--- a/ash/metrics/user_metrics_recorder_unittest.cc
+++ b/ash/metrics/user_metrics_recorder_unittest.cc
@@ -7,13 +7,13 @@
 #include <memory>
 
 #include "ash/login_status.h"
+#include "ash/metrics/user_metrics_recorder_test_api.h"
 #include "ash/public/cpp/config.h"
 #include "ash/public/cpp/shelf_model.h"
 #include "ash/session/session_controller.h"
+#include "ash/session/test_session_controller_client.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/test_session_controller_client.h"
-#include "ash/test/user_metrics_recorder_test_api.h"
 #include "base/test/histogram_tester.h"
 
 using session_manager::SessionState;
diff --git a/ash/mus/BUILD.gn b/ash/mus/BUILD.gn
index 4c34f846..f990801f6 100644
--- a/ash/mus/BUILD.gn
+++ b/ash/mus/BUILD.gn
@@ -206,8 +206,8 @@
     ":lib",
     ":resources",
     "//ash",
+    "//ash:test_support_without_content",
     "//ash/public/cpp:ash_public_cpp",
-    "//ash/test:test_support_without_content",
     "//base",
     "//base/test:test_config",
     "//base/test:test_support",
diff --git a/ash/palette_delegate.h b/ash/palette_delegate.h
index 8f370d6b..1051328 100644
--- a/ash/palette_delegate.h
+++ b/ash/palette_delegate.h
@@ -15,6 +15,7 @@
 
 // This delegate allows the UI code in ash, e.g. |PaletteTray|, to perform
 // Chrome-specific actions.
+// TODO(jamescook): Move this to //ash/system/palette.
 class PaletteDelegate {
  public:
   using EnableListener = base::Callback<void(bool)>;
diff --git a/ash/test/immersive_fullscreen_controller_test_api.cc b/ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.cc
similarity index 94%
rename from ash/test/immersive_fullscreen_controller_test_api.cc
rename to ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.cc
index 5db39abf..c00cf023 100644
--- a/ash/test/immersive_fullscreen_controller_test_api.cc
+++ b/ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.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 "ash/test/immersive_fullscreen_controller_test_api.h"
+#include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h"
 
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller.h"
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller_delegate.h"
diff --git a/ash/test/immersive_fullscreen_controller_test_api.h b/ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h
similarity index 77%
rename from ash/test/immersive_fullscreen_controller_test_api.h
rename to ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h
index f5ca9a1c..4ebe13f3 100644
--- a/ash/test/immersive_fullscreen_controller_test_api.h
+++ b/ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.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 ASH_TEST_IMMERSIVE_FULLSCREEN_CONTROLLER_TEST_API_H_
-#define ASH_TEST_IMMERSIVE_FULLSCREEN_CONTROLLER_TEST_API_H_
+#ifndef ASH_PUBLIC_CPP_IMMERSIVE_IMMERSIVE_FULLSCREEN_CONTROLLER_TEST_API_H_
+#define ASH_PUBLIC_CPP_IMMERSIVE_IMMERSIVE_FULLSCREEN_CONTROLLER_TEST_API_H_
 
 #include "base/macros.h"
 
@@ -30,4 +30,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_IMMERSIVE_FULLSCREEN_CONTROLLER_TEST_API_H_
+#endif  // ASH_PUBLIC_CPP_IMMERSIVE_IMMERSIVE_FULLSCREEN_CONTROLLER_TEST_API_H_
diff --git a/ash/root_window_controller_unittest.cc b/ash/root_window_controller_unittest.cc
index 84807f5..ce7e1d6 100644
--- a/ash/root_window_controller_unittest.cc
+++ b/ash/root_window_controller_unittest.cc
@@ -9,9 +9,9 @@
 #include "ash/public/cpp/config.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/session/session_controller.h"
+#include "ash/session/test_session_controller_client.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/test_session_controller_client.h"
 #include "ash/wm/system_modal_container_layout_manager.h"
 #include "ash/wm/window_properties.h"
 #include "ash/wm/window_state.h"
diff --git a/ash/rotator/screen_rotation_animator.cc b/ash/rotator/screen_rotation_animator.cc
index 31cae7a..1c88f98 100644
--- a/ash/rotator/screen_rotation_animator.cc
+++ b/ash/rotator/screen_rotation_animator.cc
@@ -246,19 +246,19 @@
 ScreenRotationAnimator::CopyCallback
 ScreenRotationAnimator::CreateAfterCopyCallbackBeforeRotation(
     std::unique_ptr<ScreenRotationRequest> rotation_request) {
-  return base::Bind(&ScreenRotationAnimator::
-                        OnScreenRotationContainerLayerCopiedBeforeRotation,
-                    weak_factory_.GetWeakPtr(),
-                    base::Passed(&rotation_request));
+  return base::BindOnce(&ScreenRotationAnimator::
+                            OnScreenRotationContainerLayerCopiedBeforeRotation,
+                        weak_factory_.GetWeakPtr(),
+                        base::Passed(&rotation_request));
 }
 
 ScreenRotationAnimator::CopyCallback
 ScreenRotationAnimator::CreateAfterCopyCallbackAfterRotation(
     std::unique_ptr<ScreenRotationRequest> rotation_request) {
-  return base::Bind(&ScreenRotationAnimator::
-                        OnScreenRotationContainerLayerCopiedAfterRotation,
-                    weak_factory_.GetWeakPtr(),
-                    base::Passed(&rotation_request));
+  return base::BindOnce(&ScreenRotationAnimator::
+                            OnScreenRotationContainerLayerCopiedAfterRotation,
+                        weak_factory_.GetWeakPtr(),
+                        base::Passed(&rotation_request));
 }
 
 void ScreenRotationAnimator::OnScreenRotationContainerLayerCopiedBeforeRotation(
diff --git a/ash/rotator/screen_rotation_animator.h b/ash/rotator/screen_rotation_animator.h
index 23b0ddb..04db364 100644
--- a/ash/rotator/screen_rotation_animator.h
+++ b/ash/rotator/screen_rotation_animator.h
@@ -67,7 +67,7 @@
 
  protected:
   using CopyCallback =
-      base::Callback<void(std::unique_ptr<cc::CopyOutputResult> result)>;
+      base::OnceCallback<void(std::unique_ptr<cc::CopyOutputResult> result)>;
   struct ScreenRotationRequest {
     ScreenRotationRequest(int64_t id,
                           int64_t display_id,
diff --git a/ash/rotator/test/screen_rotation_animator_test_api.cc b/ash/rotator/screen_rotation_animator_test_api.cc
similarity index 94%
rename from ash/rotator/test/screen_rotation_animator_test_api.cc
rename to ash/rotator/screen_rotation_animator_test_api.cc
index 30aa67b0..7860876e 100644
--- a/ash/rotator/test/screen_rotation_animator_test_api.cc
+++ b/ash/rotator/screen_rotation_animator_test_api.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 "ash/rotator/test/screen_rotation_animator_test_api.h"
+#include "ash/rotator/screen_rotation_animator_test_api.h"
 
 #include "ash/rotator/screen_rotation_animator.h"
 #include "ui/compositor/layer.h"
diff --git a/ash/rotator/test/screen_rotation_animator_test_api.h b/ash/rotator/screen_rotation_animator_test_api.h
similarity index 87%
rename from ash/rotator/test/screen_rotation_animator_test_api.h
rename to ash/rotator/screen_rotation_animator_test_api.h
index 2fdf3c1e..74158f4 100644
--- a/ash/rotator/test/screen_rotation_animator_test_api.h
+++ b/ash/rotator/screen_rotation_animator_test_api.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 ASH_ROTATOR_TEST_SCREEN_ROTATION_ANIMATOR_TEST_API_H_
-#define ASH_ROTATOR_TEST_SCREEN_ROTATION_ANIMATOR_TEST_API_H_
+#ifndef ASH_ROTATOR_SCREEN_ROTATION_ANIMATOR_TEST_API_H_
+#define ASH_ROTATOR_SCREEN_ROTATION_ANIMATOR_TEST_API_H_
 
 #include <stdint.h>
 
@@ -43,4 +43,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_ROTATOR_TEST_SCREEN_ROTATION_ANIMATOR_TEST_API_H_
+#endif  // ASH_ROTATOR_SCREEN_ROTATION_ANIMATOR_TEST_API_H_
diff --git a/ash/rotator/screen_rotation_animator_unittest.cc b/ash/rotator/screen_rotation_animator_unittest.cc
index 1949dce..15bd582 100644
--- a/ash/rotator/screen_rotation_animator_unittest.cc
+++ b/ash/rotator/screen_rotation_animator_unittest.cc
@@ -8,13 +8,13 @@
 #include "ash/display/window_tree_host_manager.h"
 #include "ash/public/cpp/config.h"
 #include "ash/rotator/screen_rotation_animator_observer.h"
-#include "ash/rotator/test/screen_rotation_animator_test_api.h"
+#include "ash/rotator/screen_rotation_animator_test_api.h"
 #include "ash/shell.h"
 #include "ash/system/overview/overview_button_tray.h"
 #include "ash/system/status_area_widget.h"
+#include "ash/system/status_area_widget_test_helper.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/ash_test_helper.h"
-#include "ash/test/status_area_widget_test_helper.h"
 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
 #include "base/callback_forward.h"
 #include "base/command_line.h"
@@ -106,8 +106,8 @@
   CopyCallback next_callback =
       ScreenRotationAnimator::CreateAfterCopyCallbackBeforeRotation(
           std::move(rotation_request));
-  return base::Bind(&TestScreenRotationAnimator::IntersectBefore,
-                    base::Unretained(this), next_callback);
+  return base::BindOnce(&TestScreenRotationAnimator::IntersectBefore,
+                        base::Unretained(this), std::move(next_callback));
 }
 
 ScreenRotationAnimator::CopyCallback
@@ -116,22 +116,22 @@
   CopyCallback next_callback =
       ScreenRotationAnimator::CreateAfterCopyCallbackAfterRotation(
           std::move(rotation_request));
-  return base::Bind(&TestScreenRotationAnimator::IntersectAfter,
-                    base::Unretained(this), next_callback);
+  return base::BindOnce(&TestScreenRotationAnimator::IntersectAfter,
+                        base::Unretained(this), std::move(next_callback));
 }
 
 void TestScreenRotationAnimator::IntersectBefore(
     CopyCallback next_callback,
     std::unique_ptr<cc::CopyOutputResult> result) {
   intersect_before_callback_.Run();
-  next_callback.Run(std::move(result));
+  std::move(next_callback).Run(std::move(result));
 }
 
 void TestScreenRotationAnimator::IntersectAfter(
     CopyCallback next_callback,
     std::unique_ptr<cc::CopyOutputResult> result) {
   intersect_after_callback_.Run();
-  next_callback.Run(std::move(result));
+  std::move(next_callback).Run(std::move(result));
 }
 
 }  // namespace
diff --git a/ash/test/test_session_controller_client.cc b/ash/session/test_session_controller_client.cc
similarity index 98%
rename from ash/test/test_session_controller_client.cc
rename to ash/session/test_session_controller_client.cc
index d5308d3..5c88c226 100644
--- a/ash/test/test_session_controller_client.cc
+++ b/ash/session/test_session_controller_client.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 "ash/test/test_session_controller_client.h"
+#include "ash/session/test_session_controller_client.h"
 
 #include <algorithm>
 #include <string>
diff --git a/ash/test/test_session_controller_client.h b/ash/session/test_session_controller_client.h
similarity index 94%
rename from ash/test/test_session_controller_client.h
rename to ash/session/test_session_controller_client.h
index b935294f..97824f03 100644
--- a/ash/test/test_session_controller_client.h
+++ b/ash/session/test_session_controller_client.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 ASH_TEST_TEST_SESSION_CONTROLLER_CLIENT_H_
-#define ASH_TEST_TEST_SESSION_CONTROLLER_CLIENT_H_
+#ifndef ASH_SESSION_TEST_SESSION_CONTROLLER_CLIENT_H_
+#define ASH_SESSION_TEST_SESSION_CONTROLLER_CLIENT_H_
 
 #include <stdint.h>
 
@@ -81,4 +81,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_TEST_SESSION_CONTROLLER_CLIENT_H_
+#endif  // ASH_SESSION_TEST_SESSION_CONTROLLER_CLIENT_H_
diff --git a/ash/test/overflow_bubble_view_test_api.cc b/ash/shelf/overflow_bubble_view_test_api.cc
similarity index 93%
rename from ash/test/overflow_bubble_view_test_api.cc
rename to ash/shelf/overflow_bubble_view_test_api.cc
index f18df467..bdecaa9 100644
--- a/ash/test/overflow_bubble_view_test_api.cc
+++ b/ash/shelf/overflow_bubble_view_test_api.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 "ash/test/overflow_bubble_view_test_api.h"
+#include "ash/shelf/overflow_bubble_view_test_api.h"
 
 #include "ash/shelf/overflow_bubble_view.h"
 
diff --git a/ash/test/overflow_bubble_view_test_api.h b/ash/shelf/overflow_bubble_view_test_api.h
similarity index 85%
rename from ash/test/overflow_bubble_view_test_api.h
rename to ash/shelf/overflow_bubble_view_test_api.h
index 5bfcf74..2adf9aa 100644
--- a/ash/test/overflow_bubble_view_test_api.h
+++ b/ash/shelf/overflow_bubble_view_test_api.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 ASH_TEST_OVERFLOW_BUBBLE_VIEW_TEST_API_
-#define ASH_TEST_OVERFLOW_BUBBLE_VIEW_TEST_API_
+#ifndef ASH_SHELF_OVERFLOW_BUBBLE_VIEW_TEST_API_H_
+#define ASH_SHELF_OVERFLOW_BUBBLE_VIEW_TEST_API_H_
 
 #include "base/macros.h"
 
@@ -41,4 +41,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_OVERFLOW_BUBBLE_VIEW_TEST_API_
+#endif  // ASH_SHELF_OVERFLOW_BUBBLE_VIEW_TEST_API_H_
diff --git a/ash/test/overflow_button_test_api.cc b/ash/shelf/overflow_button_test_api.cc
similarity index 95%
rename from ash/test/overflow_button_test_api.cc
rename to ash/shelf/overflow_button_test_api.cc
index 03443f7..0ad4bef 100644
--- a/ash/test/overflow_button_test_api.cc
+++ b/ash/shelf/overflow_button_test_api.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 "ash/test/overflow_button_test_api.h"
+#include "ash/shelf/overflow_button_test_api.h"
 
 namespace ash {
 namespace {
diff --git a/ash/test/overflow_button_test_api.h b/ash/shelf/overflow_button_test_api.h
similarity index 83%
rename from ash/test/overflow_button_test_api.h
rename to ash/shelf/overflow_button_test_api.h
index 5fd56eb..9c39b5a4 100644
--- a/ash/test/overflow_button_test_api.h
+++ b/ash/shelf/overflow_button_test_api.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 ASH_TEST_OVERFLOW_BUTTON_TEST_API_H_
-#define ASH_TEST_OVERFLOW_BUTTON_TEST_API_H_
+#ifndef ASH_SHELF_OVERFLOW_BUTTON_TEST_API_H_
+#define ASH_SHELF_OVERFLOW_BUTTON_TEST_API_H_
 
 #include <iosfwd>
 
@@ -30,4 +30,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_OVERFLOW_BUTTON_TEST_API_H_
+#endif  // ASH_SHELF_OVERFLOW_BUTTON_TEST_API_H_
diff --git a/ash/test/shelf_button_pressed_metric_tracker_test_api.cc b/ash/shelf/shelf_button_pressed_metric_tracker_test_api.cc
similarity index 91%
rename from ash/test/shelf_button_pressed_metric_tracker_test_api.cc
rename to ash/shelf/shelf_button_pressed_metric_tracker_test_api.cc
index 72f6ad1d..e2bdb029 100644
--- a/ash/test/shelf_button_pressed_metric_tracker_test_api.cc
+++ b/ash/shelf/shelf_button_pressed_metric_tracker_test_api.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 "ash/test/shelf_button_pressed_metric_tracker_test_api.h"
+#include "ash/shelf/shelf_button_pressed_metric_tracker_test_api.h"
 
 #include "base/time/tick_clock.h"
 
diff --git a/ash/test/shelf_button_pressed_metric_tracker_test_api.h b/ash/shelf/shelf_button_pressed_metric_tracker_test_api.h
similarity index 81%
rename from ash/test/shelf_button_pressed_metric_tracker_test_api.h
rename to ash/shelf/shelf_button_pressed_metric_tracker_test_api.h
index ad72040..2dfe192 100644
--- a/ash/test/shelf_button_pressed_metric_tracker_test_api.h
+++ b/ash/shelf/shelf_button_pressed_metric_tracker_test_api.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 ASH_TEST_SHELF_BUTTON_PRESSED_METRIC_TRACKER_TEST_API_H_
-#define ASH_TEST_SHELF_BUTTON_PRESSED_METRIC_TRACKER_TEST_API_H_
+#ifndef ASH_SHELF_SHELF_BUTTON_PRESSED_METRIC_TRACKER_TEST_API_H_
+#define ASH_SHELF_SHELF_BUTTON_PRESSED_METRIC_TRACKER_TEST_API_H_
 
 #include "ash/shelf/shelf_button_pressed_metric_tracker.h"
 
@@ -35,4 +35,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_SHELF_BUTTON_PRESSED_METRIC_TRACKER_TEST_API _H_
+#endif  // ASH_SHELF_SHELF_BUTTON_PRESSED_METRIC_TRACKER_TEST_API_H_
diff --git a/ash/shelf/shelf_button_pressed_metric_tracker_unittest.cc b/ash/shelf/shelf_button_pressed_metric_tracker_unittest.cc
index 5703bbd..8a689c74 100644
--- a/ash/shelf/shelf_button_pressed_metric_tracker_unittest.cc
+++ b/ash/shelf/shelf_button_pressed_metric_tracker_unittest.cc
@@ -8,10 +8,10 @@
 
 #include "ash/public/cpp/config.h"
 #include "ash/shelf/shelf.h"
+#include "ash/shelf/shelf_button_pressed_metric_tracker_test_api.h"
+#include "ash/shelf/shelf_view_test_api.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/shelf_button_pressed_metric_tracker_test_api.h"
-#include "ash/test/shelf_view_test_api.h"
 #include "base/macros.h"
 #include "base/test/histogram_tester.h"
 #include "base/test/simple_test_tick_clock.h"
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc
index 703f119..14c91940 100644
--- a/ash/shelf/shelf_layout_manager_unittest.cc
+++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "ash/accelerators/accelerator_controller.h"
 #include "ash/accelerators/accelerator_table.h"
+#include "ash/app_list/test_app_list_view_presenter_impl.h"
 #include "ash/focus_cycler.h"
 #include "ash/public/cpp/config.h"
 #include "ash/public/cpp/shell_window_ids.h"
@@ -21,9 +22,8 @@
 #include "ash/system/status_area_widget.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_item.h"
+#include "ash/system/tray/test_system_tray_item.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/test_app_list_view_presenter_impl.h"
-#include "ash/test/test_system_tray_item.h"
 #include "ash/wm/lock_state_controller.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
diff --git a/ash/shelf/shelf_tooltip_manager_unittest.cc b/ash/shelf/shelf_tooltip_manager_unittest.cc
index 429ebd0..9923b75 100644
--- a/ash/shelf/shelf_tooltip_manager_unittest.cc
+++ b/ash/shelf/shelf_tooltip_manager_unittest.cc
@@ -9,9 +9,9 @@
 #include "ash/shelf/app_list_button.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_view.h"
+#include "ash/shelf/shelf_view_test_api.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/shelf_view_test_api.h"
 #include "base/memory/ptr_util.h"
 #include "ui/events/event_constants.h"
 #include "ui/events/test/event_generator.h"
diff --git a/ash/shelf/shelf_unittest.cc b/ash/shelf/shelf_unittest.cc
index 6b370cbf..53cbaa7 100644
--- a/ash/shelf/shelf_unittest.cc
+++ b/ash/shelf/shelf_unittest.cc
@@ -8,9 +8,9 @@
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_button.h"
 #include "ash/shelf/shelf_view.h"
+#include "ash/shelf/shelf_view_test_api.h"
 #include "ash/shelf/shelf_widget.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/shelf_view_test_api.h"
 #include "base/strings/string_number_conversions.h"
 
 namespace ash {
diff --git a/ash/test/shelf_view_test_api.cc b/ash/shelf/shelf_view_test_api.cc
similarity index 98%
rename from ash/test/shelf_view_test_api.cc
rename to ash/shelf/shelf_view_test_api.cc
index 7f1dd5c..c19a93de 100644
--- a/ash/test/shelf_view_test_api.cc
+++ b/ash/shelf/shelf_view_test_api.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 "ash/test/shelf_view_test_api.h"
+#include "ash/shelf/shelf_view_test_api.h"
 
 #include "ash/public/cpp/shelf_model.h"
 #include "ash/shelf/overflow_button.h"
diff --git a/ash/test/shelf_view_test_api.h b/ash/shelf/shelf_view_test_api.h
similarity index 95%
rename from ash/test/shelf_view_test_api.h
rename to ash/shelf/shelf_view_test_api.h
index d87d83d60..0d42595 100644
--- a/ash/test/shelf_view_test_api.h
+++ b/ash/shelf/shelf_view_test_api.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 ASH_TEST_SHELF_VIEW_TEST_API_H_
-#define ASH_TEST_SHELF_VIEW_TEST_API_H_
+#ifndef ASH_SHELF_SHELF_VIEW_TEST_API_H_
+#define ASH_SHELF_SHELF_VIEW_TEST_API_H_
 
 #include "ash/public/cpp/shelf_item.h"
 #include "base/macros.h"
@@ -110,4 +110,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_SHELF_VIEW_TEST_API_H_
+#endif  // ASH_SHELF_SHELF_VIEW_TEST_API_H_
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc
index 2b4dbaf..8e83fb79 100644
--- a/ash/shelf/shelf_view_unittest.cc
+++ b/ash/shelf/shelf_view_unittest.cc
@@ -17,24 +17,24 @@
 #include "ash/shelf/app_list_button.h"
 #include "ash/shelf/overflow_bubble.h"
 #include "ash/shelf/overflow_bubble_view.h"
+#include "ash/shelf/overflow_bubble_view_test_api.h"
 #include "ash/shelf/overflow_button.h"
+#include "ash/shelf/overflow_button_test_api.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_button.h"
 #include "ash/shelf/shelf_constants.h"
 #include "ash/shelf/shelf_observer.h"
 #include "ash/shelf/shelf_tooltip_manager.h"
+#include "ash/shelf/shelf_view_test_api.h"
 #include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
+#include "ash/shell_test_api.h"
 #include "ash/system/web_notification/web_notification_tray.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/ash_test_helper.h"
-#include "ash/test/overflow_bubble_view_test_api.h"
-#include "ash/test/overflow_button_test_api.h"
-#include "ash/test/shelf_view_test_api.h"
-#include "ash/test/shell_test_api.h"
-#include "ash/test/test_shell_delegate.h"
-#include "ash/test/wallpaper_controller_test_api.h"
+#include "ash/test_shell_delegate.h"
 #include "ash/wallpaper/wallpaper_controller.h"
+#include "ash/wallpaper/wallpaper_controller_test_api.h"
 #include "base/i18n/rtl.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
diff --git a/ash/shelf/shelf_widget_unittest.cc b/ash/shelf/shelf_widget_unittest.cc
index 4623f35..d530568 100644
--- a/ash/shelf/shelf_widget_unittest.cc
+++ b/ash/shelf/shelf_widget_unittest.cc
@@ -9,12 +9,12 @@
 #include "ash/shelf/shelf_constants.h"
 #include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shelf/shelf_view.h"
+#include "ash/shelf/shelf_view_test_api.h"
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/ash_test_helper.h"
-#include "ash/test/shelf_view_test_api.h"
-#include "ash/test/test_shell_delegate.h"
+#include "ash/test_shell_delegate.h"
 #include "ash/wm/window_util.h"
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/display/display.h"
diff --git a/ash/shell/example_session_controller_client.h b/ash/shell/example_session_controller_client.h
index cd71a3b..952a5300 100644
--- a/ash/shell/example_session_controller_client.h
+++ b/ash/shell/example_session_controller_client.h
@@ -5,7 +5,7 @@
 #ifndef ASH_SHELL_EXAMPLE_SESSION_CONTROLLER_CLIENT_H_
 #define ASH_SHELL_EXAMPLE_SESSION_CONTROLLER_CLIENT_H_
 
-#include "ash/test/test_session_controller_client.h"
+#include "ash/session/test_session_controller_client.h"
 #include "base/macros.h"
 
 namespace ash {
diff --git a/ash/shell/shell_delegate_impl.cc b/ash/shell/shell_delegate_impl.cc
index 099966c..32e0f145 100644
--- a/ash/shell/shell_delegate_impl.cc
+++ b/ash/shell/shell_delegate_impl.cc
@@ -8,6 +8,7 @@
 #include "ash/default_accessibility_delegate.h"
 #include "ash/default_wallpaper_delegate.h"
 #include "ash/gpu_support_stub.h"
+#include "ash/keyboard/test_keyboard_ui.h"
 #include "ash/palette_delegate.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/shell.h"
@@ -15,7 +16,6 @@
 #include "ash/shell/example_factory.h"
 #include "ash/shell/toplevel_window.h"
 #include "ash/system/tray/system_tray_delegate.h"
-#include "ash/test/test_keyboard_ui.h"
 #include "ash/wm/window_state.h"
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
diff --git a/ash/test/shell_test_api.cc b/ash/shell_test_api.cc
similarity index 96%
rename from ash/test/shell_test_api.cc
rename to ash/shell_test_api.cc
index 9dd82d8..99decb71 100644
--- a/ash/test/shell_test_api.cc
+++ b/ash/shell_test_api.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 "ash/test/shell_test_api.h"
+#include "ash/shell_test_api.h"
 
 #include <utility>
 
diff --git a/ash/test/shell_test_api.h b/ash/shell_test_api.h
similarity index 90%
rename from ash/test/shell_test_api.h
rename to ash/shell_test_api.h
index a85d51ee..a3418f4 100644
--- a/ash/test/shell_test_api.h
+++ b/ash/shell_test_api.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 ASH_TEST_SHELL_TEST_API_H_
-#define ASH_TEST_SHELL_TEST_API_H_
+#ifndef ASH_SHELL_TEST_API_H_
+#define ASH_SHELL_TEST_API_H_
 
 #include <memory>
 
@@ -42,4 +42,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_SHELL_TEST_API_H_
+#endif  // ASH_SHELL_TEST_API_H_
diff --git a/ash/shell_unittest.cc b/ash/shell_unittest.cc
index 28a9ac71..1129e28 100644
--- a/ash/shell_unittest.cc
+++ b/ash/shell_unittest.cc
@@ -13,12 +13,12 @@
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
 #include "ash/session/session_controller.h"
+#include "ash/session/test_session_controller_client.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shelf/shelf_widget.h"
+#include "ash/shell_test_api.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/shell_test_api.h"
-#include "ash/test/test_session_controller_client.h"
 #include "ash/wallpaper/wallpaper_widget_controller.h"
 #include "ash/wm/window_util.h"
 #include "base/command_line.h"
diff --git a/ash/system/audio/tray_audio_unittest.cc b/ash/system/audio/tray_audio_unittest.cc
index 0b61152..97b829f 100644
--- a/ash/system/audio/tray_audio_unittest.cc
+++ b/ash/system/audio/tray_audio_unittest.cc
@@ -5,9 +5,9 @@
 #include "ash/system/audio/tray_audio.h"
 
 #include "ash/system/status_area_widget.h"
+#include "ash/system/status_area_widget_test_helper.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/status_area_widget_test_helper.h"
 
 namespace ash {
 
diff --git a/ash/test/tray_cast_test_api.cc b/ash/system/cast/tray_cast_test_api.cc
similarity index 96%
rename from ash/test/tray_cast_test_api.cc
rename to ash/system/cast/tray_cast_test_api.cc
index e4cf206..0a0355a 100644
--- a/ash/test/tray_cast_test_api.cc
+++ b/ash/system/cast/tray_cast_test_api.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 "ash/test/tray_cast_test_api.h"
+#include "ash/system/cast/tray_cast_test_api.h"
 
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_delegate.h"
diff --git a/ash/test/tray_cast_test_api.h b/ash/system/cast/tray_cast_test_api.h
similarity index 91%
rename from ash/test/tray_cast_test_api.h
rename to ash/system/cast/tray_cast_test_api.h
index 7726f017..7cc41da 100644
--- a/ash/test/tray_cast_test_api.h
+++ b/ash/system/cast/tray_cast_test_api.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 ASH_TEST_TRAY_CAST_TEST_API_H_
-#define ASH_TEST_TRAY_CAST_TEST_API_H_
+#ifndef ASH_SYSTEM_CAST_TRAY_CAST_TEST_API_H_
+#define ASH_SYSTEM_CAST_TRAY_CAST_TEST_API_H_
 
 #include <string>
 
@@ -52,4 +52,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_TRAY_CAST_TEST_API_H_
+#endif  // ASH_SYSTEM_CAST_TRAY_CAST_TEST_API_H_
diff --git a/ash/system/ime_menu/ime_menu_tray.cc b/ash/system/ime_menu/ime_menu_tray.cc
index 084e9fc..4b2b6b1 100644
--- a/ash/system/ime_menu/ime_menu_tray.cc
+++ b/ash/system/ime_menu/ime_menu_tray.cc
@@ -195,7 +195,7 @@
   // views::ButtonListener:
   void ButtonPressed(views::Button* sender, const ui::Event& event) override {
     if (sender == settings_button_) {
-      ime_menu_tray_->HideImeMenuBubble();
+      ime_menu_tray_->CloseBubble();
       ShowIMESettings();
       return;
     }
@@ -312,6 +312,9 @@
   SystemTrayNotifier* tray_notifier = Shell::Get()->system_tray_notifier();
   tray_notifier->AddIMEObserver(this);
   tray_notifier->AddVirtualKeyboardObserver(this);
+
+  if (!drag_controller())
+    set_drag_controller(base::MakeUnique<TrayDragController>(shelf));
 }
 
 ImeMenuTray::~ImeMenuTray() {
@@ -326,19 +329,6 @@
     keyboard_controller->RemoveObserver(this);
 }
 
-void ImeMenuTray::ShowImeMenuBubble() {
-  keyboard::KeyboardController* keyboard_controller =
-      keyboard::KeyboardController::GetInstance();
-  if (keyboard_controller && keyboard_controller->keyboard_visible()) {
-    show_bubble_after_keyboard_hidden_ = true;
-    keyboard_controller->AddObserver(this);
-    keyboard_controller->HideKeyboard(
-        keyboard::KeyboardController::HIDE_REASON_AUTOMATIC);
-  } else {
-    ShowImeMenuBubbleInternal();
-  }
-}
-
 void ImeMenuTray::ShowImeMenuBubbleInternal() {
   views::TrayBubbleView::InitParams init_params;
   init_params.delegate = this;
@@ -371,19 +361,8 @@
   SetIsActive(true);
 }
 
-void ImeMenuTray::HideImeMenuBubble() {
-  bubble_.reset();
-  ime_list_view_ = nullptr;
-  SetIsActive(false);
-  shelf()->UpdateAutoHideState();
-}
-
-bool ImeMenuTray::IsImeMenuBubbleShown() {
-  return !!bubble_;
-}
-
 void ImeMenuTray::ShowKeyboardWithKeyset(const std::string& keyset) {
-  HideImeMenuBubble();
+  CloseBubble();
 
   // Overrides the keyboard url ref to make it shown with the given keyset.
   if (InputMethodManager::Get())
@@ -461,21 +440,45 @@
 
 void ImeMenuTray::HideBubbleWithView(const views::TrayBubbleView* bubble_view) {
   if (bubble_->bubble_view() == bubble_view)
-    HideImeMenuBubble();
+    CloseBubble();
 }
 
 void ImeMenuTray::ClickedOutsideBubble() {
-  HideImeMenuBubble();
+  CloseBubble();
 }
 
 bool ImeMenuTray::PerformAction(const ui::Event& event) {
   if (bubble_)
-    HideImeMenuBubble();
+    CloseBubble();
   else
-    ShowImeMenuBubble();
+    ShowBubble();
   return true;
 }
 
+void ImeMenuTray::CloseBubble() {
+  bubble_.reset();
+  ime_list_view_ = nullptr;
+  SetIsActive(false);
+  shelf()->UpdateAutoHideState();
+}
+
+void ImeMenuTray::ShowBubble() {
+  keyboard::KeyboardController* keyboard_controller =
+      keyboard::KeyboardController::GetInstance();
+  if (keyboard_controller && keyboard_controller->keyboard_visible()) {
+    show_bubble_after_keyboard_hidden_ = true;
+    keyboard_controller->AddObserver(this);
+    keyboard_controller->HideKeyboard(
+        keyboard::KeyboardController::HIDE_REASON_AUTOMATIC);
+  } else {
+    ShowImeMenuBubbleInternal();
+  }
+}
+
+views::TrayBubbleView* ImeMenuTray::GetBubbleView() {
+  return bubble_ ? bubble_->bubble_view() : nullptr;
+}
+
 void ImeMenuTray::OnIMERefresh() {
   UpdateTrayLabel();
   if (bubble_ && ime_list_view_) {
@@ -491,7 +494,7 @@
   if (is_activated)
     UpdateTrayLabel();
   else
-    HideImeMenuBubble();
+    CloseBubble();
 }
 
 void ImeMenuTray::BubbleViewDestroyed() {
@@ -578,7 +581,7 @@
 
 void ImeMenuTray::OnKeyboardSuppressionChanged(bool suppressed) {
   if (suppressed != keyboard_suppressed_ && bubble_)
-    HideImeMenuBubble();
+    CloseBubble();
   keyboard_suppressed_ = suppressed;
 }
 
diff --git a/ash/system/ime_menu/ime_menu_tray.h b/ash/system/ime_menu/ime_menu_tray.h
index 4717ea04..c94b4331 100644
--- a/ash/system/ime_menu/ime_menu_tray.h
+++ b/ash/system/ime_menu/ime_menu_tray.h
@@ -29,22 +29,12 @@
 // for emoji, handwriting, and voice.
 class ASH_EXPORT ImeMenuTray : public TrayBackgroundView,
                                public IMEObserver,
-                               public views::TrayBubbleView::Delegate,
                                public keyboard::KeyboardControllerObserver,
                                public VirtualKeyboardObserver {
  public:
   explicit ImeMenuTray(Shelf* shelf);
   ~ImeMenuTray() override;
 
-  // Shows the IME menu bubble and highlights the button.
-  void ShowImeMenuBubble();
-
-  // Hides the IME menu bubble and lowlights the button.
-  void HideImeMenuBubble();
-
-  // Returns true if the IME menu bubble has been shown.
-  bool IsImeMenuBubbleShown();
-
   // Shows the virtual keyboard with the given keyset: emoji, handwriting or
   // voice.
   void ShowKeyboardWithKeyset(const std::string& keyset);
@@ -63,6 +53,9 @@
   void HideBubbleWithView(const views::TrayBubbleView* bubble_view) override;
   void ClickedOutsideBubble() override;
   bool PerformAction(const ui::Event& event) override;
+  void CloseBubble() override;
+  void ShowBubble() override;
+  views::TrayBubbleView* GetBubbleView() override;
 
   // IMEObserver:
   void OnIMERefresh() override;
diff --git a/ash/system/ime_menu/ime_menu_tray_unittest.cc b/ash/system/ime_menu/ime_menu_tray_unittest.cc
index fb2a9a98..e3b93e3 100644
--- a/ash/system/ime_menu/ime_menu_tray_unittest.cc
+++ b/ash/system/ime_menu/ime_menu_tray_unittest.cc
@@ -11,8 +11,8 @@
 #include "ash/shell.h"
 #include "ash/system/ime_menu/ime_list_view.h"
 #include "ash/system/status_area_widget.h"
+#include "ash/system/status_area_widget_test_helper.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/status_area_widget_test_helper.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/accessibility/ax_node_data.h"
@@ -76,7 +76,7 @@
   bool IsTrayBackgroundActive() { return GetTray()->is_active(); }
 
   // Returns true if the IME menu bubble has been shown.
-  bool IsBubbleShown() { return GetTray()->IsImeMenuBubbleShown(); }
+  bool IsBubbleShown() { return GetTray()->GetBubbleView() != nullptr; }
 
   // Returns true if emoji palatte is enabled for the current keyboard.
   bool IsEmojiEnabled() { return GetTray()->emoji_enabled_; }
diff --git a/ash/system/lock_screen_action/lock_screen_action_tray_unittest.cc b/ash/system/lock_screen_action/lock_screen_action_tray_unittest.cc
index c2ed06e..4bb4baf 100644
--- a/ash/system/lock_screen_action/lock_screen_action_tray_unittest.cc
+++ b/ash/system/lock_screen_action/lock_screen_action_tray_unittest.cc
@@ -5,12 +5,12 @@
 #include "ash/system/lock_screen_action/lock_screen_action_tray.h"
 
 #include "ash/resources/vector_icons/vector_icons.h"
+#include "ash/session/test_session_controller_client.h"
 #include "ash/shelf/shelf_constants.h"
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
+#include "ash/system/status_area_widget_test_helper.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/status_area_widget_test_helper.h"
-#include "ash/test/test_session_controller_client.h"
 #include "ash/tray_action/tray_action.h"
 #include "base/macros.h"
 #include "components/session_manager/session_manager_types.h"
diff --git a/ash/system/media_security/multi_profile_media_tray_item_unittest.cc b/ash/system/media_security/multi_profile_media_tray_item_unittest.cc
index d0b96ed..ee7481f 100644
--- a/ash/system/media_security/multi_profile_media_tray_item_unittest.cc
+++ b/ash/system/media_security/multi_profile_media_tray_item_unittest.cc
@@ -10,13 +10,13 @@
 #include "ash/session/session_controller.h"
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
+#include "ash/system/status_area_widget_test_helper.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_bubble.h"
 #include "ash/system/tray/tray_item_view.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/ash_test_helper.h"
-#include "ash/test/status_area_widget_test_helper.h"
-#include "ash/test/test_shell_delegate.h"
+#include "ash/test_shell_delegate.h"
 #include "ui/views/bubble/tray_bubble_view.h"
 
 namespace ash {
diff --git a/ash/system/night_light/night_light_controller_unittest.cc b/ash/system/night_light/night_light_controller_unittest.cc
index c8813b7..9a2b0a7 100644
--- a/ash/system/night_light/night_light_controller_unittest.cc
+++ b/ash/system/night_light/night_light_controller_unittest.cc
@@ -10,11 +10,11 @@
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/public/cpp/config.h"
 #include "ash/public/cpp/session_types.h"
+#include "ash/session/test_session_controller_client.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/ash_test_helper.h"
-#include "ash/test/test_session_controller_client.h"
-#include "ash/test/test_shell_delegate.h"
+#include "ash/test_shell_delegate.h"
 #include "base/bind.h"
 #include "base/callback_forward.h"
 #include "base/macros.h"
diff --git a/ash/system/night_light/night_light_toggle_button.cc b/ash/system/night_light/night_light_toggle_button.cc
index 74b0d45..a040f85 100644
--- a/ash/system/night_light/night_light_toggle_button.cc
+++ b/ash/system/night_light/night_light_toggle_button.cc
@@ -74,13 +74,12 @@
 }
 
 void NightLightToggleButton::GetAccessibleNodeData(ui::AXNodeData* node_data) {
-  node_data->SetName(
-      l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NIGHT_LIGHT));
+  const bool is_enabled = Shell::Get()->night_light_controller()->GetEnabled();
+  node_data->SetName(GetNightLightTooltipText(is_enabled));
   node_data->role = ui::AX_ROLE_TOGGLE_BUTTON;
-  const bool is_pressed = Shell::Get()->night_light_controller()->GetEnabled();
   node_data->AddIntAttribute(
       ui::AX_ATTR_CHECKED_STATE,
-      is_pressed ? ui::AX_CHECKED_STATE_TRUE : ui::AX_CHECKED_STATE_FALSE);
+      is_enabled ? ui::AX_CHECKED_STATE_TRUE : ui::AX_CHECKED_STATE_FALSE);
 }
 
 }  // namespace ash
diff --git a/ash/system/night_light/tray_night_light_unittest.cc b/ash/system/night_light/tray_night_light_unittest.cc
index 02885af..99db620 100644
--- a/ash/system/night_light/tray_night_light_unittest.cc
+++ b/ash/system/night_light/tray_night_light_unittest.cc
@@ -10,7 +10,7 @@
 #include "ash/system/tray/system_tray.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/ash_test_helper.h"
-#include "ash/test/test_shell_delegate.h"
+#include "ash/test_shell_delegate.h"
 #include "base/macros.h"
 #include "components/prefs/testing_pref_service.h"
 
diff --git a/ash/system/overview/overview_button_tray_unittest.cc b/ash/system/overview/overview_button_tray_unittest.cc
index f6c1a19..f8adc09 100644
--- a/ash/system/overview/overview_button_tray_unittest.cc
+++ b/ash/system/overview/overview_button_tray_unittest.cc
@@ -14,9 +14,9 @@
 #include "ash/shell.h"
 #include "ash/shell_port.h"
 #include "ash/system/status_area_widget.h"
+#include "ash/system/status_area_widget_test_helper.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/ash_test_helper.h"
-#include "ash/test/status_area_widget_test_helper.h"
 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/wm/overview/window_selector_controller.h"
 #include "ash/wm/window_state.h"
diff --git a/ash/system/palette/palette_tray.cc b/ash/system/palette/palette_tray.cc
index c7da960..9c623809 100644
--- a/ash/system/palette/palette_tray.cc
+++ b/ash/system/palette/palette_tray.cc
@@ -153,6 +153,9 @@
 
   Shell::Get()->AddShellObserver(this);
   ui::InputDeviceManager::GetInstance()->AddObserver(this);
+
+  if (!drag_controller())
+    set_drag_controller(base::MakeUnique<TrayDragController>(shelf));
 }
 
 PaletteTray::~PaletteTray() {
@@ -163,68 +166,6 @@
   Shell::Get()->RemoveShellObserver(this);
 }
 
-bool PaletteTray::PerformAction(const ui::Event& event) {
-  if (bubble_) {
-    if (num_actions_in_bubble_ == 0)
-      RecordPaletteOptionsUsage(PaletteTrayOptions::PALETTE_CLOSED_NO_ACTION);
-    HidePalette();
-    return true;
-  }
-
-  return ShowPalette();
-}
-
-bool PaletteTray::ShowPalette() {
-  if (bubble_)
-    return false;
-
-  DCHECK(tray_container());
-
-  views::TrayBubbleView::InitParams init_params;
-  init_params.delegate = this;
-  init_params.parent_window = GetBubbleWindowContainer();
-  init_params.anchor_view = GetBubbleAnchor();
-  init_params.anchor_alignment = GetAnchorAlignment();
-  init_params.min_width = kPaletteWidth;
-  init_params.max_width = kPaletteWidth;
-  init_params.close_on_deactivate = true;
-
-  // TODO(tdanderson): Refactor into common row layout code.
-  // TODO(tdanderson|jdufault): Add material design ripple effects to the menu
-  // rows.
-
-  // Create and customize bubble view.
-  views::TrayBubbleView* bubble_view = new views::TrayBubbleView(init_params);
-  bubble_view->set_anchor_view_insets(GetBubbleAnchorInsets());
-  bubble_view->set_margins(
-      gfx::Insets(kPalettePaddingOnTop, 0, kPalettePaddingOnBottom, 0));
-
-  // Add title.
-  auto* title_view = new TitleView(this);
-  title_view->SetBorder(views::CreateEmptyBorder(
-      gfx::Insets(0, kPaddingBetweenTitleAndLeftEdge, 0, 0)));
-  bubble_view->AddChildView(title_view);
-
-  // Add horizontal separator.
-  views::Separator* separator = new views::Separator();
-  separator->SetColor(kPaletteSeparatorColor);
-  separator->SetBorder(views::CreateEmptyBorder(gfx::Insets(
-      kPaddingBetweenTitleAndSeparator, 0, kMenuSeparatorVerticalPadding, 0)));
-  bubble_view->AddChildView(separator);
-
-  // Add palette tools.
-  // TODO(tdanderson|jdufault): Use SystemMenuButton to get the material design
-  // ripples.
-  std::vector<PaletteToolView> views = palette_tool_manager_->CreateViews();
-  for (const PaletteToolView& view : views)
-    bubble_view->AddChildView(view.view);
-
-  // Show the bubble.
-  bubble_.reset(new ash::TrayBubbleWrapper(this, bubble_view));
-  SetIsActive(true);
-  return true;
-}
-
 bool PaletteTray::ContainsPointInScreen(const gfx::Point& point) {
   if (icon_ && icon_->GetBoundsInScreen().Contains(point))
     return true;
@@ -280,7 +221,7 @@
   if (palette_delegate->ShouldAutoOpenPalette()) {
     if (stylus_state == ui::StylusState::REMOVED && !bubble_) {
       is_bubble_auto_opened_ = true;
-      ShowPalette();
+      ShowBubble();
     } else if (stylus_state == ui::StylusState::INSERTED && bubble_) {
       HidePalette();
     }
@@ -385,6 +326,76 @@
       &PaletteTray::OnPaletteEnabledPrefChanged, weak_factory_.GetWeakPtr()));
 }
 
+bool PaletteTray::PerformAction(const ui::Event& event) {
+  if (bubble_) {
+    if (num_actions_in_bubble_ == 0)
+      RecordPaletteOptionsUsage(PaletteTrayOptions::PALETTE_CLOSED_NO_ACTION);
+    HidePalette();
+    return true;
+  }
+
+  ShowBubble();
+  return true;
+}
+
+void PaletteTray::CloseBubble() {
+  HidePalette();
+}
+
+void PaletteTray::ShowBubble() {
+  if (bubble_)
+    return;
+
+  DCHECK(tray_container());
+
+  views::TrayBubbleView::InitParams init_params;
+  init_params.delegate = this;
+  init_params.parent_window = GetBubbleWindowContainer();
+  init_params.anchor_view = GetBubbleAnchor();
+  init_params.anchor_alignment = GetAnchorAlignment();
+  init_params.min_width = kPaletteWidth;
+  init_params.max_width = kPaletteWidth;
+  init_params.close_on_deactivate = true;
+
+  // TODO(tdanderson): Refactor into common row layout code.
+  // TODO(tdanderson|jdufault): Add material design ripple effects to the menu
+  // rows.
+
+  // Create and customize bubble view.
+  views::TrayBubbleView* bubble_view = new views::TrayBubbleView(init_params);
+  bubble_view->set_anchor_view_insets(GetBubbleAnchorInsets());
+  bubble_view->set_margins(
+      gfx::Insets(kPalettePaddingOnTop, 0, kPalettePaddingOnBottom, 0));
+
+  // Add title.
+  auto* title_view = new TitleView(this);
+  title_view->SetBorder(views::CreateEmptyBorder(
+      gfx::Insets(0, kPaddingBetweenTitleAndLeftEdge, 0, 0)));
+  bubble_view->AddChildView(title_view);
+
+  // Add horizontal separator.
+  views::Separator* separator = new views::Separator();
+  separator->SetColor(kPaletteSeparatorColor);
+  separator->SetBorder(views::CreateEmptyBorder(gfx::Insets(
+      kPaddingBetweenTitleAndSeparator, 0, kMenuSeparatorVerticalPadding, 0)));
+  bubble_view->AddChildView(separator);
+
+  // Add palette tools.
+  // TODO(tdanderson|jdufault): Use SystemMenuButton to get the material design
+  // ripples.
+  std::vector<PaletteToolView> views = palette_tool_manager_->CreateViews();
+  for (const PaletteToolView& view : views)
+    bubble_view->AddChildView(view.view);
+
+  // Show the bubble.
+  bubble_ = base::MakeUnique<ash::TrayBubbleWrapper>(this, bubble_view);
+  SetIsActive(true);
+}
+
+views::TrayBubbleView* PaletteTray::GetBubbleView() {
+  return bubble_ ? bubble_->bubble_view() : nullptr;
+}
+
 void PaletteTray::UpdateTrayIcon() {
   icon_->SetImage(CreateVectorIcon(
       palette_tool_manager_->GetActiveTrayIcon(
diff --git a/ash/system/palette/palette_tray.h b/ash/system/palette/palette_tray.h
index 3d818a9..f8375c8 100644
--- a/ash/system/palette/palette_tray.h
+++ b/ash/system/palette/palette_tray.h
@@ -38,15 +38,11 @@
                                public SessionObserver,
                                public ShellObserver,
                                public PaletteToolManager::Delegate,
-                               public ui::InputDeviceEventObserver,
-                               public views::TrayBubbleView::Delegate {
+                               public ui::InputDeviceEventObserver {
  public:
   explicit PaletteTray(Shelf* shelf);
   ~PaletteTray() override;
 
-  // ActionableView:
-  bool PerformAction(const ui::Event& event) override;
-
   // SessionObserver:
   void OnSessionStateChanged(session_manager::SessionState state) override;
 
@@ -59,6 +55,10 @@
   void HideBubbleWithView(const views::TrayBubbleView* bubble_view) override;
   void AnchorUpdated() override;
   void Initialize() override;
+  bool PerformAction(const ui::Event& event) override;
+  void CloseBubble() override;
+  void ShowBubble() override;
+  views::TrayBubbleView* GetBubbleView() override;
 
   // PaletteToolManager::Delegate:
   void HidePalette() override;
@@ -66,10 +66,6 @@
   void RecordPaletteOptionsUsage(PaletteTrayOptions option) override;
   void RecordPaletteModeCancellation(PaletteModeCancelType type) override;
 
-  // Opens up the palette if it is not already open. Returns true if the palette
-  // was opened.
-  bool ShowPalette();
-
   // Returns true if the palette tray contains the given point. This is useful
   // for determining if an event should be propagated through to the palette.
   bool ContainsPointInScreen(const gfx::Point& point);
diff --git a/ash/test/test_palette_delegate.cc b/ash/system/palette/test_palette_delegate.cc
similarity index 95%
rename from ash/test/test_palette_delegate.cc
rename to ash/system/palette/test_palette_delegate.cc
index eb529bf..467769c 100644
--- a/ash/test/test_palette_delegate.cc
+++ b/ash/system/palette/test_palette_delegate.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 "ash/test/test_palette_delegate.h"
+#include "ash/system/palette/test_palette_delegate.h"
 
 namespace ash {
 
diff --git a/ash/test/test_palette_delegate.h b/ash/system/palette/test_palette_delegate.h
similarity index 93%
rename from ash/test/test_palette_delegate.h
rename to ash/system/palette/test_palette_delegate.h
index 4bf0a31..fae0aadf 100644
--- a/ash/test/test_palette_delegate.h
+++ b/ash/system/palette/test_palette_delegate.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 ASH_TEST_TEST_PALETTE_DELEGATE_H_
-#define ASH_TEST_TEST_PALETTE_DELEGATE_H_
+#ifndef ASH_SYSTEM_PALETTE_TEST_PALETTE_DELEGATE_H_
+#define ASH_SYSTEM_PALETTE_TEST_PALETTE_DELEGATE_H_
 
 #include "ash/palette_delegate.h"
 #include "base/macros.h"
@@ -80,4 +80,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_TEST_PALETTE_DELEGATE_H_
+#endif  // ASH_SYSTEM_PALETTE_TEST_PALETTE_DELEGATE_H_
diff --git a/ash/system/palette/tools/create_note_unittest.cc b/ash/system/palette/tools/create_note_unittest.cc
index 1d01a1b..49f5216 100644
--- a/ash/system/palette/tools/create_note_unittest.cc
+++ b/ash/system/palette/tools/create_note_unittest.cc
@@ -3,13 +3,13 @@
 // found in the LICENSE file.
 
 #include "ash/shell.h"
+#include "ash/shell_test_api.h"
 #include "ash/system/palette/mock_palette_tool_delegate.h"
 #include "ash/system/palette/palette_ids.h"
 #include "ash/system/palette/palette_tool.h"
+#include "ash/system/palette/test_palette_delegate.h"
 #include "ash/system/palette/tools/create_note_action.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/shell_test_api.h"
-#include "ash/test/test_palette_delegate.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "ui/views/view.h"
diff --git a/ash/system/palette/tools/metalayer_unittest.cc b/ash/system/palette/tools/metalayer_unittest.cc
index 9cd44899..b1529f45 100644
--- a/ash/system/palette/tools/metalayer_unittest.cc
+++ b/ash/system/palette/tools/metalayer_unittest.cc
@@ -3,13 +3,13 @@
 // found in the LICENSE file.
 
 #include "ash/shell.h"
+#include "ash/shell_test_api.h"
 #include "ash/system/palette/mock_palette_tool_delegate.h"
 #include "ash/system/palette/palette_ids.h"
 #include "ash/system/palette/palette_tool.h"
+#include "ash/system/palette/test_palette_delegate.h"
 #include "ash/system/palette/tools/metalayer_mode.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/shell_test_api.h"
-#include "ash/test/test_palette_delegate.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "ui/views/view.h"
diff --git a/ash/system/palette/tools/screenshot_unittest.cc b/ash/system/palette/tools/screenshot_unittest.cc
index 3b5f012a5..435823c 100644
--- a/ash/system/palette/tools/screenshot_unittest.cc
+++ b/ash/system/palette/tools/screenshot_unittest.cc
@@ -3,14 +3,14 @@
 // found in the LICENSE file.
 
 #include "ash/shell.h"
+#include "ash/shell_test_api.h"
 #include "ash/system/palette/mock_palette_tool_delegate.h"
 #include "ash/system/palette/palette_ids.h"
 #include "ash/system/palette/palette_tool.h"
+#include "ash/system/palette/test_palette_delegate.h"
 #include "ash/system/palette/tools/capture_region_mode.h"
 #include "ash/system/palette/tools/capture_screen_action.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/shell_test_api.h"
-#include "ash/test/test_palette_delegate.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 
diff --git a/ash/system/power/tablet_power_button_controller_unittest.cc b/ash/system/power/tablet_power_button_controller_unittest.cc
index 76615a20..691cbad0 100644
--- a/ash/system/power/tablet_power_button_controller_unittest.cc
+++ b/ash/system/power/tablet_power_button_controller_unittest.cc
@@ -9,12 +9,12 @@
 #include "ash/ash_switches.h"
 #include "ash/public/cpp/config.h"
 #include "ash/session/session_controller.h"
+#include "ash/session/test_session_controller_client.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/lock_state_controller_test_api.h"
-#include "ash/test/test_session_controller_client.h"
-#include "ash/test/test_shell_delegate.h"
+#include "ash/test_shell_delegate.h"
 #include "ash/wm/lock_state_controller.h"
+#include "ash/wm/lock_state_controller_test_api.h"
 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/wm/power_button_controller.h"
 #include "base/command_line.h"
diff --git a/ash/system/rotation/tray_rotation_lock_unittest.cc b/ash/system/rotation/tray_rotation_lock_unittest.cc
index f463c0d..b66ebee 100644
--- a/ash/system/rotation/tray_rotation_lock_unittest.cc
+++ b/ash/system/rotation/tray_rotation_lock_unittest.cc
@@ -10,10 +10,10 @@
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
+#include "ash/system/status_area_widget_test_helper.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_delegate.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/status_area_widget_test_helper.h"
 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
 #include "base/command_line.h"
 #include "base/time/time.h"
diff --git a/ash/test/status_area_widget_test_helper.cc b/ash/system/status_area_widget_test_helper.cc
similarity index 94%
rename from ash/test/status_area_widget_test_helper.cc
rename to ash/system/status_area_widget_test_helper.cc
index 134473e..60c1e68 100644
--- a/ash/test/status_area_widget_test_helper.cc
+++ b/ash/system/status_area_widget_test_helper.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 "ash/test/status_area_widget_test_helper.h"
+#include "ash/system/status_area_widget_test_helper.h"
 
 #include "ash/root_window_controller.h"
 #include "ash/session/session_controller.h"
diff --git a/ash/test/status_area_widget_test_helper.h b/ash/system/status_area_widget_test_helper.h
similarity index 100%
rename from ash/test/status_area_widget_test_helper.h
rename to ash/system/status_area_widget_test_helper.h
diff --git a/ash/system/status_area_widget_unittest.cc b/ash/system/status_area_widget_unittest.cc
index 7db3a02c..8e2832ba 100644
--- a/ash/system/status_area_widget_unittest.cc
+++ b/ash/system/status_area_widget_unittest.cc
@@ -7,19 +7,19 @@
 #include "ash/ash_switches.h"
 #include "ash/focus_cycler.h"
 #include "ash/session/session_controller.h"
+#include "ash/session/test_session_controller_client.h"
 #include "ash/shell.h"
 #include "ash/system/ime_menu/ime_menu_tray.h"
 #include "ash/system/overview/overview_button_tray.h"
 #include "ash/system/palette/palette_tray.h"
 #include "ash/system/session/logout_button_tray.h"
 #include "ash/system/status_area_focus_observer.h"
+#include "ash/system/status_area_widget_test_helper.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "ash/system/virtual_keyboard/virtual_keyboard_tray.h"
 #include "ash/system/web_notification/web_notification_tray.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/status_area_widget_test_helper.h"
-#include "ash/test/test_session_controller_client.h"
 #include "base/command_line.h"
 #include "components/session_manager/session_manager_types.h"
 #include "ui/aura/env.h"
diff --git a/ash/system/supervised/tray_supervised_user_unittest.cc b/ash/system/supervised/tray_supervised_user_unittest.cc
index b3e419a..d1ce6dc 100644
--- a/ash/system/supervised/tray_supervised_user_unittest.cc
+++ b/ash/system/supervised/tray_supervised_user_unittest.cc
@@ -6,12 +6,12 @@
 
 #include "ash/login_status.h"
 #include "ash/session/session_controller.h"
+#include "ash/session/test_session_controller_client.h"
 #include "ash/shell.h"
 #include "ash/system/tray/label_tray_view.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_test_api.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/test_session_controller_client.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/message_center/message_center.h"
diff --git a/ash/system/tiles/tray_tiles_unittest.cc b/ash/system/tiles/tray_tiles_unittest.cc
index 160f1622..20ac3ff 100644
--- a/ash/system/tiles/tray_tiles_unittest.cc
+++ b/ash/system/tiles/tray_tiles_unittest.cc
@@ -4,12 +4,12 @@
 
 #include "ash/system/tiles/tray_tiles.h"
 
+#include "ash/session/test_session_controller_client.h"
 #include "ash/system/night_light/night_light_controller.h"
 #include "ash/system/night_light/night_light_toggle_button.h"
 #include "ash/system/tiles/tiles_default_view.h"
 #include "ash/system/tray/system_menu_button.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/test_session_controller_client.h"
 #include "components/user_manager/user_type.h"
 #include "ui/views/view.h"
 
diff --git a/ash/system/tray/system_tray.cc b/ash/system/tray/system_tray.cc
index d4ee519..bfad00fb 100644
--- a/ash/system/tray/system_tray.cc
+++ b/ash/system/tray/system_tray.cc
@@ -52,7 +52,6 @@
 #include "ash/system/user/tray_user.h"
 #include "ash/system/web_notification/web_notification_tray.h"
 #include "ash/wm/container_finder.h"
-#include "ash/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/wm/widget_finder.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
@@ -198,14 +197,16 @@
 
 // SystemTray
 
-SystemTray::SystemTray(Shelf* shelf)
-    : TrayBackgroundView(shelf), shelf_(shelf) {
+SystemTray::SystemTray(Shelf* shelf) : TrayBackgroundView(shelf) {
   SetInkDropMode(InkDropMode::ON);
 
   // Since user avatar is on the right hand side of System tray of a
   // horizontal shelf and that is sufficient to indicate separation, no
   // separator is required.
   set_separator_visibility(false);
+
+  if (!drag_controller())
+    set_drag_controller(base::MakeUnique<TrayDragController>(shelf));
 }
 
 SystemTray::~SystemTray() {
@@ -558,6 +559,36 @@
   HideBubbleWithView(system_bubble_->bubble_view());
 }
 
+bool SystemTray::PerformAction(const ui::Event& event) {
+  // If we're already showing a full system tray menu, either default or
+  // detailed menu, hide it; otherwise, show it (and hide any popup that's
+  // currently shown).
+  if (HasSystemBubble() && full_system_tray_menu_) {
+    system_bubble_->bubble()->Close();
+  } else {
+    ShowDefaultView(BUBBLE_CREATE_NEW);
+    if (event.IsKeyEvent() || (event.flags() & ui::EF_TOUCH_ACCESSIBILITY))
+      ActivateBubble();
+  }
+  return true;
+}
+
+void SystemTray::CloseBubble() {
+  CloseSystemBubble();
+}
+
+void SystemTray::ShowBubble() {
+  ShowDefaultView(BUBBLE_CREATE_NEW);
+}
+
+views::TrayBubbleView* SystemTray::GetBubbleView() {
+  // Only return the bubble view when it's showing the main system tray bubble,
+  // not the volume or brightness bubbles etc., to avoid client confusion.
+  return system_bubble_ && full_system_tray_menu_
+             ? system_bubble_->bubble_view()
+             : nullptr;
+}
+
 void SystemTray::BubbleViewDestroyed() {
   if (system_bubble_) {
     system_bubble_->bubble()->DestroyItemViews();
@@ -622,125 +653,6 @@
   bubble_view->GetWidget()->Activate();
 }
 
-void SystemTray::OnGestureEvent(ui::GestureEvent* event) {
-  if (Shell::Get()
-          ->maximize_mode_controller()
-          ->IsMaximizeModeWindowManagerEnabled() &&
-      shelf_->IsHorizontalAlignment() && ProcessGestureEvent(*event)) {
-    event->SetHandled();
-  } else {
-    TrayBackgroundView::OnGestureEvent(event);
-  }
-}
-
-gfx::Rect SystemTray::GetWorkAreaBoundsInScreen() const {
-  return shelf_->GetUserWorkAreaBounds();
-}
-
-bool SystemTray::PerformAction(const ui::Event& event) {
-  // If we're already showing a full system tray menu, either default or
-  // detailed menu, hide it; otherwise, show it (and hide any popup that's
-  // currently shown).
-  if (HasSystemBubble() && full_system_tray_menu_) {
-    system_bubble_->bubble()->Close();
-  } else {
-    ShowDefaultView(BUBBLE_CREATE_NEW);
-    if (event.IsKeyEvent() || (event.flags() & ui::EF_TOUCH_ACCESSIBILITY))
-      ActivateBubble();
-  }
-  return true;
-}
-
-bool SystemTray::ProcessGestureEvent(const ui::GestureEvent& event) {
-  if (event.type() == ui::ET_GESTURE_SCROLL_BEGIN)
-    return StartGestureDrag(event);
-
-  if (!HasSystemBubble() || !is_in_drag_)
-    return false;
-
-  if (event.type() == ui::ET_GESTURE_SCROLL_UPDATE) {
-    UpdateGestureDrag(event);
-    return true;
-  }
-
-  if (event.type() == ui::ET_GESTURE_SCROLL_END ||
-      event.type() == ui::ET_SCROLL_FLING_START) {
-    CompleteGestureDrag(event);
-    return true;
-  }
-
-  // Unexpected event. Reset the drag state and close the bubble.
-  is_in_drag_ = false;
-  CloseSystemBubble();
-  return false;
-}
-
-bool SystemTray::StartGestureDrag(const ui::GestureEvent& gesture) {
-  // Close the system bubble if there is already a full one opened. And return
-  // false to let shelf handle the event.
-  if (HasSystemBubble() && full_system_tray_menu_) {
-    system_bubble_->bubble()->Close();
-    return false;
-  }
-
-  // If the scroll sequence begins to scroll downward, return false so that the
-  // event will instead by handled by the shelf.
-  if (gesture.details().scroll_y_hint() > 0)
-    return false;
-
-  is_in_drag_ = true;
-  gesture_drag_amount_ = 0.f;
-  ShowDefaultView(BUBBLE_CREATE_NEW);
-  system_tray_bubble_bounds_ =
-      system_bubble_->bubble_view()->GetWidget()->GetWindowBoundsInScreen();
-  SetBubbleBounds(gesture.location());
-  return true;
-}
-
-void SystemTray::UpdateGestureDrag(const ui::GestureEvent& gesture) {
-  SetBubbleBounds(gesture.location());
-  gesture_drag_amount_ += gesture.details().scroll_y();
-}
-
-void SystemTray::CompleteGestureDrag(const ui::GestureEvent& gesture) {
-  const bool hide_bubble = !ShouldShowSystemBubbleAfterScrollSequence(gesture);
-  gfx::Rect target_bounds = system_tray_bubble_bounds_;
-
-  if (hide_bubble)
-    target_bounds.set_y(shelf_->GetIdealBounds().y());
-
-  system_bubble_->bubble()->AnimateToTargetBounds(target_bounds, hide_bubble);
-  is_in_drag_ = false;
-}
-
-void SystemTray::SetBubbleBounds(const gfx::Point& location) {
-  gfx::Point location_in_screen_coordinates(location);
-  View::ConvertPointToScreen(this, &location_in_screen_coordinates);
-
-  // System tray bubble should not be dragged higher than its original height.
-  if (location_in_screen_coordinates.y() < system_tray_bubble_bounds_.y())
-    location_in_screen_coordinates.set_y(system_tray_bubble_bounds_.y());
-
-  gfx::Rect bounds_on_location = system_tray_bubble_bounds_;
-  bounds_on_location.set_y(location_in_screen_coordinates.y());
-  system_bubble_->bubble_view()->GetWidget()->SetBounds(bounds_on_location);
-}
-
-bool SystemTray::ShouldShowSystemBubbleAfterScrollSequence(
-    const ui::GestureEvent& sequence_end) {
-  // If the scroll sequence terminates with a fling, show the system menu if the
-  // fling was fast enough and in the correct direction.
-  if (sequence_end.type() == ui::ET_SCROLL_FLING_START &&
-      fabs(sequence_end.details().velocity_y()) > kFlingVelocity) {
-    return sequence_end.details().velocity_y() < 0;
-  }
-
-  DCHECK(sequence_end.type() == ui::ET_GESTURE_SCROLL_END ||
-         sequence_end.type() == ui::ET_SCROLL_FLING_START);
-  // Show the system menu if it is already at least one-third visible.
-  return -gesture_drag_amount_ >= system_tray_bubble_bounds_.height() / 3.0;
-}
-
 void SystemTray::CloseSystemBubbleAndDeactivateSystemTray() {
   activation_observer_.reset();
   system_bubble_.reset();
diff --git a/ash/system/tray/system_tray.h b/ash/system/tray/system_tray.h
index 42a24571..ab5ff6b 100644
--- a/ash/system/tray/system_tray.h
+++ b/ash/system/tray/system_tray.h
@@ -44,11 +44,8 @@
   BUBBLE_USE_EXISTING,  // Uses any existing bubble, or creates a new one.
 };
 
-class ASH_EXPORT SystemTray : public TrayBackgroundView,
-                              public views::TrayBubbleView::Delegate {
+class ASH_EXPORT SystemTray : public TrayBackgroundView {
  public:
-  // The threshold of the velocity of the fling event.
-  static constexpr float kFlingVelocity = 100.0f;
 
   explicit SystemTray(Shelf* shelf);
   ~SystemTray() override;
@@ -114,6 +111,8 @@
   // Returns true if system bubble is visible.
   bool IsSystemBubbleVisible() const;
 
+  // TODO(minch): Remove CloseSystemBubble which is redundant with CloseBubble.
+  // http://crbug.com/741953
   // Closes system bubble and returns true if it did exist.
   bool CloseSystemBubble() const;
 
@@ -124,13 +123,17 @@
   // Returns TrayAudio object if present or null otherwise.
   TrayAudio* GetTrayAudio() const;
 
-  // Overridden from TrayBackgroundView.
+  // TrayBackgroundView:
   void UpdateAfterShelfAlignmentChange() override;
   void AnchorUpdated() override;
   base::string16 GetAccessibleNameForTray() override;
   void BubbleResized(const views::TrayBubbleView* bubble_view) override;
   void HideBubbleWithView(const views::TrayBubbleView* bubble_view) override;
   void ClickedOutsideBubble() override;
+  bool PerformAction(const ui::Event& event) override;
+  void CloseBubble() override;
+  void ShowBubble() override;
+  views::TrayBubbleView* GetBubbleView() override;
 
   // views::TrayBubbleView::Delegate:
   void BubbleViewDestroyed() override;
@@ -150,11 +153,6 @@
   // Activates the system tray bubble.
   void ActivateBubble();
 
-  // ui::EventHandler:
-  void OnGestureEvent(ui::GestureEvent* event) override;
-
-  gfx::Rect GetWorkAreaBoundsInScreen() const;
-
  private:
   friend class SystemTrayTestApi;
   class ActivationObserver;
@@ -196,40 +194,6 @@
   // and the percentage of the work area height covered by the system menu.
   void RecordSystemMenuMetrics();
 
-  // Overridden from ActionableView.
-  bool PerformAction(const ui::Event& event) override;
-
-  // Gesture related functions:
-  bool ProcessGestureEvent(const ui::GestureEvent& event);
-  bool StartGestureDrag(const ui::GestureEvent& gesture);
-  void UpdateGestureDrag(const ui::GestureEvent& gesture);
-  void CompleteGestureDrag(const ui::GestureEvent& gesture);
-
-  // Update the bounds of the system tray bubble according to |location|. Note
-  // that |location| is in the local coordinate space of |this|.
-  void SetBubbleBounds(const gfx::Point& location);
-
-  // Return true if the system bubble should be shown (i.e., animated upward to
-  // be made fully visible) after a sequence of scroll events terminated by
-  // |sequence_end|. Otherwise return false, indicating that the
-  // partially-visible system bubble should be animated downward and made fully
-  // hidden.
-  bool ShouldShowSystemBubbleAfterScrollSequence(
-      const ui::GestureEvent& sequence_end);
-
-  // Shelf the system tray is in.
-  Shelf* const shelf_;
-
-  // The original bounds of the system tray bubble.
-  gfx::Rect system_tray_bubble_bounds_;
-
-  // Tracks the amount of the drag. Only valid if |is_in_drag_| is true.
-  float gesture_drag_amount_ = 0.f;
-
-  // True if the user is in the process of gesture-dragging to open the system
-  // tray bubble, false otherwise.
-  bool is_in_drag_ = false;
-
   // The web notification tray view that appears adjacent to this view.
   WebNotificationTray* web_notification_tray_ = nullptr;
 
diff --git a/ash/system/tray/system_tray_bubble.cc b/ash/system/tray/system_tray_bubble.cc
index a9036cd..bd639391 100644
--- a/ash/system/tray/system_tray_bubble.cc
+++ b/ash/system/tray/system_tray_bubble.cc
@@ -15,7 +15,6 @@
 #include "ash/system/tray/system_tray_item.h"
 #include "ash/system/tray/tray_bubble_wrapper.h"
 #include "ash/system/tray/tray_constants.h"
-#include "ash/wm/maximize_mode/maximize_mode_controller.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "ui/compositor/layer.h"
@@ -69,26 +68,6 @@
 
 }  // namespace
 
-// CloseBubbleObserver is used to delay closing the system tray bubble until the
-// animation completes.
-class CloseBubbleObserver : public ui::ImplicitAnimationObserver {
- public:
-  explicit CloseBubbleObserver(SystemTrayBubble* system_tray_bubble)
-      : system_tray_bubble_(system_tray_bubble) {}
-
-  ~CloseBubbleObserver() override {}
-
-  void OnImplicitAnimationsCompleted() override {
-    system_tray_bubble_->Close();
-    delete this;
-  }
-
- private:
-  SystemTrayBubble* system_tray_bubble_ = nullptr;
-
-  DISALLOW_COPY_AND_ASSIGN(CloseBubbleObserver);
-};
-
 // SystemTrayBubble
 
 SystemTrayBubble::SystemTrayBubble(
@@ -221,27 +200,8 @@
   }
 
   init_params->delegate = tray_;
-  // Place the bubble on same display as this system tray if it is not on
-  // maximize mode. Otherwise, create an clipping window to hold the system
-  // bubble. And place the clipping window on the same display as the system
-  // tray.
-  if (Shell::Get()
-          ->maximize_mode_controller()
-          ->IsMaximizeModeWindowManagerEnabled()) {
-    if (!clipping_window_.get()) {
-      clipping_window_ =
-          std::unique_ptr<aura::Window>(new aura::Window(nullptr));
-      clipping_window_->Init(ui::LAYER_NOT_DRAWN);
-      clipping_window_->layer()->SetMasksToBounds(true);
-      tray_->GetBubbleWindowContainer()->AddChild(clipping_window_.get());
-      clipping_window_->Show();
-    }
-    clipping_window_->SetBounds(tray_->GetWorkAreaBoundsInScreen());
-    init_params->parent_window = clipping_window_.get();
-  } else {
-    init_params->parent_window = tray_->GetBubbleWindowContainer();
-  }
-
+  // Place the bubble on same display as this system tray.
+  init_params->parent_window = tray_->GetBubbleWindowContainer();
   init_params->anchor_view = anchor;
   bubble_view_ = new TrayBubbleView(*init_params);
   UpdateBottomPadding();
@@ -330,22 +290,6 @@
   }
 }
 
-void SystemTrayBubble::AnimateToTargetBounds(const gfx::Rect& target_bounds,
-                                             bool close_bubble) {
-  const int kAnimationDurationMS = 200;
-
-  ui::ScopedLayerAnimationSettings settings(
-      bubble_view()->GetWidget()->GetNativeView()->layer()->GetAnimator());
-  settings.SetTransitionDuration(
-      base::TimeDelta::FromMilliseconds(kAnimationDurationMS));
-  settings.SetTweenType(gfx::Tween::EASE_OUT);
-  settings.SetPreemptionStrategy(
-      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
-  if (close_bubble)
-    settings.AddObserver(new CloseBubbleObserver(this));
-  bubble_view()->GetWidget()->SetBounds(target_bounds);
-}
-
 void SystemTrayBubble::UpdateBottomPadding() {
   if (bubble_type_ == BUBBLE_TYPE_DEFAULT)
     bubble_view_->SetBottomPadding(kDefaultViewBottomPadding);
diff --git a/ash/system/tray/system_tray_bubble.h b/ash/system/tray/system_tray_bubble.h
index 89c490f..bafdbc2d 100644
--- a/ash/system/tray/system_tray_bubble.h
+++ b/ash/system/tray/system_tray_bubble.h
@@ -6,7 +6,6 @@
 #define ASH_SYSTEM_TRAY_SYSTEM_TRAY_BUBBLE_H_
 
 #include <map>
-#include <memory>
 #include <vector>
 
 #include "ash/login_status.h"
@@ -58,10 +57,6 @@
   // BUBBLE_TYPE_DEFAULT BubbleType.
   void RecordVisibleRowMetrics();
 
-  // Update the bounds of the system tray bubble. Close the bubble if
-  // |close_bubble| is set.
-  void AnimateToTargetBounds(const gfx::Rect& target_bounds, bool close_bubble);
-
  private:
   // Updates the bottom padding of the |bubble_view_| based on the
   // |bubble_type_|.
@@ -79,10 +74,6 @@
   int autoclose_delay_;
   base::OneShotTimer autoclose_;
 
-  // Used in maximize mode to make sure the system tray bubble only be shown in
-  // work area.
-  std::unique_ptr<aura::Window> clipping_window_;
-
   DISALLOW_COPY_AND_ASSIGN(SystemTrayBubble);
 };
 
diff --git a/ash/system/tray/system_tray_unittest.cc b/ash/system/tray/system_tray_unittest.cc
index 41e30c25..37fd07a 100644
--- a/ash/system/tray/system_tray_unittest.cc
+++ b/ash/system/tray/system_tray_unittest.cc
@@ -15,13 +15,14 @@
 #include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
+#include "ash/system/status_area_widget_test_helper.h"
 #include "ash/system/tray/system_tray_bubble.h"
 #include "ash/system/tray/system_tray_item.h"
+#include "ash/system/tray/test_system_tray_item.h"
 #include "ash/system/tray/tray_constants.h"
+#include "ash/system/tray_drag_controller.h"
 #include "ash/system/web_notification/web_notification_tray.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/status_area_widget_test_helper.h"
-#include "ash/test/test_system_tray_item.h"
 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/wm/window_util.h"
 #include "base/memory/ptr_util.h"
@@ -57,19 +58,24 @@
 
 }  // namespace
 
+// TODO(minch): move swiping related tests from SystemTrayTest to
+// TraybackgroundView / TrayDragController. crbug.com/745073
 class SystemTrayTest : public AshTestBase {
  public:
   SystemTrayTest() {}
   ~SystemTrayTest() override {}
 
-  // Swiping on the system tray and ends with finger released.
+  // Swiping on the system tray and ends with finger released. Note, |start| is
+  // based on the system tray or system tray bubble's coordinate space.
   void SendGestureEvent(gfx::Point& start,
                         float delta,
                         bool is_fling,
-                        float velocity_y) {
-    SystemTray* system_tray = GetPrimarySystemTray();
+                        float velocity_y,
+                        float scroll_y_hint = -1.0f,
+                        bool drag_on_bubble = false) {
     base::TimeTicks timestamp = base::TimeTicks::Now();
-    SendScrollStartAndUpdate(start, delta, timestamp);
+    SendScrollStartAndUpdate(start, delta, timestamp, scroll_y_hint,
+                             drag_on_bubble);
 
     ui::GestureEventDetails details =
         is_fling
@@ -77,25 +83,37 @@
             : ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_END);
     ui::GestureEvent event = ui::GestureEvent(start.x(), start.y() + delta,
                                               ui::EF_NONE, timestamp, details);
-    system_tray->OnGestureEvent(&event);
+    DispatchGestureEvent(&event, drag_on_bubble);
   }
 
   // Swiping on the system tray without releasing the finger.
   void SendScrollStartAndUpdate(gfx::Point& start,
                                 float delta,
-                                base::TimeTicks& timestamp) {
-    SystemTray* system_tray = GetPrimarySystemTray();
-    ui::GestureEventDetails begin_details(ui::ET_GESTURE_SCROLL_BEGIN);
+                                base::TimeTicks& timestamp,
+                                float scroll_y_hint = -1.0f,
+                                bool drag_on_bubble = false) {
+    ui::GestureEventDetails begin_details(ui::ET_GESTURE_SCROLL_BEGIN, 0,
+                                          scroll_y_hint);
     ui::GestureEvent begin_event = ui::GestureEvent(
         start.x(), start.y(), ui::EF_NONE, timestamp, begin_details);
-    system_tray->OnGestureEvent(&begin_event);
+    DispatchGestureEvent(&begin_event, drag_on_bubble);
 
     ui::GestureEventDetails update_details(ui::ET_GESTURE_SCROLL_UPDATE, 0,
                                            delta);
     timestamp += base::TimeDelta::FromMilliseconds(100);
     ui::GestureEvent update_event = ui::GestureEvent(
         start.x(), start.y() + delta, ui::EF_NONE, timestamp, update_details);
-    system_tray->OnGestureEvent(&update_event);
+    DispatchGestureEvent(&update_event, drag_on_bubble);
+  }
+
+  // Dispatches |event| to target according to |drag_on_bubble|.
+  void DispatchGestureEvent(ui::GestureEvent* event, bool drag_on_bubble) {
+    SystemTray* system_tray = GetPrimarySystemTray();
+    views::View* target = drag_on_bubble
+                              ? system_tray->GetSystemBubble()->bubble_view()
+                              : static_cast<views::View*>(system_tray);
+    ui::Event::DispatcherApi(event).set_target(target);
+    target->OnGestureEvent(event);
   }
 
   // Open the default system tray bubble to get the height of the bubble and
@@ -126,7 +144,7 @@
   Shelf* shelf = GetPrimaryShelf();
   SystemTray* system_tray = GetPrimarySystemTray();
   gfx::Point start = system_tray->GetLocalBounds().CenterPoint();
-  shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
+  EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, shelf->alignment());
   Shell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager(
       true);
 
@@ -163,7 +181,7 @@
 
   // Fling down on the shelf with a velocity that exceeds |kFlingVelocity|.
   EXPECT_FALSE(system_tray->HasSystemBubble());
-  SendGestureEvent(start, delta, true, SystemTray::kFlingVelocity + 1);
+  SendGestureEvent(start, delta, true, TrayDragController::kFlingVelocity + 1);
   current_bounds = GetSystemBubbleBoundsInScreen();
   EXPECT_TRUE(system_tray->HasSystemBubble());
 
@@ -179,8 +197,8 @@
 TEST_F(SystemTrayTest, FlingOnSystemTray) {
   Shelf* shelf = GetPrimaryShelf();
   SystemTray* system_tray = GetPrimarySystemTray();
-  gfx::Point start = system_tray->GetBoundsInScreen().CenterPoint();
-  shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
+  gfx::Point start = system_tray->GetLocalBounds().CenterPoint();
+  EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, shelf->alignment());
   Shell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager(
       true);
 
@@ -188,7 +206,8 @@
   // larger than |kFlingVelocity| and the dragging amount is larger than one
   // third of the height of the bubble.
   float delta = -GetSystemBubbleHeight();
-  SendGestureEvent(start, delta, true, -(SystemTray::kFlingVelocity + 1));
+  SendGestureEvent(start, delta, true,
+                   -(TrayDragController::kFlingVelocity + 1));
   EXPECT_TRUE(system_tray->HasSystemBubble());
   system_tray->CloseSystemBubble();
 
@@ -196,7 +215,8 @@
   // larger than |kFlingVelocity| even the dragging amount is less than one
   // third of the height of the bubble.
   delta /= 4;
-  SendGestureEvent(start, delta, true, -(SystemTray::kFlingVelocity + 1));
+  SendGestureEvent(start, delta, true,
+                   -(TrayDragController::kFlingVelocity + 1));
   EXPECT_TRUE(system_tray->HasSystemBubble());
   system_tray->CloseSystemBubble();
 
@@ -204,7 +224,8 @@
   // less than |kFlingVelocity| but the dragging amount if larger than one third
   // of the height of the bubble.
   delta = -GetSystemBubbleHeight();
-  SendGestureEvent(start, delta, true, -(SystemTray::kFlingVelocity - 1));
+  SendGestureEvent(start, delta, true,
+                   -(TrayDragController::kFlingVelocity - 1));
   EXPECT_TRUE(system_tray->HasSystemBubble());
   system_tray->CloseSystemBubble();
 
@@ -212,25 +233,26 @@
   // is less than |kFlingVelocity| and the dragging amount is less than one
   // third of the height of the bubble.
   delta /= 4;
-  SendGestureEvent(start, delta, true, -(SystemTray::kFlingVelocity - 1));
+  SendGestureEvent(start, delta, true,
+                   -(TrayDragController::kFlingVelocity - 1));
   EXPECT_FALSE(system_tray->HasSystemBubble());
 
   // Fling down on the system tray should close the bubble if the |velocity_y|
   // is larger than kFLingVelocity.
-  SendGestureEvent(start, delta, true, SystemTray::kFlingVelocity + 1);
+  SendGestureEvent(start, delta, true, TrayDragController::kFlingVelocity + 1);
   EXPECT_FALSE(system_tray->HasSystemBubble());
 
   // Fling down on the system tray should close the bubble if the |velocity_y|
   // is larger than |kFlingVelocity| even the dragging amount is larger than one
   // third of the height of the bubble.
   delta = -GetSystemBubbleHeight();
-  SendGestureEvent(start, delta, true, SystemTray::kFlingVelocity + 1);
+  SendGestureEvent(start, delta, true, TrayDragController::kFlingVelocity + 1);
   EXPECT_FALSE(system_tray->HasSystemBubble());
 
   // Fling down on the system tray should open the bubble if the |velocity_y| is
   // less than |kFlingVelocity| but the dragging amount exceed one third of the
   // height of the bubble.
-  SendGestureEvent(start, delta, true, SystemTray::kFlingVelocity - 1);
+  SendGestureEvent(start, delta, true, TrayDragController::kFlingVelocity - 1);
   EXPECT_TRUE(system_tray->HasSystemBubble());
   system_tray->CloseSystemBubble();
 
@@ -238,7 +260,7 @@
   // is less than |kFlingVelocity| and the dragging amount is less than one
   // third of the height of the bubble.
   delta /= 4;
-  SendGestureEvent(start, delta, true, SystemTray::kFlingVelocity - 1);
+  SendGestureEvent(start, delta, true, TrayDragController::kFlingVelocity - 1);
   EXPECT_FALSE(system_tray->HasSystemBubble());
 }
 
@@ -247,7 +269,7 @@
   Shelf* shelf = GetPrimaryShelf();
   SystemTray* system_tray = GetPrimarySystemTray();
   gfx::Point start = system_tray->GetLocalBounds().CenterPoint();
-  shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
+  EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, shelf->alignment());
 
   float delta = -GetSystemBubbleHeight();
   Shell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager(
@@ -268,7 +290,7 @@
   Shelf* shelf = GetPrimaryShelf();
   SystemTray* system_tray = GetPrimarySystemTray();
   gfx::Point start = system_tray->GetLocalBounds().CenterPoint();
-  shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
+  EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, shelf->alignment());
 
   // Swiping up on the system tray has no effect if it is not in maximize mode.
   float delta = -GetSystemBubbleHeight();
@@ -312,13 +334,47 @@
   SendGestureEvent(start, delta, false, 0);
   EXPECT_FALSE(system_tray->HasSystemBubble());
 
-  // Swiping down on the shelf should not show the system tray bubble.
+  // Beginning to scroll downward on the shelf should not show the system tray
+  // bubble, even if the drag then moves upwards.
   shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
-  delta = -delta;
-  SendGestureEvent(start, delta, false, 0);
+  SendGestureEvent(start, delta, false, 0, 1);
   EXPECT_FALSE(system_tray->HasSystemBubble());
 }
 
+// Tests for swiping down on an open system tray bubble in order to
+// close it.
+TEST_F(SystemTrayTest, SwipingOnSystemTrayBubble) {
+  Shelf* shelf = GetPrimaryShelf();
+  SystemTray* system_tray = GetPrimarySystemTray();
+  EXPECT_EQ(SHELF_ALIGNMENT_BOTTOM, shelf->alignment());
+
+  // Beginning to scroll downward and then swiping down more than one third of
+  // the bubble's height should close the bubble. This only takes effect in
+  // maximize mode.
+  Shell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager(
+      true);
+  system_tray->ShowDefaultView(BUBBLE_CREATE_NEW);
+  gfx::Rect bounds =
+      system_tray->GetSystemBubble()->bubble_view()->GetLocalBounds();
+  float delta = bounds.height() / 2;
+  gfx::Point start(bounds.x() + 5, bounds.y() + 5);
+  SendGestureEvent(start, delta, false, 0, 1, true);
+  EXPECT_FALSE(system_tray->HasSystemBubble());
+
+  // Beginning to scroll upward and then swiping down more than one third of the
+  // bubble's height should also close the bubble.
+  system_tray->ShowDefaultView(BUBBLE_CREATE_NEW);
+  SendGestureEvent(start, delta, false, 0, -1, true);
+  EXPECT_FALSE(system_tray->HasSystemBubble());
+
+  // Swiping on the bubble has no effect if it is not in maximize mode.
+  Shell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager(
+      false);
+  system_tray->ShowDefaultView(BUBBLE_CREATE_NEW);
+  SendGestureEvent(start, delta, false, 0, -1, true);
+  EXPECT_TRUE(system_tray->HasSystemBubble());
+}
+
 // Verifies only the visible default views are recorded in the
 // "Ash.SystemMenu.DefaultView.VisibleItems" histogram.
 TEST_F(SystemTrayTest, OnlyVisibleItemsRecorded) {
diff --git a/ash/test/test_system_tray_item.cc b/ash/system/tray/test_system_tray_item.cc
similarity index 97%
rename from ash/test/test_system_tray_item.cc
rename to ash/system/tray/test_system_tray_item.cc
index 53d8e5e..7dd8011c 100644
--- a/ash/test/test_system_tray_item.cc
+++ b/ash/system/tray/test_system_tray_item.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 "ash/test/test_system_tray_item.h"
+#include "ash/system/tray/test_system_tray_item.h"
 
 #include "ash/test/ash_test_base.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/ash/test/test_system_tray_item.h b/ash/system/tray/test_system_tray_item.h
similarity index 89%
rename from ash/test/test_system_tray_item.h
rename to ash/system/tray/test_system_tray_item.h
index 450f430f..7b72992 100644
--- a/ash/test/test_system_tray_item.h
+++ b/ash/system/tray/test_system_tray_item.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 ASH_COMMON_SYSTEM_TRAY_TEST_TEST_SYSTEM_TRAY_ITEM_H_
-#define ASH_COMMON_SYSTEM_TRAY_TEST_TEST_SYSTEM_TRAY_ITEM_H_
+#ifndef ASH_SYSTEM_TRAY_TEST_SYSTEM_TRAY_ITEM_H_
+#define ASH_SYSTEM_TRAY_TEST_SYSTEM_TRAY_ITEM_H_
 
 #include "ash/system/tray/system_tray_item.h"
 
@@ -47,4 +47,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_COMMON_SYSTEM_TRAY_TEST_TEST_SYSTEM_TRAY_ITEM_H_
+#endif  // ASH_SYSTEM_TRAY_TEST_SYSTEM_TRAY_ITEM_H_
diff --git a/ash/system/tray/tray_background_view.cc b/ash/system/tray/tray_background_view.cc
index ec269d2..c719127 100644
--- a/ash/system/tray/tray_background_view.cc
+++ b/ash/system/tray/tray_background_view.cc
@@ -16,6 +16,7 @@
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/tray/tray_container.h"
 #include "ash/system/tray/tray_event_filter.h"
+#include "ash/wm/maximize_mode/maximize_mode_controller.h"
 #include "base/memory/ptr_util.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/compositor/layer.h"
@@ -130,6 +131,26 @@
   DISALLOW_COPY_AND_ASSIGN(TrayBackground);
 };
 
+// CloseBubbleObserver is used to delay closing the tray bubbles until the
+// animation completes.
+class CloseBubbleObserver : public ui::ImplicitAnimationObserver {
+ public:
+  explicit CloseBubbleObserver(TrayBackgroundView* tray_background_view)
+      : tray_background_view_(tray_background_view) {}
+
+  ~CloseBubbleObserver() override {}
+
+  void OnImplicitAnimationsCompleted() override {
+    tray_background_view_->CloseBubble();
+    delete this;
+  }
+
+ private:
+  TrayBackgroundView* tray_background_view_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(CloseBubbleObserver);
+};
+
 ////////////////////////////////////////////////////////////////////////////////
 // TrayBackgroundView
 
@@ -236,13 +257,12 @@
   return kViewClassName;
 }
 
-void TrayBackgroundView::ChildPreferredSizeChanged(views::View* child) {
-  PreferredSizeChanged();
-}
+void TrayBackgroundView::OnGestureEvent(ui::GestureEvent* event) {
+  if (drag_controller())
+    drag_controller_->ProcessGestureEvent(event, this);
 
-void TrayBackgroundView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
-  ActionableView::GetAccessibleNodeData(node_data);
-  node_data->SetName(GetAccessibleNameForTray());
+  if (!event->handled())
+    ActionableView::OnGestureEvent(event);
 }
 
 void TrayBackgroundView::AboutToRequestFocusFromTabTraversal(bool reverse) {
@@ -252,6 +272,15 @@
     Shell::Get()->system_tray_notifier()->NotifyFocusOut(reverse);
 }
 
+void TrayBackgroundView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
+  ActionableView::GetAccessibleNodeData(node_data);
+  node_data->SetName(GetAccessibleNameForTray());
+}
+
+void TrayBackgroundView::ChildPreferredSizeChanged(views::View* child) {
+  PreferredSizeChanged();
+}
+
 std::unique_ptr<views::InkDropRipple> TrayBackgroundView::CreateInkDropRipple()
     const {
   return base::MakeUnique<views::FloodFillInkDropRipple>(
@@ -306,6 +335,19 @@
   }
 }
 
+void TrayBackgroundView::ProcessGestureEventForBubble(ui::GestureEvent* event) {
+  if (drag_controller())
+    drag_controller_->ProcessGestureEvent(event, this);
+}
+
+TrayBubbleView* TrayBackgroundView::GetBubbleView() {
+  return nullptr;
+}
+
+void TrayBackgroundView::CloseBubble() {}
+
+void TrayBackgroundView::ShowBubble() {}
+
 void TrayBackgroundView::UpdateAfterShelfAlignmentChange() {
   tray_container_->UpdateAfterShelfAlignmentChange();
 
@@ -319,6 +361,11 @@
       GetLocalBounds().InsetsFrom(paint_bounds)));
 }
 
+void TrayBackgroundView::AnchorUpdated() {}
+
+void TrayBackgroundView::BubbleResized(
+    const views::TrayBubbleView* bubble_view) {}
+
 void TrayBackgroundView::OnImplicitAnimationsCompleted() {
   // If there is another animation in the queue, the reverse animation was
   // triggered before the completion of animating to invisible. Do not turn off
@@ -392,10 +439,43 @@
   }
 }
 
-aura::Window* TrayBackgroundView::GetBubbleWindowContainer() const {
-  return Shell::GetContainer(
+aura::Window* TrayBackgroundView::GetBubbleWindowContainer() {
+  aura::Window* container = Shell::GetContainer(
       tray_container()->GetWidget()->GetNativeWindow()->GetRootWindow(),
       kShellWindowId_SettingBubbleContainer);
+
+  // Place the bubble in |container|, or in a window clipped to the work area
+  // in maximize mode, to avoid tray bubble and shelf overlap.
+  if (Shell::Get()
+          ->maximize_mode_controller()
+          ->IsMaximizeModeWindowManagerEnabled()) {
+    if (!clipping_window_.get()) {
+      clipping_window_ = base::MakeUnique<aura::Window>(nullptr);
+      clipping_window_->Init(ui::LAYER_NOT_DRAWN);
+      clipping_window_->layer()->SetMasksToBounds(true);
+      container->AddChild(clipping_window_.get());
+      clipping_window_->Show();
+    }
+    clipping_window_->SetBounds(shelf_->GetUserWorkAreaBounds());
+    return clipping_window_.get();
+  }
+  return container;
+}
+
+void TrayBackgroundView::AnimateToTargetBounds(const gfx::Rect& target_bounds,
+                                               bool close_bubble) {
+  const int kAnimationDurationMS = 200;
+
+  ui::ScopedLayerAnimationSettings settings(
+      GetBubbleView()->GetWidget()->GetNativeView()->layer()->GetAnimator());
+  settings.SetTransitionDuration(
+      base::TimeDelta::FromMilliseconds(kAnimationDurationMS));
+  settings.SetTweenType(gfx::Tween::EASE_OUT);
+  settings.SetPreemptionStrategy(
+      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
+  if (close_bubble)
+    settings.AddObserver(new CloseBubbleObserver(this));
+  GetBubbleView()->GetWidget()->SetBounds(target_bounds);
 }
 
 std::unique_ptr<views::InkDropMask> TrayBackgroundView::CreateInkDropMask()
diff --git a/ash/system/tray/tray_background_view.h b/ash/system/tray/tray_background_view.h
index 0429417..8ef054f 100644
--- a/ash/system/tray/tray_background_view.h
+++ b/ash/system/tray/tray_background_view.h
@@ -10,6 +10,7 @@
 #include "ash/ash_export.h"
 #include "ash/shelf/shelf_background_animator_observer.h"
 #include "ash/system/tray/actionable_view.h"
+#include "ash/system/tray_drag_controller.h"
 #include "base/macros.h"
 #include "ui/compositor/layer_animation_observer.h"
 #include "ui/gfx/geometry/insets.h"
@@ -27,7 +28,8 @@
 // PerformAction when clicked on.
 class ASH_EXPORT TrayBackgroundView : public ActionableView,
                                       public ui::ImplicitAnimationObserver,
-                                      public ShelfBackgroundAnimatorObserver {
+                                      public ShelfBackgroundAnimatorObserver,
+                                      public views::TrayBubbleView::Delegate {
  public:
   static const char kViewClassName[];
 
@@ -43,9 +45,10 @@
   // views::View:
   void SetVisible(bool visible) override;
   const char* GetClassName() const override;
-  void ChildPreferredSizeChanged(views::View* child) override;
-  void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
+  void OnGestureEvent(ui::GestureEvent* event) override;
   void AboutToRequestFocusFromTabTraversal(bool reverse) override;
+  void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
+  void ChildPreferredSizeChanged(views::View* child) override;
 
   // ActionableView:
   std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override;
@@ -53,17 +56,31 @@
       const override;
   void PaintButtonContents(gfx::Canvas* canvas) override;
 
+  // TrayBubbleView::Delegate:
+  void ProcessGestureEventForBubble(ui::GestureEvent* event) override;
+
+  // Returns the associated tray bubble view, if one exists. Otherwise returns
+  // nullptr.
+  virtual views::TrayBubbleView* GetBubbleView();
+
+  // Closes the associated tray bubble view if it exists and is currently
+  // showing.
+  virtual void CloseBubble();
+
+  // Shows the associated tray bubble if one exists.
+  virtual void ShowBubble();
+
   // Called whenever the shelf alignment changes.
   virtual void UpdateAfterShelfAlignmentChange();
 
   // Called when the anchor (tray or bubble) may have moved or changed.
-  virtual void AnchorUpdated() {}
+  virtual void AnchorUpdated();
 
   // Called from GetAccessibleNodeData, must return a valid accessible name.
   virtual base::string16 GetAccessibleNameForTray() = 0;
 
   // Called when the bubble is resized.
-  virtual void BubbleResized(const views::TrayBubbleView* bubble_view) {}
+  virtual void BubbleResized(const views::TrayBubbleView* bubble_view);
 
   // Hides the bubble associated with |bubble_view|. Called when the widget
   // is closed.
@@ -100,7 +117,11 @@
   gfx::Insets GetBubbleAnchorInsets() const;
 
   // Returns the container window for the bubble (on the proper display).
-  aura::Window* GetBubbleWindowContainer() const;
+  aura::Window* GetBubbleWindowContainer();
+
+  // Update the bounds of the associated tray bubble. Close the bubble if
+  // |close_bubble| is set.
+  void AnimateToTargetBounds(const gfx::Rect& target_bounds, bool close_bubble);
 
  protected:
   // ActionableView:
@@ -110,6 +131,12 @@
   void HandlePerformActionResult(bool action_performed,
                                  const ui::Event& event) override;
 
+  TrayDragController* drag_controller() { return drag_controller_.get(); }
+  void set_drag_controller(
+      std::unique_ptr<TrayDragController> drag_controller) {
+    drag_controller_ = std::move(drag_controller);
+  }
+
  private:
   class TrayWidgetObserver;
 
@@ -145,6 +172,13 @@
   // right of tray.
   bool separator_visible_;
 
+  // Handles touch drag gestures on the tray area and its associated bubble.
+  std::unique_ptr<TrayDragController> drag_controller_;
+
+  // Used in maximize mode to make sure the system tray bubble only be shown in
+  // work area.
+  std::unique_ptr<aura::Window> clipping_window_;
+
   std::unique_ptr<TrayWidgetObserver> widget_observer_;
   std::unique_ptr<TrayEventFilter> tray_event_filter_;
 
diff --git a/ash/system/tray_drag_controller.cc b/ash/system/tray_drag_controller.cc
new file mode 100644
index 0000000..b3ec4b3
--- /dev/null
+++ b/ash/system/tray_drag_controller.cc
@@ -0,0 +1,128 @@
+// Copyright 2017 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/system/tray_drag_controller.h"
+
+#include "ash/shell.h"
+#include "ash/system/tray/tray_background_view.h"
+#include "ash/wm/maximize_mode/maximize_mode_controller.h"
+
+namespace ash {
+
+TrayDragController::TrayDragController(Shelf* shelf) : shelf_(shelf) {}
+
+void TrayDragController::ProcessGestureEvent(ui::GestureEvent* event,
+                                             TrayBackgroundView* tray_view) {
+  if (!Shell::Get()
+           ->maximize_mode_controller()
+           ->IsMaximizeModeWindowManagerEnabled() ||
+      !shelf_->IsHorizontalAlignment()) {
+    return;
+  }
+
+  tray_view_ = tray_view;
+  is_on_bubble_ = event->target() != tray_view;
+  if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN) {
+    if (StartGestureDrag(*event))
+      event->SetHandled();
+    return;
+  }
+
+  if (!tray_view_->GetBubbleView() || !is_in_drag_)
+    return;
+
+  if (event->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
+    UpdateGestureDrag(*event);
+    event->SetHandled();
+    return;
+  }
+
+  if (event->type() == ui::ET_GESTURE_SCROLL_END ||
+      event->type() == ui::ET_SCROLL_FLING_START) {
+    CompleteGestureDrag(*event);
+    event->SetHandled();
+    return;
+  }
+
+  // Unexpected event. Reset the drag state and close the bubble.
+  is_in_drag_ = false;
+  tray_view_->CloseBubble();
+}
+
+bool TrayDragController::StartGestureDrag(const ui::GestureEvent& gesture) {
+  if (!is_on_bubble_) {
+    // Dragging happens on the tray view. Close the bubble if there is already
+    // one opened. And return false to let shelf handle the event.
+    if (tray_view_->GetBubbleView()) {
+      tray_view_->CloseBubble();
+      return false;
+    }
+
+    // If the scroll sequence begins to scroll downward, return false so that
+    // the event will instead by handled by the shelf.
+    if (gesture.details().scroll_y_hint() > 0)
+      return false;
+
+    tray_view_->ShowBubble();
+  }
+
+  if (!tray_view_->GetBubbleView())
+    return false;
+
+  is_in_drag_ = true;
+  gesture_drag_amount_ = 0.f;
+  tray_bubble_bounds_ =
+      tray_view_->GetBubbleView()->GetWidget()->GetWindowBoundsInScreen();
+  UpdateBubbleBounds();
+  return true;
+}
+
+void TrayDragController::UpdateGestureDrag(const ui::GestureEvent& gesture) {
+  gesture_drag_amount_ += gesture.details().scroll_y();
+  UpdateBubbleBounds();
+}
+
+void TrayDragController::CompleteGestureDrag(const ui::GestureEvent& gesture) {
+  const bool hide_bubble = !ShouldShowBubbleAfterScrollSequence(gesture);
+  gfx::Rect target_bounds = tray_bubble_bounds_;
+
+  if (hide_bubble)
+    target_bounds.set_y(shelf_->GetIdealBounds().y());
+
+  tray_view_->AnimateToTargetBounds(target_bounds, hide_bubble);
+  is_in_drag_ = false;
+}
+
+void TrayDragController::UpdateBubbleBounds() {
+  DCHECK(tray_view_->GetBubbleView());
+
+  gfx::Rect current_tray_bubble_bounds = tray_bubble_bounds_;
+  const int bounds_y =
+      (is_on_bubble_ ? tray_bubble_bounds_.y() : shelf_->GetIdealBounds().y()) +
+      gesture_drag_amount_;
+  current_tray_bubble_bounds.set_y(std::max(bounds_y, tray_bubble_bounds_.y()));
+  tray_view_->GetBubbleView()->GetWidget()->SetBounds(
+      current_tray_bubble_bounds);
+}
+
+bool TrayDragController::ShouldShowBubbleAfterScrollSequence(
+    const ui::GestureEvent& sequence_end) {
+  // If the scroll sequence terminates with a fling, show the bubble if the
+  // fling was fast enough and in the correct direction.
+  if (sequence_end.type() == ui::ET_SCROLL_FLING_START &&
+      fabs(sequence_end.details().velocity_y()) > kFlingVelocity) {
+    return sequence_end.details().velocity_y() < 0;
+  }
+
+  DCHECK(sequence_end.type() == ui::ET_GESTURE_SCROLL_END ||
+         sequence_end.type() == ui::ET_SCROLL_FLING_START);
+
+  // Keep the bubble's original state if the |gesture_drag_amount_| doesn't
+  // exceed one-third of the bubble's height.
+  if (is_on_bubble_)
+    return gesture_drag_amount_ < tray_bubble_bounds_.height() / 3.0;
+  return -gesture_drag_amount_ >= tray_bubble_bounds_.height() / 3.0;
+}
+
+}  // namespace ash
diff --git a/ash/system/tray_drag_controller.h b/ash/system/tray_drag_controller.h
new file mode 100644
index 0000000..09b5398
--- /dev/null
+++ b/ash/system/tray_drag_controller.h
@@ -0,0 +1,75 @@
+// Copyright 2017 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 ASH_SYSTEM_TRAY_DRAG_CONTROLLER_H_
+#define ASH_SYSTEM_TRAY_DRAG_CONTROLLER_H_
+
+#include "ash/ash_export.h"
+#include "ash/shelf/shelf.h"
+#include "ui/views/view.h"
+
+namespace ash {
+class TrayBackgroundView;
+
+// The TrayDragController helps to process the swiping events that happened on
+// TrayBackgroundView or TrayBubbleView. Not all the TrayBackgroundView can be
+// dragged currently. Only ImeMenuTray, SystemTray, PaletteTray,
+// WebNotificationTray and their associated tray bubbles can be dragged.
+class ASH_EXPORT TrayDragController {
+ public:
+  // The threshold of the velocity of the fling event.
+  static constexpr float kFlingVelocity = 100.0f;
+
+  explicit TrayDragController(Shelf* shelf);
+
+  // Processes a gesture event and updates the dragging state of the bubble when
+  // appropriate.
+  void ProcessGestureEvent(ui::GestureEvent* event,
+                           TrayBackgroundView* tray_view);
+
+ private:
+  // Gesture related functions:
+  bool StartGestureDrag(const ui::GestureEvent& gesture);
+  void UpdateGestureDrag(const ui::GestureEvent& gesture);
+  void CompleteGestureDrag(const ui::GestureEvent& gesture);
+
+  // Update the bounds of the tray bubble according to
+  // |gesture_drag_amount_|.
+  void UpdateBubbleBounds();
+
+  // Return true if the bubble should be shown (i.e., animated upward to
+  // be made fully visible) after a sequence of scroll events terminated by
+  // |sequence_end|. Otherwise return false, indicating that the
+  // partially-visible bubble should be animated downward and made fully
+  // hidden.
+  bool ShouldShowBubbleAfterScrollSequence(
+      const ui::GestureEvent& sequence_end);
+
+  // The shelf containing the TrayBackgroundView.
+  Shelf* shelf_;
+
+  // The specific TrayBackgroundView that dragging happened on. e.g, SystemTray.
+  TrayBackgroundView* tray_view_ = nullptr;
+
+  // The original bounds of the tray bubble.
+  gfx::Rect tray_bubble_bounds_;
+
+  // Tracks the amount of the drag. Only valid if |is_in_drag_| is true.
+  float gesture_drag_amount_ = 0.f;
+
+  // True if the user is in the process of gesture-dragging on
+  // TrayBackgroundView to open the tray bubble, or on the already-opened
+  // TrayBubbleView to close it. Otherwise false.
+  bool is_in_drag_ = false;
+
+  // True if the dragging happened on the bubble view, false if it happened on
+  // the tray view. Note, only valid if |is_in_drag_| is true.
+  bool is_on_bubble_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(TrayDragController);
+};
+
+}  // namespace ash
+
+#endif  // ASH_SYSTEM_TRAY_DRAG_CONTROLLER_H_
diff --git a/ash/system/user/tray_user_unittest.cc b/ash/system/user/tray_user_unittest.cc
index 7e482c4..9604cfa 100644
--- a/ash/system/user/tray_user_unittest.cc
+++ b/ash/system/user/tray_user_unittest.cc
@@ -6,6 +6,7 @@
 #include <vector>
 
 #include "ash/session/session_controller.h"
+#include "ash/session/test_session_controller_client.h"
 #include "ash/shell.h"
 #include "ash/shell_delegate.h"
 #include "ash/system/tray/system_tray.h"
@@ -14,8 +15,7 @@
 #include "ash/system/user/tray_user.h"
 #include "ash/system/user/user_view.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/test_session_controller_client.h"
-#include "ash/test/test_shell_delegate.h"
+#include "ash/test_shell_delegate.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/signin/core/account_id/account_id.h"
diff --git a/ash/system/web_notification/web_notification_tray.cc b/ash/system/web_notification/web_notification_tray.cc
index 831c1320..be9e165 100644
--- a/ash/system/web_notification/web_notification_tray.cc
+++ b/ash/system/web_notification/web_notification_tray.cc
@@ -305,6 +305,9 @@
   OnMessageCenterTrayChanged();
 
   tray_container()->SetMargin(kTrayMainAxisInset, kTrayCrossAxisInset);
+
+  if (!drag_controller())
+    set_drag_controller(base::MakeUnique<TrayDragController>(shelf));
 }
 
 WebNotificationTray::~WebNotificationTray() {
@@ -399,11 +402,6 @@
           message_center_bubble()->bubble()->IsVisible());
 }
 
-void WebNotificationTray::ShowMessageCenterBubble() {
-  if (!IsMessageCenterBubbleVisible())
-    message_center_tray_->ShowMessageCenterBubble();
-}
-
 void WebNotificationTray::UpdateAfterLoginStatusChange(
     LoginStatus login_status) {
   message_center()->SetLockedState(login_status == LoginStatus::LOCKED);
@@ -438,14 +436,6 @@
   }
 }
 
-bool WebNotificationTray::PerformAction(const ui::Event& event) {
-  if (message_center_bubble())
-    message_center_tray_->HideMessageCenterBubble();
-  else
-    message_center_tray_->ShowMessageCenterBubble();
-  return true;
-}
-
 void WebNotificationTray::BubbleViewDestroyed() {
   if (message_center_bubble())
     message_center_bubble()->bubble()->BubbleViewDestroyed();
@@ -602,6 +592,28 @@
   message_center_tray_->HideMessageCenterBubble();
 }
 
+bool WebNotificationTray::PerformAction(const ui::Event& event) {
+  if (message_center_bubble())
+    message_center_tray_->HideMessageCenterBubble();
+  else
+    message_center_tray_->ShowMessageCenterBubble();
+  return true;
+}
+
+void WebNotificationTray::CloseBubble() {
+  message_center_tray_->HideMessageCenterBubble();
+}
+
+void WebNotificationTray::ShowBubble() {
+  if (!IsMessageCenterBubbleVisible())
+    message_center_tray_->ShowMessageCenterBubble();
+}
+
+views::TrayBubbleView* WebNotificationTray::GetBubbleView() {
+  return message_center_bubble_ ? message_center_bubble_->bubble_view()
+                                : nullptr;
+}
+
 message_center::MessageCenter* WebNotificationTray::message_center() const {
   return message_center_tray_->message_center();
 }
diff --git a/ash/system/web_notification/web_notification_tray.h b/ash/system/web_notification/web_notification_tray.h
index 6545949..0a801663 100644
--- a/ash/system/web_notification/web_notification_tray.h
+++ b/ash/system/web_notification/web_notification_tray.h
@@ -45,7 +45,6 @@
 // is controlled by StatusAreaWidget.
 class ASH_EXPORT WebNotificationTray
     : public TrayBackgroundView,
-      public views::TrayBubbleView::Delegate,
       public message_center::MessageCenterTrayDelegate,
       public base::SupportsWeakPtr<WebNotificationTray>,
       public ui::SimpleMenuModel::Delegate {
@@ -71,9 +70,6 @@
   // Returns true if the message center bubble is visible.
   bool IsMessageCenterBubbleVisible() const;
 
-  // Shows the message center bubble.
-  void ShowMessageCenterBubble();
-
   // Called when the login status is changed.
   void UpdateAfterLoginStatusChange(LoginStatus login_status);
 
@@ -83,9 +79,10 @@
   base::string16 GetAccessibleNameForTray() override;
   void HideBubbleWithView(const views::TrayBubbleView* bubble_view) override;
   void ClickedOutsideBubble() override;
-
-  // Overridden from ActionableView.
   bool PerformAction(const ui::Event& event) override;
+  void CloseBubble() override;
+  void ShowBubble() override;
+  views::TrayBubbleView* GetBubbleView() override;
 
   // Overridden from views::TrayBubbleView::Delegate.
   void BubbleViewDestroyed() override;
diff --git a/ash/system/web_notification/web_notification_tray_unittest.cc b/ash/system/web_notification/web_notification_tray_unittest.cc
index 8a07cab..6f9ed0731 100644
--- a/ash/system/web_notification/web_notification_tray_unittest.cc
+++ b/ash/system/web_notification/web_notification_tray_unittest.cc
@@ -14,11 +14,11 @@
 #include "ash/shell.h"
 #include "ash/system/screen_layout_observer.h"
 #include "ash/system/status_area_widget.h"
+#include "ash/system/status_area_widget_test_helper.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_item.h"
 #include "ash/system/web_notification/ash_popup_alignment_delegate.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/status_area_widget_test_helper.h"
 #include "ash/wm/window_state.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
diff --git a/ash/test/BUILD.gn b/ash/test/BUILD.gn
deleted file mode 100644
index d7e3f43..0000000
--- a/ash/test/BUILD.gn
+++ /dev/null
@@ -1,206 +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("//build/config/ui.gni")
-
-static_library("test_support_without_content") {
-  testonly = true
-  sources = [
-    "ash_test_environment_default.cc",
-  ]
-
-  public_deps = [
-    ":test_support_common",
-  ]
-
-  deps = [
-    "//base",
-    "//base/test:test_support",
-    "//skia",
-  ]
-}
-
-static_library("test_support_with_content") {
-  testonly = true
-  sources = [
-    "ash_test_environment_content.cc",
-    "ash_test_environment_content.h",
-    "content/test_shell_content_state.cc",
-    "content/test_shell_content_state.h",
-  ]
-  configs += [ "//build/config:precompiled_headers" ]
-
-  public_deps = [
-    ":test_support_common",
-    "//ash:ash_with_content",
-    "//content/public/browser",
-    "//content/test:test_support",
-    "//skia",
-  ]
-}
-
-# Internal target consumed by |test_support_with_content| and
-# |test_support_without_content|. This target contains all the test support
-# files, with the exception of an implementation of AshTestEnvironment.
-# Consumers of ash should use one of |test_support_with_content| or
-# |test_support_without_content|.
-static_library("test_support_common") {
-  testonly = true
-  visibility = [ ":*" ]
-  sources = [
-    "../laser/laser_pointer_controller_test_api.cc",
-    "../laser/laser_pointer_controller_test_api.h",
-    "../laser/laser_pointer_points_test_api.cc",
-    "../laser/laser_pointer_points_test_api.h",
-    "../rotator/test/screen_rotation_animator_test_api.cc",
-    "../rotator/test/screen_rotation_animator_test_api.h",
-    "../shell/toplevel_window.cc",
-    "../shell/toplevel_window.h",
-    "../system/tray/system_tray_test_api.h",
-    "ash_test_base.cc",
-    "ash_test_base.h",
-    "ash_test_environment.h",
-    "ash_test_helper.cc",
-    "ash_test_helper.h",
-    "ash_test_views_delegate.cc",
-    "ash_test_views_delegate.h",
-    "child_modal_window.cc",
-    "child_modal_window.h",
-    "cursor_manager_test_api.cc",
-    "cursor_manager_test_api.h",
-    "display_configuration_controller_test_api.cc",
-    "display_configuration_controller_test_api.h",
-    "immersive_fullscreen_controller_test_api.cc",
-    "immersive_fullscreen_controller_test_api.h",
-    "lock_state_controller_test_api.cc",
-    "lock_state_controller_test_api.h",
-    "mirror_window_test_api.cc",
-    "mirror_window_test_api.h",
-    "overflow_bubble_view_test_api.cc",
-    "overflow_bubble_view_test_api.h",
-    "overflow_button_test_api.cc",
-    "overflow_button_test_api.h",
-    "screen_orientation_controller_test_api.cc",
-    "screen_orientation_controller_test_api.h",
-    "shelf_button_pressed_metric_tracker_test_api.cc",
-    "shelf_button_pressed_metric_tracker_test_api.h",
-    "shelf_view_test_api.cc",
-    "shelf_view_test_api.h",
-    "shell_test_api.cc",
-    "shell_test_api.h",
-    "status_area_widget_test_helper.cc",
-    "status_area_widget_test_helper.h",
-    "task_switch_time_tracker_test_api.cc",
-    "task_switch_time_tracker_test_api.h",
-    "test_accessibility_delegate.cc",
-    "test_accessibility_delegate.h",
-    "test_activation_delegate.cc",
-    "test_activation_delegate.h",
-    "test_app_list_view_presenter_impl.cc",
-    "test_app_list_view_presenter_impl.h",
-    "test_keyboard_ui.cc",
-    "test_keyboard_ui.h",
-    "test_overlay_delegate.cc",
-    "test_overlay_delegate.h",
-    "test_palette_delegate.cc",
-    "test_palette_delegate.h",
-    "test_screenshot_delegate.cc",
-    "test_screenshot_delegate.h",
-    "test_session_controller_client.cc",
-    "test_session_controller_client.h",
-    "test_session_state_animator.cc",
-    "test_session_state_animator.h",
-    "test_shell_delegate.cc",
-    "test_shell_delegate.h",
-    "test_system_tray_item.cc",
-    "test_system_tray_item.h",
-    "test_wallpaper_delegate.cc",
-    "test_wallpaper_delegate.h",
-    "tray_cast_test_api.cc",
-    "tray_cast_test_api.h",
-    "ui_controls_factory_ash.cc",
-    "ui_controls_factory_ash.h",
-    "user_metrics_recorder_test_api.cc",
-    "user_metrics_recorder_test_api.h",
-    "wallpaper_controller_test_api.cc",
-    "wallpaper_controller_test_api.h",
-    "workspace_controller_test_api.cc",
-    "workspace_controller_test_api.h",
-    "workspace_event_handler_test_helper.cc",
-    "workspace_event_handler_test_helper.h",
-  ]
-  configs += [ "//build/config:precompiled_headers" ]
-
-  public_deps = [
-    "//ash",
-    "//testing/gtest",
-    "//third_party/WebKit/public:blink_headers",
-    "//ui/display:display_manager_test_api",
-  ]
-  deps = [
-    "//ash",
-    "//ash/mus:lib",
-    "//ash/public/cpp:ash_public_cpp",
-    "//ash/resources",
-    "//base",
-    "//base:i18n",
-    "//base/test:test_support",
-    "//chromeos",
-    "//components/prefs:test_support",
-    "//components/signin/core/account_id",
-    "//components/user_manager:user_manager",
-    "//device/bluetooth",
-    "//services/ui/public/cpp/input_devices",
-    "//services/ui/public/interfaces",
-    "//skia",
-    "//testing/gtest",
-    "//ui/accessibility",
-    "//ui/app_list:test_support",
-    "//ui/app_list/presenter",
-    "//ui/app_list/presenter:test_support",
-    "//ui/aura",
-    "//ui/aura:test_support",
-    "//ui/base:test_support",
-    "//ui/compositor:test_support",
-    "//ui/display",
-    "//ui/display/types",
-    "//ui/events:events_base",
-    "//ui/events:test_support",
-    "//ui/events/devices",
-    "//ui/gl",
-    "//ui/gl:test_support",
-    "//ui/keyboard",
-    "//ui/message_center",
-    "//ui/views",
-    "//ui/views:test_support",
-    "//ui/wm",
-    "//ui/wm/public",
-  ]
-
-  if (use_x11) {
-    deps += [ "//ui/gfx/x" ]
-  }
-}
-
-static_library("interactive_ui_test_support") {
-  testonly = true
-  configs += [ "//build/config:precompiled_headers" ]
-  public_deps = [
-    ":test_support_without_content",
-    "//ash",
-  ]
-  sources = [
-    "ash_interactive_ui_test_base.cc",
-    "ash_interactive_ui_test_base.h",
-  ]
-  deps = [
-    ":test_support_with_content",
-    "//base",
-    "//skia",
-    "//testing/gtest",
-    "//ui/aura",
-    "//ui/base",
-    "//ui/gl:test_support",
-  ]
-}
diff --git a/ash/test/DEPS b/ash/test/DEPS
index f15a004..0f482bc 100644
--- a/ash/test/DEPS
+++ b/ash/test/DEPS
@@ -17,10 +17,4 @@
     "+ash/host",
     "+chromeos/cryptohome",
   ],
-  "mirror_window_test_api\.cc": [
-    "+ash/host"
-  ],
-  "screen_orientation_controller_test_api.h": [
-    "+third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h",
-  ],
 }
diff --git a/ash/test/ash_test_base.cc b/ash/test/ash_test_base.cc
index 8fd9c4f..3b0bfe4 100644
--- a/ash/test/ash_test_base.cc
+++ b/ash/test/ash_test_base.cc
@@ -18,12 +18,12 @@
 #include "ash/public/cpp/window_properties.h"
 #include "ash/root_window_controller.h"
 #include "ash/session/session_controller.h"
+#include "ash/session/test_session_controller_client.h"
 #include "ash/shell.h"
 #include "ash/shell/toplevel_window.h"
 #include "ash/test/ash_test_environment.h"
 #include "ash/test/ash_test_helper.h"
-#include "ash/test/test_session_controller_client.h"
-#include "ash/test/test_shell_delegate.h"
+#include "ash/test_shell_delegate.h"
 #include "ash/wm/window_positioner.h"
 #include "services/ui/public/cpp/property_type_converters.h"
 #include "services/ui/public/interfaces/window_manager.mojom.h"
diff --git a/ash/test/ash_test_environment.h b/ash/test/ash_test_environment.h
index 11ac414..ed2ecf1b 100644
--- a/ash/test/ash_test_environment.h
+++ b/ash/test/ash_test_environment.h
@@ -18,9 +18,9 @@
 //
 // AshTestBase creates an AshTestEnvironment by way of
 // AshTestEnvironment::Create(). The implementation of Create() depends upon
-// the ash target that was linked against: //ash/test:test_support_with_content
+// the ash target that was linked against: //ash:test_support_with_content
 // includes AshTestEnvironmentContent and
-// //ash/test:test_support_without_content includes AshTestEnvironmentDefault.
+// //ash:test_support_without_content includes AshTestEnvironmentDefault.
 class AshTestEnvironment {
  public:
   virtual ~AshTestEnvironment() {}
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc
index d48ec7c..4beca1f 100644
--- a/ash/test/ash_test_helper.cc
+++ b/ash/test/ash_test_helper.cc
@@ -10,6 +10,7 @@
 #include "ash/accelerators/accelerator_controller_delegate_aura.h"
 #include "ash/ash_switches.h"
 #include "ash/aura/shell_port_classic.h"
+#include "ash/display/display_configuration_controller_test_api.h"
 #include "ash/mus/bridge/shell_port_mash.h"
 #include "ash/mus/window_manager.h"
 #include "ash/mus/window_manager_application.h"
@@ -20,9 +21,8 @@
 #include "ash/system/screen_layout_observer.h"
 #include "ash/test/ash_test_environment.h"
 #include "ash/test/ash_test_views_delegate.h"
-#include "ash/test/display_configuration_controller_test_api.h"
-#include "ash/test/test_screenshot_delegate.h"
-#include "ash/test/test_shell_delegate.h"
+#include "ash/test_screenshot_delegate.h"
+#include "ash/test_shell_delegate.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/strings/string_split.h"
diff --git a/ash/test/ash_test_helper.h b/ash/test/ash_test_helper.h
index 4c2f7621..566c61e 100644
--- a/ash/test/ash_test_helper.h
+++ b/ash/test/ash_test_helper.h
@@ -12,7 +12,7 @@
 #include <utility>
 #include <vector>
 
-#include "ash/test/test_session_controller_client.h"
+#include "ash/session/test_session_controller_client.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/test/scoped_command_line.h"
diff --git a/ash/test/child_modal_window.h b/ash/test/child_modal_window.h
index 3ef52433..73f846ad 100644
--- a/ash/test/child_modal_window.h
+++ b/ash/test/child_modal_window.h
@@ -25,6 +25,8 @@
 
 void CreateChildModalParent(aura::Window* context);
 
+// TODO(jamescook): Rename to TestChildModalParent, remove the test namespcae,
+// and move to //ash/wm.
 class ChildModalParent : public views::WidgetDelegateView,
                          public views::ButtonListener,
                          public views::WidgetObserver {
diff --git a/ash/test/test_accessibility_delegate.h b/ash/test/test_accessibility_delegate.h
index 4615f57..b32b002 100644
--- a/ash/test/test_accessibility_delegate.h
+++ b/ash/test/test_accessibility_delegate.h
@@ -11,6 +11,7 @@
 
 namespace ash {
 
+// TODO(jamescook): Move to //ash/accessibility.
 class TestAccessibilityDelegate : public DefaultAccessibilityDelegate {
  public:
   TestAccessibilityDelegate() {}
diff --git a/ash/test/test_screenshot_delegate.cc b/ash/test_screenshot_delegate.cc
similarity index 95%
rename from ash/test/test_screenshot_delegate.cc
rename to ash/test_screenshot_delegate.cc
index b0ba55c..da33214 100644
--- a/ash/test/test_screenshot_delegate.cc
+++ b/ash/test_screenshot_delegate.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 "ash/test/test_screenshot_delegate.h"
+#include "ash/test_screenshot_delegate.h"
 
 namespace ash {
 
diff --git a/ash/test/test_screenshot_delegate.h b/ash/test_screenshot_delegate.h
similarity index 91%
rename from ash/test/test_screenshot_delegate.h
rename to ash/test_screenshot_delegate.h
index 9ef8cd8..d220be0 100644
--- a/ash/test/test_screenshot_delegate.h
+++ b/ash/test_screenshot_delegate.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 ASH_TEST_TEST_SCREENSHOT_DELEGATE_H_
-#define ASH_TEST_TEST_SCREENSHOT_DELEGATE_H_
+#ifndef ASH_TEST_SCREENSHOT_DELEGATE_H_
+#define ASH_TEST_SCREENSHOT_DELEGATE_H_
 
 #include "ash/screenshot_delegate.h"
 #include "base/compiler_specific.h"
@@ -52,4 +52,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_TEST_SCREENSHOT_DELEGATE_H_
+#endif  // ASH_TEST_SCREENSHOT_DELEGATE_H_
diff --git a/ash/test/test_shell_delegate.cc b/ash/test_shell_delegate.cc
similarity index 96%
rename from ash/test/test_shell_delegate.cc
rename to ash/test_shell_delegate.cc
index 4edb20f9..97d8063 100644
--- a/ash/test/test_shell_delegate.cc
+++ b/ash/test_shell_delegate.cc
@@ -2,11 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/test/test_shell_delegate.h"
+#include "ash/test_shell_delegate.h"
 
 #include <limits>
 
 #include "ash/gpu_support_stub.h"
+#include "ash/keyboard/test_keyboard_ui.h"
 #include "ash/palette_delegate.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
@@ -16,8 +17,7 @@
 #include "ash/system/tray/system_tray_delegate.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "ash/test/test_accessibility_delegate.h"
-#include "ash/test/test_keyboard_ui.h"
-#include "ash/test/test_wallpaper_delegate.h"
+#include "ash/wallpaper/test_wallpaper_delegate.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "base/logging.h"
diff --git a/ash/test/test_shell_delegate.h b/ash/test_shell_delegate.h
similarity index 95%
rename from ash/test/test_shell_delegate.h
rename to ash/test_shell_delegate.h
index f1cb2b9..3f4e26a 100644
--- a/ash/test/test_shell_delegate.h
+++ b/ash/test_shell_delegate.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 ASH_TEST_TEST_SHELL_DELEGATE_H_
-#define ASH_TEST_TEST_SHELL_DELEGATE_H_
+#ifndef ASH_TEST_SHELL_DELEGATE_H_
+#define ASH_TEST_SHELL_DELEGATE_H_
 
 #include <memory>
 #include <string>
@@ -90,4 +90,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_TEST_SHELL_DELEGATE_H_
+#endif  // ASH_TEST_SHELL_DELEGATE_H_
diff --git a/ash/utility/screenshot_controller_unittest.cc b/ash/utility/screenshot_controller_unittest.cc
index e85077cd..a431205 100644
--- a/ash/utility/screenshot_controller_unittest.cc
+++ b/ash/utility/screenshot_controller_unittest.cc
@@ -5,13 +5,13 @@
 #include "ash/utility/screenshot_controller.h"
 
 #include "ash/display/cursor_window_controller.h"
+#include "ash/display/mirror_window_test_api.h"
 #include "ash/display/mouse_cursor_event_filter.h"
 #include "ash/display/window_tree_host_manager.h"
 #include "ash/screenshot_delegate.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/mirror_window_test_api.h"
-#include "ash/test/test_screenshot_delegate.h"
+#include "ash/test_screenshot_delegate.h"
 #include "ash/wm/window_util.h"
 #include "ui/aura/env.h"
 #include "ui/aura/window_event_dispatcher.h"
diff --git a/ash/test/test_wallpaper_delegate.cc b/ash/wallpaper/test_wallpaper_delegate.cc
similarity index 94%
rename from ash/test/test_wallpaper_delegate.cc
rename to ash/wallpaper/test_wallpaper_delegate.cc
index 03e4a1a..05f7bbbf 100644
--- a/ash/test/test_wallpaper_delegate.cc
+++ b/ash/wallpaper/test_wallpaper_delegate.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 "ash/test/test_wallpaper_delegate.h"
+#include "ash/wallpaper/test_wallpaper_delegate.h"
 
 #include "ash/shell.h"
 #include "ash/wallpaper/wallpaper_controller.h"
diff --git a/ash/test/test_wallpaper_delegate.h b/ash/wallpaper/test_wallpaper_delegate.h
similarity index 86%
rename from ash/test/test_wallpaper_delegate.h
rename to ash/wallpaper/test_wallpaper_delegate.h
index 829119f1..2edc6dcd 100644
--- a/ash/test/test_wallpaper_delegate.h
+++ b/ash/wallpaper/test_wallpaper_delegate.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 ASH_TEST_TEST_WALLPAPER_DELEGATE_H_
-#define ASH_TEST_TEST_WALLPAPER_DELEGATE_H_
+#ifndef ASH_WALLPAPER_TEST_WALLPAPER_DELEGATE_H_
+#define ASH_WALLPAPER_TEST_WALLPAPER_DELEGATE_H_
 
 #include "ash/default_wallpaper_delegate.h"
 #include "base/macros.h"
@@ -38,4 +38,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_TEST_WALLPAPER_DELEGATE_H_
+#endif  // ASH_WALLPAPER_TEST_WALLPAPER_DELEGATE_H_
diff --git a/ash/test/wallpaper_controller_test_api.cc b/ash/wallpaper/wallpaper_controller_test_api.cc
similarity index 94%
rename from ash/test/wallpaper_controller_test_api.cc
rename to ash/wallpaper/wallpaper_controller_test_api.cc
index 6ef3a614..cb40c40 100644
--- a/ash/test/wallpaper_controller_test_api.cc
+++ b/ash/wallpaper/wallpaper_controller_test_api.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 "ash/test/wallpaper_controller_test_api.h"
+#include "ash/wallpaper/wallpaper_controller_test_api.h"
 #include "ash/wallpaper/wallpaper_controller.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/size.h"
diff --git a/ash/test/wallpaper_controller_test_api.h b/ash/wallpaper/wallpaper_controller_test_api.h
similarity index 85%
rename from ash/test/wallpaper_controller_test_api.h
rename to ash/wallpaper/wallpaper_controller_test_api.h
index 719a445..e46d4d2 100644
--- a/ash/test/wallpaper_controller_test_api.h
+++ b/ash/wallpaper/wallpaper_controller_test_api.h
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifndef ASH_WALLPAPER_WALLPAPER_CONTROLLER_TEST_API_H_
+#define ASH_WALLPAPER_WALLPAPER_CONTROLLER_TEST_API_H_
+
 #include "ash/ash_export.h"
 #include "base/macros.h"
 #include "third_party/skia/include/core/SkColor.h"
@@ -30,3 +33,5 @@
 };
 
 }  // namespace ash
+
+#endif  // ASH_WALLPAPER_WALLPAPER_CONTROLLER_TEST_API_H_
diff --git a/ash/wallpaper/wallpaper_controller_unittest.cc b/ash/wallpaper/wallpaper_controller_unittest.cc
index 0d247bf..613168d0 100644
--- a/ash/wallpaper/wallpaper_controller_unittest.cc
+++ b/ash/wallpaper/wallpaper_controller_unittest.cc
@@ -12,10 +12,10 @@
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
 #include "ash/session/session_controller.h"
+#include "ash/session/test_session_controller_client.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/test_session_controller_client.h"
-#include "ash/test/test_wallpaper_delegate.h"
+#include "ash/wallpaper/test_wallpaper_delegate.h"
 #include "ash/wallpaper/wallpaper_view.h"
 #include "ash/wallpaper/wallpaper_widget_controller.h"
 #include "base/command_line.h"
diff --git a/ash/wm/ash_focus_rules_unittest.cc b/ash/wm/ash_focus_rules_unittest.cc
index 0c796474..ff37b1a 100644
--- a/ash/wm/ash_focus_rules_unittest.cc
+++ b/ash/wm/ash_focus_rules_unittest.cc
@@ -4,10 +4,10 @@
 
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/session/session_controller.h"
+#include "ash/session/test_session_controller_client.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/ash_test_helper.h"
-#include "ash/test/test_session_controller_client.h"
 #include "ash/wm/lock_state_controller.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
diff --git a/ash/test/cursor_manager_test_api.cc b/ash/wm/cursor_manager_test_api.cc
similarity index 93%
rename from ash/test/cursor_manager_test_api.cc
rename to ash/wm/cursor_manager_test_api.cc
index ed972ab..f73ef04 100644
--- a/ash/test/cursor_manager_test_api.cc
+++ b/ash/wm/cursor_manager_test_api.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/test/cursor_manager_test_api.h"
+#include "ash/wm/cursor_manager_test_api.h"
 
 #include "ash/shell.h"
-#include "ash/test/shell_test_api.h"
+#include "ash/shell_test_api.h"
 #include "ash/wm/native_cursor_manager_ash.h"
 #include "ui/base/cursor/image_cursors.h"
 #include "ui/display/display.h"
diff --git a/ash/test/cursor_manager_test_api.h b/ash/wm/cursor_manager_test_api.h
similarity index 86%
rename from ash/test/cursor_manager_test_api.h
rename to ash/wm/cursor_manager_test_api.h
index ec50117a..87ef7fc 100644
--- a/ash/test/cursor_manager_test_api.h
+++ b/ash/wm/cursor_manager_test_api.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 ASH_TEST_CURSOR_MANAGER_TEST_API_H_
-#define ASH_TEST_CURSOR_MANAGER_TEST_API_H_
+#ifndef ASH_WM_CURSOR_MANAGER_TEST_API_H_
+#define ASH_WM_CURSOR_MANAGER_TEST_API_H_
 
 #include "base/macros.h"
 #include "ui/base/cursor/cursor.h"
@@ -35,4 +35,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_CURSOR_MANAGER_TEST_API_H_
+#endif  // ASH_WM_CURSOR_MANAGER_TEST_API_H_
diff --git a/ash/wm/drag_window_resizer_unittest.cc b/ash/wm/drag_window_resizer_unittest.cc
index f0bd6a5..a1361db2 100644
--- a/ash/wm/drag_window_resizer_unittest.cc
+++ b/ash/wm/drag_window_resizer_unittest.cc
@@ -10,7 +10,7 @@
 #include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/cursor_manager_test_api.h"
+#include "ash/wm/cursor_manager_test_api.h"
 #include "ash/wm/drag_window_controller.h"
 #include "ash/wm/window_positioning_utils.h"
 #include "ash/wm/window_util.h"
diff --git a/ash/wm/immersive_fullscreen_controller_unittest.cc b/ash/wm/immersive_fullscreen_controller_unittest.cc
index 464f8f7..a81dc47 100644
--- a/ash/wm/immersive_fullscreen_controller_unittest.cc
+++ b/ash/wm/immersive_fullscreen_controller_unittest.cc
@@ -6,12 +6,12 @@
 
 #include "ash/public/cpp/config.h"
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller_delegate.h"
+#include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h"
 #include "ash/public/cpp/shelf_types.h"
 #include "ash/root_window_controller.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/immersive_fullscreen_controller_test_api.h"
 #include "ash/wm/window_state.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/cursor_client.h"
diff --git a/ash/wm/lock_action_handler_layout_manager_unittest.cc b/ash/wm/lock_action_handler_layout_manager_unittest.cc
index dacdbc1..8d8360c5 100644
--- a/ash/wm/lock_action_handler_layout_manager_unittest.cc
+++ b/ash/wm/lock_action_handler_layout_manager_unittest.cc
@@ -10,11 +10,11 @@
 #include "ash/public/interfaces/tray_action.mojom.h"
 #include "ash/root_window_controller.h"
 #include "ash/screen_util.h"
+#include "ash/session/test_session_controller_client.h"
 #include "ash/shelf/shelf_constants.h"
 #include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/test_session_controller_client.h"
 #include "ash/tray_action/tray_action.h"
 #include "ash/wm/window_state.h"
 #include "base/command_line.h"
diff --git a/ash/test/lock_state_controller_test_api.cc b/ash/wm/lock_state_controller_test_api.cc
similarity index 88%
rename from ash/test/lock_state_controller_test_api.cc
rename to ash/wm/lock_state_controller_test_api.cc
index 8ef36d6..72af1ae0 100644
--- a/ash/test/lock_state_controller_test_api.cc
+++ b/ash/wm/lock_state_controller_test_api.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 "ash/test/lock_state_controller_test_api.h"
+#include "ash/wm/lock_state_controller_test_api.h"
 
 namespace ash {
 
diff --git a/ash/test/lock_state_controller_test_api.h b/ash/wm/lock_state_controller_test_api.h
similarity index 92%
rename from ash/test/lock_state_controller_test_api.h
rename to ash/wm/lock_state_controller_test_api.h
index d4e8c74..7bdf0ff0 100644
--- a/ash/test/lock_state_controller_test_api.h
+++ b/ash/wm/lock_state_controller_test_api.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 ASH_TEST_LOCK_STATE_CONTROLLER_TEST_API_H_
-#define ASH_TEST_LOCK_STATE_CONTROLLER_TEST_API_H_
+#ifndef ASH_WM_LOCK_STATE_CONTROLLER_TEST_API_H_
+#define ASH_WM_LOCK_STATE_CONTROLLER_TEST_API_H_
 
 #include <memory>
 
@@ -65,4 +65,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_LOCK_STATE_CONTROLLER_TEST_API_H_
+#endif  // ASH_WM_LOCK_STATE_CONTROLLER_TEST_API_H_
diff --git a/ash/wm/lock_state_controller_unittest.cc b/ash/wm/lock_state_controller_unittest.cc
index e79b375..e33cb009 100644
--- a/ash/wm/lock_state_controller_unittest.cc
+++ b/ash/wm/lock_state_controller_unittest.cc
@@ -9,18 +9,18 @@
 
 #include "ash/public/cpp/config.h"
 #include "ash/session/session_controller.h"
+#include "ash/session/test_session_controller_client.h"
 #include "ash/shell.h"
 #include "ash/shutdown_controller.h"
 #include "ash/shutdown_reason.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/lock_state_controller_test_api.h"
-#include "ash/test/test_screenshot_delegate.h"
-#include "ash/test/test_session_controller_client.h"
-#include "ash/test/test_session_state_animator.h"
-#include "ash/test/test_shell_delegate.h"
+#include "ash/test_screenshot_delegate.h"
+#include "ash/test_shell_delegate.h"
+#include "ash/wm/lock_state_controller_test_api.h"
 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/wm/power_button_controller.h"
 #include "ash/wm/session_state_animator.h"
+#include "ash/wm/test_session_state_animator.h"
 #include "base/memory/ptr_util.h"
 #include "base/time/time.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
diff --git a/ash/wm/maximize_mode/maximize_mode_window_manager_unittest.cc b/ash/wm/maximize_mode/maximize_mode_window_manager_unittest.cc
index e27be2c..f11ba073 100644
--- a/ash/wm/maximize_mode/maximize_mode_window_manager_unittest.cc
+++ b/ash/wm/maximize_mode/maximize_mode_window_manager_unittest.cc
@@ -13,8 +13,8 @@
 #include "ash/shelf/shelf.h"
 #include "ash/shell.h"
 #include "ash/shell_port.h"
+#include "ash/shell_test_api.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/shell_test_api.h"
 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/overview/window_selector_controller.h"
diff --git a/ash/wm/maximize_mode/maximize_mode_window_state.cc b/ash/wm/maximize_mode/maximize_mode_window_state.cc
index 4b9e6eb..260ad80 100644
--- a/ash/wm/maximize_mode/maximize_mode_window_state.cc
+++ b/ash/wm/maximize_mode/maximize_mode_window_state.cc
@@ -87,7 +87,7 @@
     return Shell::Get()
         ->split_view_controller()
         ->GetSnappedWindowBoundsInParent(state_object->window(),
-                                         SplitViewController::LEFT);
+                                         SplitViewController::LEFT_SNAPPED);
   }
 
   if (state_object->GetStateType() == wm::WINDOW_STATE_TYPE_RIGHT_SNAPPED) {
@@ -95,7 +95,7 @@
     return Shell::Get()
         ->split_view_controller()
         ->GetSnappedWindowBoundsInParent(state_object->window(),
-                                         SplitViewController::RIGHT);
+                                         SplitViewController::RIGHT_SNAPPED);
   }
 
   gfx::Rect bounds_in_parent;
@@ -338,11 +338,11 @@
   } else if (target_state == wm::WINDOW_STATE_TYPE_LEFT_SNAPPED) {
     window_state->SetBoundsDirectAnimated(
         Shell::Get()->split_view_controller()->GetSnappedWindowBoundsInParent(
-            window_state->window(), SplitViewController::LEFT));
+            window_state->window(), SplitViewController::LEFT_SNAPPED));
   } else if (target_state == wm::WINDOW_STATE_TYPE_RIGHT_SNAPPED) {
     window_state->SetBoundsDirectAnimated(
         Shell::Get()->split_view_controller()->GetSnappedWindowBoundsInParent(
-            window_state->window(), SplitViewController::RIGHT));
+            window_state->window(), SplitViewController::RIGHT_SNAPPED));
   } else {
     UpdateBounds(window_state, animated);
   }
diff --git a/ash/wm/native_cursor_manager_ash_interactive_uitest.cc b/ash/wm/native_cursor_manager_ash_interactive_uitest.cc
index 50f87bb..752fb6d 100644
--- a/ash/wm/native_cursor_manager_ash_interactive_uitest.cc
+++ b/ash/wm/native_cursor_manager_ash_interactive_uitest.cc
@@ -6,7 +6,7 @@
 
 #include "ash/shell.h"
 #include "ash/test/ash_interactive_ui_test_base.h"
-#include "ash/test/cursor_manager_test_api.h"
+#include "ash/wm/cursor_manager_test_api.h"
 #include "base/run_loop.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_tree_host.h"
diff --git a/ash/wm/native_cursor_manager_ash_unittest.cc b/ash/wm/native_cursor_manager_ash_unittest.cc
index f742516..5d73ae33 100644
--- a/ash/wm/native_cursor_manager_ash_unittest.cc
+++ b/ash/wm/native_cursor_manager_ash_unittest.cc
@@ -7,7 +7,7 @@
 #include "ash/display/display_util.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/cursor_manager_test_api.h"
+#include "ash/wm/cursor_manager_test_api.h"
 #include "ui/aura/test/aura_test_utils.h"
 #include "ui/aura/test/test_window_delegate.h"
 #include "ui/aura/test/test_windows.h"
diff --git a/ash/wm/overlay_event_filter_unittest.cc b/ash/wm/overlay_event_filter_unittest.cc
index 20cb1d74..14f2b10 100644
--- a/ash/wm/overlay_event_filter_unittest.cc
+++ b/ash/wm/overlay_event_filter_unittest.cc
@@ -6,7 +6,7 @@
 
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/test_overlay_delegate.h"
+#include "ash/wm/test_overlay_delegate.h"
 
 namespace ash {
 
diff --git a/ash/wm/overview/overview_animation_type.h b/ash/wm/overview/overview_animation_type.h
index 294f0297..089277e 100644
--- a/ash/wm/overview/overview_animation_type.h
+++ b/ash/wm/overview/overview_animation_type.h
@@ -27,10 +27,7 @@
   OVERVIEW_ANIMATION_CLOSING_SELECTOR_ITEM,
   // Used to animate hiding of a window that is closed while overview mode is
   // active.
-  OVERVIEW_ANIMATION_CLOSE_SELECTOR_ITEM,
-  // Used to animate scaling up of a window that is about to get dragged while
-  // overview mode is active.
-  OVERVIEW_ANIMATION_DRAGGING_SELECTOR_ITEM,
+  OVERVIEW_ANIMATION_CLOSE_SELECTOR_ITEM
 };
 
 }  // namespace ash
diff --git a/ash/wm/overview/overview_window_drag_controller.cc b/ash/wm/overview/overview_window_drag_controller.cc
deleted file mode 100644
index 5f6f394..0000000
--- a/ash/wm/overview/overview_window_drag_controller.cc
+++ /dev/null
@@ -1,152 +0,0 @@
-// Copyright 2017 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/wm/overview/overview_window_drag_controller.h"
-
-#include "ash/screen_util.h"
-#include "ash/shell.h"
-#include "ash/wm/overview/scoped_transform_overview_window.h"
-#include "ash/wm/overview/window_selector.h"
-#include "ash/wm/overview/window_selector_item.h"
-#include "ash/wm/window_positioning_utils.h"
-#include "ash/wm/window_state.h"
-#include "ash/wm/wm_event.h"
-#include "ash/wm/workspace/phantom_window_controller.h"
-#include "ui/aura/window.h"
-#include "ui/wm/core/coordinate_conversion.h"
-
-namespace ash {
-
-namespace {
-
-// The minimum offset that will be considered as a drag event.
-constexpr int kMinimiumDragOffset = 5;
-
-// Snapping distance between the dragged window with the screen edge. It's
-// useful especially for touch events.
-constexpr int kScreenEdgeInsetForDrag = 200;
-
-}  // namespace
-
-OverviewWindowDragController::OverviewWindowDragController(
-    WindowSelector* window_selector)
-    : window_selector_(window_selector),
-      split_view_controller_(Shell::Get()->split_view_controller()) {}
-
-OverviewWindowDragController::~OverviewWindowDragController() {}
-
-void OverviewWindowDragController::InitiateDrag(
-    WindowSelectorItem* item,
-    const gfx::Point& location_in_screen) {
-  previous_event_location_ = location_in_screen;
-  item_ = item;
-}
-
-void OverviewWindowDragController::Drag(const gfx::Point& location_in_screen) {
-  if (!did_move_ &&
-      (std::abs(location_in_screen.x() - previous_event_location_.x()) <
-           kMinimiumDragOffset ||
-       std::abs(location_in_screen.y() - previous_event_location_.y()) <
-           kMinimiumDragOffset)) {
-    return;
-  }
-  did_move_ = true;
-
-  // Update the dragged |item_|'s bounds accordingly.
-  gfx::Rect bounds(item_->target_bounds());
-  bounds.Offset(location_in_screen.x() - previous_event_location_.x(),
-                location_in_screen.y() - previous_event_location_.y());
-  item_->SetBounds(bounds, OverviewAnimationType::OVERVIEW_ANIMATION_NONE);
-  previous_event_location_ = location_in_screen;
-
-  UpdatePhantomWindow(location_in_screen);
-}
-
-void OverviewWindowDragController::CompleteDrag() {
-  phantom_window_controller_.reset();
-
-  if (!did_move_) {
-    // If no drag was initiated (e.g., a click/tap on the overview window),
-    // activate the window. If the split view is active and has a left window,
-    // snap the current window to right. If the split view is active and has a
-    // right window, snap the current window to left.
-    SplitViewController::State split_state = split_view_controller_->state();
-    if (split_state == SplitViewController::NO_SNAP) {
-      window_selector_->SelectWindow(item_);
-    } else {
-      SnapWindow(split_state == SplitViewController::LEFT_SNAPPED
-                     ? SplitViewController::RIGHT
-                     : SplitViewController::LEFT);
-    }
-  } else {
-    // If the window was dragged around but should not be snapped, move it back
-    // to overview window grid.
-    if (snap_position_ == SplitViewController::NONE)
-      window_selector_->PositionWindows(true /* animate */);
-    else
-      SnapWindow(snap_position_);
-    did_move_ = false;
-  }
-}
-
-void OverviewWindowDragController::UpdatePhantomWindow(
-    const gfx::Point& location_in_screen) {
-  SplitViewController::SnapPosition last_snap_position = snap_position_;
-  snap_position_ = GetSnapPosition(location_in_screen);
-  if (snap_position_ == SplitViewController::NONE ||
-      snap_position_ != last_snap_position) {
-    phantom_window_controller_.reset();
-    if (snap_position_ == SplitViewController::NONE)
-      return;
-  }
-
-  const bool can_snap = snap_position_ != SplitViewController::NONE &&
-                        wm::GetWindowState(item_->GetWindow())->CanSnap();
-  if (!can_snap) {
-    snap_position_ = SplitViewController::NONE;
-    phantom_window_controller_.reset();
-    return;
-  }
-
-  aura::Window* target_window = item_->GetWindow();
-  gfx::Rect phantom_bounds_in_screen =
-      split_view_controller_->GetSnappedWindowBoundsInScreen(target_window,
-                                                             snap_position_);
-
-  if (!phantom_window_controller_) {
-    phantom_window_controller_ =
-        base::MakeUnique<PhantomWindowController>(target_window);
-  }
-  phantom_window_controller_->Show(phantom_bounds_in_screen);
-}
-
-SplitViewController::SnapPosition OverviewWindowDragController::GetSnapPosition(
-    const gfx::Point& location_in_screen) const {
-  gfx::Rect area(
-      ScreenUtil::GetDisplayWorkAreaBoundsInParent(item_->GetWindow()));
-  ::wm::ConvertRectToScreen(item_->GetWindow()->GetRootWindow(), &area);
-  area.Inset(kScreenEdgeInsetForDrag, 0);
-
-  if (location_in_screen.x() <= area.x())
-    return SplitViewController::LEFT;
-  if (location_in_screen.x() >= area.right() - 1)
-    return SplitViewController::RIGHT;
-  return SplitViewController::NONE;
-}
-
-void OverviewWindowDragController::SnapWindow(
-    SplitViewController::SnapPosition snap_position) {
-  DCHECK_NE(snap_position, SplitViewController::NONE);
-
-  item_->EnsureVisible();
-  item_->RestoreWindow();
-
-  // |item_| will be deleted after RemoveWindowSelectorItem().
-  aura::Window* window = item_->GetWindow();
-  window_selector_->RemoveWindowSelectorItem(item_);
-  split_view_controller_->SnapWindow(window, snap_position);
-  item_ = nullptr;
-}
-
-}  // namespace ash
diff --git a/ash/wm/overview/overview_window_drag_controller.h b/ash/wm/overview/overview_window_drag_controller.h
deleted file mode 100644
index c12fee4..0000000
--- a/ash/wm/overview/overview_window_drag_controller.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2017 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 ASH_WM_OVERVIEW_OVERVIEW_WINDOW_DRAG_CONTROLLER_H_
-#define ASH_WM_OVERVIEW_OVERVIEW_WINDOW_DRAG_CONTROLLER_H_
-
-#include <memory>
-
-#include "ash/ash_export.h"
-#include "ash/wm/splitview/split_view_controller.h"
-#include "base/macros.h"
-#include "ui/gfx/geometry/point.h"
-
-namespace ash {
-
-class PhantomWindowController;
-class WindowSelector;
-class WindowSelectorItem;
-
-// The drag controller for an overview window item in overview mode. It updates
-// the position of the corresponding window item using transform while dragging
-// and shows/hides the phantom window accordingly.
-class ASH_EXPORT OverviewWindowDragController {
- public:
-  explicit OverviewWindowDragController(WindowSelector* window_selector);
-  ~OverviewWindowDragController();
-
-  void InitiateDrag(WindowSelectorItem* item,
-                    const gfx::Point& location_in_screen);
-  void Drag(const gfx::Point& location_in_screen);
-  void CompleteDrag();
-
-  WindowSelectorItem* item() { return item_; }
-
- private:
-  void UpdatePhantomWindow(const gfx::Point& location_in_screen);
-
-  SplitViewController::SnapPosition GetSnapPosition(
-      const gfx::Point& location_in_screen) const;
-
-  void SnapWindow(SplitViewController::SnapPosition snap_position);
-
-  WindowSelector* window_selector_;
-
-  SplitViewController* split_view_controller_;
-
-  // Shows a highlight of where the dragged window will end up.
-  std::unique_ptr<PhantomWindowController> phantom_window_controller_;
-
-  // The drag target window in the overview mode.
-  WindowSelectorItem* item_ = nullptr;
-
-  // The location of the previous mouse/touch/gesture event in screen.
-  gfx::Point previous_event_location_;
-
-  // Set to true once the bounds of |item_| change.
-  bool did_move_ = false;
-
-  SplitViewController::SnapPosition snap_position_ = SplitViewController::NONE;
-
-  DISALLOW_COPY_AND_ASSIGN(OverviewWindowDragController);
-};
-
-}  // namespace ash
-
-#endif  // ASH_WM_OVERVIEW_OVERVIEW_WINDOW_DRAG_CONTROLLER_H_
diff --git a/ash/wm/overview/scoped_overview_animation_settings.cc b/ash/wm/overview/scoped_overview_animation_settings.cc
index bd73707..f4c44f7 100644
--- a/ash/wm/overview/scoped_overview_animation_settings.cc
+++ b/ash/wm/overview/scoped_overview_animation_settings.cc
@@ -48,8 +48,6 @@
       return base::TimeDelta::FromMilliseconds(kCloseScaleMilliseconds);
     case OVERVIEW_ANIMATION_CLOSE_SELECTOR_ITEM:
       return base::TimeDelta::FromMilliseconds(kCloseFadeOutMilliseconds);
-    case OVERVIEW_ANIMATION_DRAGGING_SELECTOR_ITEM:
-      return base::TimeDelta::FromMilliseconds(kTransitionMilliseconds);
   }
   NOTREACHED();
   return base::TimeDelta();
@@ -108,7 +106,6 @@
     OverviewAnimationType animation_type) {
   switch (animation_type) {
     case OVERVIEW_ANIMATION_NONE:
-    case OVERVIEW_ANIMATION_DRAGGING_SELECTOR_ITEM:
       return nullptr;
     case OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_IN:
     case OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS:
@@ -157,7 +154,6 @@
       break;
     case OVERVIEW_ANIMATION_CLOSING_SELECTOR_ITEM:
     case OVERVIEW_ANIMATION_CLOSE_SELECTOR_ITEM:
-    case OVERVIEW_ANIMATION_DRAGGING_SELECTOR_ITEM:
       animation_settings_->SetPreemptionStrategy(
           ui::LayerAnimator::ENQUEUE_NEW_ANIMATION);
       animation_settings_->SetTweenType(gfx::Tween::EASE_OUT);
diff --git a/ash/wm/overview/scoped_transform_overview_window.cc b/ash/wm/overview/scoped_transform_overview_window.cc
index 47cd5825..9e5cbde 100644
--- a/ash/wm/overview/scoped_transform_overview_window.cc
+++ b/ash/wm/overview/scoped_transform_overview_window.cc
@@ -9,7 +9,6 @@
 
 #include "ash/wm/overview/scoped_overview_animation_settings.h"
 #include "ash/wm/overview/window_selector_item.h"
-#include "ash/wm/splitview/split_view_controller.h"
 #include "ash/wm/window_mirror_view.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
@@ -165,10 +164,8 @@
 }  // namespace
 
 ScopedTransformOverviewWindow::ScopedTransformOverviewWindow(
-    WindowSelectorItem* selector_item,
     aura::Window* window)
-    : selector_item_(selector_item),
-      window_(window),
+    : window_(window),
       determined_original_window_shape_(false),
       ignored_by_shelf_(wm::GetWindowState(window)->ignored_by_shelf()),
       overview_started_(false),
@@ -459,25 +456,7 @@
 }
 
 void ScopedTransformOverviewWindow::OnGestureEvent(ui::GestureEvent* event) {
-  if (minimized_widget_ && SplitViewController::ShouldAllowSplitView()) {
-    gfx::Point location(event->location());
-    ::wm::ConvertPointToScreen(minimized_widget_->GetNativeWindow(), &location);
-    switch (event->type()) {
-      case ui::ET_GESTURE_SCROLL_BEGIN:
-      case ui::ET_GESTURE_TAP_DOWN:
-        selector_item_->HandlePressEvent(location);
-        break;
-      case ui::ET_GESTURE_SCROLL_UPDATE:
-        selector_item_->HandleDragEvent(location);
-        break;
-      case ui::ET_GESTURE_END:
-        selector_item_->HandleReleaseEvent(location);
-        break;
-      default:
-        break;
-    }
-    event->SetHandled();
-  } else if (event->type() == ui::ET_GESTURE_TAP) {
+  if (event->type() == ui::ET_GESTURE_TAP) {
     EnsureVisible();
     window_->Show();
     wm::ActivateWindow(window_);
@@ -485,25 +464,7 @@
 }
 
 void ScopedTransformOverviewWindow::OnMouseEvent(ui::MouseEvent* event) {
-  if (minimized_widget_ && SplitViewController::ShouldAllowSplitView()) {
-    gfx::Point location(event->location());
-    ::wm::ConvertPointToScreen(minimized_widget_->GetNativeWindow(), &location);
-    switch (event->type()) {
-      case ui::ET_MOUSE_PRESSED:
-        selector_item_->HandlePressEvent(location);
-        break;
-      case ui::ET_MOUSE_DRAGGED:
-        selector_item_->HandleDragEvent(location);
-        break;
-      case ui::ET_MOUSE_RELEASED:
-        selector_item_->HandleReleaseEvent(location);
-        break;
-      default:
-        break;
-    }
-    event->SetHandled();
-  } else if (event->type() == ui::ET_MOUSE_PRESSED &&
-             event->IsOnlyLeftMouseButton()) {
+  if (event->type() == ui::ET_MOUSE_PRESSED && event->IsOnlyLeftMouseButton()) {
     EnsureVisible();
     window_->Show();
     wm::ActivateWindow(window_);
diff --git a/ash/wm/overview/scoped_transform_overview_window.h b/ash/wm/overview/scoped_transform_overview_window.h
index 83d1812..56b12cf9 100644
--- a/ash/wm/overview/scoped_transform_overview_window.h
+++ b/ash/wm/overview/scoped_transform_overview_window.h
@@ -34,7 +34,6 @@
 namespace ash {
 
 class ScopedOverviewAnimationSettings;
-class WindowSelectorItem;
 
 // Manages a window, and its transient children, in the overview mode. This
 // class allows transforming the windows with a helper to determine the best
@@ -66,8 +65,7 @@
   static gfx::Transform GetTransformForRect(const gfx::Rect& src_rect,
                                             const gfx::Rect& dst_rect);
 
-  ScopedTransformOverviewWindow(WindowSelectorItem* selector_item,
-                                aura::Window* window);
+  explicit ScopedTransformOverviewWindow(aura::Window* window);
   ~ScopedTransformOverviewWindow() override;
 
   // Starts an animation sequence which will use animation settings specified by
@@ -167,9 +165,6 @@
   // Makes Close() execute synchronously when used in tests.
   static void SetImmediateCloseForTests();
 
-  // A weak pointer to the window selector item that owns the transform window.
-  WindowSelectorItem* selector_item_;
-
   // A weak pointer to the real window in the overview.
   aura::Window* window_;
 
diff --git a/ash/wm/overview/window_grid.cc b/ash/wm/overview/window_grid.cc
index acb22d7..e8d26c2 100644
--- a/ash/wm/overview/window_grid.cc
+++ b/ash/wm/overview/window_grid.cc
@@ -257,16 +257,14 @@
 
 WindowGrid::WindowGrid(aura::Window* root_window,
                        const std::vector<aura::Window*>& windows,
-                       WindowSelector* window_selector,
-                       const gfx::Rect& bounds_in_screen)
+                       WindowSelector* window_selector)
     : root_window_(root_window),
       window_selector_(window_selector),
       window_observer_(this),
       window_state_observer_(this),
       selected_index_(0),
       num_columns_(0),
-      prepared_for_overview_(false),
-      bounds_(bounds_in_screen) {
+      prepared_for_overview_(false) {
   aura::Window::Windows windows_in_root;
   for (auto* window : windows) {
     if (window->GetRootWindow() == root_window)
@@ -277,7 +275,7 @@
     window_observer_.Add(window);
     window_state_observer_.Add(wm::GetWindowState(window));
     window_list_.push_back(
-        base::MakeUnique<WindowSelectorItem>(window, window_selector_, this));
+        base::MakeUnique<WindowSelectorItem>(window, window_selector_));
   }
 }
 
@@ -328,8 +326,9 @@
   aura::Window* widget_window = shield_widget_->GetNativeWindow();
   const gfx::Rect bounds = widget_window->parent()->bounds();
   widget_window->SetBounds(bounds);
-
-  gfx::Rect total_bounds = bounds_;
+  gfx::Rect total_bounds = ScreenUtil::GetDisplayWorkAreaBoundsInParent(
+      root_window_->GetChildById(kShellWindowId_DefaultContainer));
+  ::wm::ConvertRectToScreen(root_window_, &total_bounds);
   // Windows occupy vertically centered area with additional vertical insets.
   int horizontal_inset =
       gfx::ToFlooredInt(std::min(kOverviewInsetRatio * total_bounds.width(),
@@ -519,20 +518,6 @@
   return false;
 }
 
-void WindowGrid::RemoveItem(WindowSelectorItem* selector_item) {
-  auto iter =
-      std::find_if(window_list_.begin(), window_list_.end(),
-                   [selector_item](std::unique_ptr<WindowSelectorItem>& item) {
-                     return (item.get() == selector_item);
-                   });
-  if (iter != window_list_.end()) {
-    window_observer_.Remove(selector_item->GetWindow());
-    window_state_observer_.Remove(
-        wm::GetWindowState(selector_item->GetWindow()));
-    window_list_.erase(iter);
-  }
-}
-
 void WindowGrid::FilterItems(const base::string16& pattern) {
   base::i18n::FixedPatternStringSearchIgnoringCaseAndAccents finder(pattern);
   for (const auto& window : window_list_) {
@@ -559,11 +544,6 @@
   selection_widget_->SetOpacity(0.f);
 }
 
-void WindowGrid::SetBoundsAndUpdatePositions(const gfx::Rect& bounds) {
-  bounds_ = bounds;
-  PositionWindows(true /* animate */);
-}
-
 void WindowGrid::OnWindowDestroying(aura::Window* window) {
   window_observer_.Remove(window);
   window_state_observer_.Remove(wm::GetWindowState(window));
diff --git a/ash/wm/overview/window_grid.h b/ash/wm/overview/window_grid.h
index 7164cfd..a0352d9 100644
--- a/ash/wm/overview/window_grid.h
+++ b/ash/wm/overview/window_grid.h
@@ -16,7 +16,6 @@
 #include "base/macros.h"
 #include "base/scoped_observer.h"
 #include "ui/aura/window_observer.h"
-#include "ui/gfx/geometry/rect.h"
 
 namespace views {
 class Widget;
@@ -53,8 +52,7 @@
  public:
   WindowGrid(aura::Window* root_window,
              const std::vector<aura::Window*>& window_list,
-             WindowSelector* window_selector,
-             const gfx::Rect& bounds_in_screen);
+             WindowSelector* window_selector);
   ~WindowGrid() override;
 
   // Exits overview mode, fading out the |shield_widget_| if necessary.
@@ -90,9 +88,6 @@
   // this grid owns.
   bool Contains(const aura::Window* window) const;
 
-  // Removes |selector_item| from the grid.
-  void RemoveItem(WindowSelectorItem* selector_item);
-
   // Dims the items whose titles do not contain |pattern| and prevents their
   // selection. The pattern has its accents removed and is converted to
   // lowercase in a l10n sensitive context.
@@ -104,9 +99,6 @@
   // opacity, effectively hiding the selector widget.
   void WindowClosing(WindowSelectorItem* window);
 
-  // Sets bounds for the window grid and positions all windows in the grid.
-  void SetBoundsAndUpdatePositions(const gfx::Rect& bounds_in_screen);
-
   // Returns true if the grid has no more windows.
   bool empty() const { return window_list_.empty(); }
 
@@ -198,9 +190,6 @@
   // True only after all windows have been prepared for overview.
   bool prepared_for_overview_;
 
-  // This WindowGrid's total bounds in screen coordinates.
-  gfx::Rect bounds_;
-
   DISALLOW_COPY_AND_ASSIGN(WindowGrid);
 };
 
diff --git a/ash/wm/overview/window_selector.cc b/ash/wm/overview/window_selector.cc
index a38bd9e..7e50d44 100644
--- a/ash/wm/overview/window_selector.cc
+++ b/ash/wm/overview/window_selector.cc
@@ -19,7 +19,6 @@
 #include "ash/shelf/shelf.h"
 #include "ash/shell.h"
 #include "ash/wm/mru_window_tracker.h"
-#include "ash/wm/overview/overview_window_drag_controller.h"
 #include "ash/wm/overview/window_grid.h"
 #include "ash/wm/overview/window_selector_delegate.h"
 #include "ash/wm/overview/window_selector_item.h"
@@ -138,31 +137,13 @@
     Shelf::ForWindow(root)->UpdateVisibilityState();
 }
 
-// Returns the bounds for the overview window grid according to the split view
-// state. If split view mode is active, the overview window should open on the
-// opposite side of the default snap window.
-gfx::Rect GetGridBoundsInScreen(aura::Window* root_window) {
-  SplitViewController* split_view_controller =
-      Shell::Get()->split_view_controller();
-  if (split_view_controller->IsSplitViewModeActive()) {
-    SplitViewController::SnapPosition oppsite_position =
-        (split_view_controller->default_snap_position() ==
-         SplitViewController::LEFT)
-            ? SplitViewController::RIGHT
-            : SplitViewController::LEFT;
-    return split_view_controller->GetSnappedWindowBoundsInScreen(
-        root_window, oppsite_position);
-  } else {
-    return split_view_controller->GetDisplayWorkAreaBoundsInScreen(root_window);
-  }
-}
-
 gfx::Rect GetTextFilterPosition(aura::Window* root_window) {
-  const gfx::Rect total_bounds = GetGridBoundsInScreen(root_window);
+  gfx::Rect total_bounds = ScreenUtil::GetDisplayWorkAreaBoundsInParent(
+      root_window->GetChildById(kShellWindowId_DefaultContainer));
+  ::wm::ConvertRectToScreen(root_window, &total_bounds);
   return gfx::Rect(
-      total_bounds.x() +
-          0.5 * (total_bounds.width() -
-                 std::min(kTextFilterWidth, total_bounds.width())),
+      0.5 * (total_bounds.width() -
+             std::min(kTextFilterWidth, total_bounds.width())),
       total_bounds.y() + total_bounds.height() * kTextFilterTopScreenProportion,
       std::min(kTextFilterWidth, total_bounds.width()), kTextFilterHeight);
 }
@@ -287,8 +268,7 @@
     // root windows that don't contain any panel windows.
     PanelLayoutManager::Get(root)->SetShowCalloutWidgets(false);
 
-    std::unique_ptr<WindowGrid> grid(
-        new WindowGrid(root, windows, this, GetGridBoundsInScreen(root)));
+    std::unique_ptr<WindowGrid> grid(new WindowGrid(root, windows, this));
     if (grid->empty())
       continue;
     num_items_ += grid->size();
@@ -325,7 +305,6 @@
   UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.Items", num_items_);
 
   Shell::Get()->activation_client()->AddObserver(this);
-  Shell::Get()->split_view_controller()->AddObserver(this);
 
   display::Screen::GetScreen()->AddObserver(this);
   Shell::Get()->metrics()->RecordUserMetricsAction(UMA_WINDOW_OVERVIEW);
@@ -345,11 +324,6 @@
   // windows in response to work area changes from window activation.
   display::Screen::GetScreen()->RemoveObserver(this);
 
-  // Stop observing split view state changes before restoring window focus.
-  // Otherwise the activation of the window triggers OnSplitViewStateChanged()
-  // that will call into this function again.
-  Shell::Get()->split_view_controller()->RemoveObserver(this);
-
   size_t remaining_items = 0;
   for (std::unique_ptr<WindowGrid>& window_grid : grid_list_) {
     for (const auto& window_selector_item : window_grid->window_list())
@@ -469,52 +443,6 @@
   grid_list_[selected_grid_index_]->WindowClosing(window);
 }
 
-void WindowSelector::SetBoundsForWindowGridsInScreen(const gfx::Rect& bounds) {
-  for (std::unique_ptr<WindowGrid>& grid : grid_list_)
-    grid->SetBoundsAndUpdatePositions(bounds);
-}
-
-void WindowSelector::RemoveWindowSelectorItem(WindowSelectorItem* item) {
-  if (item->GetWindow()->HasObserver(this)) {
-    item->GetWindow()->RemoveObserver(this);
-    observed_windows_.erase(item->GetWindow());
-    if (item->GetWindow() == restore_focus_window_)
-      restore_focus_window_ = nullptr;
-  }
-
-  // Remove |item| from the corresponding grid.
-  for (std::unique_ptr<WindowGrid>& grid : grid_list_) {
-    if (grid->Contains(item->GetWindow())) {
-      grid->RemoveItem(item);
-      break;
-    }
-  }
-}
-
-void WindowSelector::InitiateDrag(WindowSelectorItem* item,
-                                  const gfx::Point& location_in_screen) {
-  window_drag_controller_.reset(new OverviewWindowDragController(this));
-  window_drag_controller_->InitiateDrag(item, location_in_screen);
-}
-
-void WindowSelector::Drag(WindowSelectorItem* item,
-                          const gfx::Point& location_in_screen) {
-  DCHECK(window_drag_controller_.get());
-  DCHECK_EQ(item, window_drag_controller_->item());
-  window_drag_controller_->Drag(location_in_screen);
-}
-
-void WindowSelector::CompleteDrag(WindowSelectorItem* item) {
-  DCHECK(window_drag_controller_.get());
-  DCHECK_EQ(item, window_drag_controller_->item());
-  window_drag_controller_->CompleteDrag();
-}
-
-void WindowSelector::PositionWindows(bool animate) {
-  for (std::unique_ptr<WindowGrid>& grid : grid_list_)
-    grid->PositionWindows(animate);
-}
-
 bool WindowSelector::HandleKeyEvent(views::Textfield* sender,
                                     const ui::KeyEvent& key_event) {
   if (key_event.type() != ui::ET_KEY_PRESSED)
@@ -583,11 +511,6 @@
 
 void WindowSelector::OnDisplayMetricsChanged(const display::Display& display,
                                              uint32_t metrics) {
-  // Re-calculate the bounds for the window grids and position all the windows.
-  for (std::unique_ptr<WindowGrid>& grid : grid_list_) {
-    SetBoundsForWindowGridsInScreen(
-        GetGridBoundsInScreen(const_cast<aura::Window*>(grid->root_window())));
-  }
   PositionWindows(/* animate */ false);
   RepositionTextFilterOnDisplayMetricsChange();
 }
@@ -650,11 +573,6 @@
     return;
   }
 
-  // Do not cancel the overview mode if the window activation was caused by
-  // snapping window to one side of the screen.
-  if (Shell::Get()->IsSplitViewModeActive())
-    return;
-
   // Don't restore focus on exit if a window was just activated.
   ResetFocusRestoreWindow(false);
   CancelSelection();
@@ -705,43 +623,15 @@
   Move(WindowSelector::RIGHT, false);
 }
 
-void WindowSelector::OnSplitViewStateChanged(
-    SplitViewController::State previous_state,
-    SplitViewController::State state) {
-  if (state != SplitViewController::NO_SNAP) {
-    // Do not restore focus if a window was just snapped and activated.
-    ResetFocusRestoreWindow(false);
-  }
-
-  if (state == SplitViewController::LEFT_SNAPPED) {
-    aura::Window* snapped_window =
-        Shell::Get()->split_view_controller()->left_window();
-    const gfx::Rect bounds_in_screen =
-        Shell::Get()->split_view_controller()->GetSnappedWindowBoundsInScreen(
-            snapped_window, SplitViewController::RIGHT);
-    SetBoundsForWindowGridsInScreen(bounds_in_screen);
-  } else if (state == SplitViewController::RIGHT_SNAPPED) {
-    aura::Window* snapped_window =
-        Shell::Get()->split_view_controller()->right_window();
-    const gfx::Rect bounds_in_screen =
-        Shell::Get()->split_view_controller()->GetSnappedWindowBoundsInScreen(
-            snapped_window, SplitViewController::LEFT);
-    SetBoundsForWindowGridsInScreen(bounds_in_screen);
-  } else {
-    DCHECK(state == SplitViewController::BOTH_SNAPPED ||
-           state == SplitViewController::NO_SNAP);
-    // If two windows were snapped to both sides of the screen, end overview
-    // mode. If split view mode was ended (e.g., one of the snapped window was
-    // closed or minimized / fullscreened / maximized), also end overview mode
-    // if overview mode is active.
-    CancelSelection();
-  }
-}
-
 aura::Window* WindowSelector::GetTextFilterWidgetWindow() {
   return text_filter_widget_->GetNativeWindow();
 }
 
+void WindowSelector::PositionWindows(bool animate) {
+  for (std::unique_ptr<WindowGrid>& grid : grid_list_)
+    grid->PositionWindows(animate);
+}
+
 void WindowSelector::RepositionTextFilterOnDisplayMetricsChange() {
   const gfx::Rect rect = GetTextFilterPosition(Shell::GetPrimaryRootWindow());
   text_filter_bottom_ = rect.bottom() + kTextFieldBottomMargin;
diff --git a/ash/wm/overview/window_selector.h b/ash/wm/overview/window_selector.h
index 8e99394..72913ff 100644
--- a/ash/wm/overview/window_selector.h
+++ b/ash/wm/overview/window_selector.h
@@ -13,7 +13,6 @@
 #include <vector>
 
 #include "ash/ash_export.h"
-#include "ash/wm/splitview/split_view_controller.h"
 #include "base/macros.h"
 #include "base/time/time.h"
 #include "ui/aura/window_observer.h"
@@ -22,11 +21,6 @@
 #include "ui/views/controls/textfield/textfield_controller.h"
 #include "ui/wm/public/activation_change_observer.h"
 
-namespace gfx {
-class Point;
-class Rect;
-}  // namespace gfx
-
 namespace views {
 class Textfield;
 class Widget;
@@ -37,15 +31,13 @@
 class WindowSelectorItem;
 class WindowSelectorTest;
 class WindowGrid;
-class OverviewWindowDragController;
 
 // The WindowSelector shows a grid of all of your windows, allowing to select
 // one by clicking or tapping on it.
 class ASH_EXPORT WindowSelector : public display::DisplayObserver,
                                   public aura::WindowObserver,
                                   public ::wm::ActivationChangeObserver,
-                                  public views::TextfieldController,
-                                  public SplitViewController::Observer {
+                                  public views::TextfieldController {
  public:
   // Returns true if the window can be selected in overview mode.
   static bool IsSelectable(aura::Window* window);
@@ -83,20 +75,6 @@
   // Called when |window| is about to get closed.
   void WindowClosing(WindowSelectorItem* window);
 
-  // Called to set bounds for window grids. Used for split view.
-  void SetBoundsForWindowGridsInScreen(const gfx::Rect& bounds);
-
-  // Removes the window selector item from the overview window grid.
-  void RemoveWindowSelectorItem(WindowSelectorItem* item);
-
-  void InitiateDrag(WindowSelectorItem* item,
-                    const gfx::Point& location_in_screen);
-  void Drag(WindowSelectorItem* item, const gfx::Point& location_in_screen);
-  void CompleteDrag(WindowSelectorItem* item);
-
-  // Positions all of the windows in the overview.
-  void PositionWindows(bool animate);
-
   WindowSelectorDelegate* delegate() { return delegate_; }
 
   bool restoring_minimized_windows() const {
@@ -107,11 +85,6 @@
 
   bool is_shut_down() const { return is_shut_down_; }
 
-  const std::vector<std::unique_ptr<WindowGrid>>& grid_list_for_testing()
-      const {
-    return grid_list_;
-  }
-
   // display::DisplayObserver:
   void OnDisplayAdded(const display::Display& display) override;
   void OnDisplayRemoved(const display::Display& display) override;
@@ -135,16 +108,15 @@
   bool HandleKeyEvent(views::Textfield* sender,
                       const ui::KeyEvent& key_event) override;
 
-  // SplitViewController::Observer:
-  void OnSplitViewStateChanged(SplitViewController::State previous_state,
-                               SplitViewController::State state) override;
-
  private:
   friend class WindowSelectorTest;
 
   // Returns the aura::Window for |text_filter_widget_|.
   aura::Window* GetTextFilterWidgetWindow();
 
+  // Position all of the windows in the overview.
+  void PositionWindows(bool animate);
+
   // Repositions and resizes |text_filter_widget_| on
   // DisplayMetricsChanged event.
   void RepositionTextFilterOnDisplayMetricsChange();
@@ -221,9 +193,6 @@
 
   bool is_shut_down_ = false;
 
-  // The drag controller for a window in the overview mode.
-  std::unique_ptr<OverviewWindowDragController> window_drag_controller_;
-
   DISALLOW_COPY_AND_ASSIGN(WindowSelector);
 };
 
diff --git a/ash/wm/overview/window_selector_controller.cc b/ash/wm/overview/window_selector_controller.cc
index e35229f1..19b12afa 100644
--- a/ash/wm/overview/window_selector_controller.cc
+++ b/ash/wm/overview/window_selector_controller.cc
@@ -10,11 +10,8 @@
 #include "ash/shell.h"
 #include "ash/shell_port.h"
 #include "ash/wm/mru_window_tracker.h"
-#include "ash/wm/overview/window_grid.h"
 #include "ash/wm/overview/window_selector.h"
-#include "ash/wm/overview/window_selector_item.h"
 #include "ash/wm/screen_pinning_controller.h"
-#include "ash/wm/splitview/split_view_controller.h"
 #include "ash/wm/window_state.h"
 #include "base/metrics/histogram_macros.h"
 
@@ -57,28 +54,9 @@
                        std::not1(std::ptr_fun(&WindowSelector::IsSelectable)));
     windows.resize(end - windows.begin());
 
-    if (!Shell::Get()->IsSplitViewModeActive()) {
-      // Don't enter overview with no window if the split view mode is inactive.
-      if (windows.empty())
-        return false;
-    } else {
-      // Don't enter overview with less than 1 window if the split view mode is
-      // active.
-      if (windows.size() <= 1)
-        return false;
-
-      // Remove the default snapped window from the window list. The default
-      // snapped window occupies one side of the screen, while the other windows
-      // occupy the other side of the screen in overview mode. The default snap
-      // position is the position where the window was first snapped. See
-      // |default_snap_position_| in SplitViewController for more detail.
-      aura::Window* default_snapped_window =
-          Shell::Get()->split_view_controller()->GetDefaultSnappedWindow();
-      auto iter =
-          std::find(windows.begin(), windows.end(), default_snapped_window);
-      DCHECK(iter != windows.end());
-      windows.erase(iter);
-    }
+    // Don't enter overview mode with no windows.
+    if (windows.empty())
+      return false;
 
     Shell::Get()->NotifyOverviewModeStarting();
     window_selector_.reset(new WindowSelector(this));
@@ -107,17 +85,6 @@
          window_selector_->restoring_minimized_windows();
 }
 
-std::vector<aura::Window*>
-WindowSelectorController::GetWindowsListInOverviewGridsForTesting() {
-  std::vector<aura::Window*> windows;
-  for (const std::unique_ptr<WindowGrid>& grid :
-       window_selector_->grid_list_for_testing()) {
-    for (const auto& window_selector_item : grid->window_list())
-      windows.push_back(window_selector_item->GetWindow());
-  }
-  return windows;
-}
-
 // TODO(flackr): Make WindowSelectorController observe the activation of
 // windows, so we can remove WindowSelectorDelegate.
 void WindowSelectorController::OnSelectionEnded() {
diff --git a/ash/wm/overview/window_selector_controller.h b/ash/wm/overview/window_selector_controller.h
index dfd6556..83dcdb3 100644
--- a/ash/wm/overview/window_selector_controller.h
+++ b/ash/wm/overview/window_selector_controller.h
@@ -49,10 +49,6 @@
   // are visible during overview mode.
   bool IsRestoringMinimizedWindows() const;
 
-  // Gets the windows list that are shown in the overview windows grids if the
-  // overview mode is active for testing.
-  std::vector<aura::Window*> GetWindowsListInOverviewGridsForTesting();
-
   // WindowSelectorDelegate:
   void OnSelectionEnded() override;
   void AddDelayedAnimationObserver(
diff --git a/ash/wm/overview/window_selector_item.cc b/ash/wm/overview/window_selector_item.cc
index e207b2de..8889005 100644
--- a/ash/wm/overview/window_selector_item.cc
+++ b/ash/wm/overview/window_selector_item.cc
@@ -17,7 +17,6 @@
 #include "ash/wm/overview/overview_animation_type.h"
 #include "ash/wm/overview/scoped_overview_animation_settings.h"
 #include "ash/wm/overview/scoped_transform_overview_window.h"
-#include "ash/wm/overview/window_grid.h"
 #include "ash/wm/overview/window_selector.h"
 #include "ash/wm/overview/window_selector_controller.h"
 #include "ash/wm/window_state.h"
@@ -101,10 +100,6 @@
 // this fraction of size.
 static const float kPreCloseScale = 0.02f;
 
-// Before dragging an overview window, the window will scale up |kPreDragScale|
-// to indicate its selection.
-static const float kDragWindowScale = 0.04f;
-
 // Convenience method to fade in a Window with predefined animation settings.
 // Note: The fade in animation will occur after a delay where the delay is how
 // long the lay out animations take.
@@ -117,9 +112,8 @@
   window->layer()->SetOpacity(1.0f);
 }
 
-// A Button that has a listener and listens to mouse / gesture events on the
-// visible part of an overview window. Note that the drag events are only
-// handled in maximized mode.
+// A Button that has a listener and listens to mouse clicks on the visible part
+// of an overview window.
 class ShieldButton : public views::CustomButton {
  public:
   ShieldButton(views::ButtonListener* listener, const base::string16& name)
@@ -135,65 +129,6 @@
   // after the WindowSelectorItem has been destroyed.
   void ResetListener() { listener_ = nullptr; }
 
-  // views::CustomButton:
-  bool OnMousePressed(const ui::MouseEvent& event) override {
-    if (listener() && SplitViewController::ShouldAllowSplitView()) {
-      gfx::Point location(event.location());
-      views::View::ConvertPointToScreen(this, &location);
-      listener()->HandlePressEvent(location);
-      return true;
-    }
-    return views::CustomButton::OnMousePressed(event);
-  }
-
-  void OnMouseReleased(const ui::MouseEvent& event) override {
-    if (listener() && SplitViewController::ShouldAllowSplitView()) {
-      gfx::Point location(event.location());
-      views::View::ConvertPointToScreen(this, &location);
-      listener()->HandleReleaseEvent(location);
-      return;
-    }
-    views::CustomButton::OnMouseReleased(event);
-  }
-
-  bool OnMouseDragged(const ui::MouseEvent& event) override {
-    if (listener() && SplitViewController::ShouldAllowSplitView()) {
-      gfx::Point location(event.location());
-      views::View::ConvertPointToScreen(this, &location);
-      listener()->HandleDragEvent(location);
-      return true;
-    }
-    return views::CustomButton::OnMouseDragged(event);
-  }
-
-  void OnGestureEvent(ui::GestureEvent* event) override {
-    if (listener() && SplitViewController::ShouldAllowSplitView()) {
-      gfx::Point location(event->location());
-      views::View::ConvertPointToScreen(this, &location);
-      switch (event->type()) {
-        case ui::ET_GESTURE_SCROLL_BEGIN:
-        case ui::ET_GESTURE_TAP_DOWN:
-          listener()->HandlePressEvent(location);
-          break;
-        case ui::ET_GESTURE_SCROLL_UPDATE:
-          listener()->HandleDragEvent(location);
-          break;
-        case ui::ET_GESTURE_END:
-          listener()->HandleReleaseEvent(location);
-          break;
-        default:
-          break;
-      }
-      event->SetHandled();
-      return;
-    }
-    views::CustomButton::OnGestureEvent(event);
-  }
-
-  WindowSelectorItem* listener() {
-    return static_cast<WindowSelectorItem*>(listener_);
-  }
-
  protected:
   // views::View:
   const char* GetClassName() const override { return "ShieldButton"; }
@@ -461,19 +396,17 @@
 };
 
 WindowSelectorItem::WindowSelectorItem(aura::Window* window,
-                                       WindowSelector* window_selector,
-                                       WindowGrid* window_grid)
+                                       WindowSelector* window_selector)
     : dimmed_(false),
       root_window_(window->GetRootWindow()),
-      transform_window_(this, window),
+      transform_window_(window),
       in_bounds_update_(false),
       selected_(false),
       caption_container_view_(nullptr),
       label_view_(nullptr),
       close_button_(new OverviewCloseButton(this)),
       window_selector_(window_selector),
-      background_view_(nullptr),
-      window_grid_(window_grid) {
+      background_view_(nullptr) {
   CreateWindowLabel(window->GetTitle());
   GetWindow()->AddObserver(this);
 }
@@ -609,10 +542,7 @@
     return;
   }
   CHECK(sender == caption_container_view_->listener_button());
-
-  // For other cases, the event is handled in OverviewWindowDragController.
-  if (!SplitViewController::ShouldAllowSplitView())
-    window_selector_->SelectWindow(this);
+  window_selector_->SelectWindow(this);
 }
 
 void WindowSelectorItem::OnWindowDestroying(aura::Window* window) {
@@ -635,22 +565,6 @@
       close_button_->GetPreferredSize().height());
 }
 
-void WindowSelectorItem::HandlePressEvent(
-    const gfx::Point& location_in_screen) {
-  StartDrag();
-  window_selector_->InitiateDrag(this, location_in_screen);
-}
-
-void WindowSelectorItem::HandleReleaseEvent(
-    const gfx::Point& location_in_screen) {
-  EndDrag();
-  window_selector_->CompleteDrag(this);
-}
-
-void WindowSelectorItem::HandleDragEvent(const gfx::Point& location_in_screen) {
-  window_selector_->Drag(this, location_in_screen);
-}
-
 gfx::Rect WindowSelectorItem::GetTargetBoundsInScreen() const {
   return transform_window_.GetTargetBoundsInScreen();
 }
@@ -838,58 +752,4 @@
   return transform_window_.GetOverviewWindowForMinimizedState();
 }
 
-void WindowSelectorItem::StartDrag() {
-  gfx::Rect scaled_bounds(target_bounds_);
-  scaled_bounds.Inset(-target_bounds_.width() * kDragWindowScale,
-                      -target_bounds_.height() * kDragWindowScale);
-  OverviewAnimationType animation_type =
-      OverviewAnimationType::OVERVIEW_ANIMATION_DRAGGING_SELECTOR_ITEM;
-  SetBounds(scaled_bounds, animation_type);
-
-  aura::Window* widget_window = item_widget_->GetNativeWindow();
-  if (widget_window && widget_window->parent() == GetWindow()->parent()) {
-    // TODO(xdai): This might not work if there is an always on top window.
-    // See crbug.com/733760.
-    widget_window->parent()->StackChildAtTop(widget_window);
-    widget_window->parent()->StackChildBelow(GetWindow(), widget_window);
-  }
-}
-
-void WindowSelectorItem::EndDrag() {
-  // First stack this item's window below the snapped window if split view mode
-  // is active.
-  aura::Window* dragged_window = GetWindow();
-  aura::Window* dragged_widget_window = item_widget_->GetNativeWindow();
-  aura::Window* parent_window = dragged_widget_window->parent();
-  if (Shell::Get()->IsSplitViewModeActive()) {
-    aura::Window* snapped_window =
-        Shell::Get()->split_view_controller()->GetDefaultSnappedWindow();
-    if (snapped_window->parent() == parent_window &&
-        dragged_window->parent() == parent_window) {
-      parent_window->StackChildBelow(dragged_widget_window, snapped_window);
-      parent_window->StackChildBelow(dragged_window, dragged_widget_window);
-    }
-  }
-
-  // Then find the window which was stacked right above this selector item's
-  // window before dragging and stack this selector item's window below it.
-  const std::vector<std::unique_ptr<WindowSelectorItem>>& selector_items =
-      window_grid_->window_list();
-  aura::Window* stacking_target = nullptr;
-  for (size_t index = 0; index < selector_items.size(); index++) {
-    if (index > 0) {
-      aura::Window* window = selector_items[index - 1].get()->GetWindow();
-      if (window->parent() == parent_window &&
-          dragged_window->parent() == parent_window) {
-        stacking_target = window;
-      }
-    }
-    if (selector_items[index].get() == this && stacking_target) {
-      parent_window->StackChildBelow(dragged_widget_window, stacking_target);
-      parent_window->StackChildBelow(dragged_window, dragged_widget_window);
-      break;
-    }
-  }
-}
-
 }  // namespace ash
diff --git a/ash/wm/overview/window_selector_item.h b/ash/wm/overview/window_selector_item.h
index 4e7f00e4..6e77d73 100644
--- a/ash/wm/overview/window_selector_item.h
+++ b/ash/wm/overview/window_selector_item.h
@@ -29,7 +29,6 @@
 namespace ash {
 
 class WindowSelector;
-class WindowGrid;
 
 // This class represents an item in overview mode.
 class ASH_EXPORT WindowSelectorItem : public views::ButtonListener,
@@ -48,9 +47,7 @@
     DISALLOW_COPY_AND_ASSIGN(OverviewCloseButton);
   };
 
-  WindowSelectorItem(aura::Window* window,
-                     WindowSelector* window_selector,
-                     WindowGrid* window_grid);
+  WindowSelectorItem(aura::Window* window, WindowSelector* window_selector);
   ~WindowSelectorItem() override;
 
   aura::Window* GetWindow();
@@ -123,11 +120,6 @@
   void OnWindowDestroying(aura::Window* window) override;
   void OnWindowTitleChanged(aura::Window* window) override;
 
-  // Handle the mouse/gesture event and facilitate dragging the item.
-  void HandlePressEvent(const gfx::Point& location_in_screen);
-  void HandleReleaseEvent(const gfx::Point& location_in_screen);
-  void HandleDragEvent(const gfx::Point& location_in_screen);
-
  private:
   class CaptionContainerView;
   class RoundedContainerView;
@@ -174,15 +166,6 @@
 
   aura::Window* GetOverviewWindowForMinimizedStateForTest();
 
-  // Called before dragging. Scales up the window a little bit to indicate its
-  // selection and stacks the window at the top of the Z order in order to keep
-  // it visible while dragging around.
-  void StartDrag();
-
-  // Called after dragging. Inserts the window back to its original stacking
-  // order so that the order of windows is the same as when entering overview.
-  void EndDrag();
-
   // True if the item is being shown in the overview, false if it's being
   // filtered.
   bool dimmed_;
@@ -232,10 +215,6 @@
   // which is the only textured layer used by the |item_widget_|.
   RoundedContainerView* background_view_;
 
-  // Pointer to the WindowGrid that contains |this|. Guaranteed to be non-null
-  // for the lifetime of |this|.
-  WindowGrid* window_grid_;
-
   DISALLOW_COPY_AND_ASSIGN(WindowSelectorItem);
 };
 
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc
index 35b22883..d5a07ed 100644
--- a/ash/wm/overview/window_selector_unittest.cc
+++ b/ash/wm/overview/window_selector_unittest.cc
@@ -7,23 +7,22 @@
 
 #include "ash/accessibility_delegate.h"
 #include "ash/accessibility_types.h"
+#include "ash/app_list/test_app_list_view_presenter_impl.h"
 #include "ash/drag_drop/drag_drop_controller.h"
 #include "ash/public/cpp/config.h"
 #include "ash/public/cpp/window_properties.h"
 #include "ash/shelf/shelf.h"
+#include "ash/shelf/shelf_view_test_api.h"
 #include "ash/shell.h"
+#include "ash/shell_test_api.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/shelf_view_test_api.h"
-#include "ash/test/shell_test_api.h"
-#include "ash/test/test_app_list_view_presenter_impl.h"
 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/wm/overview/window_grid.h"
 #include "ash/wm/overview/window_selector.h"
 #include "ash/wm/overview/window_selector_controller.h"
 #include "ash/wm/overview/window_selector_item.h"
 #include "ash/wm/panels/panel_layout_manager.h"
-#include "ash/wm/splitview/split_view_controller.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "ash/wm/wm_event.h"
@@ -166,10 +165,6 @@
     return window_selector_controller()->window_selector_.get();
   }
 
-  SplitViewController* split_view_controller() {
-    return Shell::Get()->split_view_controller();
-  }
-
   void ToggleOverview() { window_selector_controller()->ToggleOverview(); }
 
   aura::Window* GetOverviewWindowForMinimizedState(int index,
@@ -1896,68 +1891,4 @@
   resizer->RevertDrag();
 }
 
-// Tests that dragging a overview window selector item to the edge of the screen
-// snaps the window. If two windows are snapped to left and right side of the
-// screen, exit the overview mode.
-TEST_F(WindowSelectorTest, DragOverviewWindowToSnap) {
-  const gfx::Rect bounds(0, 0, 400, 400);
-  std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
-  std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
-  std::unique_ptr<aura::Window> window3(CreateWindow(bounds));
-
-  ToggleOverview();
-  EXPECT_TRUE(window_selector_controller()->IsSelecting());
-  EXPECT_EQ(split_view_controller()->IsSplitViewModeActive(), false);
-
-  // Drag |window1| selector item to snap to left.
-  const int grid_index = 0;
-  WindowSelectorItem* selector_item1 =
-      GetWindowItemForWindow(grid_index, window1.get());
-  const gfx::Rect selector_item_bounds1 = selector_item1->target_bounds();
-  // Start drag in the middle of the seletor item.
-  const gfx::Point start_location1(selector_item_bounds1.CenterPoint());
-  window_selector()->InitiateDrag(selector_item1, start_location1);
-  const gfx::Point end_location1(0, 0);
-  window_selector()->Drag(selector_item1, end_location1);
-  window_selector()->CompleteDrag(selector_item1);
-
-  EXPECT_EQ(split_view_controller()->IsSplitViewModeActive(), true);
-  EXPECT_EQ(split_view_controller()->state(),
-            SplitViewController::LEFT_SNAPPED);
-  EXPECT_EQ(split_view_controller()->left_window(), window1.get());
-
-  // Drag |window2| selector item to snap to left.
-  WindowSelectorItem* selector_item2 =
-      GetWindowItemForWindow(grid_index, window2.get());
-  const gfx::Rect selector_item_bounds2 = selector_item2->target_bounds();
-  // Start drag in the middle of the seletor item.
-  const gfx::Point start_location2(selector_item_bounds2.CenterPoint());
-  window_selector()->InitiateDrag(selector_item2, start_location2);
-  const gfx::Point end_location2(0, 0);
-  window_selector()->Drag(selector_item2, end_location2);
-  window_selector()->CompleteDrag(selector_item2);
-
-  EXPECT_EQ(split_view_controller()->state(),
-            SplitViewController::LEFT_SNAPPED);
-  EXPECT_EQ(split_view_controller()->left_window(), window2.get());
-
-  // Drag |window3| selector item to snap to right.
-  WindowSelectorItem* selector_item3 =
-      GetWindowItemForWindow(grid_index, window3.get());
-  const gfx::Rect selector_item_bounds3 = selector_item3->target_bounds();
-  // Start drag in the middle of the seletor item.
-  const gfx::Point start_location3(selector_item_bounds3.CenterPoint());
-  window_selector()->InitiateDrag(selector_item3, start_location3);
-  const gfx::Rect work_area_rect =
-      split_view_controller()->GetDisplayWorkAreaBoundsInScreen(window2.get());
-  const gfx::Point end_location3(work_area_rect.width(), 0);
-  window_selector()->Drag(selector_item3, end_location3);
-  window_selector()->CompleteDrag(selector_item3);
-
-  EXPECT_EQ(split_view_controller()->state(),
-            SplitViewController::BOTH_SNAPPED);
-  EXPECT_EQ(split_view_controller()->right_window(), window3.get());
-  EXPECT_FALSE(window_selector_controller()->IsSelecting());
-}
-
 }  // namespace ash
diff --git a/ash/wm/panels/panel_layout_manager_unittest.cc b/ash/wm/panels/panel_layout_manager_unittest.cc
index 7f088e4e..7945e8d 100644
--- a/ash/wm/panels/panel_layout_manager_unittest.cc
+++ b/ash/wm/panels/panel_layout_manager_unittest.cc
@@ -14,11 +14,11 @@
 #include "ash/shelf/shelf_button.h"
 #include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shelf/shelf_view.h"
+#include "ash/shelf/shelf_view_test_api.h"
 #include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
 #include "ash/system/web_notification/web_notification_tray.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/shelf_view_test_api.h"
 #include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
diff --git a/ash/wm/panels/panel_window_resizer_unittest.cc b/ash/wm/panels/panel_window_resizer_unittest.cc
index ddd413d..df216da 100644
--- a/ash/wm/panels/panel_window_resizer_unittest.cc
+++ b/ash/wm/panels/panel_window_resizer_unittest.cc
@@ -11,11 +11,11 @@
 #include "ash/root_window_controller.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_layout_manager.h"
+#include "ash/shelf/shelf_view_test_api.h"
 #include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/cursor_manager_test_api.h"
-#include "ash/test/shelf_view_test_api.h"
+#include "ash/wm/cursor_manager_test_api.h"
 #include "ash/wm/drag_window_resizer.h"
 #include "ash/wm/window_properties.h"
 #include "ash/wm/window_state.h"
diff --git a/ash/wm/resize_shadow_and_cursor_unittest.cc b/ash/wm/resize_shadow_and_cursor_unittest.cc
index c829580..0d2434bc 100644
--- a/ash/wm/resize_shadow_and_cursor_unittest.cc
+++ b/ash/wm/resize_shadow_and_cursor_unittest.cc
@@ -6,7 +6,7 @@
 #include "ash/frame/custom_frame_view_ash.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/cursor_manager_test_api.h"
+#include "ash/wm/cursor_manager_test_api.h"
 #include "ash/wm/resize_shadow.h"
 #include "ash/wm/resize_shadow_controller.h"
 #include "ash/wm/window_state.h"
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc
index 699c26a..b86b3d5a 100644
--- a/ash/wm/splitview/split_view_controller.cc
+++ b/ash/wm/splitview/split_view_controller.cc
@@ -128,10 +128,10 @@
 
 gfx::Rect SplitViewController::GetSnappedWindowBoundsInParent(
     aura::Window* window,
-    SnapPosition snap_position) {
-  if (snap_position == LEFT)
+    State snap_state) {
+  if (snap_state == LEFT_SNAPPED)
     return GetLeftWindowBoundsInParent(window);
-  else if (snap_position == RIGHT)
+  else if (snap_state == RIGHT_SNAPPED)
     return GetRightWindowBoundsInParent(window);
 
   NOTREACHED();
@@ -140,10 +140,10 @@
 
 gfx::Rect SplitViewController::GetSnappedWindowBoundsInScreen(
     aura::Window* window,
-    SnapPosition snap_position) {
-  if (snap_position == LEFT)
+    State snap_state) {
+  if (snap_state == LEFT_SNAPPED)
     return GetLeftWindowBoundsInScreen(window);
-  else if (snap_position == RIGHT)
+  else if (snap_state == RIGHT_SNAPPED)
     return GetRightWindowBoundsInScreen(window);
 
   NOTREACHED();
@@ -220,7 +220,7 @@
   // is active.
   if (default_snap_position_ == LEFT)
     SnapWindow(gained_active, SplitViewController::RIGHT);
-  else if (default_snap_position_ == RIGHT)
+  else
     SnapWindow(gained_active, SplitViewController::LEFT);
 }
 
@@ -232,7 +232,7 @@
     if (default_snap_position_ == LEFT) {
       StopObserving(right_window_);
       state_ = LEFT_SNAPPED;
-    } else if (default_snap_position_ == RIGHT) {
+    } else {
       StopObserving(left_window_);
       state_ = RIGHT_SNAPPED;
     }
@@ -250,7 +250,7 @@
       if (CanSnap(window) && window != GetDefaultSnappedWindow()) {
         if (default_snap_position_ == LEFT)
           SnapWindow(window, SplitViewController::RIGHT);
-        else if (default_snap_position_ == RIGHT)
+        else
           SnapWindow(window, SplitViewController::LEFT);
         break;
       }
@@ -263,7 +263,7 @@
   StopObserving(right_window_);
   left_window_ = nullptr;
   right_window_ = nullptr;
-  default_snap_position_ = NONE;
+  default_snap_position_ = LEFT;
   divider_position_ = -1;
 
   State previous_state = state_;
diff --git a/ash/wm/splitview/split_view_controller.h b/ash/wm/splitview/split_view_controller.h
index 7178a53b..cab2c67 100644
--- a/ash/wm/splitview/split_view_controller.h
+++ b/ash/wm/splitview/split_view_controller.h
@@ -26,7 +26,7 @@
                                        public ShellObserver {
  public:
   enum State { NO_SNAP, LEFT_SNAPPED, RIGHT_SNAPPED, BOTH_SNAPPED };
-  enum SnapPosition { NONE, LEFT, RIGHT };
+  enum SnapPosition { LEFT, RIGHT };
 
   class Observer {
    public:
@@ -58,9 +58,9 @@
   // Gets the window bounds according to the snap state |snap_state| and the
   // separator position |separator_position_|.
   gfx::Rect GetSnappedWindowBoundsInParent(aura::Window* window,
-                                           SnapPosition snap_position);
+                                           State snap_state);
   gfx::Rect GetSnappedWindowBoundsInScreen(aura::Window* window,
-                                           SnapPosition snap_position);
+                                           State snap_state);
   gfx::Rect GetDisplayWorkAreaBoundsInParent(aura::Window* window);
   gfx::Rect GetDisplayWorkAreaBoundsInScreen(aura::Window* window);
 
@@ -87,7 +87,6 @@
   aura::Window* right_window() { return right_window_; }
   int divider_position() const { return divider_position_; }
   State state() const { return state_; }
-  SnapPosition default_snap_position() const { return default_snap_position_; }
 
  private:
   friend class SplitViewControllerTest;
@@ -123,7 +122,7 @@
   // first window was snapped left, then |default_snap_position_| equals LEFT,
   // i.e., all the other windows will open snapped on the right side - and vice
   // versa.
-  SnapPosition default_snap_position_ = NONE;
+  SnapPosition default_snap_position_ = LEFT;
 
   base::ObserverList<Observer> observers_;
 
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc
index a726183..2f1a196e 100644
--- a/ash/wm/splitview/split_view_controller_unittest.cc
+++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -6,7 +6,6 @@
 
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/wm/overview/window_selector_controller.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "ash/wm/wm_event.h"
@@ -27,16 +26,6 @@
 
   void EndSplitView() { split_view_controller()->EndSplitView(); }
 
-  void ToggleOverview() {
-    Shell::Get()->window_selector_controller()->ToggleOverview();
-  }
-
-  std::vector<aura::Window*> GetWindowsInOverviewGrids() {
-    return Shell::Get()
-        ->window_selector_controller()
-        ->GetWindowsListInOverviewGridsForTesting();
-  }
-
   SplitViewController* split_view_controller() {
     return Shell::Get()->split_view_controller();
   }
@@ -64,7 +53,7 @@
   EXPECT_EQ(split_view_controller()->IsSplitViewModeActive(), true);
   EXPECT_EQ(window1->GetBoundsInScreen(),
             split_view_controller()->GetSnappedWindowBoundsInScreen(
-                window1.get(), SplitViewController::LEFT));
+                window1.get(), SplitViewController::LEFT_SNAPPED));
 
   split_view_controller()->SnapWindow(window2.get(),
                                       SplitViewController::RIGHT);
@@ -75,7 +64,7 @@
   EXPECT_EQ(split_view_controller()->IsSplitViewModeActive(), true);
   EXPECT_EQ(window2->GetBoundsInScreen(),
             split_view_controller()->GetSnappedWindowBoundsInScreen(
-                window2.get(), SplitViewController::RIGHT));
+                window2.get(), SplitViewController::RIGHT_SNAPPED));
 
   EndSplitView();
   EXPECT_EQ(split_view_controller()->state(), SplitViewController::NO_SNAP);
@@ -171,53 +160,4 @@
             SplitViewController::BOTH_SNAPPED);
 }
 
-// Tests that if split view mode and overview mode are active at the same time,
-// i.e., half of the screen is occupied by a snapped window and half of the
-// screen is occupied by the overview windows grid, the next activatable window
-// will be picked to snap when exiting the overview mode.
-TEST_F(SplitViewControllerTest, ExitOverviewTest) {
-  const gfx::Rect bounds(0, 0, 400, 400);
-  std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
-  std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
-  std::unique_ptr<aura::Window> window3(CreateWindow(bounds));
-  EXPECT_EQ(split_view_controller()->IsSplitViewModeActive(), false);
-
-  ToggleOverview();
-  split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
-  EXPECT_EQ(split_view_controller()->IsSplitViewModeActive(), true);
-  EXPECT_EQ(split_view_controller()->state(),
-            SplitViewController::LEFT_SNAPPED);
-  EXPECT_EQ(split_view_controller()->left_window(), window1.get());
-
-  ToggleOverview();
-  EXPECT_EQ(split_view_controller()->state(),
-            SplitViewController::BOTH_SNAPPED);
-  EXPECT_EQ(split_view_controller()->right_window(), window3.get());
-}
-
-// Tests that if split view mode is active when entering overview, the overview
-// windows grid should show in the non-default side of the screen, and the
-// default snapped window should not be shown in the overview window grid.
-TEST_F(SplitViewControllerTest, EnterOverviewTest) {
-  const gfx::Rect bounds(0, 0, 400, 400);
-  std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
-  std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
-  std::unique_ptr<aura::Window> window3(CreateWindow(bounds));
-
-  split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
-  split_view_controller()->SnapWindow(window2.get(),
-                                      SplitViewController::RIGHT);
-  EXPECT_EQ(split_view_controller()->state(),
-            SplitViewController::BOTH_SNAPPED);
-  EXPECT_EQ(split_view_controller()->GetDefaultSnappedWindow(), window1.get());
-
-  ToggleOverview();
-  EXPECT_EQ(split_view_controller()->state(),
-            SplitViewController::LEFT_SNAPPED);
-  std::vector<aura::Window*> windows = GetWindowsInOverviewGrids();
-  auto iter = std::find(windows.begin(), windows.end(),
-                        split_view_controller()->GetDefaultSnappedWindow());
-  EXPECT_TRUE(iter == windows.end());
-}
-
 }  // namespace ash
diff --git a/ash/wm/system_gesture_event_filter_unittest.cc b/ash/wm/system_gesture_event_filter_unittest.cc
index f56d4be..147467e 100644
--- a/ash/wm/system_gesture_event_filter_unittest.cc
+++ b/ash/wm/system_gesture_event_filter_unittest.cc
@@ -8,9 +8,9 @@
 
 #include "ash/accelerators/accelerator_controller.h"
 #include "ash/shell.h"
+#include "ash/shell_test_api.h"
 #include "ash/system/tray/system_tray_delegate.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/shell_test_api.h"
 #include "ash/wm/window_positioning_utils.h"
 #include "ash/wm/window_state.h"
 #include "base/time/time.h"
diff --git a/ash/test/test_activation_delegate.cc b/ash/wm/test_activation_delegate.cc
similarity index 96%
rename from ash/test/test_activation_delegate.cc
rename to ash/wm/test_activation_delegate.cc
index b296dce..96edc7a 100644
--- a/ash/test/test_activation_delegate.cc
+++ b/ash/wm/test_activation_delegate.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 "ash/test/test_activation_delegate.h"
+#include "ash/wm/test_activation_delegate.h"
 
 #include "ash/wm/window_util.h"
 #include "ui/aura/client/aura_constants.h"
diff --git a/ash/test/test_activation_delegate.h b/ash/wm/test_activation_delegate.h
similarity index 92%
rename from ash/test/test_activation_delegate.h
rename to ash/wm/test_activation_delegate.h
index 714e79c..95e757a 100644
--- a/ash/test/test_activation_delegate.h
+++ b/ash/wm/test_activation_delegate.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 ASH_TEST_TEST_ACTIVATION_DELEGATE_H_
-#define ASH_TEST_TEST_ACTIVATION_DELEGATE_H_
+#ifndef ASH_WM_TEST_ACTIVATION_DELEGATE_H_
+#define ASH_WM_TEST_ACTIVATION_DELEGATE_H_
 
 #include "base/compiler_specific.h"
 #include "base/logging.h"
@@ -61,4 +61,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_TEST_ACTIVATION_DELEGATE_H_
+#endif  // ASH_WM_TEST_ACTIVATION_DELEGATE_H_
diff --git a/ash/test/test_overlay_delegate.cc b/ash/wm/test_overlay_delegate.cc
similarity index 93%
rename from ash/test/test_overlay_delegate.cc
rename to ash/wm/test_overlay_delegate.cc
index 8fa80953..05bef3a 100644
--- a/ash/test/test_overlay_delegate.cc
+++ b/ash/wm/test_overlay_delegate.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 "ash/test/test_overlay_delegate.h"
+#include "ash/wm/test_overlay_delegate.h"
 
 namespace ash {
 
diff --git a/ash/test/test_overlay_delegate.h b/ash/wm/test_overlay_delegate.h
similarity index 84%
rename from ash/test/test_overlay_delegate.h
rename to ash/wm/test_overlay_delegate.h
index b7c74b4..d9a3085 100644
--- a/ash/test/test_overlay_delegate.h
+++ b/ash/wm/test_overlay_delegate.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 ASH_TEST_TEST_OVERLAY_DELEGATE_H_
-#define ASH_TEST_TEST_OVERLAY_DELEGATE_H_
+#ifndef ASH_WM_TEST_OVERLAY_DELEGATE_H_
+#define ASH_WM_TEST_OVERLAY_DELEGATE_H_
 
 #include "ash/wm/overlay_event_filter.h"
 #include "base/macros.h"
@@ -30,4 +30,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_TEST_OVERLAY_DELEGATE_H_
+#endif  // ASH_WM_TEST_OVERLAY_DELEGATE_H_
diff --git a/ash/test/test_session_state_animator.cc b/ash/wm/test_session_state_animator.cc
similarity index 99%
rename from ash/test/test_session_state_animator.cc
rename to ash/wm/test_session_state_animator.cc
index 86c4085..9a28d45 100644
--- a/ash/test/test_session_state_animator.cc
+++ b/ash/wm/test_session_state_animator.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 "ash/test/test_session_state_animator.h"
+#include "ash/wm/test_session_state_animator.h"
 
 #include <utility>
 #include <vector>
@@ -16,7 +16,7 @@
 // A no-op callback that can be used when managing an animation that didn't
 // actually have a callback given.
 void DummyCallback() {}
-}
+}  // namespace
 
 const SessionStateAnimator::Container
     TestSessionStateAnimator::kAllContainers[] = {
diff --git a/ash/test/test_session_state_animator.h b/ash/wm/test_session_state_animator.h
similarity index 97%
rename from ash/test/test_session_state_animator.h
rename to ash/wm/test_session_state_animator.h
index ad9450e..eedd61f 100644
--- a/ash/test/test_session_state_animator.h
+++ b/ash/wm/test_session_state_animator.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 ASH_TEST_TEST_SESSION_STATE_ANIMATOR_H_
-#define ASH_TEST_TEST_SESSION_STATE_ANIMATOR_H_
+#ifndef ASH_WM_TEST_SESSION_STATE_ANIMATOR_H_
+#define ASH_WM_TEST_SESSION_STATE_ANIMATOR_H_
 
 #include <stddef.h>
 
@@ -159,4 +159,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_TEST_SESSION_STATE_ANIMATOR_H_
+#endif  // ASH_WM_TEST_SESSION_STATE_ANIMATOR_H_
diff --git a/ash/wm/window_cycle_controller_unittest.cc b/ash/wm/window_cycle_controller_unittest.cc
index 136c4d2..2043db2 100644
--- a/ash/wm/window_cycle_controller_unittest.cc
+++ b/ash/wm/window_cycle_controller_unittest.cc
@@ -7,19 +7,19 @@
 #include <algorithm>
 #include <memory>
 
+#include "ash/app_list/test_app_list_view_presenter_impl.h"
 #include "ash/focus_cycler.h"
 #include "ash/public/cpp/config.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/scoped_root_window_for_new_windows.h"
 #include "ash/session/session_controller.h"
+#include "ash/session/test_session_controller_client.h"
 #include "ash/shelf/shelf.h"
+#include "ash/shelf/shelf_view_test_api.h"
 #include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/shelf_view_test_api.h"
-#include "ash/test/test_app_list_view_presenter_impl.h"
-#include "ash/test/test_session_controller_client.h"
-#include "ash/test/test_shell_delegate.h"
+#include "ash/test_shell_delegate.h"
 #include "ash/wm/window_cycle_list.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
diff --git a/ash/wm/window_manager_unittest.cc b/ash/wm/window_manager_unittest.cc
index 4fc16af1e..4553c66 100644
--- a/ash/wm/window_manager_unittest.cc
+++ b/ash/wm/window_manager_unittest.cc
@@ -6,7 +6,7 @@
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/test_activation_delegate.h"
+#include "ash/wm/test_activation_delegate.h"
 #include "ash/wm/window_util.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/cursor_client_observer.h"
diff --git a/ash/wm/window_positioner_unittest.cc b/ash/wm/window_positioner_unittest.cc
index c40b5ec..b723e5e 100644
--- a/ash/wm/window_positioner_unittest.cc
+++ b/ash/wm/window_positioner_unittest.cc
@@ -10,7 +10,7 @@
 #include "ash/shell.h"
 #include "ash/shell/toplevel_window.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/test_shell_delegate.h"
+#include "ash/test_shell_delegate.h"
 #include "ash/wm/window_positioner.h"
 #include "ash/wm/window_state.h"
 #include "base/strings/string_number_conversions.h"
diff --git a/ash/wm/workspace/multi_window_resize_controller_unittest.cc b/ash/wm/workspace/multi_window_resize_controller_unittest.cc
index 716e20b..0a5ff97 100644
--- a/ash/wm/workspace/multi_window_resize_controller_unittest.cc
+++ b/ash/wm/workspace/multi_window_resize_controller_unittest.cc
@@ -7,12 +7,12 @@
 #include "ash/ash_constants.h"
 #include "ash/frame/custom_frame_view_ash.h"
 #include "ash/shell.h"
+#include "ash/shell_test_api.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/shell_test_api.h"
-#include "ash/test/workspace_controller_test_api.h"
-#include "ash/test/workspace_event_handler_test_helper.h"
 #include "ash/wm/window_util.h"
+#include "ash/wm/workspace/workspace_event_handler_test_helper.h"
 #include "ash/wm/workspace_controller.h"
+#include "ash/wm/workspace_controller_test_api.h"
 #include "base/stl_util.h"
 #include "ui/aura/test/test_window_delegate.h"
 #include "ui/aura/window.h"
diff --git a/ash/test/workspace_event_handler_test_helper.cc b/ash/wm/workspace/workspace_event_handler_test_helper.cc
similarity index 85%
rename from ash/test/workspace_event_handler_test_helper.cc
rename to ash/wm/workspace/workspace_event_handler_test_helper.cc
index fe7b1d9..69c5918 100644
--- a/ash/test/workspace_event_handler_test_helper.cc
+++ b/ash/wm/workspace/workspace_event_handler_test_helper.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 "ash/test/workspace_event_handler_test_helper.h"
+#include "ash/wm/workspace/workspace_event_handler_test_helper.h"
 
 namespace ash {
 
diff --git a/ash/test/workspace_event_handler_test_helper.h b/ash/wm/workspace/workspace_event_handler_test_helper.h
similarity index 77%
rename from ash/test/workspace_event_handler_test_helper.h
rename to ash/wm/workspace/workspace_event_handler_test_helper.h
index 0360328..013d0d0 100644
--- a/ash/test/workspace_event_handler_test_helper.h
+++ b/ash/wm/workspace/workspace_event_handler_test_helper.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 ASH_TEST_WORKSPACE_EVENT_HANDLER_TEST_HELPER_H_
-#define ASH_TEST_WORKSPACE_EVENT_HANDLER_TEST_HELPER_H_
+#ifndef ASH_WM_WORKSPACE_WORKSPACE_EVENT_HANDLER_TEST_HELPER_H_
+#define ASH_WM_WORKSPACE_WORKSPACE_EVENT_HANDLER_TEST_HELPER_H_
 
 #include "ash/wm/workspace/workspace_event_handler.h"
 
@@ -28,4 +28,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_WORKSPACE_EVENT_HANDLER_TEST_HELPER_H_
+#endif  // ASH_WM_WORKSPACE_WORKSPACE_EVENT_HANDLER_TEST_HELPER_H_
diff --git a/ash/wm/workspace/workspace_event_handler_unittest.cc b/ash/wm/workspace/workspace_event_handler_unittest.cc
index 779634d3..850b348 100644
--- a/ash/wm/workspace/workspace_event_handler_unittest.cc
+++ b/ash/wm/workspace/workspace_event_handler_unittest.cc
@@ -8,11 +8,11 @@
 #include "ash/screen_util.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/workspace_controller_test_api.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "ash/wm/wm_event.h"
 #include "ash/wm/workspace_controller.h"
+#include "ash/wm/workspace_controller_test_api.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "services/ui/public/interfaces/window_manager_constants.mojom.h"
 #include "ui/aura/client/aura_constants.h"
diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc
index be8d0c7..d4f5e281 100644
--- a/ash/wm/workspace/workspace_layout_manager_unittest.cc
+++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc
@@ -15,17 +15,16 @@
 #include "ash/root_window_controller.h"
 #include "ash/screen_util.h"
 #include "ash/session/session_controller.h"
+#include "ash/session/test_session_controller_client.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_constants.h"
 #include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shell.h"
 #include "ash/shell_observer.h"
+#include "ash/shell_test_api.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/shell_test_api.h"
 #include "ash/test/test_accessibility_delegate.h"
-#include "ash/test/test_session_controller_client.h"
-#include "ash/test/workspace_controller_test_api.h"
 #include "ash/wm/fullscreen_window_finder.h"
 #include "ash/wm/maximize_mode/maximize_mode_backdrop_delegate_impl.h"
 #include "ash/wm/overview/window_selector_controller.h"
@@ -34,6 +33,7 @@
 #include "ash/wm/wm_event.h"
 #include "ash/wm/workspace/backdrop_delegate.h"
 #include "ash/wm/workspace/workspace_window_resizer.h"
+#include "ash/wm/workspace_controller_test_api.h"
 #include "base/command_line.h"
 #include "base/run_loop.h"
 #include "chromeos/audio/chromeos_sounds.h"
diff --git a/ash/test/workspace_controller_test_api.cc b/ash/wm/workspace_controller_test_api.cc
similarity index 89%
rename from ash/test/workspace_controller_test_api.cc
rename to ash/wm/workspace_controller_test_api.cc
index 8e86431b..8a296517 100644
--- a/ash/test/workspace_controller_test_api.cc
+++ b/ash/wm/workspace_controller_test_api.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/test/workspace_controller_test_api.h"
+#include "ash/wm/workspace_controller_test_api.h"
 
-#include "ash/test/workspace_event_handler_test_helper.h"
 #include "ash/wm/workspace/backdrop_controller.h"
+#include "ash/wm/workspace/workspace_event_handler_test_helper.h"
 #include "ash/wm/workspace/workspace_layout_manager.h"
 #include "ash/wm/workspace_controller.h"
 #include "ui/aura/window.h"
diff --git a/ash/test/workspace_controller_test_api.h b/ash/wm/workspace_controller_test_api.h
similarity index 83%
rename from ash/test/workspace_controller_test_api.h
rename to ash/wm/workspace_controller_test_api.h
index 813e2a7..96777dae 100644
--- a/ash/test/workspace_controller_test_api.h
+++ b/ash/wm/workspace_controller_test_api.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 ASH_TEST_WORKSPACE_CONTROLLER_TEST_API_H_
-#define ASH_TEST_WORKSPACE_CONTROLLER_TEST_API_H_
+#ifndef ASH_WM_WORKSPACE_CONTROLLER_TEST_API_H_
+#define ASH_WM_WORKSPACE_CONTROLLER_TEST_API_H_
 
 #include "ash/ash_export.h"
 #include "ash/wm/workspace_controller.h"
@@ -30,4 +30,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_TEST_WORKSPACE_CONTROLLER_TEST_API_H_
+#endif  // ASH_WM_WORKSPACE_CONTROLLER_TEST_API_H_
diff --git a/ash/wm/workspace_controller_unittest.cc b/ash/wm/workspace_controller_unittest.cc
index 28dae6d..afd8cb4 100644
--- a/ash/wm/workspace_controller_unittest.cc
+++ b/ash/wm/workspace_controller_unittest.cc
@@ -13,9 +13,9 @@
 #include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
+#include "ash/shell_test_api.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/shell_test_api.h"
 #include "ash/wm/panels/panel_layout_manager.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
diff --git a/base/metrics/persistent_histogram_allocator.cc b/base/metrics/persistent_histogram_allocator.cc
index 250b74a9..542acc4 100644
--- a/base/metrics/persistent_histogram_allocator.cc
+++ b/base/metrics/persistent_histogram_allocator.cc
@@ -683,6 +683,7 @@
     RecordCreateHistogramResult(CREATE_HISTOGRAM_UNKNOWN_TYPE);
   }
 
+  histogram->ValidateHistogramContents();
   return histogram;
 }
 
diff --git a/base/task_scheduler/scheduler_worker.cc b/base/task_scheduler/scheduler_worker.cc
index 07353443..26033d1b 100644
--- a/base/task_scheduler/scheduler_worker.cc
+++ b/base/task_scheduler/scheduler_worker.cc
@@ -15,6 +15,7 @@
 #if defined(OS_MACOSX)
 #include "base/mac/scoped_nsautorelease_pool.h"
 #elif defined(OS_WIN)
+#include "base/win/com_init_check_hook.h"
 #include "base/win/scoped_com_initializer.h"
 #endif
 
@@ -43,7 +44,10 @@
     // A SchedulerWorker starts out waiting for work.
     outer_->delegate_->WaitForWork(&wake_up_event_);
 
-#if defined(OS_WIN)
+    // When defined(COM_INIT_CHECK_HOOK_ENABLED), ignore
+    // SchedulerBackwardCompatibility::INIT_COM_STA to find incorrect uses of
+    // COM that should be running in a COM STA Task Runner.
+#if defined(OS_WIN) && !defined(COM_INIT_CHECK_HOOK_ENABLED)
     std::unique_ptr<win::ScopedCOMInitializer> com_initializer;
     if (outer_->backward_compatibility_ ==
         SchedulerBackwardCompatibility::INIT_COM_STA) {
diff --git a/base/task_scheduler/scheduler_worker_unittest.cc b/base/task_scheduler/scheduler_worker_unittest.cc
index ab5982fb2..4d22f59 100644
--- a/base/task_scheduler/scheduler_worker_unittest.cc
+++ b/base/task_scheduler/scheduler_worker_unittest.cc
@@ -30,6 +30,8 @@
 
 #if defined(OS_WIN)
 #include <objbase.h>
+
+#include "base/win/com_init_check_hook.h"
 #endif
 
 using testing::_;
@@ -931,7 +933,13 @@
 
   // The call to CoInitializeEx() should have returned S_FALSE to indicate that
   // the COM library was already initialized on the thread.
+  // See SchedulerWorker::Thread::ThreadMain for why we expect two different
+  // results here.
+#if defined(COM_INIT_CHECK_HOOK_ENABLED)
+  EXPECT_EQ(S_OK, delegate_raw->coinitialize_hresult());
+#else
   EXPECT_EQ(S_FALSE, delegate_raw->coinitialize_hresult());
+#endif
 
   worker->JoinForTesting();
 }
diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h
index f4eaac6a..bdabfa8 100644
--- a/base/trace_event/trace_event.h
+++ b/base/trace_event/trace_event.h
@@ -451,6 +451,9 @@
   // Can be combined with WithScope.
   class LocalId {
    public:
+    explicit LocalId(const void* raw_id)
+        : raw_id_(static_cast<unsigned long long>(
+              reinterpret_cast<uintptr_t>(raw_id))) {}
     explicit LocalId(unsigned long long raw_id) : raw_id_(raw_id) {}
     unsigned long long raw_id() const { return raw_id_; }
    private:
diff --git a/build/android/gyp/util/build_utils.py b/build/android/gyp/util/build_utils.py
index 422bfee3..95f81cd 100644
--- a/build/android/gyp/util/build_utils.py
+++ b/build/android/gyp/util/build_utils.py
@@ -271,7 +271,7 @@
     zip_path: Destination path within the zip file.
     src_path: Path of the source file. Mutually exclusive with |data|.
     data: File data as a string.
-    compress: Whether to enable compression. Default is take from ZipFile
+    compress: Whether to enable compression. Default is taken from ZipFile
         constructor.
   """
   assert (src_path is None) != (data is None), (
@@ -303,13 +303,15 @@
   zip_file.writestr(zipinfo, data, compress_type)
 
 
-def DoZip(inputs, output, base_dir=None):
+def DoZip(inputs, output, base_dir=None, compress_fn=None):
   """Creates a zip file from a list of files.
 
   Args:
     inputs: A list of paths to zip, or a list of (zip_path, fs_path) tuples.
     output: Destination .zip file.
     base_dir: Prefix to strip from inputs.
+    compress_fn: Applied to each input to determine whether or not to compress.
+        By default, items will be |zipfile.ZIP_STORED|.
   """
   input_tuples = []
   for tup in inputs:
@@ -321,16 +323,17 @@
   input_tuples.sort(key=lambda tup: tup[0])
   with zipfile.ZipFile(output, 'w') as outfile:
     for zip_path, fs_path in input_tuples:
-      AddToZipHermetic(outfile, zip_path, src_path=fs_path)
+      compress = compress_fn(zip_path) if compress_fn else None
+      AddToZipHermetic(outfile, zip_path, src_path=fs_path, compress=compress)
 
 
-def ZipDir(output, base_dir):
+def ZipDir(output, base_dir, compress_fn=None):
   """Creates a zip file from a directory."""
   inputs = []
   for root, _, files in os.walk(base_dir):
     for f in files:
       inputs.append(os.path.join(root, f))
-  DoZip(inputs, output, base_dir)
+  DoZip(inputs, output, base_dir, compress_fn=compress_fn)
 
 
 def MatchesGlob(path, filters):
diff --git a/build/android/pylib/instrumentation/instrumentation_test_instance.py b/build/android/pylib/instrumentation/instrumentation_test_instance.py
index 2443384..cb5d691 100644
--- a/build/android/pylib/instrumentation/instrumentation_test_instance.py
+++ b/build/android/pylib/instrumentation/instrumentation_test_instance.py
@@ -18,6 +18,7 @@
 from pylib.instrumentation import test_result
 from pylib.instrumentation import instrumentation_parser
 from pylib.utils import dexdump
+from pylib.utils import instrumentation_tracing
 from pylib.utils import proguard
 from pylib.utils import shared_preference_utils
 
@@ -281,6 +282,7 @@
 
 
 # TODO(yolandyan): remove this once the test listing from java runner lands
+@instrumentation_tracing.no_tracing
 def _GetTestsFromProguard(jar_path):
   p = proguard.Dump(jar_path)
   class_lookup = dict((c['class'], c) for c in p['classes'])
@@ -813,7 +815,7 @@
         t['flags'] = [parameters[0]]
         for p in parameters[1:]:
           parameterized_t = copy.copy(t)
-          parameterized_t['flags'] = [p]
+          parameterized_t['flags'] = ['--%s' % p]
           new_tests.append(parameterized_t)
     return tests + new_tests
 
diff --git a/build/android/pylib/instrumentation/instrumentation_test_instance_test.py b/build/android/pylib/instrumentation/instrumentation_test_instance_test.py
index a0bf464..a71095d 100755
--- a/build/android/pylib/instrumentation/instrumentation_test_instance_test.py
+++ b/build/android/pylib/instrumentation/instrumentation_test_instance_test.py
@@ -708,6 +708,123 @@
     self.assertEqual(1, len(results))
     self.assertEqual(base_test_result.ResultType.SKIP, results[0].GetType())
 
+  def testCommandLineParameterization(self):
+    o = self.createTestInstance()
+    raw_tests = [
+      {
+        'annotations': {'CommandLineParameter': {
+          'value': ['', 'enable-features=abc']}},
+        'class': 'org.chromium.test.SampleTest',
+        'superclass': 'java.lang.Object',
+        'methods': [
+          {
+            'annotations': {'SmallTest': None},
+            'method': 'testMethod1',
+          },
+          {
+            'annotations': {'MediumTest': None},
+            'method': 'testMethod2',
+          },
+        ],
+      }
+    ]
+
+    expected_tests = [
+        {
+          'annotations': {
+            'CommandLineParameter': {'value': ['', 'enable-features=abc']},
+            'SmallTest': None},
+          'class': 'org.chromium.test.SampleTest',
+          'flags': [''],
+          'is_junit4': True,
+          'method': 'testMethod1'},
+        {
+          'annotations': {
+            'CommandLineParameter': {'value': ['', 'enable-features=abc']},
+            'MediumTest': None},
+          'class': 'org.chromium.test.SampleTest',
+          'flags': [''],
+          'is_junit4': True,
+          'method': 'testMethod2'},
+        {
+          'annotations': {
+            'CommandLineParameter': {'value': ['', 'enable-features=abc']},
+            'SmallTest': None},
+          'class': 'org.chromium.test.SampleTest',
+          'flags': ['--enable-features=abc'],
+          'is_junit4': True,
+          'method': 'testMethod1'},
+        {
+          'annotations': {
+            'CommandLineParameter': {'value': ['', 'enable-features=abc']},
+             'MediumTest': None},
+          'class': 'org.chromium.test.SampleTest',
+          'flags': ['--enable-features=abc'],
+          'is_junit4': True,
+          'method': 'testMethod2'}]
+
+    o._test_jar = 'path/to/test.jar'
+    o._test_runner_junit4 = 'J4Runner'
+    with mock.patch(_INSTRUMENTATION_TEST_INSTANCE_PATH % '_GetTestsFromPickle',
+                    return_value=raw_tests):
+      actual_tests = o.GetTests()
+    self.assertEquals(actual_tests, expected_tests)
+
+  def testCommandLineParameterization_skipped(self):
+    o = self.createTestInstance()
+    raw_tests = [
+      {
+        'annotations': {'CommandLineParameter': {
+          'value': ['', 'enable-features=abc']}},
+        'class': 'org.chromium.test.SampleTest',
+        'superclass': 'java.lang.Object',
+        'methods': [
+          {
+            'annotations': {
+              'SmallTest': None,
+              'SkipCommandLineParameterization': None},
+            'method': 'testMethod1',
+          },
+          {
+            'annotations': {'MediumTest': None},
+            'method': 'testMethod2',
+          },
+        ],
+      }
+    ]
+
+    expected_tests = [
+        {
+          'annotations': {
+            'CommandLineParameter': {'value': ['', 'enable-features=abc']},
+            'SkipCommandLineParameterization': None,
+            'SmallTest': None},
+          'class': 'org.chromium.test.SampleTest',
+          'is_junit4': True,
+          'method': 'testMethod1'},
+        {
+          'annotations': {
+            'CommandLineParameter': {'value': ['', 'enable-features=abc']},
+            'MediumTest': None},
+          'class': 'org.chromium.test.SampleTest',
+          'flags': [''],
+          'is_junit4': True,
+          'method': 'testMethod2'},
+        {
+          'annotations': {
+            'CommandLineParameter': {'value': ['', 'enable-features=abc']},
+             'MediumTest': None},
+          'class': 'org.chromium.test.SampleTest',
+          'flags': ['--enable-features=abc'],
+          'is_junit4': True,
+          'method': 'testMethod2'}]
+
+    o._test_jar = 'path/to/test.jar'
+    o._test_runner_junit4 = 'J4Runner'
+    with mock.patch(_INSTRUMENTATION_TEST_INSTANCE_PATH % '_GetTestsFromPickle',
+                    return_value=raw_tests):
+      actual_tests = o.GetTests()
+    self.assertEquals(actual_tests, expected_tests)
 
 if __name__ == '__main__':
   unittest.main(verbosity=2)
diff --git a/build/android/pylib/local/device/local_device_environment.py b/build/android/pylib/local/device/local_device_environment.py
index 09fde59..9abda2d 100644
--- a/build/android/pylib/local/device/local_device_environment.py
+++ b/build/android/pylib/local/device/local_device_environment.py
@@ -22,8 +22,8 @@
 from devil.utils import parallelizer
 from pylib import constants
 from pylib.base import environment
+from pylib.utils import instrumentation_tracing
 from py_trace_event import trace_event
-from tracing_build import trace2html
 
 
 def _DeviceCachePath(device):
@@ -97,6 +97,9 @@
     self._trace_output = None
     if hasattr(args, 'trace_output'):
       self._trace_output = args.trace_output
+    self._trace_all = None
+    if hasattr(args, 'trace_all'):
+      self._trace_all = args.trace_all
 
     devil_chromium.Initialize(
         output_directory=constants.GetOutDirectory(),
@@ -109,7 +112,12 @@
 
   #override
   def SetUp(self):
-    if self.trace_output:
+    if self.trace_output and self._trace_all:
+      to_include = [r"pylib\..*", r"devil\..*", "__main__"]
+      to_exclude = ["logging"]
+      instrumentation_tracing.start_instrumenting(self.trace_output, to_include,
+                                                  to_exclude)
+    elif self.trace_output:
       self.EnableTracing()
 
   def _InitDevices(self):
@@ -161,15 +169,6 @@
 
     self.parallel_devices.pMap(prepare_device)
 
-  @staticmethod
-  def _JsonToTrace(json_path, html_path, delete_json=True):
-    # First argument is call site.
-    cmd = [__file__, json_path, '--title', 'Android Test Runner Trace',
-           '--output', html_path]
-    trace2html.Main(cmd)
-    if delete_json:
-      os.remove(json_path)
-
   @property
   def blacklist(self):
     return self._blacklist
@@ -267,16 +266,15 @@
       raise device_errors.NoDevicesError(
           'All devices were blacklisted due to errors')
 
-  def DisableTracing(self):
+  @staticmethod
+  def DisableTracing():
     if not trace_event.trace_is_enabled():
       logging.warning('Tracing is not running.')
     else:
       trace_event.trace_disable()
-    self._JsonToTrace(self._trace_output + '.json',
-                      self._trace_output)
 
   def EnableTracing(self):
     if trace_event.trace_is_enabled():
       logging.warning('Tracing is already running.')
     else:
-      trace_event.trace_enable(self._trace_output + '.json')
+      trace_event.trace_enable(self._trace_output)
diff --git a/build/android/pylib/local/device/local_device_instrumentation_test_run.py b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
index 7ba90321..34e275d3 100644
--- a/build/android/pylib/local/device/local_device_instrumentation_test_run.py
+++ b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
@@ -25,6 +25,7 @@
 from pylib.local.device import local_device_environment
 from pylib.local.device import local_device_test_run
 from pylib.utils import google_storage_helper
+from pylib.utils import instrumentation_tracing
 from pylib.utils import logdog_helper
 from pylib.utils import shared_preference_utils
 from py_trace_event import trace_event
@@ -143,6 +144,7 @@
         steps.append(self._replace_package_contextmanager.__enter__)
 
       def install_helper(apk, permissions):
+        @instrumentation_tracing.no_tracing
         @trace_event.traced("apk_path")
         def install_helper_internal(d, apk_path=apk.path):
           # pylint: disable=unused-argument
@@ -202,7 +204,7 @@
         shared_preference_utils.ApplySharedPreferenceSettings(
             dev, self._test_instance.edit_shared_prefs)
 
-      @trace_event.traced
+      @instrumentation_tracing.no_tracing
       def push_test_data():
         device_root = posixpath.join(dev.GetExternalStoragePath(),
                                      'chromium_tests_root')
diff --git a/build/android/pylib/utils/instrumentation_tracing.py b/build/android/pylib/utils/instrumentation_tracing.py
new file mode 100644
index 0000000..fe23894
--- /dev/null
+++ b/build/android/pylib/utils/instrumentation_tracing.py
@@ -0,0 +1,186 @@
+# Copyright 2017 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.
+
+"""Functions to instrument all Python function calls.
+
+Generates a JSON file readable by Chrome's about:tracing."""
+
+import contextlib
+import functools
+import inspect
+import re
+import sys
+import threading
+
+from py_trace_event import trace_event
+
+
+# Modules to exclude by default (to avoid problems like infinite loops)
+DEFAULT_EXCLUDE = [r'py_trace_event\..*']
+
+class _TraceArguments(object):
+  def __init__(self):
+    """Wraps a dictionary to ensure safe evaluation of repr()."""
+    self._arguments = {}
+
+  @staticmethod
+  def _safeStringify(item):
+    try:
+      item_str = repr(item)
+    except Exception: # pylint: disable=broad-except
+      try:
+        item_str = str(item)
+      except Exception: # pylint: disable=broad-except
+        item_str = "<ERROR>"
+    return item_str
+
+  def add(self, key, val):
+    key_str = _TraceArguments._safeStringify(key)
+    val_str = _TraceArguments._safeStringify(val)
+
+    self._arguments[key_str] = val_str
+
+  def __repr__(self):
+    return repr(self._arguments)
+
+
+saved_thread_ids = set()
+
+def _shouldTrace(frame, to_include, to_exclude, included, excluded):
+  """
+  Decides whether or not the function called in frame should be traced.
+
+  Args:
+    frame: The Python frame object of this function call.
+    to_include: Set of regex objects for modules which should be traced.
+    to_exclude: Set of regex objects for modules which should not be traced.
+    included: Set of module names we've determined should be traced.
+    excluded: Set of module names we've determined should not be traced.
+  """
+  if not inspect.getmodule(frame):
+    return False
+
+  module_name = inspect.getmodule(frame).__name__
+
+  if module_name in included:
+    includes = True
+  elif to_include:
+    includes = any([pattern.match(module_name) for pattern in to_include])
+  else:
+    includes = True
+
+  if includes:
+    included.add(module_name)
+  else:
+    return False
+
+  # Find the modules of every function in the stack trace.
+  frames = inspect.getouterframes(frame)
+  calling_module_names = [inspect.getmodule(fr[0]).__name__ for fr in frames]
+
+  # Return False for anything with an excluded module's function anywhere in the
+  # stack trace (even if the function itself is in an included module).
+  if to_exclude:
+    for calling_module in calling_module_names:
+      if calling_module in excluded:
+        return False
+      for pattern in to_exclude:
+        if pattern.match(calling_module):
+          excluded.add(calling_module)
+          return False
+
+  return True
+
+def _generate_trace_function(to_include, to_exclude):
+  to_include = {re.compile(item) for item in to_include}
+  to_exclude = {re.compile(item) for item in to_exclude}
+  to_exclude.update({re.compile(item) for item in DEFAULT_EXCLUDE})
+
+  included = set()
+  excluded = set()
+
+  def traceFunction(frame, event, arg):
+    # pylint: disable=unused-argument
+    if event not in ("call", "return"):
+      return None
+
+    function_name = frame.f_code.co_name
+    filename = frame.f_code.co_filename
+    line_number = frame.f_lineno
+
+    if _shouldTrace(frame, to_include, to_exclude, included, excluded):
+      if event == "call":
+        # This function is beginning; we save the thread name (if that hasn't
+        # been done), record the Begin event, and return this function to be
+        # used as the local trace function.
+
+        thread_id = threading.current_thread().ident
+
+        if thread_id not in saved_thread_ids:
+          thread_name = threading.current_thread().name
+
+          trace_event.trace_set_thread_name(thread_name)
+
+          saved_thread_ids.add(thread_id)
+
+        arguments = _TraceArguments()
+        # The function's argument values are stored in the frame's
+        # |co_varnames| as the first |co_argcount| elements. (Following that
+        # are local variables.)
+        for idx in range(frame.f_code.co_argcount):
+          arg_name = frame.f_code.co_varnames[idx]
+          arguments.add(arg_name, frame.f_locals[arg_name])
+        trace_event.trace_begin(function_name, arguments=arguments,
+                                module=inspect.getmodule(frame).__name__,
+                                filename=filename, line_number=line_number)
+
+        # Return this function, so it gets used as the "local trace function"
+        # within this function's frame (and in particular, gets called for this
+        # function's "return" event).
+        return traceFunction
+
+      if event == "return":
+        trace_event.trace_end(function_name)
+        return None
+
+  return traceFunction
+
+
+def no_tracing(f):
+  @functools.wraps(f)
+  def wrapper(*args, **kwargs):
+    trace_func = sys.gettrace()
+    try:
+      sys.settrace(None)
+      threading.settrace(None)
+      return f(*args, **kwargs)
+    finally:
+      sys.settrace(trace_func)
+      threading.settrace(trace_func)
+  return wrapper
+
+
+def start_instrumenting(output_file, to_include=(), to_exclude=()):
+  """Enable tracing of all function calls (from specified modules)."""
+  trace_event.trace_enable(output_file)
+
+  traceFunc = _generate_trace_function(to_include, to_exclude)
+  sys.settrace(traceFunc)
+  threading.settrace(traceFunc)
+
+
+def stop_instrumenting():
+  trace_event.trace_disable()
+
+  sys.settrace(None)
+  threading.settrace(None)
+
+
+@contextlib.contextmanager
+def Instrument(output_file, to_include=(), to_exclude=()):
+  try:
+    start_instrumenting(output_file, to_include, to_exclude)
+    yield None
+  finally:
+    stop_instrumenting()
diff --git a/build/android/pylib/utils/proguard.py b/build/android/pylib/utils/proguard.py
index 89dc4c79..cefe38e 100644
--- a/build/android/pylib/utils/proguard.py
+++ b/build/android/pylib/utils/proguard.py
@@ -287,5 +287,4 @@
       else:
         state.InitMethod(None)
 
-
   return results
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index 3e32f81b..cba25eb 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -100,7 +100,12 @@
   parser.add_argument(
       '--trace-output',
       metavar='FILENAME', type=os.path.realpath,
-      help='Path to save test_runner trace data to.')
+      help='Path to save test_runner trace json output to.')
+
+  parser.add_argument(
+      '--trace-all',
+      action='store_true',
+      help='Whether to trace all function calls.')
 
 
 def AddCommonOptions(parser):
diff --git a/build/android/test_runner.pydeps b/build/android/test_runner.pydeps
index fddebbd3f..ea68a58 100644
--- a/build/android/test_runner.pydeps
+++ b/build/android/test_runner.pydeps
@@ -80,44 +80,7 @@
 ../../third_party/catapult/devil/devil/utils/timeout_retry.py
 ../../third_party/catapult/devil/devil/utils/watchdog_timer.py
 ../../third_party/catapult/devil/devil/utils/zip_utils.py
-../../third_party/catapult/third_party/beautifulsoup4/bs4/__init__.py
-../../third_party/catapult/third_party/beautifulsoup4/bs4/builder/__init__.py
-../../third_party/catapult/third_party/beautifulsoup4/bs4/builder/_html5lib.py
-../../third_party/catapult/third_party/beautifulsoup4/bs4/builder/_htmlparser.py
-../../third_party/catapult/third_party/beautifulsoup4/bs4/builder/_lxml.py
-../../third_party/catapult/third_party/beautifulsoup4/bs4/dammit.py
-../../third_party/catapult/third_party/beautifulsoup4/bs4/element.py
-../../third_party/catapult/third_party/html5lib-python/html5lib/__init__.py
-../../third_party/catapult/third_party/html5lib-python/html5lib/constants.py
-../../third_party/catapult/third_party/html5lib-python/html5lib/html5parser.py
-../../third_party/catapult/third_party/html5lib-python/html5lib/inputstream.py
-../../third_party/catapult/third_party/html5lib-python/html5lib/serializer/__init__.py
-../../third_party/catapult/third_party/html5lib-python/html5lib/serializer/htmlserializer.py
-../../third_party/catapult/third_party/html5lib-python/html5lib/tokenizer.py
-../../third_party/catapult/third_party/html5lib-python/html5lib/treebuilders/__init__.py
-../../third_party/catapult/third_party/html5lib-python/html5lib/treebuilders/_base.py
-../../third_party/catapult/third_party/html5lib-python/html5lib/treewalkers/__init__.py
-../../third_party/catapult/third_party/html5lib-python/html5lib/trie/__init__.py
-../../third_party/catapult/third_party/html5lib-python/html5lib/trie/_base.py
-../../third_party/catapult/third_party/html5lib-python/html5lib/trie/py.py
-../../third_party/catapult/third_party/html5lib-python/html5lib/utils.py
-../../third_party/catapult/third_party/py_vulcanize/py_vulcanize/__init__.py
-../../third_party/catapult/third_party/py_vulcanize/py_vulcanize/generate.py
-../../third_party/catapult/third_party/py_vulcanize/py_vulcanize/html_generation_controller.py
-../../third_party/catapult/third_party/py_vulcanize/py_vulcanize/html_module.py
-../../third_party/catapult/third_party/py_vulcanize/py_vulcanize/js_utils.py
-../../third_party/catapult/third_party/py_vulcanize/py_vulcanize/module.py
-../../third_party/catapult/third_party/py_vulcanize/py_vulcanize/parse_html_deps.py
-../../third_party/catapult/third_party/py_vulcanize/py_vulcanize/project.py
-../../third_party/catapult/third_party/py_vulcanize/py_vulcanize/resource.py
-../../third_party/catapult/third_party/py_vulcanize/py_vulcanize/resource_loader.py
-../../third_party/catapult/third_party/py_vulcanize/py_vulcanize/strip_js_comments.py
-../../third_party/catapult/third_party/py_vulcanize/py_vulcanize/style_sheet.py
-../../third_party/catapult/third_party/six/six.py
 ../../third_party/catapult/third_party/zipfile/zipfile_2_7_13.py
-../../third_party/catapult/tracing/tracing_build/__init__.py
-../../third_party/catapult/tracing/tracing_build/trace2html.py
-../../third_party/catapult/tracing/tracing_project.py
 ../../third_party/colorama/src/colorama/__init__.py
 ../../third_party/colorama/src/colorama/ansi.py
 ../../third_party/colorama/src/colorama/ansitowin32.py
@@ -208,6 +171,7 @@
 pylib/utils/device_dependencies.py
 pylib/utils/dexdump.py
 pylib/utils/google_storage_helper.py
+pylib/utils/instrumentation_tracing.py
 pylib/utils/logdog_helper.py
 pylib/utils/logging_utils.py
 pylib/utils/proguard.py
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 3714b1f..d7712d53 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -1631,7 +1631,18 @@
     }
 
     template("package_resources_helper") {
-      action(target_name) {
+      _resource_packaged_apk_path = invoker.resource_packaged_apk_path
+      _package_resources_target = target_name
+      _post_process = defined(invoker.post_process_package_resources_script) &&
+                      defined(invoker.post_process_package_resources_args)
+      if (_post_process) {
+        _package_resources_target = "${_package_resources_target}__intermediate"
+        _post_processed_resource_packaged_apk_path = _resource_packaged_apk_path
+        _resource_packaged_apk_path =
+            "${_resource_packaged_apk_path}__intermediate.ap_"
+      }
+
+      action(_package_resources_target) {
         deps = invoker.deps
 
         script = "//build/android/gyp/package_resources.py"
@@ -1643,7 +1654,7 @@
           inputs += [ _resources_zip ]
         }
         outputs = [
-          invoker.resource_packaged_apk_path,
+          _resource_packaged_apk_path,
         ]
 
         if (defined(invoker.android_aapt_path)) {
@@ -1674,7 +1685,7 @@
           "--version-name",
           _version_name,
           "--apk-path",
-          rebase_path(invoker.resource_packaged_apk_path, root_build_dir),
+          rebase_path(_resource_packaged_apk_path, root_build_dir),
         ]
 
         if (defined(_resources_zip)) {
@@ -1727,6 +1738,32 @@
           }
         }
       }
+
+      if (_post_process) {
+        action(target_name) {
+          depfile = "${target_gen_dir}/${target_name}.d"
+          script = invoker.post_process_package_resources_script
+          args = [
+            "--depfile",
+            rebase_path(depfile, root_build_dir),
+            "--apk-path",
+            rebase_path(_resource_packaged_apk_path, root_build_dir),
+            "--output",
+            rebase_path(_post_processed_resource_packaged_apk_path,
+                        root_build_dir),
+          ]
+          args += invoker.post_process_package_resources_args
+          inputs = [
+            _resource_packaged_apk_path,
+          ]
+          outputs = [
+            _post_processed_resource_packaged_apk_path,
+          ]
+          deps = [
+            ":${_package_resources_target}",
+          ]
+        }
+      }
     }
 
     _package_resources_target_name = "${target_name}__package_resources"
@@ -1739,6 +1776,8 @@
                                "png_to_webp",
                                "exclude_xxxhdpi",
                                "extensions_to_not_compress",
+                               "post_process_package_resources_args",
+                               "post_process_package_resources_script",
                                "xxxhdpi_whitelist",
                              ])
       deps = _deps
@@ -1791,6 +1830,8 @@
                                "png_to_webp",
                                "exclude_xxxhdpi",
                                "extensions_to_not_compress",
+                               "post_process_package_resources_args",
+                               "post_process_package_resources_script",
                                "xxxhdpi_whitelist",
                              ])
       deps =
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 6c7fb50..db737be 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -2269,6 +2269,8 @@
                                "exclude_xxxhdpi",
                                "extensions_to_not_compress",
                                "language_splits",
+                               "post_process_package_resources_args",
+                               "post_process_package_resources_script",
                                "public_deps",
                                "secondary_native_libs",
                                "shared_resources",
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 67a898b..673912b3 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -935,7 +935,7 @@
   assert_no_deps = [ "//chrome" ]
 
   data = [
-    "test/data/",
+    "//components/viz/test/data/",
 
     # Needed for isolate script to execute.
     "//testing/scripts/common.py",
diff --git a/cc/animation/OWNERS b/cc/animation/OWNERS
index 4cd8d66b..d84ea709 100644
--- a/cc/animation/OWNERS
+++ b/cc/animation/OWNERS
@@ -1,4 +1,4 @@
 loyso@chromium.org
 
-# TEAM: style-dev@chromium.org
+# TEAM: threaded-rendering-dev@chromium.org
 # COMPONENT: Internals>Compositing>Animation
diff --git a/cc/ipc/copy_output_request_struct_traits.cc b/cc/ipc/copy_output_request_struct_traits.cc
index dc93b7c0..93fcacdc 100644
--- a/cc/ipc/copy_output_request_struct_traits.cc
+++ b/cc/ipc/copy_output_request_struct_traits.cc
@@ -4,7 +4,9 @@
 
 #include "cc/ipc/copy_output_request_struct_traits.h"
 
-#include "base/callback_helpers.h"
+#include <utility>
+
+#include "base/bind.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 
 namespace {
@@ -16,20 +18,22 @@
  public:
   CopyOutputResultSenderImpl(
       cc::CopyOutputRequest::CopyOutputRequestCallback result_callback)
-      : result_callback_(result_callback) {
+      : result_callback_(std::move(result_callback)) {
     DCHECK(result_callback_);
   }
 
   ~CopyOutputResultSenderImpl() override {
-    if (result_callback_)
-      result_callback_.Run(cc::CopyOutputResult::CreateEmptyResult());
+    if (result_callback_) {
+      std::move(result_callback_)
+          .Run(cc::CopyOutputResult::CreateEmptyResult());
+    }
   }
 
   // mojom::TextureMailboxReleaser implementation:
   void SendResult(std::unique_ptr<cc::CopyOutputResult> result) override {
     if (!result_callback_)
       return;
-    base::ResetAndReturn(&result_callback_).Run(std::move(result));
+    std::move(result_callback_).Run(std::move(result));
   }
 
  private:
@@ -78,7 +82,7 @@
   auto result_sender =
       data.TakeResultSender<cc::mojom::CopyOutputResultSenderPtr>();
   request->result_callback_ =
-      base::Bind(SendResult, base::Passed(&result_sender));
+      base::BindOnce(SendResult, base::Passed(&result_sender));
 
   *out_p = std::move(request);
 
diff --git a/cc/ipc/struct_traits_unittest.cc b/cc/ipc/struct_traits_unittest.cc
index 59fc43b..e2482698 100644
--- a/cc/ipc/struct_traits_unittest.cc
+++ b/cc/ipc/struct_traits_unittest.cc
@@ -442,11 +442,9 @@
   auto bitmap = base::MakeUnique<SkBitmap>();
   bitmap->allocN32Pixels(size.width(), size.height());
   base::RunLoop run_loop;
-  auto callback =
-      base::Bind(CopyOutputRequestCallback, run_loop.QuitClosure(), size);
-
-  std::unique_ptr<CopyOutputRequest> input;
-  input = CopyOutputRequest::CreateBitmapRequest(callback);
+  std::unique_ptr<CopyOutputRequest> input =
+      CopyOutputRequest::CreateBitmapRequest(base::BindOnce(
+          CopyOutputRequestCallback, run_loop.QuitClosure(), size));
   input->set_area(area);
   input->set_source(source);
   mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy();
@@ -472,10 +470,9 @@
   mailbox.SetName(mailbox_name);
   viz::TextureMailbox texture_mailbox(mailbox, gpu::SyncToken(), target);
   base::RunLoop run_loop;
-  auto callback = base::Bind(CopyOutputRequestCallback, run_loop.QuitClosure(),
-                             gfx::Size());
-
-  auto input = CopyOutputRequest::CreateRequest(callback);
+  std::unique_ptr<CopyOutputRequest> input =
+      CopyOutputRequest::CreateRequest(base::BindOnce(
+          CopyOutputRequestCallback, run_loop.QuitClosure(), gfx::Size()));
   input->SetTextureMailbox(texture_mailbox);
 
   mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy();
@@ -496,7 +493,7 @@
 TEST_F(StructTraitsTest, CopyOutputRequest_CallbackRunsOnce) {
   int n_called = 0;
   auto request = CopyOutputRequest::CreateRequest(
-      base::Bind(CopyOutputRequestCallbackRunsOnceCallback, &n_called));
+      base::BindOnce(CopyOutputRequestCallbackRunsOnceCallback, &n_called));
   auto result_sender = mojo::StructTraits<
       mojom::CopyOutputRequestDataView,
       std::unique_ptr<CopyOutputRequest>>::result_sender(request);
@@ -509,7 +506,7 @@
 
 TEST_F(StructTraitsTest, CopyOutputRequest_MessagePipeBroken) {
   base::RunLoop run_loop;
-  auto request = CopyOutputRequest::CreateRequest(base::Bind(
+  auto request = CopyOutputRequest::CreateRequest(base::BindOnce(
       CopyOutputRequestMessagePipeBrokenCallback, run_loop.QuitClosure()));
   auto result_sender = mojo::StructTraits<
       mojom::CopyOutputRequestDataView,
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index d96b381..dfd75fc 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -933,7 +933,7 @@
 }
 
 void Layer::SetTransformTreeIndex(int index) {
-  CHECK(IsPropertyChangeAllowed());
+  DCHECK(IsPropertyChangeAllowed());
   if (transform_tree_index_ == index)
     return;
   if (index == TransformTree::kInvalidNodeId)
@@ -952,7 +952,7 @@
 }
 
 void Layer::SetClipTreeIndex(int index) {
-  CHECK(IsPropertyChangeAllowed());
+  DCHECK(IsPropertyChangeAllowed());
   if (clip_tree_index_ == index)
     return;
   clip_tree_index_ = index;
@@ -969,7 +969,7 @@
 }
 
 void Layer::SetEffectTreeIndex(int index) {
-  CHECK(IsPropertyChangeAllowed());
+  DCHECK(IsPropertyChangeAllowed());
   if (effect_tree_index_ == index)
     return;
   effect_tree_index_ = index;
@@ -986,7 +986,7 @@
 }
 
 void Layer::SetScrollTreeIndex(int index) {
-  CHECK(IsPropertyChangeAllowed());
+  DCHECK(IsPropertyChangeAllowed());
   if (scroll_tree_index_ == index)
     return;
   scroll_tree_index_ = index;
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 90915577b..0fd73cc 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -959,26 +959,11 @@
   return GetPropertyTrees()->transform_tree;
 }
 
-bool LayerImpl::HasValidPropertyTreeIndices() const {
-  // TODO(crbug.com/726423): LayerImpls should never have invalid PropertyTree
-  // indices.
-  const bool has_valid_transform_node =
-      !!GetTransformTree().Node(transform_tree_index());
-  DCHECK(has_valid_transform_node);
-
-  const bool has_valid_effect_node =
-      !!GetEffectTree().Node(effect_tree_index());
-  DCHECK(has_valid_effect_node);
-
-  const bool has_valid_clip_node = !!GetClipTree().Node(clip_tree_index());
-  DCHECK(has_valid_clip_node);
-
-  const bool has_valid_scroll_node =
-      !!GetScrollTree().Node(scroll_tree_index());
-  DCHECK(has_valid_scroll_node);
-
-  return has_valid_transform_node && has_valid_effect_node &&
-         has_valid_clip_node && has_valid_scroll_node;
+void LayerImpl::EnsureValidPropertyTreeIndices() const {
+  DCHECK(GetTransformTree().Node(transform_tree_index()));
+  DCHECK(GetEffectTree().Node(effect_tree_index()));
+  DCHECK(GetClipTree().Node(clip_tree_index()));
+  DCHECK(GetScrollTree().Node(scroll_tree_index()));
 }
 
 }  // namespace cc
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index 57c5c6d..5751294e 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -433,7 +433,7 @@
   }
   bool raster_even_if_not_drawn() const { return raster_even_if_not_drawn_; }
 
-  bool HasValidPropertyTreeIndices() const;
+  void EnsureValidPropertyTreeIndices() const;
 
  protected:
   LayerImpl(LayerTreeImpl* layer_impl,
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc
index 6355412b..857a69e 100644
--- a/cc/layers/layer_unittest.cc
+++ b/cc/layers/layer_unittest.cc
@@ -1325,11 +1325,11 @@
   // Create identical requests without the source being set, and expect the
   // layer does not abort either one.
   std::unique_ptr<CopyOutputRequest> request = CopyOutputRequest::CreateRequest(
-      base::Bind(&ReceiveCopyOutputResult, &result_count));
+      base::BindOnce(&ReceiveCopyOutputResult, &result_count));
   layer->RequestCopyOfOutput(std::move(request));
   EXPECT_EQ(0, result_count);
   request = CopyOutputRequest::CreateRequest(
-      base::Bind(&ReceiveCopyOutputResult, &result_count));
+      base::BindOnce(&ReceiveCopyOutputResult, &result_count));
   layer->RequestCopyOfOutput(std::move(request));
   EXPECT_EQ(0, result_count);
 
@@ -1344,27 +1344,27 @@
   // the first request using |kArbitrarySourceId1| aborts immediately when
   // the second request using |kArbitrarySourceId1| is made.
   int did_receive_first_result_from_this_source = 0;
-  request = CopyOutputRequest::CreateRequest(base::Bind(
+  request = CopyOutputRequest::CreateRequest(base::BindOnce(
       &ReceiveCopyOutputResult, &did_receive_first_result_from_this_source));
   request->set_source(kArbitrarySourceId1);
   layer->RequestCopyOfOutput(std::move(request));
   EXPECT_EQ(0, did_receive_first_result_from_this_source);
   // Make a request from a different source.
   int did_receive_result_from_different_source = 0;
-  request = CopyOutputRequest::CreateRequest(base::Bind(
+  request = CopyOutputRequest::CreateRequest(base::BindOnce(
       &ReceiveCopyOutputResult, &did_receive_result_from_different_source));
   request->set_source(kArbitrarySourceId2);
   layer->RequestCopyOfOutput(std::move(request));
   EXPECT_EQ(0, did_receive_result_from_different_source);
   // Make a request without specifying the source.
   int did_receive_result_from_anonymous_source = 0;
-  request = CopyOutputRequest::CreateRequest(base::Bind(
+  request = CopyOutputRequest::CreateRequest(base::BindOnce(
       &ReceiveCopyOutputResult, &did_receive_result_from_anonymous_source));
   layer->RequestCopyOfOutput(std::move(request));
   EXPECT_EQ(0, did_receive_result_from_anonymous_source);
   // Make the second request from |kArbitrarySourceId1|.
   int did_receive_second_result_from_this_source = 0;
-  request = CopyOutputRequest::CreateRequest(base::Bind(
+  request = CopyOutputRequest::CreateRequest(base::BindOnce(
       &ReceiveCopyOutputResult, &did_receive_second_result_from_this_source));
   request->set_source(kArbitrarySourceId1);
   layer->RequestCopyOfOutput(
diff --git a/cc/output/copy_output_request.cc b/cc/output/copy_output_request.cc
index b08a066..f00140a 100644
--- a/cc/output/copy_output_request.cc
+++ b/cc/output/copy_output_request.cc
@@ -5,7 +5,6 @@
 #include "cc/output/copy_output_request.h"
 
 #include "base/bind.h"
-#include "base/callback_helpers.h"
 #include "base/logging.h"
 #include "base/trace_event/trace_event.h"
 #include "cc/output/copy_output_result.h"
@@ -16,11 +15,10 @@
 
 CopyOutputRequest::CopyOutputRequest() : force_bitmap_result_(false) {}
 
-CopyOutputRequest::CopyOutputRequest(
-    bool force_bitmap_result,
-    const CopyOutputRequestCallback& result_callback)
+CopyOutputRequest::CopyOutputRequest(bool force_bitmap_result,
+                                     CopyOutputRequestCallback result_callback)
     : force_bitmap_result_(force_bitmap_result),
-      result_callback_(result_callback) {
+      result_callback_(std::move(result_callback)) {
   DCHECK(!result_callback_.is_null());
   TRACE_EVENT_ASYNC_BEGIN0("cc", "CopyOutputRequest", this);
 }
@@ -35,11 +33,11 @@
                          !result->IsEmpty());
   if (result_task_runner_) {
     result_task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(base::ResetAndReturn(&result_callback_),
-                                  std::move(result)));
+        FROM_HERE,
+        base::BindOnce(std::move(result_callback_), std::move(result)));
     result_task_runner_ = nullptr;
   } else {
-    base::ResetAndReturn(&result_callback_).Run(std::move(result));
+    std::move(result_callback_).Run(std::move(result));
   }
 }
 
diff --git a/cc/output/copy_output_request.h b/cc/output/copy_output_request.h
index 0194b77..0ee355e6 100644
--- a/cc/output/copy_output_request.h
+++ b/cc/output/copy_output_request.h
@@ -30,19 +30,21 @@
 
 class CC_EXPORT CopyOutputRequest {
  public:
-  typedef base::Callback<void(std::unique_ptr<CopyOutputResult> result)>
-      CopyOutputRequestCallback;
+  using CopyOutputRequestCallback =
+      base::OnceCallback<void(std::unique_ptr<CopyOutputResult> result)>;
 
   static std::unique_ptr<CopyOutputRequest> CreateEmptyRequest() {
     return base::WrapUnique(new CopyOutputRequest);
   }
   static std::unique_ptr<CopyOutputRequest> CreateRequest(
-      const CopyOutputRequestCallback& result_callback) {
-    return base::WrapUnique(new CopyOutputRequest(false, result_callback));
+      CopyOutputRequestCallback result_callback) {
+    return base::WrapUnique(
+        new CopyOutputRequest(false, std::move(result_callback)));
   }
   static std::unique_ptr<CopyOutputRequest> CreateBitmapRequest(
-      const CopyOutputRequestCallback& result_callback) {
-    return base::WrapUnique(new CopyOutputRequest(true, result_callback));
+      CopyOutputRequestCallback result_callback) {
+    return base::WrapUnique(
+        new CopyOutputRequest(true, std::move(result_callback)));
   }
 
   ~CopyOutputRequest();
@@ -97,7 +99,7 @@
 
   CopyOutputRequest();
   CopyOutputRequest(bool force_bitmap_result,
-                    const CopyOutputRequestCallback& result_callback);
+                    CopyOutputRequestCallback result_callback);
 
   scoped_refptr<base::TaskRunner> result_task_runner_;
   base::Optional<base::UnguessableToken> source_;
diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc
index c0713fc..287441a 100644
--- a/cc/output/gl_renderer_unittest.cc
+++ b/cc/output/gl_renderer_unittest.cc
@@ -1795,7 +1795,7 @@
                     gfx::Transform(), FilterOperations());
   root_pass->has_transparent_background = false;
   root_pass->copy_requests.push_back(
-      CopyOutputRequest::CreateRequest(base::Bind(&IgnoreCopyResult)));
+      CopyOutputRequest::CreateRequest(base::BindOnce(&IgnoreCopyResult)));
 
   viz::TextureMailbox mailbox =
       viz::TextureMailbox(gpu::Mailbox::Generate(), gpu::SyncToken(),
diff --git a/cc/output/software_renderer_unittest.cc b/cc/output/software_renderer_unittest.cc
index 3dce9d3..1eed08fc 100644
--- a/cc/output/software_renderer_unittest.cc
+++ b/cc/output/software_renderer_unittest.cc
@@ -63,10 +63,9 @@
     base::RunLoop loop;
 
     list->back()->copy_requests.push_back(
-        CopyOutputRequest::CreateBitmapRequest(
-            base::Bind(&SoftwareRendererTest::SaveBitmapResult,
-                       base::Unretained(&bitmap_result),
-                       loop.QuitClosure())));
+        CopyOutputRequest::CreateBitmapRequest(base::BindOnce(
+            &SoftwareRendererTest::SaveBitmapResult,
+            base::Unretained(&bitmap_result), loop.QuitClosure())));
 
     renderer()->DrawFrame(list, device_scale_factor, viewport_size);
     loop.Run();
diff --git a/cc/paint/BUILD.gn b/cc/paint/BUILD.gn
index 1c53186..591bb6a31f 100644
--- a/cc/paint/BUILD.gn
+++ b/cc/paint/BUILD.gn
@@ -9,8 +9,6 @@
   sources = [
     "discardable_image_map.cc",
     "discardable_image_map.h",
-    "discardable_image_store.cc",
-    "discardable_image_store.h",
     "display_item_list.cc",
     "display_item_list.h",
     "draw_image.cc",
diff --git a/cc/paint/discardable_image_map.cc b/cc/paint/discardable_image_map.cc
index 5eac691..6aca722 100644
--- a/cc/paint/discardable_image_map.cc
+++ b/cc/paint/discardable_image_map.cc
@@ -9,31 +9,275 @@
 #include <algorithm>
 #include <limits>
 
+#include "base/containers/adapters.h"
 #include "base/memory/ptr_util.h"
-#include "cc/paint/discardable_image_store.h"
+#include "base/trace_event/trace_event.h"
+#include "cc/paint/paint_op_buffer.h"
+#include "third_party/skia/include/utils/SkNoDrawCanvas.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/skia_util.h"
 
 namespace cc {
+namespace {
 
-DiscardableImageMap::DiscardableImageMap() {}
-
-DiscardableImageMap::~DiscardableImageMap() {}
-
-std::unique_ptr<DiscardableImageStore>
-DiscardableImageMap::BeginGeneratingMetadata(const gfx::Size& bounds) {
-  return base::MakeUnique<DiscardableImageStore>(bounds.width(),
-                                                 bounds.height());
+SkRect MapRect(const SkMatrix& matrix, const SkRect& src) {
+  SkRect dst;
+  matrix.mapRect(&dst, src);
+  return dst;
 }
 
-void DiscardableImageMap::EndGeneratingMetadata(
-    std::vector<std::pair<DrawImage, gfx::Rect>> images,
-    base::flat_map<PaintImage::Id, gfx::Rect> image_id_to_rect) {
+class PaintTrackingCanvas final : public SkNoDrawCanvas {
+ public:
+  PaintTrackingCanvas(int width, int height) : SkNoDrawCanvas(width, height) {}
+  ~PaintTrackingCanvas() override = default;
+
+  bool ComputePaintBounds(const SkRect& rect,
+                          const SkPaint* current_paint,
+                          SkRect* paint_bounds) {
+    *paint_bounds = rect;
+    if (current_paint) {
+      if (!current_paint->canComputeFastBounds())
+        return false;
+      *paint_bounds =
+          current_paint->computeFastBounds(*paint_bounds, paint_bounds);
+    }
+
+    for (const auto& paint : base::Reversed(saved_paints_)) {
+      if (!paint.canComputeFastBounds())
+        return false;
+      *paint_bounds = paint.computeFastBounds(*paint_bounds, paint_bounds);
+    }
+
+    return true;
+  }
+
+ private:
+  // SkNoDrawCanvas overrides.
+  SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override {
+    saved_paints_.push_back(rec.fPaint ? *rec.fPaint : SkPaint());
+    return SkNoDrawCanvas::getSaveLayerStrategy(rec);
+  }
+
+  void willSave() override {
+    saved_paints_.push_back(SkPaint());
+    return SkNoDrawCanvas::willSave();
+  }
+
+  void willRestore() override {
+    DCHECK_GT(saved_paints_.size(), 0u);
+    saved_paints_.pop_back();
+    SkNoDrawCanvas::willRestore();
+  }
+
+  std::vector<SkPaint> saved_paints_;
+};
+
+class DiscardableImageGenerator {
+ public:
+  DiscardableImageGenerator(int width, int height) : canvas_(width, height) {}
+  ~DiscardableImageGenerator() = default;
+
+  void GatherDiscardableImages(const PaintOpBuffer* buffer) {
+    if (!buffer->HasDiscardableImages())
+      return;
+
+    SkMatrix original = canvas_.getTotalMatrix();
+    canvas_.save();
+    // TODO(khushalsagar): Optimize out save/restore blocks if there are no
+    // images in the draw ops between them.
+    for (auto* op : PaintOpBuffer::Iterator(buffer)) {
+      if (op->IsDrawOp()) {
+        switch (op->GetType()) {
+          case PaintOpType::DrawArc: {
+            auto* arc_op = static_cast<DrawArcOp*>(op);
+            AddImageFromFlags(arc_op->oval, arc_op->flags);
+          } break;
+          case PaintOpType::DrawCircle: {
+            auto* circle_op = static_cast<DrawCircleOp*>(op);
+            SkRect rect =
+                SkRect::MakeXYWH(circle_op->cx - circle_op->radius,
+                                 circle_op->cy - circle_op->radius,
+                                 2 * circle_op->radius, 2 * circle_op->radius);
+            AddImageFromFlags(rect, circle_op->flags);
+          } break;
+          case PaintOpType::DrawImage: {
+            auto* image_op = static_cast<DrawImageOp*>(op);
+            const SkImage* sk_image = image_op->image.sk_image().get();
+            AddImage(image_op->image,
+                     SkRect::MakeIWH(sk_image->width(), sk_image->height()),
+                     SkRect::MakeXYWH(image_op->left, image_op->top,
+                                      sk_image->width(), sk_image->height()),
+                     nullptr, image_op->flags);
+          } break;
+          case PaintOpType::DrawImageRect: {
+            auto* image_rect_op = static_cast<DrawImageRectOp*>(op);
+            SkMatrix matrix;
+            matrix.setRectToRect(image_rect_op->src, image_rect_op->dst,
+                                 SkMatrix::kFill_ScaleToFit);
+            AddImage(image_rect_op->image, image_rect_op->src,
+                     image_rect_op->dst, &matrix, image_rect_op->flags);
+          } break;
+          case PaintOpType::DrawIRect: {
+            auto* rect_op = static_cast<DrawIRectOp*>(op);
+            AddImageFromFlags(SkRect::Make(rect_op->rect), rect_op->flags);
+          } break;
+          case PaintOpType::DrawOval: {
+            auto* oval_op = static_cast<DrawOvalOp*>(op);
+            AddImageFromFlags(oval_op->oval, oval_op->flags);
+          } break;
+          case PaintOpType::DrawPath: {
+            auto* path_op = static_cast<DrawPathOp*>(op);
+            AddImageFromFlags(path_op->path.getBounds(), path_op->flags);
+          } break;
+          case PaintOpType::DrawRecord: {
+            auto* record_op = static_cast<DrawRecordOp*>(op);
+            GatherDiscardableImages(record_op->record.get());
+          } break;
+          case PaintOpType::DrawRect: {
+            auto* rect_op = static_cast<DrawRectOp*>(op);
+            AddImageFromFlags(rect_op->rect, rect_op->flags);
+          } break;
+          case PaintOpType::DrawRRect: {
+            auto* rect_op = static_cast<DrawRRectOp*>(op);
+            AddImageFromFlags(rect_op->rrect.rect(), rect_op->flags);
+          } break;
+          // TODO(khushalsagar): Check if we should be querying images from any
+          // of the following ops.
+          case PaintOpType::DrawPosText:
+          case PaintOpType::DrawLine:
+          case PaintOpType::DrawDRRect:
+          case PaintOpType::DrawText:
+          case PaintOpType::DrawTextBlob:
+          case PaintOpType::DrawColor:
+            break;
+          default:
+            NOTREACHED();
+        }
+      } else {
+        op->Raster(&canvas_, original);
+      }
+    }
+    canvas_.restore();
+  }
+
+  std::vector<std::pair<DrawImage, gfx::Rect>> TakeImages() {
+    return std::move(image_set_);
+  }
+  base::flat_map<PaintImage::Id, gfx::Rect> TakeImageIdToRectMap() {
+    return std::move(image_id_to_rect_);
+  }
+
+ private:
+  void AddImageFromFlags(const SkRect& rect, const PaintFlags& flags) {
+    SkShader* shader = flags.getSkShader();
+    if (shader) {
+      SkMatrix matrix;
+      SkShader::TileMode xy[2];
+      SkImage* image = shader->isAImage(&matrix, xy);
+      if (image) {
+        // We currently use the wrong id for images that come from shaders. We
+        // don't know what the stable id is, but since the completion and
+        // animation states are both unknown, this value doesn't matter as it
+        // won't be used in checker imaging anyway. Keep this value the same to
+        // avoid id churn.
+        // TODO(vmpstr): Remove this when we can add paint images into shaders
+        // directly.
+        PaintImage paint_image(PaintImage::kUnknownStableId, sk_ref_sp(image),
+                               PaintImage::AnimationType::UNKNOWN,
+                               PaintImage::CompletionState::UNKNOWN);
+        // TODO(ericrk): Handle cases where we only need a sub-rect from the
+        // image. crbug.com/671821
+        AddImage(std::move(paint_image), SkRect::MakeFromIRect(image->bounds()),
+                 rect, &matrix, flags);
+      }
+    }
+  }
+
+  void AddImage(PaintImage paint_image,
+                const SkRect& src_rect,
+                const SkRect& rect,
+                const SkMatrix* local_matrix,
+                const PaintFlags& flags) {
+    if (!paint_image.sk_image()->isLazyGenerated())
+      return;
+
+    const SkRect& clip_rect = SkRect::Make(canvas_.getDeviceClipBounds());
+    const SkMatrix& ctm = canvas_.getTotalMatrix();
+
+    SkRect paint_rect = MapRect(ctm, rect);
+    bool computed_paint_bounds =
+        canvas_.ComputePaintBounds(paint_rect, ToSkPaint(&flags), &paint_rect);
+    if (!computed_paint_bounds) {
+      // TODO(vmpstr): UMA this case.
+      paint_rect = clip_rect;
+    }
+
+    // Clamp the image rect by the current clip rect.
+    if (!paint_rect.intersect(clip_rect))
+      return;
+
+    SkFilterQuality filter_quality = flags.getFilterQuality();
+
+    SkIRect src_irect;
+    src_rect.roundOut(&src_irect);
+    gfx::Rect image_rect = gfx::ToEnclosingRect(gfx::SkRectToRectF(paint_rect));
+
+    // During raster, we use the device clip bounds on the canvas, which outsets
+    // the actual clip by 1 due to the possibility of antialiasing. Account for
+    // this here by outsetting the image rect by 1. Note that this only affects
+    // queries into the rtree, which will now return images that only touch the
+    // bounds of the query rect.
+    //
+    // Note that it's not sufficient for us to inset the device clip bounds at
+    // raster time, since we might be sending a larger-than-one-item display
+    // item to skia, which means that skia will internally determine whether to
+    // raster the picture (using device clip bounds that are outset).
+    image_rect.Inset(-1, -1);
+
+    // The true target color space will be assigned when it is known, in
+    // GetDiscardableImagesInRect.
+    gfx::ColorSpace target_color_space;
+
+    SkMatrix matrix = ctm;
+    if (local_matrix)
+      matrix.postConcat(*local_matrix);
+
+    image_id_to_rect_[paint_image.stable_id()].Union(image_rect);
+    image_set_.emplace_back(
+        DrawImage(std::move(paint_image), src_irect, filter_quality, matrix,
+                  target_color_space),
+        image_rect);
+  }
+
+  // This canvas is used only for tracking transform/clip/filter state from the
+  // non-drawing ops.
+  PaintTrackingCanvas canvas_;
+  std::vector<std::pair<DrawImage, gfx::Rect>> image_set_;
+  base::flat_map<PaintImage::Id, gfx::Rect> image_id_to_rect_;
+};
+
+}  // namespace
+
+DiscardableImageMap::DiscardableImageMap() = default;
+DiscardableImageMap::~DiscardableImageMap() = default;
+
+void DiscardableImageMap::Generate(const PaintOpBuffer* paint_op_buffer,
+                                   const gfx::Rect& bounds) {
+  TRACE_EVENT0("cc", "DiscardableImageMap::Generate");
+
+  if (!paint_op_buffer->HasDiscardableImages())
+    return;
+
+  DiscardableImageGenerator generator(bounds.right(), bounds.bottom());
+  generator.GatherDiscardableImages(paint_op_buffer);
+  image_id_to_rect_ = generator.TakeImageIdToRectMap();
+  auto images = generator.TakeImages();
   images_rtree_.Build(
       images,
       [](const std::vector<std::pair<DrawImage, gfx::Rect>>& items,
          size_t index) { return items[index].second; },
       [](const std::vector<std::pair<DrawImage, gfx::Rect>>& items,
          size_t index) { return items[index].first; });
-  image_id_to_rect_ = std::move(image_id_to_rect);
 }
 
 void DiscardableImageMap::GetDiscardableImagesInRect(
@@ -57,19 +301,9 @@
   return it == image_id_to_rect_.end() ? gfx::Rect() : it->second;
 }
 
-DiscardableImageMap::ScopedMetadataGenerator::ScopedMetadataGenerator(
-    DiscardableImageMap* image_map,
-    const gfx::Size& bounds)
-    : image_map_(image_map),
-      image_store_(image_map->BeginGeneratingMetadata(bounds)) {}
-
-DiscardableImageMap::ScopedMetadataGenerator::~ScopedMetadataGenerator() {
-  image_map_->EndGeneratingMetadata(image_store_->TakeImages(),
-                                    image_store_->TakeImageIdToRectMap());
-}
-
 void DiscardableImageMap::Reset() {
   image_id_to_rect_.clear();
+  image_id_to_rect_.shrink_to_fit();
   images_rtree_.Reset();
 }
 
diff --git a/cc/paint/discardable_image_map.h b/cc/paint/discardable_image_map.h
index 398c4a8..b76fef1 100644
--- a/cc/paint/discardable_image_map.h
+++ b/cc/paint/discardable_image_map.h
@@ -22,25 +22,13 @@
 
 namespace cc {
 class DiscardableImageStore;
+class PaintOpBuffer;
 
 // This class is used for generating discardable images data (see DrawImage
 // for the type of data it stores). It allows the client to query a particular
 // rect and get back a list of DrawImages in that rect.
 class CC_PAINT_EXPORT DiscardableImageMap {
  public:
-  class CC_PAINT_EXPORT ScopedMetadataGenerator {
-   public:
-    ScopedMetadataGenerator(DiscardableImageMap* image_map,
-                            const gfx::Size& bounds);
-    ~ScopedMetadataGenerator();
-
-    DiscardableImageStore* image_store() { return image_store_.get(); }
-
-   private:
-    DiscardableImageMap* image_map_;
-    std::unique_ptr<DiscardableImageStore> image_store_;
-  };
-
   DiscardableImageMap();
   ~DiscardableImageMap();
 
@@ -52,6 +40,7 @@
   gfx::Rect GetRectForImage(PaintImage::Id image_id) const;
 
   void Reset();
+  void Generate(const PaintOpBuffer* paint_op_buffer, const gfx::Rect& bounds);
 
  private:
   friend class ScopedMetadataGenerator;
diff --git a/cc/paint/discardable_image_map_unittest.cc b/cc/paint/discardable_image_map_unittest.cc
index 91cd167..e020bf11 100644
--- a/cc/paint/discardable_image_map_unittest.cc
+++ b/cc/paint/discardable_image_map_unittest.cc
@@ -11,7 +11,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/values.h"
 #include "cc/base/region.h"
-#include "cc/paint/discardable_image_store.h"
 #include "cc/paint/paint_flags.h"
 #include "cc/paint/paint_op_buffer.h"
 #include "cc/paint/paint_recorder.h"
@@ -127,9 +126,7 @@
       content_layer_client.PaintContentsToDisplayList(
           ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
   display_list->GenerateDiscardableImagesMetadata();
-
-  const DiscardableImageMap& image_map =
-      display_list->discardable_image_map_for_testing();
+  const DiscardableImageMap& image_map = display_list->discardable_image_map();
 
   for (int y = 0; y < 4; ++y) {
     for (int x = 0; x < 4; ++x) {
@@ -212,9 +209,7 @@
       content_layer_client.PaintContentsToDisplayList(
           ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
   display_list->GenerateDiscardableImagesMetadata();
-
-  const DiscardableImageMap& image_map =
-      display_list->discardable_image_map_for_testing();
+  const DiscardableImageMap& image_map = display_list->discardable_image_map();
 
   for (int y = 0; y < 4; ++y) {
     for (int x = 0; x < 4; ++x) {
@@ -326,9 +321,7 @@
       content_layer_client.PaintContentsToDisplayList(
           ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
   display_list->GenerateDiscardableImagesMetadata();
-
-  const DiscardableImageMap& image_map =
-      display_list->discardable_image_map_for_testing();
+  const DiscardableImageMap& image_map = display_list->discardable_image_map();
 
   for (int y = 0; y < 4; ++y) {
     for (int x = 0; x < 4; ++x) {
@@ -365,9 +358,8 @@
       content_layer_client.PaintContentsToDisplayList(
           ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
   display_list->GenerateDiscardableImagesMetadata();
+  const DiscardableImageMap& image_map = display_list->discardable_image_map();
 
-  const DiscardableImageMap& image_map =
-      display_list->discardable_image_map_for_testing();
   std::vector<PositionScaleDrawImage> images =
       GetDiscardableImagesInRect(image_map, gfx::Rect(0, 0, 1, 1));
   std::vector<gfx::Rect> inset_rects = InsetImageRects(images);
@@ -386,20 +378,18 @@
   PaintImage discardable_image = CreateDiscardablePaintImage(gfx::Size(10, 10));
   sk_sp<PaintRecord> record = CreateRecording(discardable_image, visible_rect);
 
-  DiscardableImageMap image_map;
-  {
-    DiscardableImageMap::ScopedMetadataGenerator generator(&image_map,
-                                                           visible_rect.size());
-    DiscardableImageStore* image_store = generator.image_store();
-    {
-      std::unique_ptr<SkPaint> paint(new SkPaint());
-      image_store->GetNoDrawCanvas()->saveLayer(gfx::RectToSkRect(visible_rect),
-                                                paint.get());
-    }
-    image_store->GatherDiscardableImages(record.get());
-    image_store->GetNoDrawCanvas()->restore();
-  }
+  scoped_refptr<DisplayItemList> display_list = new DisplayItemList;
+  PaintFlags paint;
+  PaintOpBuffer* buffer = display_list->StartPaint();
+  SkRect visible_sk_rect(gfx::RectToSkRect(visible_rect));
+  buffer->push<SaveLayerOp>(&visible_sk_rect, &paint);
+  buffer->push<DrawRecordOp>(std::move(record));
+  buffer->push<RestoreOp>();
+  display_list->EndPaintOfUnpaired(visible_rect);
+  display_list->Finalize();
 
+  display_list->GenerateDiscardableImagesMetadata();
+  const DiscardableImageMap& image_map = display_list->discardable_image_map();
   std::vector<PositionScaleDrawImage> images =
       GetDiscardableImagesInRect(image_map, gfx::Rect(0, 0, 1, 1));
   EXPECT_EQ(1u, images.size());
@@ -414,18 +404,17 @@
   PaintImage discardable_image = CreateDiscardablePaintImage(gfx::Size(10, 10));
   sk_sp<PaintRecord> record = CreateRecording(discardable_image, visible_rect);
 
-  DiscardableImageMap image_map;
-  {
-    DiscardableImageMap::ScopedMetadataGenerator generator(&image_map,
-                                                           visible_rect.size());
-    DiscardableImageStore* image_store = generator.image_store();
-    SkPaint* null_paint = nullptr;
-    image_store->GetNoDrawCanvas()->saveLayer(gfx::RectToSkRect(visible_rect),
-                                              null_paint);
-    image_store->GatherDiscardableImages(record.get());
-    image_store->GetNoDrawCanvas()->restore();
-  }
+  scoped_refptr<DisplayItemList> display_list = new DisplayItemList;
+  PaintOpBuffer* buffer = display_list->StartPaint();
+  SkRect visible_sk_rect(gfx::RectToSkRect(visible_rect));
+  buffer->push<SaveLayerOp>(&visible_sk_rect, nullptr);
+  buffer->push<DrawRecordOp>(std::move(record));
+  buffer->push<RestoreOp>();
+  display_list->EndPaintOfUnpaired(visible_rect);
+  display_list->Finalize();
 
+  display_list->GenerateDiscardableImagesMetadata();
+  const DiscardableImageMap& image_map = display_list->discardable_image_map();
   std::vector<PositionScaleDrawImage> images =
       GetDiscardableImagesInRect(image_map, gfx::Rect(0, 0, 1, 1));
   EXPECT_EQ(1u, images.size());
@@ -448,9 +437,8 @@
       content_layer_client.PaintContentsToDisplayList(
           ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
   display_list->GenerateDiscardableImagesMetadata();
+  const DiscardableImageMap& image_map = display_list->discardable_image_map();
 
-  const DiscardableImageMap& image_map =
-      display_list->discardable_image_map_for_testing();
   std::vector<PositionScaleDrawImage> images =
       GetDiscardableImagesInRect(image_map, gfx::Rect(42, 42, 1, 1));
   std::vector<gfx::Rect> inset_rects = InsetImageRects(images);
@@ -492,9 +480,8 @@
       content_layer_client.PaintContentsToDisplayList(
           ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
   display_list->GenerateDiscardableImagesMetadata();
+  const DiscardableImageMap& image_map = display_list->discardable_image_map();
 
-  const DiscardableImageMap& image_map =
-      display_list->discardable_image_map_for_testing();
   std::vector<PositionScaleDrawImage> images =
       GetDiscardableImagesInRect(image_map, gfx::Rect(0, 0, 1, 1));
   std::vector<gfx::Rect> inset_rects = InsetImageRects(images);
@@ -543,9 +530,8 @@
       content_layer_client.PaintContentsToDisplayList(
           ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
   display_list->GenerateDiscardableImagesMetadata();
+  const DiscardableImageMap& image_map = display_list->discardable_image_map();
 
-  const DiscardableImageMap& image_map =
-      display_list->discardable_image_map_for_testing();
   std::vector<PositionScaleDrawImage> images =
       GetDiscardableImagesInRect(image_map, gfx::Rect(0, 0, 1, 1));
   std::vector<gfx::Rect> inset_rects = InsetImageRects(images);
@@ -605,9 +591,7 @@
       content_layer_client.PaintContentsToDisplayList(
           ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
   display_list->GenerateDiscardableImagesMetadata();
-
-  const DiscardableImageMap& image_map =
-      display_list->discardable_image_map_for_testing();
+  const DiscardableImageMap& image_map = display_list->discardable_image_map();
 
   gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateXYZD50();
   for (int y = 0; y < 4; ++y) {
@@ -656,10 +640,9 @@
   display_list->EndPaintOfUnpaired(gfx::Rect(250, 250));
 
   display_list->Finalize();
-  display_list->GenerateDiscardableImagesMetadata();
 
-  const DiscardableImageMap& image_map =
-      display_list->discardable_image_map_for_testing();
+  display_list->GenerateDiscardableImagesMetadata();
+  const DiscardableImageMap& image_map = display_list->discardable_image_map();
   std::vector<PositionScaleDrawImage> images =
       GetDiscardableImagesInRect(image_map, visible_rect);
   std::vector<gfx::Rect> inset_rects = InsetImageRects(images);
@@ -692,23 +675,19 @@
   PaintOpBuffer root_buffer;
   root_buffer.push<DrawRecordOp>(internal_record);
   root_buffer.push<DrawRecordOp>(record2);
-  DiscardableImageMap image_map_;
-  {
-    DiscardableImageMap::ScopedMetadataGenerator generator(&image_map_,
-                                                           gfx::Size(200, 200));
-    generator.image_store()->GatherDiscardableImages(&root_buffer);
-  }
+  DiscardableImageMap image_map;
+  image_map.Generate(&root_buffer, gfx::Rect(200, 200));
 
   gfx::ColorSpace target_color_space;
   std::vector<DrawImage> images;
-  image_map_.GetDiscardableImagesInRect(gfx::Rect(0, 0, 5, 95), 1.f,
-                                        target_color_space, &images);
+  image_map.GetDiscardableImagesInRect(gfx::Rect(0, 0, 5, 95), 1.f,
+                                       target_color_space, &images);
   EXPECT_EQ(1u, images.size());
   EXPECT_TRUE(discardable_image == images[0].paint_image());
 
   images.clear();
-  image_map_.GetDiscardableImagesInRect(gfx::Rect(105, 105, 5, 95), 1.f,
-                                        target_color_space, &images);
+  image_map.GetDiscardableImagesInRect(gfx::Rect(105, 105, 5, 95), 1.f,
+                                       target_color_space, &images);
   EXPECT_EQ(1u, images.size());
   EXPECT_TRUE(discardable_image2 == images[0].paint_image());
 }
diff --git a/cc/paint/discardable_image_store.cc b/cc/paint/discardable_image_store.cc
deleted file mode 100644
index 8fc62a89..0000000
--- a/cc/paint/discardable_image_store.cc
+++ /dev/null
@@ -1,248 +0,0 @@
-// Copyright 2017 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 "cc/paint/discardable_image_store.h"
-
-#include "base/containers/adapters.h"
-#include "base/memory/ptr_util.h"
-#include "cc/paint/display_item_list.h"
-#include "third_party/skia/include/utils/SkNoDrawCanvas.h"
-#include "ui/gfx/geometry/rect_conversions.h"
-#include "ui/gfx/skia_util.h"
-
-namespace cc {
-namespace {
-
-SkRect MapRect(const SkMatrix& matrix, const SkRect& src) {
-  SkRect dst;
-  matrix.mapRect(&dst, src);
-  return dst;
-}
-
-}  // namespace
-
-class DiscardableImageStore::PaintTrackingCanvas : public SkNoDrawCanvas {
- public:
-  PaintTrackingCanvas(int width, int height) : SkNoDrawCanvas(width, height) {}
-  ~PaintTrackingCanvas() override = default;
-
-  bool ComputePaintBounds(const SkRect& rect,
-                          const SkPaint* current_paint,
-                          SkRect* paint_bounds) {
-    *paint_bounds = rect;
-    if (current_paint) {
-      if (!current_paint->canComputeFastBounds())
-        return false;
-      *paint_bounds =
-          current_paint->computeFastBounds(*paint_bounds, paint_bounds);
-    }
-
-    for (const auto& paint : base::Reversed(saved_paints_)) {
-      if (!paint.canComputeFastBounds())
-        return false;
-      *paint_bounds = paint.computeFastBounds(*paint_bounds, paint_bounds);
-    }
-
-    return true;
-  }
-
- protected:
-  SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override {
-    saved_paints_.push_back(rec.fPaint ? *rec.fPaint : SkPaint());
-    return SkNoDrawCanvas::getSaveLayerStrategy(rec);
-  }
-
-  void willSave() override {
-    saved_paints_.push_back(SkPaint());
-    return SkNoDrawCanvas::willSave();
-  }
-
-  void willRestore() override {
-    DCHECK_GT(saved_paints_.size(), 0u);
-    saved_paints_.pop_back();
-    SkNoDrawCanvas::willRestore();
-  }
-
- private:
-  std::vector<SkPaint> saved_paints_;
-};
-
-DiscardableImageStore::DiscardableImageStore(int width, int height)
-    : canvas_(base::MakeUnique<PaintTrackingCanvas>(width, height)) {}
-
-DiscardableImageStore::~DiscardableImageStore() = default;
-
-SkNoDrawCanvas* DiscardableImageStore::GetNoDrawCanvas() {
-  return canvas_.get();
-}
-
-void DiscardableImageStore::GatherDiscardableImages(
-    const PaintOpBuffer* buffer) {
-  if (!buffer->HasDiscardableImages())
-    return;
-
-  SkMatrix original = canvas_->getTotalMatrix();
-  canvas_->save();
-  // TODO(khushalsagar): Optimize out save/restore blocks if there are no images
-  // in the draw ops between them.
-  for (auto* op : PaintOpBuffer::Iterator(buffer)) {
-    if (op->IsDrawOp()) {
-      switch (op->GetType()) {
-        case PaintOpType::DrawArc: {
-          auto* arc_op = static_cast<DrawArcOp*>(op);
-          AddImageFromFlags(arc_op->oval, arc_op->flags);
-        } break;
-        case PaintOpType::DrawCircle: {
-          auto* circle_op = static_cast<DrawCircleOp*>(op);
-          SkRect rect =
-              SkRect::MakeXYWH(circle_op->cx - circle_op->radius,
-                               circle_op->cy - circle_op->radius,
-                               2 * circle_op->radius, 2 * circle_op->radius);
-          AddImageFromFlags(rect, circle_op->flags);
-        } break;
-        case PaintOpType::DrawImage: {
-          auto* image_op = static_cast<DrawImageOp*>(op);
-          const SkImage* sk_image = image_op->image.sk_image().get();
-          AddImage(image_op->image,
-                   SkRect::MakeIWH(sk_image->width(), sk_image->height()),
-                   SkRect::MakeXYWH(image_op->left, image_op->top,
-                                    sk_image->width(), sk_image->height()),
-                   nullptr, image_op->flags);
-        } break;
-        case PaintOpType::DrawImageRect: {
-          auto* image_rect_op = static_cast<DrawImageRectOp*>(op);
-          SkMatrix matrix;
-          matrix.setRectToRect(image_rect_op->src, image_rect_op->dst,
-                               SkMatrix::kFill_ScaleToFit);
-          AddImage(image_rect_op->image, image_rect_op->src, image_rect_op->dst,
-                   &matrix, image_rect_op->flags);
-        } break;
-        case PaintOpType::DrawIRect: {
-          auto* rect_op = static_cast<DrawIRectOp*>(op);
-          AddImageFromFlags(SkRect::Make(rect_op->rect), rect_op->flags);
-        } break;
-        case PaintOpType::DrawOval: {
-          auto* oval_op = static_cast<DrawOvalOp*>(op);
-          AddImageFromFlags(oval_op->oval, oval_op->flags);
-        } break;
-        case PaintOpType::DrawPath: {
-          auto* path_op = static_cast<DrawPathOp*>(op);
-          AddImageFromFlags(path_op->path.getBounds(), path_op->flags);
-        } break;
-        case PaintOpType::DrawRecord: {
-          auto* record_op = static_cast<DrawRecordOp*>(op);
-          GatherDiscardableImages(record_op->record.get());
-        } break;
-        case PaintOpType::DrawRect: {
-          auto* rect_op = static_cast<DrawRectOp*>(op);
-          AddImageFromFlags(rect_op->rect, rect_op->flags);
-        } break;
-        case PaintOpType::DrawRRect: {
-          auto* rect_op = static_cast<DrawRRectOp*>(op);
-          AddImageFromFlags(rect_op->rrect.rect(), rect_op->flags);
-        } break;
-        // TODO(khushalsagar): Check if we should be querying images from any of
-        // the following ops.
-        case PaintOpType::DrawPosText:
-        case PaintOpType::DrawLine:
-        case PaintOpType::DrawDRRect:
-        case PaintOpType::DrawText:
-        case PaintOpType::DrawTextBlob:
-        case PaintOpType::DrawColor:
-          break;
-        default:
-          NOTREACHED();
-      }
-    } else {
-      op->Raster(canvas_.get(), original);
-    }
-  }
-  canvas_->restore();
-}
-
-// Currently this function only handles extracting images from SkImageShaders
-// embedded in SkPaints. Other embedded image cases, such as SkPictures,
-// are not yet handled.
-void DiscardableImageStore::AddImageFromFlags(const SkRect& rect,
-                                              const PaintFlags& flags) {
-  SkShader* shader = flags.getSkShader();
-  if (shader) {
-    SkMatrix matrix;
-    SkShader::TileMode xy[2];
-    SkImage* image = shader->isAImage(&matrix, xy);
-    if (image) {
-      // We currently use the wrong id for images that come from shaders. We
-      // don't know what the stable id is, but since the completion and
-      // animation states are both unknown, this value doesn't matter as it
-      // won't be used in checker imaging anyway. Keep this value the same to
-      // avoid id churn.
-      // TODO(vmpstr): Remove this when we can add paint images into shaders
-      // directly.
-      PaintImage paint_image(PaintImage::kUnknownStableId, sk_ref_sp(image),
-                             PaintImage::AnimationType::UNKNOWN,
-                             PaintImage::CompletionState::UNKNOWN);
-      // TODO(ericrk): Handle cases where we only need a sub-rect from the
-      // image. crbug.com/671821
-      AddImage(std::move(paint_image), SkRect::MakeFromIRect(image->bounds()),
-               rect, &matrix, flags);
-    }
-  }
-}
-
-void DiscardableImageStore::AddImage(PaintImage paint_image,
-                                     const SkRect& src_rect,
-                                     const SkRect& rect,
-                                     const SkMatrix* local_matrix,
-                                     const PaintFlags& flags) {
-  if (!paint_image.sk_image()->isLazyGenerated())
-    return;
-
-  const SkRect& clip_rect = SkRect::Make(canvas_->getDeviceClipBounds());
-  const SkMatrix& ctm = canvas_->getTotalMatrix();
-
-  SkRect paint_rect = MapRect(ctm, rect);
-  bool computed_paint_bounds =
-      canvas_->ComputePaintBounds(paint_rect, ToSkPaint(&flags), &paint_rect);
-  if (!computed_paint_bounds) {
-    // TODO(vmpstr): UMA this case.
-    paint_rect = clip_rect;
-  }
-
-  // Clamp the image rect by the current clip rect.
-  if (!paint_rect.intersect(clip_rect))
-    return;
-
-  SkFilterQuality filter_quality = flags.getFilterQuality();
-
-  SkIRect src_irect;
-  src_rect.roundOut(&src_irect);
-  gfx::Rect image_rect = gfx::ToEnclosingRect(gfx::SkRectToRectF(paint_rect));
-
-  // During raster, we use the device clip bounds on the canvas, which outsets
-  // the actual clip by 1 due to the possibility of antialiasing. Account for
-  // this here by outsetting the image rect by 1. Note that this only affects
-  // queries into the rtree, which will now return images that only touch the
-  // bounds of the query rect.
-  //
-  // Note that it's not sufficient for us to inset the device clip bounds at
-  // raster time, since we might be sending a larger-than-one-item display
-  // item to skia, which means that skia will internally determine whether to
-  // raster the picture (using device clip bounds that are outset).
-  image_rect.Inset(-1, -1);
-
-  // The true target color space will be assigned when it is known, in
-  // GetDiscardableImagesInRect.
-  gfx::ColorSpace target_color_space;
-
-  SkMatrix matrix = ctm;
-  if (local_matrix)
-    matrix.postConcat(*local_matrix);
-
-  image_id_to_rect_[paint_image.stable_id()].Union(image_rect);
-  image_set_.emplace_back(DrawImage(std::move(paint_image), src_irect,
-                                    filter_quality, matrix, target_color_space),
-                          image_rect);
-}
-
-}  // namespace cc
diff --git a/cc/paint/discardable_image_store.h b/cc/paint/discardable_image_store.h
deleted file mode 100644
index 2f2809b..0000000
--- a/cc/paint/discardable_image_store.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2017 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 CC_PAINT_DISCARDABLE_IMAGE_STORE_H_
-#define CC_PAINT_DISCARDABLE_IMAGE_STORE_H_
-
-#include "base/containers/flat_map.h"
-#include "cc/paint/draw_image.h"
-#include "cc/paint/image_id.h"
-#include "cc/paint/paint_export.h"
-#include "cc/paint/paint_op_buffer.h"
-#include "third_party/skia/include/core/SkMatrix.h"
-#include "third_party/skia/include/core/SkRect.h"
-#include "third_party/skia/include/utils/SkNoDrawCanvas.h"
-
-namespace cc {
-class PaintFlags;
-class PaintImage;
-
-class CC_PAINT_EXPORT DiscardableImageStore {
- public:
-  DiscardableImageStore(int width, int height);
-  ~DiscardableImageStore();
-
-  void GatherDiscardableImages(const PaintOpBuffer* buffer);
-  SkNoDrawCanvas* GetNoDrawCanvas();
-
-  std::vector<std::pair<DrawImage, gfx::Rect>> TakeImages() {
-    return std::move(image_set_);
-  }
-  base::flat_map<PaintImage::Id, gfx::Rect> TakeImageIdToRectMap() {
-    return std::move(image_id_to_rect_);
-  }
-
- private:
-  class PaintTrackingCanvas;
-
-  void AddImageFromFlags(const SkRect& rect, const PaintFlags& flags);
-  void AddImage(PaintImage paint_image,
-                const SkRect& src_rect,
-                const SkRect& rect,
-                const SkMatrix* local_matrix,
-                const PaintFlags& flags);
-
-  // This canvas is used only for tracking transform/clip/filter state from the
-  // non-drawing ops.
-  std::unique_ptr<PaintTrackingCanvas> canvas_;
-  std::vector<std::pair<DrawImage, gfx::Rect>> image_set_;
-  base::flat_map<PaintImage::Id, gfx::Rect> image_id_to_rect_;
-};
-
-}  // namespace cc
-
-#endif  // CC_PAINT_DISCARDABLE_IMAGE_STORE_H_
diff --git a/cc/paint/display_item_list.cc b/cc/paint/display_item_list.cc
index 93da499a..61aa873 100644
--- a/cc/paint/display_item_list.cc
+++ b/cc/paint/display_item_list.cc
@@ -14,7 +14,6 @@
 #include "cc/base/math_util.h"
 #include "cc/base/render_surface_filters.h"
 #include "cc/debug/picture_debug_util.h"
-#include "cc/paint/discardable_image_store.h"
 #include "cc/paint/solid_color_analyzer.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkPictureRecorder.h"
@@ -90,7 +89,8 @@
       TRACE_DISABLED_BY_DEFAULT("cc.debug.display_items") ","
       TRACE_DISABLED_BY_DEFAULT("cc.debug.picture") ","
       TRACE_DISABLED_BY_DEFAULT("devtools.timeline.picture"),
-      "cc::DisplayItemList", this, CreateTracedValue(include_items));
+      "cc::DisplayItemList", TRACE_ID_LOCAL(this),
+      CreateTracedValue(include_items));
 }
 
 std::unique_ptr<base::trace_event::TracedValue>
@@ -141,28 +141,7 @@
 }
 
 void DisplayItemList::GenerateDiscardableImagesMetadata() {
-  // This should be only called once.
-  DCHECK(image_map_.empty());
-  if (!paint_op_buffer_.HasDiscardableImages())
-    return;
-
-  gfx::Rect bounds = rtree_.GetBounds();
-  DiscardableImageMap::ScopedMetadataGenerator generator(
-      &image_map_, gfx::Size(bounds.right(), bounds.bottom()));
-  generator.image_store()->GatherDiscardableImages(&paint_op_buffer_);
-}
-
-void DisplayItemList::GetDiscardableImagesInRect(
-    const gfx::Rect& rect,
-    float contents_scale,
-    const gfx::ColorSpace& target_color_space,
-    std::vector<DrawImage>* images) {
-  image_map_.GetDiscardableImagesInRect(rect, contents_scale,
-                                        target_color_space, images);
-}
-
-gfx::Rect DisplayItemList::GetRectForImage(PaintImage::Id image_id) const {
-  return image_map_.GetRectForImage(image_id);
+  image_map_.Generate(&paint_op_buffer_, rtree_.GetBounds());
 }
 
 void DisplayItemList::Reset() {
diff --git a/cc/paint/display_item_list.h b/cc/paint/display_item_list.h
index 4801bb9..989539e4 100644
--- a/cc/paint/display_item_list.h
+++ b/cc/paint/display_item_list.h
@@ -114,24 +114,14 @@
   size_t op_count() const { return paint_op_buffer_.size(); }
   size_t BytesUsed() const;
 
-  void EmitTraceSnapshot() const;
-
-  void GenerateDiscardableImagesMetadata();
-  void GetDiscardableImagesInRect(const gfx::Rect& rect,
-                                  float contents_scale,
-                                  const gfx::ColorSpace& target_color_space,
-                                  std::vector<DrawImage>* images);
-  gfx::Rect GetRectForImage(PaintImage::Id image_id) const;
-
-  gfx::Rect VisualRectForTesting(int index) { return visual_rects_[index]; }
-
-  const DiscardableImageMap& discardable_image_map_for_testing() const {
+  const DiscardableImageMap& discardable_image_map() const {
     return image_map_;
   }
 
-  bool HasDiscardableImages() const {
-    return paint_op_buffer_.HasDiscardableImages();
-  }
+  void EmitTraceSnapshot() const;
+  void GenerateDiscardableImagesMetadata();
+
+  gfx::Rect VisualRectForTesting(int index) { return visual_rects_[index]; }
 
   // Generate a PaintRecord from this DisplayItemList, leaving |this| in
   // an empty state.
diff --git a/cc/raster/raster_source.cc b/cc/raster/raster_source.cc
index 4a2a81ca..1e7168c 100644
--- a/cc/raster/raster_source.cc
+++ b/cc/raster/raster_source.cc
@@ -228,14 +228,14 @@
     const gfx::ColorSpace& target_color_space,
     std::vector<DrawImage>* images) const {
   DCHECK_EQ(0u, images->size());
-  display_list_->GetDiscardableImagesInRect(layer_rect, contents_scale,
-                                            target_color_space, images);
+  display_list_->discardable_image_map().GetDiscardableImagesInRect(
+      layer_rect, contents_scale, target_color_space, images);
 }
 
 gfx::Rect RasterSource::GetRectForImage(PaintImage::Id image_id) const {
   if (!display_list_)
     return gfx::Rect();
-  return display_list_->GetRectForImage(image_id);
+  return display_list_->discardable_image_map().GetRectForImage(image_id);
 }
 
 bool RasterSource::CoversRect(const gfx::Rect& layer_rect) const {
diff --git a/cc/surfaces/surface_unittest.cc b/cc/surfaces/surface_unittest.cc
index 3fccb58..32992e0 100644
--- a/cc/surfaces/surface_unittest.cc
+++ b/cc/surfaces/surface_unittest.cc
@@ -72,7 +72,7 @@
 
   bool copy_called = false;
   support->RequestCopyOfSurface(CopyOutputRequest::CreateRequest(
-      base::Bind(&TestCopyResultCallback, &copy_called)));
+      base::BindOnce(&TestCopyResultCallback, &copy_called)));
   EXPECT_TRUE(surface_manager->GetSurfaceForId(surface_id));
   EXPECT_FALSE(copy_called);
 
diff --git a/cc/test/layer_test_common.cc b/cc/test/layer_test_common.cc
index 0f61bac..31f4aeb8 100644
--- a/cc/test/layer_test_common.cc
+++ b/cc/test/layer_test_common.cc
@@ -236,7 +236,8 @@
 
 void LayerTestCommon::LayerImplTest::RequestCopyOfOutput() {
   root_layer_for_testing()->test_properties()->copy_requests.push_back(
-      CopyOutputRequest::CreateRequest(base::Bind(&EmptyCopyOutputCallback)));
+      CopyOutputRequest::CreateRequest(
+          base::BindOnce(&EmptyCopyOutputCallback)));
 }
 
 }  // namespace cc
diff --git a/cc/test/layer_tree_pixel_test.cc b/cc/test/layer_tree_pixel_test.cc
index a3a6eee66..a4c413a3 100644
--- a/cc/test/layer_tree_pixel_test.cc
+++ b/cc/test/layer_tree_pixel_test.cc
@@ -90,8 +90,8 @@
 
 std::unique_ptr<CopyOutputRequest>
 LayerTreePixelTest::CreateCopyOutputRequest() {
-  return CopyOutputRequest::CreateBitmapRequest(
-      base::Bind(&LayerTreePixelTest::ReadbackResult, base::Unretained(this)));
+  return CopyOutputRequest::CreateBitmapRequest(base::BindOnce(
+      &LayerTreePixelTest::ReadbackResult, base::Unretained(this)));
 }
 
 void LayerTreePixelTest::ReadbackResult(
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc
index 9938446..5e24f70 100644
--- a/cc/test/pixel_test.cc
+++ b/cc/test/pixel_test.cc
@@ -68,8 +68,8 @@
 
   std::unique_ptr<CopyOutputRequest> request =
       CopyOutputRequest::CreateBitmapRequest(
-          base::Bind(&PixelTest::ReadbackResult, base::Unretained(this),
-                     run_loop.QuitClosure()));
+          base::BindOnce(&PixelTest::ReadbackResult, base::Unretained(this),
+                         run_loop.QuitClosure()));
   if (copy_rect)
     request->set_area(*copy_rect);
   target->copy_requests.push_back(std::move(request));
@@ -99,8 +99,8 @@
 
   std::unique_ptr<CopyOutputRequest> request =
       CopyOutputRequest::CreateBitmapRequest(
-          base::Bind(&PixelTest::ReadbackResult, base::Unretained(this),
-                     run_loop.QuitClosure()));
+          base::BindOnce(&PixelTest::ReadbackResult, base::Unretained(this),
+                         run_loop.QuitClosure()));
   target->copy_requests.push_back(std::move(request));
 
   if (software_renderer_) {
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc
index 3e8bca8..3321177 100644
--- a/cc/trees/draw_property_utils.cc
+++ b/cc/trees/draw_property_utils.cc
@@ -823,11 +823,7 @@
   for (auto* layer_impl : *layer_tree_impl) {
     DCHECK(layer_impl);
     DCHECK(layer_impl->layer_tree_impl());
-    // TODO(crbug.com/726423) : This is a workaround for crbug.com/725851 to
-    // avoid crashing when layer_impl is nullptr. This workaround should be
-    // removed as layer_impl should not be nullptr here.
-    if (!layer_impl || !layer_impl->HasValidPropertyTreeIndices())
-      continue;
+    layer_impl->EnsureValidPropertyTreeIndices();
 
     if (!IsRootLayer(layer_impl) &&
         LayerShouldBeSkippedForDrawPropertiesComputation(
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index e43d7a93..3ec934d 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -63,29 +63,6 @@
 }
 
 namespace cc {
-namespace {
-
-void EnsureValidIndicesOnLayer(Layer* layer, PropertyTrees* property_trees) {
-  CHECK_EQ(property_trees->sequence_number,
-           layer->property_tree_sequence_number());
-  CHECK(property_trees->transform_tree.Node(layer->transform_tree_index()));
-  CHECK(property_trees->clip_tree.Node(layer->clip_tree_index()));
-  CHECK(property_trees->effect_tree.Node(layer->effect_tree_index()));
-  CHECK(property_trees->scroll_tree.Node(layer->scroll_tree_index()));
-}
-
-void EnsureValidPropertyTreeState(LayerTreeHost* host) {
-  // Temporary check to debug crbug.com/726423. The property tree indices on
-  // the LayerTreeImpl should be valid after all state synchronization has
-  // finished.
-  for (auto* layer : *host)
-    EnsureValidIndicesOnLayer(layer, host->property_trees());
-
-  for (auto id : host->property_trees()->effect_tree.mask_layer_ids())
-    EnsureValidIndicesOnLayer(host->LayerById(id), host->property_trees());
-}
-
-}  // namespace
 
 LayerTreeHost::InitParams::InitParams() {}
 
@@ -326,8 +303,6 @@
 
   sync_tree->set_source_frame_number(SourceFrameNumber());
 
-  EnsureValidPropertyTreeState(this);
-
   if (needs_full_tree_sync_)
     TreeSynchronizer::SynchronizeTrees(root_layer(), sync_tree);
 
@@ -381,20 +356,6 @@
     sync_tree->lifecycle().AdvanceTo(LayerTreeLifecycle::kNotSyncing);
   }
 
-  // Temporary check to debug crbug.com/726423. The property tree indices on the
-  // LayerTree should be valid after the PropertyTree update above.
-  for (auto* layer_impl : *sync_tree) {
-    CHECK(layer_impl);
-    CHECK(sync_tree->property_trees()->transform_tree.Node(
-        layer_impl->transform_tree_index()));
-    CHECK(sync_tree->property_trees()->clip_tree.Node(
-        layer_impl->clip_tree_index()));
-    CHECK(sync_tree->property_trees()->effect_tree.Node(
-        layer_impl->effect_tree_index()));
-    CHECK(sync_tree->property_trees()->scroll_tree.Node(
-        layer_impl->scroll_tree_index()));
-  }
-
   // Transfer image decode requests to the impl thread.
   for (auto& request : queued_image_decodes_)
     host_impl->QueueImageDecode(std::move(request.first), request.second);
@@ -775,8 +736,6 @@
                                                    &update_layer_list);
   }
 
-  EnsureValidPropertyTreeState(this);
-
   bool content_has_slow_paths = false;
   bool content_has_non_aa_paint = false;
   bool did_paint_content = PaintContent(
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index 9b35214..82304423 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -359,16 +359,11 @@
   // surface's accumulated content rect.
   for (LayerImpl* layer : *layer_tree_impl) {
     DCHECK(layer);
-    // TODO(crbug.com/726423): LayerImpls should never have invalid PropertyTree
-    // indices.
-    if (!layer)
-      continue;
+    layer->EnsureValidPropertyTreeIndices();
+
     layer->set_contributes_to_drawn_render_surface(false);
     layer->set_raster_even_if_not_drawn(false);
 
-    if (!layer->HasValidPropertyTreeIndices())
-      continue;
-
     bool is_root = layer_tree_impl->IsRootLayer(layer);
 
     bool skip_draw_properties_computation =
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index 4c8c459..b267e06 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -4884,7 +4884,8 @@
   copy_grand_child_layer->test_properties()->hide_layer_and_subtree = true;
 
   copy_layer->test_properties()->copy_requests.push_back(
-      CopyOutputRequest::CreateRequest(base::Bind(&EmptyCopyOutputCallback)));
+      CopyOutputRequest::CreateRequest(
+          base::BindOnce(&EmptyCopyOutputCallback)));
 
   RenderSurfaceList render_surface_list;
   LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
@@ -4980,7 +4981,8 @@
   copy_child->SetDrawsContent(true);
 
   copy_layer->test_properties()->copy_requests.push_back(
-      CopyOutputRequest::CreateRequest(base::Bind(&EmptyCopyOutputCallback)));
+      CopyOutputRequest::CreateRequest(
+          base::BindOnce(&EmptyCopyOutputCallback)));
 
   copy_layer->test_properties()->AddChild(std::move(copy_child));
   copy_parent->test_properties()->AddChild(std::move(copy_layer));
@@ -5021,7 +5023,8 @@
   copy_layer->SetBounds(gfx::Size(100, 100));
   copy_layer->SetDrawsContent(true);
   copy_layer->test_properties()->copy_requests.push_back(
-      CopyOutputRequest::CreateRequest(base::Bind(&EmptyCopyOutputCallback)));
+      CopyOutputRequest::CreateRequest(
+          base::BindOnce(&EmptyCopyOutputCallback)));
 
   LayerImpl* copy_child = AddChild<LayerImpl>(copy_layer);
   copy_child->SetBounds(gfx::Size(100, 100));
@@ -5081,7 +5084,8 @@
   copy_surface->test_properties()->force_render_surface = true;
 
   copy_layer->test_properties()->copy_requests.push_back(
-      CopyOutputRequest::CreateRequest(base::Bind(&EmptyCopyOutputCallback)));
+      CopyOutputRequest::CreateRequest(
+          base::BindOnce(&EmptyCopyOutputCallback)));
 
   DCHECK(!copy_layer->test_properties()->copy_requests.empty());
   ExecuteCalculateDrawProperties(root);
@@ -5096,7 +5100,8 @@
   copy_layer->SetBounds(gfx::Size(50, 50));
   copy_layer->SetMasksToBounds(true);
   copy_layer->test_properties()->copy_requests.push_back(
-      CopyOutputRequest::CreateRequest(base::Bind(&EmptyCopyOutputCallback)));
+      CopyOutputRequest::CreateRequest(
+          base::BindOnce(&EmptyCopyOutputCallback)));
   root->layer_tree_impl()->property_trees()->needs_rebuild = true;
 
   DCHECK(!copy_layer->test_properties()->copy_requests.empty());
@@ -5111,7 +5116,8 @@
   // Case 3: When there is device scale factor.
   float device_scale_factor = 2.f;
   copy_layer->test_properties()->copy_requests.push_back(
-      CopyOutputRequest::CreateRequest(base::Bind(&EmptyCopyOutputCallback)));
+      CopyOutputRequest::CreateRequest(
+          base::BindOnce(&EmptyCopyOutputCallback)));
 
   DCHECK(!copy_layer->test_properties()->copy_requests.empty());
   ExecuteCalculateDrawProperties(root, device_scale_factor);
@@ -8681,10 +8687,10 @@
   grandchild->AddChild(greatgrandchild);
   host()->SetRootLayer(root);
 
-  child1->RequestCopyOfOutput(
-      CopyOutputRequest::CreateBitmapRequest(base::Bind(&CopyOutputCallback)));
-  greatgrandchild->RequestCopyOfOutput(
-      CopyOutputRequest::CreateBitmapRequest(base::Bind(&CopyOutputCallback)));
+  child1->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
+      base::BindOnce(&CopyOutputCallback)));
+  greatgrandchild->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
+      base::BindOnce(&CopyOutputCallback)));
   child2->SetOpacity(0.f);
   ExecuteCalculateDrawPropertiesAndSaveUpdateLayerList(root.get());
 
@@ -8770,8 +8776,8 @@
   // Now, even though child has zero opacity, we will configure |grandchild| and
   // |greatgrandchild| in several ways that should force the subtree to be
   // processed anyhow.
-  grandchild->RequestCopyOfOutput(
-      CopyOutputRequest::CreateBitmapRequest(base::Bind(&CopyOutputCallback)));
+  grandchild->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
+      base::BindOnce(&CopyOutputCallback)));
   ExecuteCalculateDrawPropertiesAndSaveUpdateLayerList(root.get());
   update_list = GetUpdateLayerList();
   EXPECT_TRUE(VerifyLayerInList(grandchild, update_list));
@@ -9093,8 +9099,8 @@
   parent->AddChild(child);
   host()->SetRootLayer(root);
 
-  child->RequestCopyOfOutput(
-      CopyOutputRequest::CreateRequest(base::Bind(&EmptyCopyOutputCallback)));
+  child->RequestCopyOfOutput(CopyOutputRequest::CreateRequest(
+      base::BindOnce(&EmptyCopyOutputCallback)));
 
   ExecuteCalculateDrawPropertiesAndSaveUpdateLayerList(root.get());
   EXPECT_TRUE(root->has_copy_requests_in_target_subtree());
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index dd5579d..8ddf7d7 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -3757,7 +3757,7 @@
 
   void AddCopyRequest() {
     test_properties()->copy_requests.push_back(
-        CopyOutputRequest::CreateRequest(base::Bind(&IgnoreResult)));
+        CopyOutputRequest::CreateRequest(base::BindOnce(&IgnoreResult)));
   }
 
  protected:
@@ -8826,7 +8826,7 @@
   LayerImpl* root = host_impl_->active_tree()->root_layer_for_testing();
   root->test_properties()->copy_requests.push_back(
       CopyOutputRequest::CreateRequest(
-          base::Bind(&ShutdownReleasesContext_Callback)));
+          base::BindOnce(&ShutdownReleasesContext_Callback)));
   host_impl_->active_tree()->BuildPropertyTreesForTesting();
 
   TestFrameData frame;
diff --git a/cc/trees/layer_tree_host_pixeltest_readback.cc b/cc/trees/layer_tree_host_pixeltest_readback.cc
index 4a605a0d..189da3b 100644
--- a/cc/trees/layer_tree_host_pixeltest_readback.cc
+++ b/cc/trees/layer_tree_host_pixeltest_readback.cc
@@ -64,20 +64,20 @@
     std::unique_ptr<CopyOutputRequest> request;
 
     if (readback_type_ == READBACK_BITMAP) {
-      request = CopyOutputRequest::CreateBitmapRequest(
-          base::Bind(&LayerTreeHostReadbackPixelTest::ReadbackResultAsBitmap,
-                     base::Unretained(this)));
+      request = CopyOutputRequest::CreateBitmapRequest(base::BindOnce(
+          &LayerTreeHostReadbackPixelTest::ReadbackResultAsBitmap,
+          base::Unretained(this)));
     } else {
       DCHECK_EQ(readback_type_, READBACK_DEFAULT);
       if (test_type_ == PIXEL_TEST_SOFTWARE) {
-        request = CopyOutputRequest::CreateRequest(
-            base::Bind(&LayerTreeHostReadbackPixelTest::ReadbackResultAsBitmap,
-                       base::Unretained(this)));
+        request = CopyOutputRequest::CreateRequest(base::BindOnce(
+            &LayerTreeHostReadbackPixelTest::ReadbackResultAsBitmap,
+            base::Unretained(this)));
       } else {
         DCHECK_EQ(test_type_, PIXEL_TEST_GL);
-        request = CopyOutputRequest::CreateRequest(
-            base::Bind(&LayerTreeHostReadbackPixelTest::ReadbackResultAsTexture,
-                       base::Unretained(this)));
+        request = CopyOutputRequest::CreateRequest(base::BindOnce(
+            &LayerTreeHostReadbackPixelTest::ReadbackResultAsTexture,
+            base::Unretained(this)));
       }
     }
 
@@ -290,7 +290,7 @@
   hidden_target->AddChild(blue);
 
   hidden_target->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
-      base::Bind(&IgnoreReadbackResult)));
+      base::BindOnce(&IgnoreReadbackResult)));
   RunReadbackTest(GetParam().pixel_test_type, GetParam().readback_type,
                   background, base::FilePath(FILE_PATH_LITERAL("black.png")));
 }
@@ -415,7 +415,7 @@
   scoped_refptr<SolidColorLayer> blue =
       CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
   blue->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
-      base::Bind(&IgnoreReadbackResult)));
+      base::BindOnce(&IgnoreReadbackResult)));
   background->AddChild(blue);
 
   RunReadbackTestWithReadbackTarget(
@@ -435,7 +435,7 @@
       CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
 
   background->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
-      base::Bind(&IgnoreReadbackResult)));
+      base::BindOnce(&IgnoreReadbackResult)));
 
   RunReadbackTestWithReadbackTarget(
       GetParam().pixel_test_type, GetParam().readback_type, background,
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 1d9f172c..ace4820e1 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -6852,7 +6852,7 @@
     switch (layer_tree_host()->SourceFrameNumber()) {
       case 1:
         child->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
-            base::Bind(CopyOutputCallback)));
+            base::BindOnce(CopyOutputCallback)));
         transform.Scale(2.0, 2.0);
         child->SetTransform(transform);
         break;
diff --git a/cc/trees/layer_tree_host_unittest_copyrequest.cc b/cc/trees/layer_tree_host_unittest_copyrequest.cc
index b190d8a..017cc509 100644
--- a/cc/trees/layer_tree_host_unittest_copyrequest.cc
+++ b/cc/trees/layer_tree_host_unittest_copyrequest.cc
@@ -63,9 +63,9 @@
     switch (frame) {
       case 1:
         child->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
-            base::Bind(&LayerTreeHostCopyRequestTestMultipleRequests::
-                           CopyOutputCallback,
-                       base::Unretained(this), 0)));
+            base::BindOnce(&LayerTreeHostCopyRequestTestMultipleRequests::
+                               CopyOutputCallback,
+                           base::Unretained(this), 0)));
         EXPECT_EQ(0u, callbacks_.size());
         break;
       case 2:
@@ -80,17 +80,17 @@
         EXPECT_EQ(gfx::Size(10, 10).ToString(), callbacks_[0].ToString());
 
         child->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
-            base::Bind(&LayerTreeHostCopyRequestTestMultipleRequests::
-                           CopyOutputCallback,
-                       base::Unretained(this), 1)));
+            base::BindOnce(&LayerTreeHostCopyRequestTestMultipleRequests::
+                               CopyOutputCallback,
+                           base::Unretained(this), 1)));
         root->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
-            base::Bind(&LayerTreeHostCopyRequestTestMultipleRequests::
-                           CopyOutputCallback,
-                       base::Unretained(this), 2)));
+            base::BindOnce(&LayerTreeHostCopyRequestTestMultipleRequests::
+                               CopyOutputCallback,
+                           base::Unretained(this), 2)));
         grand_child->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
-            base::Bind(&LayerTreeHostCopyRequestTestMultipleRequests::
-                           CopyOutputCallback,
-                       base::Unretained(this), 3)));
+            base::BindOnce(&LayerTreeHostCopyRequestTestMultipleRequests::
+                               CopyOutputCallback,
+                           base::Unretained(this), 3)));
         EXPECT_EQ(1u, callbacks_.size());
         break;
       case 4:
@@ -219,8 +219,8 @@
     switch (frame) {
       case 1:
         layer_->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
-            base::Bind(&LayerTreeHostCopyRequestCompletionCausesCommit::
-                           CopyOutputCallback)));
+            base::BindOnce(&LayerTreeHostCopyRequestCompletionCausesCommit::
+                               CopyOutputCallback)));
         break;
       case 2:
         // This commit is triggered by the copy request.
@@ -275,11 +275,11 @@
     switch (frame) {
       case 1:
         main_destroyed_->RequestCopyOfOutput(
-            CopyOutputRequest::CreateBitmapRequest(base::Bind(
+            CopyOutputRequest::CreateBitmapRequest(base::BindOnce(
                 &LayerTreeHostCopyRequestTestLayerDestroyed::CopyOutputCallback,
                 base::Unretained(this))));
         impl_destroyed_->RequestCopyOfOutput(
-            CopyOutputRequest::CreateBitmapRequest(base::Bind(
+            CopyOutputRequest::CreateBitmapRequest(base::BindOnce(
                 &LayerTreeHostCopyRequestTestLayerDestroyed::CopyOutputCallback,
                 base::Unretained(this))));
         EXPECT_EQ(0, callback_count_);
@@ -366,7 +366,7 @@
 
   void AddCopyRequest(Layer* layer) {
     layer->RequestCopyOfOutput(
-        CopyOutputRequest::CreateBitmapRequest(base::Bind(
+        CopyOutputRequest::CreateBitmapRequest(base::BindOnce(
             &LayerTreeHostCopyRequestTestInHiddenSubtree::CopyOutputCallback,
             base::Unretained(this))));
   }
@@ -480,9 +480,9 @@
     PostSetNeedsCommitToMainThread();
 
     copy_layer_->RequestCopyOfOutput(
-        CopyOutputRequest::CreateBitmapRequest(base::Bind(
+        CopyOutputRequest::CreateBitmapRequest(base::BindOnce(
             &LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest::
-                 CopyOutputCallback,
+                CopyOutputCallback,
             base::Unretained(this))));
   }
 
@@ -573,9 +573,10 @@
   void BeginTest() override {
     PostSetNeedsCommitToMainThread();
 
-    copy_layer_->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
-        base::Bind(&LayerTreeHostCopyRequestTestClippedOut::CopyOutputCallback,
-                   base::Unretained(this))));
+    copy_layer_->RequestCopyOfOutput(
+        CopyOutputRequest::CreateBitmapRequest(base::BindOnce(
+            &LayerTreeHostCopyRequestTestClippedOut::CopyOutputCallback,
+            base::Unretained(this))));
   }
 
   void CopyOutputCallback(std::unique_ptr<CopyOutputResult> result) {
@@ -628,7 +629,7 @@
     PostSetNeedsCommitToMainThread();
 
     std::unique_ptr<CopyOutputRequest> request =
-        CopyOutputRequest::CreateBitmapRequest(base::Bind(
+        CopyOutputRequest::CreateBitmapRequest(base::BindOnce(
             &LayerTreeHostCopyRequestTestScaledLayer::CopyOutputCallback,
             base::Unretained(this)));
     request->set_area(gfx::Rect(5, 5));
@@ -670,7 +671,7 @@
 
   void AddCopyRequest(Layer* layer) {
     layer->RequestCopyOfOutput(
-        CopyOutputRequest::CreateBitmapRequest(base::Bind(
+        CopyOutputRequest::CreateBitmapRequest(base::BindOnce(
             &LayerTreeHostTestAsyncTwoReadbacksWithoutDraw::CopyOutputCallback,
             base::Unretained(this))));
   }
@@ -777,9 +778,9 @@
 
   void InsertCopyRequest() {
     copy_layer_->RequestCopyOfOutput(CopyOutputRequest::CreateRequest(
-        base::Bind(&LayerTreeHostCopyRequestTestDeleteTexture::
-                       ReceiveCopyRequestOutputAndCommit,
-                   base::Unretained(this))));
+        base::BindOnce(&LayerTreeHostCopyRequestTestDeleteTexture::
+                           ReceiveCopyRequestOutputAndCommit,
+                       base::Unretained(this))));
   }
 
   void DestroyCopyResultAndCheckNumTextures() {
@@ -967,7 +968,7 @@
   void RequestCopy(Layer* layer) override {
     // Request a normal texture copy. This should create a new texture.
     copy_layer_->RequestCopyOfOutput(
-        CopyOutputRequest::CreateRequest(base::Bind(
+        CopyOutputRequest::CreateRequest(base::BindOnce(
             &LayerTreeHostCopyRequestTestCreatesTexture::CopyOutputCallback,
             base::Unretained(this))));
   }
@@ -1018,7 +1019,7 @@
     // Request a copy to a provided texture. This should not create a new
     // texture.
     std::unique_ptr<CopyOutputRequest> request =
-        CopyOutputRequest::CreateRequest(base::Bind(
+        CopyOutputRequest::CreateRequest(base::BindOnce(
             &LayerTreeHostCopyRequestTestProvideTexture::CopyOutputCallback,
             base::Unretained(this)));
 
@@ -1093,9 +1094,9 @@
         // drawing to take place.
         std::unique_ptr<CopyOutputRequest> request =
             CopyOutputRequest::CreateRequest(
-                base::Bind(&LayerTreeHostCopyRequestTestDestroyBeforeCopy::
-                               CopyOutputCallback,
-                           base::Unretained(this)));
+                base::BindOnce(&LayerTreeHostCopyRequestTestDestroyBeforeCopy::
+                                   CopyOutputCallback,
+                               base::Unretained(this)));
         copy_layer_->RequestCopyOfOutput(std::move(request));
 
         layer_tree_host()->SetViewportSize(gfx::Size());
@@ -1171,9 +1172,9 @@
         // drawing to take place.
         std::unique_ptr<CopyOutputRequest> request =
             CopyOutputRequest::CreateRequest(
-                base::Bind(&LayerTreeHostCopyRequestTestShutdownBeforeCopy::
-                               CopyOutputCallback,
-                           base::Unretained(this)));
+                base::BindOnce(&LayerTreeHostCopyRequestTestShutdownBeforeCopy::
+                                   CopyOutputCallback,
+                               base::Unretained(this)));
         copy_layer_->RequestCopyOfOutput(std::move(request));
 
         layer_tree_host()->SetViewportSize(gfx::Size());
@@ -1230,7 +1231,7 @@
     // Send a copy request after the first commit.
     if (layer_tree_host()->SourceFrameNumber() == 1) {
       child_->RequestCopyOfOutput(
-          CopyOutputRequest::CreateBitmapRequest(base::Bind(
+          CopyOutputRequest::CreateBitmapRequest(base::BindOnce(
               &LayerTreeHostCopyRequestTestMultipleDrawsHiddenCopyRequest::
                   CopyOutputCallback,
               base::Unretained(this))));
diff --git a/cc/trees/occlusion_tracker_unittest.cc b/cc/trees/occlusion_tracker_unittest.cc
index a0218f64..715029576 100644
--- a/cc/trees/occlusion_tracker_unittest.cc
+++ b/cc/trees/occlusion_tracker_unittest.cc
@@ -199,15 +199,15 @@
 
   void AddCopyRequest(Layer* layer) {
     layer->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
-        base::Bind(&OcclusionTrackerTest::CopyOutputCallback,
-                   base::Unretained(this))));
+        base::BindOnce(&OcclusionTrackerTest::CopyOutputCallback,
+                       base::Unretained(this))));
   }
 
   void AddCopyRequest(LayerImpl* layer) {
     layer->test_properties()->copy_requests.push_back(
         CopyOutputRequest::CreateBitmapRequest(
-            base::Bind(&OcclusionTrackerTest::CopyOutputCallback,
-                       base::Unretained(this))));
+            base::BindOnce(&OcclusionTrackerTest::CopyOutputCallback,
+                           base::Unretained(this))));
   }
 
   void CalcDrawEtc(TestContentLayerImpl* root) {
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 5bfc650..1ba3a19 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -529,11 +529,11 @@
     "//chrome/test/data/image_search/valid.png",
     "//chrome/test/data/navigation_interception/",
     "//chrome/test/data/notifications/",
-    "//chrome/test/data/payments/",
     "//chrome/test/data/popup_blocker/",
     "//chrome/test/data/push_messaging/",
     "//chrome/test/data/translate/",
     "//chrome/test/media_router/resources/",
+    "//components/test/data/payments/",
     "//content/test/data/android/geolocation.html",
     "//content/test/data/android/media_permissions.html",
     "//content/test/data/android/permission_navigation.html",
@@ -733,29 +733,29 @@
               "/libmonochrome$shlib_extension.whitelist"
       output = monochrome_resource_whitelist
     }
-    
+
     # Use custom resource ID list instead of android_webview's compiler
     # resource whitelist because //android_webview: generate_webui_resources
     # and //android_webview: generate_components_resources use hand-written
     # resource whitelists.
     action("system_webview_locale_resource_id_list") {
       script = "//tools/grit/pak_util.py"
-      
+
       _system_webview_en_US_locale_pak =
           "$root_out_dir/android_webview/locales/en-US.pak"
-      
+
       inputs = [
         _system_webview_en_US_locale_pak,
       ]
-      
+
       outputs = [
         system_webview_locale_resource_id_list,
       ]
-      
+
       deps = [
         "//android_webview:repack_locales",
       ]
-      
+
       args = [
         "list-id",
         "--output",
@@ -763,25 +763,25 @@
         rebase_path(_system_webview_en_US_locale_pak, root_build_dir),
       ]
     }
-    
+
     action("monochrome_locale_whitelist") {
       script = "//tools/resources/filter_resource_whitelist.py"
-      
+
       inputs = [
         monochrome_resource_whitelist,
         system_webview_locale_resource_id_list,
       ]
-      
+
       outputs = [
         monochrome_locale_whitelist,
       ]
-      
+
       deps = [
         ":monochrome_resource_whitelist",
         ":system_webview_locale_resource_id_list",
         "//android_webview:system_webview_pak_whitelist",
       ]
-      
+
       args = [
         "--input",
         rebase_path(monochrome_resource_whitelist, root_build_dir),
@@ -790,7 +790,7 @@
         "--output",
         rebase_path(monochrome_locale_whitelist, root_build_dir),
       ]
-    } 
+    }
   }
 
   chrome_paks("monochrome_paks") {
@@ -808,7 +808,7 @@
       deps += [ ":monochrome_locale_whitelist" ]
     }
   }
-  
+
   # This target is separate from monochrome_pak_assets because it does not
   # disable compression.
   android_assets("monochrome_locale_pak_assets") {
@@ -816,7 +816,7 @@
     foreach(_locale, locales - android_chrome_omitted_locales) {
       sources += [ "$target_gen_dir/monochrome_paks/locales/$_locale.pak" ]
     }
-  
+
     deps = [
       ":monochrome_paks",
     ]
diff --git a/chrome/android/java/res/layout/bottom_control_container.xml b/chrome/android/java/res/layout/bottom_control_container.xml
index 3b2d02b..34b469a 100644
--- a/chrome/android/java/res/layout/bottom_control_container.xml
+++ b/chrome/android/java/res/layout/bottom_control_container.xml
@@ -9,13 +9,6 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content" >
 
-    <FrameLayout
-        android:id="@+id/bottom_sheet_content"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:paddingBottom="@dimen/bottom_nav_height"
-        android:background="@color/default_primary_color" />
-
     <org.chromium.chrome.browser.toolbar.ToolbarControlContainer
         android:id="@+id/control_container"
         android:layout_width="match_parent"
@@ -69,6 +62,13 @@
         </view>
     </org.chromium.chrome.browser.toolbar.ToolbarControlContainer>
 
+    <FrameLayout
+        android:id="@+id/bottom_sheet_content"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:paddingBottom="@dimen/bottom_nav_height"
+        android:background="@color/default_primary_color" />
+
     <ViewStub
         android:id="@+id/bottom_omnibox_results_container_stub"
         android:layout_width="match_parent"
diff --git a/chrome/android/java/res/layout/signin_promo_view.xml b/chrome/android/java/res/layout/signin_promo_view.xml
new file mode 100644
index 0000000..bf18ff1
--- /dev/null
+++ b/chrome/android/java/res/layout/signin_promo_view.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2017 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. -->
+
+<org.chromium.chrome.browser.signin.SigninPromoView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/signin_promo_view_container"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="?android:attr/selectableItemBackground"
+    android:gravity="center_horizontal"
+    android:orientation="vertical"
+    android:padding="16dp">
+
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+
+        <ImageView
+            android:id="@+id/signin_promo_image"
+            android:layout_width="@dimen/signin_promo_account_image_size"
+            android:layout_height="@dimen/signin_promo_account_image_size"
+            android:layout_gravity="center"
+            android:layout_marginBottom="12dp"
+            android:layout_marginTop="12dp"
+            android:contentDescription="@null"
+            android:scaleType="fitCenter"/>
+
+        <ImageButton
+            android:id="@+id/signin_promo_close_button"
+            android:layout_width="24dp"
+            android:layout_height="24dp"
+            android:layout_gravity="top|end"
+            android:background="?attr/selectableItemBackground"
+            android:contentDescription="@string/close"
+            android:scaleType="fitCenter"
+            android:src="@drawable/btn_close"
+            android:visibility="gone"/>
+    </FrameLayout>
+
+    <TextView
+        android:id="@+id/signin_promo_description"
+        style="@style/RobotoMediumStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="12dp"
+        android:layout_marginEnd="24dp"
+        android:layout_marginStart="24dp"
+        android:gravity="center"
+        android:text="@string/signin_promo_settings"
+        android:textColor="#FF333333"
+        android:textSize="14sp"/>
+
+    <org.chromium.ui.widget.ButtonCompat
+        android:id="@+id/signin_promo_signin_button"
+        style="@style/SigninButtonCompat"
+        android:layout_width="match_parent"
+        android:layout_height="36dp"
+        android:layout_marginBottom="6dp"
+        android:layout_marginEnd="24dp"
+        android:layout_marginStart="24dp"
+        android:layout_marginTop="6dp"
+        android:text="@string/signin_promo_continue_as"/>
+
+    <Button
+        android:id="@+id/signin_promo_choose_account_button"
+        style="@style/SigninButtonBorderlessRegular"
+        android:layout_width="match_parent"
+        android:layout_height="36dp"
+        android:layout_marginEnd="24dp"
+        android:layout_marginStart="24dp"
+        android:text="@string/signin_promo_choose_account" />
+</org.chromium.chrome.browser.signin.SigninPromoView>
\ No newline at end of file
diff --git a/chrome/android/java/res/layout/suggestions_bottom_sheet_content.xml b/chrome/android/java/res/layout/suggestions_bottom_sheet_content.xml
index 73dc38d..78d8cda 100644
--- a/chrome/android/java/res/layout/suggestions_bottom_sheet_content.xml
+++ b/chrome/android/java/res/layout/suggestions_bottom_sheet_content.xml
@@ -6,11 +6,8 @@
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:paddingTop="@dimen/bottom_control_container_height" >
+    android:layout_height="match_parent">
 
-    <!-- TODO(twellington): move padding to the recycler view and set
-         android:cliptoPadding="false" to draw beneath the toolbar. -->
     <org.chromium.chrome.browser.suggestions.SuggestionsRecyclerView
         android:id="@+id/recycler_view"
         android:layout_width="match_parent"
diff --git a/chrome/android/java/res/values-v17/styles.xml b/chrome/android/java/res/values-v17/styles.xml
index 437ac49..d044789 100644
--- a/chrome/android/java/res/values-v17/styles.xml
+++ b/chrome/android/java/res/values-v17/styles.xml
@@ -593,6 +593,19 @@
         <item name="android:textSize">14sp</item>
         <item name="android:layout_gravity">start</item>
     </style>
+    <style name="SigninButtonCompat">
+        <item name="android:textColor">@android:color/white</item>
+        <item name="android:textSize">14sp</item>
+        <item name="buttonColor">@color/light_active_color</item>
+        <item name="buttonRaised">false</item>
+    </style>
+    <style name="SigninButtonBorderlessRegular">
+        <item name="android:background">?android:attr/selectableItemBackground</item>
+        <item name="android:fontFamily">sans-serif</item>
+        <item name="android:textAllCaps">false</item>
+        <item name="android:textColor">@color/light_active_color</item>
+        <item name="android:textSize">14sp</item>
+    </style>
 
     <!-- New tab page RecyclerView overscroll color -->
     <style name="NewTabPageRecyclerView">
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index 12e50b9..a6030ec 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -189,6 +189,10 @@
     <dimen name="signin_chooser_padding">16dp</dimen>
     <dimen name="signin_screen_top_padding">50dp</dimen>
 
+    <!-- Signin promo dimensions -->
+    <dimen name="signin_promo_account_image_size">48dp</dimen>
+    <dimen name="signin_promo_cold_state_image_size">24dp</dimen>
+
     <!-- Autofill card unmasking prompt dimensions -->
     <dimen name="autofill_card_unmask_tooltip_horizontal_padding">16dp</dimen>
     <dimen name="autofill_card_unmask_tooltip_vertical_padding">4dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/banners/InstallerDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/banners/InstallerDelegate.java
index 498cceb..29111c90 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/banners/InstallerDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/banners/InstallerDelegate.java
@@ -4,135 +4,139 @@
 
 package org.chromium.chrome.browser.banners;
 
+import android.app.Activity;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.SystemClock;
+import android.support.annotation.IntDef;
+import android.text.TextUtils;
 
+import org.chromium.base.ActivityState;
+import org.chromium.base.ApplicationStatus;
+import org.chromium.base.ContextUtils;
+import org.chromium.base.Log;
 import org.chromium.base.VisibleForTesting;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.ui.base.WindowAndroid;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.TimeUnit;
 
 /**
- * Monitors the PackageManager to see when an app has been installed.
+ * Monitors the app installation process and informs an observer of updates.
  */
-public class InstallerDelegate implements Runnable {
-    /**
-     * Callback for when the app install has completed.
-     */
+public class InstallerDelegate {
+    /** Observer methods called for the different stages of app installation. */
     public static interface Observer {
         /**
+         * Called when the installation intent completes to inform the observer if installation has
+         * begun. For instance, the user may have rejected the intent.
+         * @param delegate     The delegate object sending the message.
+         * @param isInstalling true if the app is currently installing.
+         */
+        public void onInstallIntentCompleted(InstallerDelegate delegate, boolean isInstalling);
+
+        /**
          * Called when the task has finished.
-         * @param delegate Instance of the class that finished.
+         * @param delegate The delegate object sending the message.
          * @param success  Whether or not the package was successfully installed.
          */
         public void onInstallFinished(InstallerDelegate delegate, boolean success);
+
+        /**
+         * Called when the current application state changes due to an installation.
+         * @param delegate The delegate object sending the message.
+         * @param newState The new state id.
+         */
+        public void onApplicationStateChanged(
+                InstallerDelegate delegate, @ActivityState int newState);
     }
 
-    private static final long DEFAULT_MS_BETWEEN_RUNS = 1000;
-    private static final long DEFAULT_MS_MAXIMUM_WAITING_TIME = 3 * 60 * 1000;
+    /**
+     * Object to wait for the PackageManager to finish installation an app. For convenience, this is
+     * bound to an instance of InstallerDelegate, and accesses its members and methods.
+     */
+    private class InstallMonitor implements Runnable {
+        /** Timestamp of when we started monitoring. */
+        private long mTimestampStarted;
+
+        public InstallMonitor() {}
+
+        /** Begin monitoring the PackageManager to see if it completes installing the package. */
+        public void start() {
+            mTimestampStarted = SystemClock.elapsedRealtime();
+            mIsRunning = true;
+            mHandler.postDelayed(this, mMsBetweenRuns);
+        }
+
+        /** Don't call this directly; instead, call {@link #start()}. */
+        @Override
+        public void run() {
+            boolean isPackageInstalled = isInstalled(mPackageName);
+            boolean waitedTooLong =
+                    (SystemClock.elapsedRealtime() - mTimestampStarted) > mMsMaximumWaitingTime;
+            if (isPackageInstalled || !mIsRunning || waitedTooLong) {
+                mIsRunning = false;
+                mObserver.onInstallFinished(InstallerDelegate.this, isPackageInstalled);
+            } else {
+                mHandler.postDelayed(this, mMsBetweenRuns);
+            }
+        }
+
+        /** Prevent rescheduling the Runnable. */
+        public void cancel() {
+            mIsRunning = false;
+        }
+    }
+
+    // Installation states.
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({INSTALL_STATE_NOT_INSTALLED, INSTALL_STATE_INSTALLING, INSTALL_STATE_INSTALLED})
+    public @interface InstallState {}
+    public static final int INSTALL_STATE_NOT_INSTALLED = 0;
+    public static final int INSTALL_STATE_INSTALLING = 1;
+    public static final int INSTALL_STATE_INSTALLED = 2;
+
+    private static final String TAG = "cr_InstallerDelegate";
+    private static final long DEFAULT_MS_BETWEEN_RUNS = TimeUnit.SECONDS.toMillis(1);
+    private static final long DEFAULT_MS_MAXIMUM_WAITING_TIME = TimeUnit.MINUTES.toMillis(3);
+
+    /** PackageManager to use in place of the real one. */
+    private static PackageManager sPackageManagerForTests;
+
+    /** Monitors an installation in progress. */
+    private InstallMonitor mInstallMonitor;
 
     /** Message loop to post the Runnable to. */
     private final Handler mHandler;
 
-    /** PackageManager that the Runnable is monitoring. */
-    private final PackageManager mPackageManager;
+    /** Monitors for application state changes. */
+    private final ApplicationStatus.ApplicationStateListener mListener;
 
-    /** Object that is notified when the PackageManager has finished. */
-    private final Observer mObserver;
+    /** The name of the package currently being installed. */
+    private String mPackageName;
 
-    /** Name of the package that we need to see the PackageManager has finished installing. */
-    private final String mPackageName;
-
-    /** Whether or not the Runnable is currently looping. */
-    private boolean mIsRunning;
-
-    /** Number of milliseconds to wait between calls to run(). */
+    /** Milliseconds to wait between calls to check on the PackageManager during installation. */
     private long mMsBetweenRuns;
 
-    /** Maximum number of milliseconds to wait before giving up. */
+    /** Maximum milliseconds to wait before giving up on monitoring during installation. */
     private long mMsMaximumWaitingTime;
 
-    /** Timestamp of when we first started. */
-    private long mTimestampStarted;
+    /** The observer to inform of updates during the installation process. */
+    private Observer mObserver;
 
-    /**
-     * Constructs the InstallerDelegate.
-     * @param looper         Thread to run the Runnable on.
-     * @param packageManager Provides access to the list of installed apps.
-     * @param observer       Alerted when the package has been completely installed.
-     * @param packageName    Name of the package for the app to monitor.
-     */
-    public InstallerDelegate(
-            Looper looper, PackageManager packageManager, Observer observer, String packageName) {
-        mHandler = new Handler(looper);
-        mPackageManager = packageManager;
-        mObserver = observer;
-        mPackageName = packageName;
-        mMsBetweenRuns = DEFAULT_MS_BETWEEN_RUNS;
-        mMsMaximumWaitingTime = DEFAULT_MS_MAXIMUM_WAITING_TIME;
-    }
+    /** Whether or we are currently monitoring an installation. */
+    private boolean mIsRunning;
 
-    /**
-     * Begin monitoring the PackageManager to see if it completes installing the package.
-     */
-    public void start() {
-        mTimestampStarted = SystemClock.elapsedRealtime();
-        mIsRunning = true;
-        mHandler.postDelayed(this, mMsBetweenRuns);
-    }
-
-    /**
-     * Don't call this directly; instead, call {@link #start()}.
-     */
-    @Override
-    public void run() {
-        boolean isInstalled = isInstalled();
-        boolean waitedTooLong =
-                (SystemClock.elapsedRealtime() - mTimestampStarted) > mMsMaximumWaitingTime;
-        if (isInstalled || !mIsRunning || waitedTooLong) {
-            mObserver.onInstallFinished(this, isInstalled);
-            mIsRunning = false;
-        } else {
-            mHandler.postDelayed(this, mMsBetweenRuns);
-        }
-    }
-
-    /**
-     * Checks if the app has been installed on the system.
-     * @param packageManager PackageManager to use.
-     * @param packageName Name of the package to check.
-     * @return True if the PackageManager reports that the app is installed, false otherwise.
-     */
-    public static boolean isInstalled(PackageManager packageManager, String packageName) {
-        try {
-            packageManager.getPackageInfo(packageName, 0);
-        } catch (PackageManager.NameNotFoundException e) {
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Checks if the app has been installed on the system.
-     * @return True if the PackageManager reports that the app is installed, false otherwise.
-     */
-    private boolean isInstalled() {
-        return isInstalled(mPackageManager, mPackageName);
-    }
-
-    /**
-     * Prevent rescheduling the Runnable.
-     */
-    public void cancel() {
-        mIsRunning = false;
-    }
-
-    /**
-     * Checks to see if the Runnable will continue scheduling itself.
-     * @return True if the runnable is still being scheduled.
-     */
+    /** Overrides the PackageManager for testing. */
     @VisibleForTesting
-    boolean isRunning() {
-        return mIsRunning;
+    static void setPackageManagerForTesting(PackageManager manager) {
+        sPackageManagerForTests = manager;
     }
 
     /**
@@ -145,4 +149,170 @@
         mMsBetweenRuns = msBetween;
         mMsMaximumWaitingTime = msMax;
     }
+
+    /**
+     * Checks if the app has been installed on the system.
+     * @return true if the PackageManager reports that the app is installed, false otherwise.
+     * @param packageManager PackageManager to use.
+     * @param packageName    Name of the package to check.
+     */
+    public static boolean isInstalled(PackageManager packageManager, String packageName) {
+        try {
+            packageManager.getPackageInfo(packageName, 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Construct an InstallerDelegate to monitor an installation.
+     * @param looper   Thread to run the monitor on.
+     * @param observer Object to inform of changes in the installation state.
+     */
+    public InstallerDelegate(Looper looper, Observer observer) {
+        mHandler = new Handler(looper);
+        mObserver = observer;
+        mListener = createApplicationStateListener();
+        ApplicationStatus.registerApplicationStateListener(mListener);
+
+        mMsBetweenRuns = DEFAULT_MS_BETWEEN_RUNS;
+        mMsMaximumWaitingTime = DEFAULT_MS_MAXIMUM_WAITING_TIME;
+    }
+
+    /**
+     * Checks if the app has been installed on the system.
+     * @return true if the PackageManager reports that the app is installed, false otherwise.
+     * @param packageName Name of the package to check.
+     */
+    public boolean isInstalled(String packageName) {
+        return isInstalled(getPackageManager(ContextUtils.getApplicationContext()), packageName);
+    }
+
+    /**
+     * Stops all current monitoring.
+     */
+    public void destroy() {
+        if (mInstallMonitor != null) {
+            mInstallMonitor.cancel();
+            mInstallMonitor = null;
+        }
+        ApplicationStatus.unregisterApplicationStateListener(mListener);
+    }
+
+    /**
+     * Returns the current installation state of the provided package name
+     * @return the installation state - not installed, installing, or installed.
+     * @param packageName Name of the package to check.
+     */
+    public @InstallState int determineInstallState(String packageName) {
+        if (mIsRunning || TextUtils.isEmpty(packageName)) {
+            // The package name being empty means we are installing a WebAPK, where we don't know
+            // what the package name is until installation is complete.
+            return INSTALL_STATE_INSTALLING;
+        }
+
+        if (isInstalled(packageName)) {
+            return INSTALL_STATE_INSTALLED;
+        }
+
+        return INSTALL_STATE_NOT_INSTALLED;
+    }
+
+    /**
+     * Attempts to open the specified package name in the given content.
+     * @return true if successfully opened, otherwise false (e.g. not installed/opening failed).
+     * @param packageName Name of the package to open.
+     */
+    public boolean openApp(String packageName) {
+        Context context = ContextUtils.getApplicationContext();
+        PackageManager packageManager = getPackageManager(context);
+        if (!isInstalled(packageManager, packageName)) return false;
+
+        Intent launchIntent = packageManager.getLaunchIntentForPackage(packageName);
+        if (launchIntent != null) {
+            try {
+                context.startActivity(launchIntent);
+            } catch (ActivityNotFoundException e) {
+                Log.e(TAG, "Failed to open app : %s!", packageName, e);
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Attempts to install or open a native app specified by the given data.
+     * @return true if the app was opened or installation was started successfully. false otherwise.
+     * @param tab      The current tab.
+     * @param appData  The native app data to try and open or install.
+     * @param referrer The referrer attached to the URL specifying the native app, if any.
+     */
+    public boolean installOrOpenNativeApp(Tab tab, AppData appData, String referrer) {
+        if (openApp(appData.packageName())) {
+            return true;
+        } else {
+            // If the installation was started, return false to prevent the infobar disappearing.
+            // The supplied referrer is the URL of the page requesting the native app banner. It may
+            // be empty depending on that page's referrer policy. If it is non-empty, attach it to
+            // the installation intent as Intent.EXTRA_REFERRER.
+            Intent installIntent = appData.installIntent();
+            if (!TextUtils.isEmpty(referrer)) {
+                installIntent.putExtra(Intent.EXTRA_REFERRER, referrer);
+            }
+            return !tab.getWindowAndroid().showIntent(
+                    installIntent, createIntentCallback(appData), null);
+        }
+    }
+
+    /**
+     * Start monitoring an installation. Should be called once per the lifetime of this object.
+     * @param packageName The name of the package to monitor.
+     * */
+    public void startMonitoring(String packageName) {
+        mPackageName = packageName;
+        mInstallMonitor = new InstallMonitor();
+        mInstallMonitor.start();
+    }
+
+    /** Checks to see if we are currently monitoring an installation. */
+    @VisibleForTesting
+    boolean isRunning() {
+        return mIsRunning;
+    }
+
+    /** Simulates a cancellation for testing purposes. */
+    @VisibleForTesting
+    void cancel() {
+        mInstallMonitor.cancel();
+    }
+
+    private WindowAndroid.IntentCallback createIntentCallback(final AppData appData) {
+        return new WindowAndroid.IntentCallback() {
+            @Override
+            public void onIntentCompleted(WindowAndroid window, int resultCode, Intent data) {
+                boolean isInstalling = resultCode == Activity.RESULT_OK;
+                if (isInstalling) {
+                    startMonitoring(appData.packageName());
+                }
+
+                mObserver.onInstallIntentCompleted(InstallerDelegate.this, isInstalling);
+            }
+        };
+    }
+
+    private ApplicationStatus.ApplicationStateListener createApplicationStateListener() {
+        return new ApplicationStatus.ApplicationStateListener() {
+            @Override
+            public void onApplicationStateChange(int newState) {
+                if (!ApplicationStatus.hasVisibleActivities()) return;
+                mObserver.onApplicationStateChanged(InstallerDelegate.this, newState);
+            }
+        };
+    }
+
+    private PackageManager getPackageManager(Context context) {
+        if (sPackageManagerForTests != null) return sPackageManagerForTests;
+        return context.getPackageManager();
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSheetContent.java
index 2b0985a..5113024 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSheetContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkSheetContent.java
@@ -13,14 +13,13 @@
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet.BottomSheetContent;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetContentController;
 import org.chromium.chrome.browser.widget.selection.SelectableListToolbar;
-import org.chromium.components.bookmarks.BookmarkId;
 
 /**
  * A {@link BottomSheetContent} holding a {@link BookmarkManager} for display in the BottomSheet.
  */
 public class BookmarkSheetContent implements BottomSheetContent {
     private final View mContentView;
-    private final SelectableListToolbar<BookmarkId> mToolbarView;
+    private final SelectableListToolbar mToolbarView;
     private BookmarkManager mBookmarkManager;
 
     /**
@@ -84,9 +83,4 @@
     public int getType() {
         return BottomSheetContentController.TYPE_BOOKMARKS;
     }
-
-    @Override
-    public boolean applyDefaultTopPadding() {
-        return true;
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
index 1d275ba..76313ea 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
@@ -62,6 +62,8 @@
     static final String NOT_AN_ENTITY_SUPPRESSION_ENABLED = "enable_not_an_entity_suppression";
     // The threshold for tap suppression based on duration.
     private static final String TAP_DURATION_THRESHOLD_MS = "tap_duration_threshold_ms";
+    // The threshold for tap suppression based on a recent scroll.
+    private static final String RECENT_SCROLL_DURATION_MS = "recent_scroll_duration_ms";
 
     private static final String MINIMUM_SELECTION_LENGTH = "minimum_selection_length";
 
@@ -110,6 +112,7 @@
     private static Boolean sIsRankerLoggingDisabled;
     private static Integer sWaitAfterTapDelayMs;
     private static Integer sTapDurationThresholdMs;
+    private static Integer sRecentScrollDurationMs;
 
     /**
      * Don't instantiate.
@@ -399,6 +402,18 @@
         return sTapDurationThresholdMs.intValue();
     }
 
+    /**
+     * Gets the duration to use for suppressing Taps after a recent scroll, or {@code 0} if no
+     * suppression is configured.
+     * @return The period of time after a scroll when tap triggering is suppressed.
+     */
+    static int getRecentScrollDurationMs() {
+        if (sRecentScrollDurationMs == null) {
+            sRecentScrollDurationMs = getIntParamValueOrDefault(RECENT_SCROLL_DURATION_MS, 0);
+        }
+        return sRecentScrollDurationMs.intValue();
+    }
+
     // ---------------------------
     // Feature-controlled Switches
     // ---------------------------
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/RecentScrollTapSuppression.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/RecentScrollTapSuppression.java
index d7a6ed7..8076bfe 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/RecentScrollTapSuppression.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/RecentScrollTapSuppression.java
@@ -13,6 +13,7 @@
 
     private final int mDurationSinceRecentScrollMs;
     private final boolean mIsConditionSatisfied;
+    private final int mRecentScrollDurationThreshold;
 
     /**
      * Constructs a Tap suppression heuristic that handles a Tap after a recent scroll.
@@ -29,14 +30,17 @@
         } else {
             mDurationSinceRecentScrollMs = 0;
         }
-
+        int experimentThreshold = ContextualSearchFieldTrial.getRecentScrollDurationMs();
+        mRecentScrollDurationThreshold = experimentThreshold > 0
+                ? experimentThreshold
+                : DEFAULT_RECENT_SCROLL_SUPPRESSION_DURATION_MS;
         mIsConditionSatisfied = mDurationSinceRecentScrollMs > 0
-                && mDurationSinceRecentScrollMs < DEFAULT_RECENT_SCROLL_SUPPRESSION_DURATION_MS;
+                && mDurationSinceRecentScrollMs < mRecentScrollDurationThreshold;
     }
 
     @Override
     protected boolean isConditionSatisfiedAndEnabled() {
-        return mIsConditionSatisfied;
+        return mIsConditionSatisfied && mRecentScrollDurationThreshold > 0;
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSheetContent.java
index 69aef96..6408a27fa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSheetContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSheetContent.java
@@ -12,7 +12,6 @@
 import org.chromium.base.ApplicationStatus.ActivityStateListener;
 import org.chromium.base.ThreadUtils;
 import org.chromium.chrome.browser.ChromeActivity;
-import org.chromium.chrome.browser.download.ui.DownloadHistoryItemWrapper;
 import org.chromium.chrome.browser.download.ui.DownloadManagerUi;
 import org.chromium.chrome.browser.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.toolbar.BottomToolbarPhone;
@@ -26,7 +25,7 @@
  */
 public class DownloadSheetContent implements BottomSheetContent {
     private final View mContentView;
-    private final SelectableListToolbar<DownloadHistoryItemWrapper> mToolbarView;
+    private final SelectableListToolbar mToolbarView;
     private final ActivityStateListener mActivityStateListener;
     private DownloadManagerUi mDownloadManager;
 
@@ -112,9 +111,4 @@
     public int getType() {
         return BottomSheetContentController.TYPE_DOWNLOADS;
     }
-
-    @Override
-    public boolean applyDefaultTopPadding() {
-        return true;
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/history/HistorySheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/history/HistorySheetContent.java
index fec7ffd3..e96940c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/history/HistorySheetContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/history/HistorySheetContent.java
@@ -19,7 +19,7 @@
  */
 public class HistorySheetContent implements BottomSheetContent {
     private final View mContentView;
-    private final SelectableListToolbar<HistoryItem> mToolbarView;
+    private final SelectableListToolbar mToolbarView;
     private HistoryManager mHistoryManager;
 
     /**
@@ -83,9 +83,4 @@
     public int getType() {
         return BottomSheetContentController.TYPE_HISTORY;
     }
-
-    @Override
-    public boolean applyDefaultTopPadding() {
-        return true;
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarAndroid.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarAndroid.java
index ea1ee30..74be983 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarAndroid.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarAndroid.java
@@ -17,17 +17,13 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.banners.AppBannerManager;
 import org.chromium.chrome.browser.banners.AppData;
+import org.chromium.chrome.browser.banners.InstallerDelegate;
 import org.chromium.chrome.browser.widget.DualControlLayout;
 
 /**
  * Infobar informing the user about an app related to this page.
  */
 public class AppBannerInfoBarAndroid extends ConfirmInfoBar implements View.OnClickListener {
-    // Installation states.
-    public static final int INSTALL_STATE_NOT_INSTALLED = 0;
-    public static final int INSTALL_STATE_INSTALLING = 1;
-    public static final int INSTALL_STATE_INSTALLED = 2;
-
     // Views composing the infobar.
     private Button mButton;
     private InfoBarControlLayout mMessageLayout;
@@ -38,7 +34,7 @@
 
     // Data for native app installs.
     private final AppData mAppData;
-    private int mInstallState;
+    private @InstallerDelegate.InstallState int mInstallState;
 
     // Data for web app installs.
     private final String mAppUrl;
@@ -52,7 +48,7 @@
         mAppTitle = appTitle;
         mAppData = data;
         mAppUrl = null;
-        mInstallState = INSTALL_STATE_NOT_INSTALLED;
+        mInstallState = InstallerDelegate.INSTALL_STATE_NOT_INSTALLED;
     }
 
     // Banner for web apps.
@@ -63,7 +59,7 @@
         mAppData = null;
         mAppUrl = url;
         mIsWebApk = isWebApk;
-        mInstallState = INSTALL_STATE_NOT_INSTALLED;
+        mInstallState = InstallerDelegate.INSTALL_STATE_NOT_INSTALLED;
     }
 
     @Override
@@ -125,7 +121,7 @@
 
     @Override
     public void onButtonClicked(boolean isPrimaryButton) {
-        if (isPrimaryButton && mInstallState == INSTALL_STATE_INSTALLING) {
+        if (isPrimaryButton && mInstallState == InstallerDelegate.INSTALL_STATE_INSTALLING) {
             setControlsEnabled(true);
             updateButton();
             return;
@@ -147,7 +143,7 @@
         String accessibilityText = null;
         boolean enabled = true;
         Context context = getContext();
-        if (mInstallState == INSTALL_STATE_NOT_INSTALLED) {
+        if (mInstallState == InstallerDelegate.INSTALL_STATE_NOT_INSTALLED) {
             if (mIsWebApk) {
                 // If the installation of the WebAPK fails, the banner will disappear and
                 // a failure toast will be shown.
@@ -156,7 +152,7 @@
             text = mAppData.installButtonText();
             accessibilityText = context.getString(
                     R.string.app_banner_view_native_app_install_accessibility, text);
-        } else if (mInstallState == INSTALL_STATE_INSTALLING) {
+        } else if (mInstallState == InstallerDelegate.INSTALL_STATE_INSTALLING) {
             text = mIsWebApk ? context.getString(R.string.app_banner_installing_webapk)
                     : context.getString(R.string.app_banner_installing);
             mButton.announceForAccessibility(text);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarDelegateAndroid.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarDelegateAndroid.java
index 7020011..7ad31c0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarDelegateAndroid.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarDelegateAndroid.java
@@ -4,159 +4,64 @@
 
 package org.chromium.chrome.browser.infobar;
 
-import android.app.Activity;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
 import android.os.Looper;
 
-import org.chromium.base.ApplicationStatus;
-import org.chromium.base.ContextUtils;
-import org.chromium.base.Log;
-import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.chrome.browser.banners.AppData;
 import org.chromium.chrome.browser.banners.InstallerDelegate;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.ui.base.WindowAndroid;
 
 /**
- * Handles the promotion and installation of an app specified by the current web page.  This Java
- * object is created by and owned by the native AppBannerInfoBarDelegateAndroid.
+ * Handles the promotion and installation of an app specified by the current web page. This object
+ * is created by and owned by the native AppBannerInfoBarDelegateAndroid.
  */
 @JNINamespace("banners")
-public class AppBannerInfoBarDelegateAndroid {
-    private static final String TAG = "cr_AppBannerInfoBar";
-
-    /** PackageManager to use in place of the real one. */
-    private static PackageManager sPackageManagerForTests;
-
+public class AppBannerInfoBarDelegateAndroid implements InstallerDelegate.Observer {
     /** Weak pointer to the native AppBannerInfoBarDelegateAndroid. */
     private long mNativePointer;
 
-    /** Monitors an installation in progress. */
-    private InstallerDelegate mInstallTask;
-
-    /** Monitors for application state changes. */
-    private final ApplicationStatus.ApplicationStateListener mListener;
-
-    /**
-     * Indicates whether a request to install a WebAPK has started. This flag is set while the
-     * WebAPK is being installed.
-     */
-    private boolean mIsInstallingWebApk;
-
-    /** The package name of the WebAPK. */
-    private String mWebApkPackage;
-
-    /** Overrides the PackageManager for testing. */
-    @VisibleForTesting
-    public static void setPackageManagerForTesting(PackageManager manager) {
-        sPackageManagerForTests = manager;
-    }
+    /** Delegate which does the actual monitoring of an in-progress installation. */
+    private InstallerDelegate mInstallerDelegate;
 
     private AppBannerInfoBarDelegateAndroid(long nativePtr) {
         mNativePointer = nativePtr;
-        mListener = createApplicationStateListener();
-        ApplicationStatus.registerApplicationStateListener(mListener);
+        mInstallerDelegate = new InstallerDelegate(Looper.getMainLooper(), this);
     }
 
-    private ApplicationStatus.ApplicationStateListener createApplicationStateListener() {
-        return new ApplicationStatus.ApplicationStateListener() {
-            @Override
-            public void onApplicationStateChange(int newState) {
-                if (!ApplicationStatus.hasVisibleActivities()) return;
-                nativeUpdateInstallState(mNativePointer);
-            }
-        };
+    @Override
+    public void onInstallIntentCompleted(InstallerDelegate delegate, boolean isInstalling) {
+        if (mInstallerDelegate != delegate) return;
+        nativeOnInstallIntentReturned(mNativePointer, isInstalling);
+    }
+
+    @Override
+    public void onInstallFinished(InstallerDelegate delegate, boolean success) {
+        if (mInstallerDelegate != delegate) return;
+        nativeOnInstallFinished(mNativePointer, success);
+    }
+
+    @Override
+    public void onApplicationStateChanged(InstallerDelegate delegate, int newState) {
+        if (mInstallerDelegate != delegate) return;
+        nativeUpdateInstallState(mNativePointer);
     }
 
     @CalledByNative
     private void destroy() {
-        if (mInstallTask != null) {
-            mInstallTask.cancel();
-            mInstallTask = null;
-        }
-        ApplicationStatus.unregisterApplicationStateListener(mListener);
+        mInstallerDelegate.destroy();
+        mInstallerDelegate = null;
         mNativePointer = 0;
     }
 
     @CalledByNative
     private boolean installOrOpenNativeApp(Tab tab, AppData appData, String referrer) {
-        Context context = ContextUtils.getApplicationContext();
-        String packageName = appData.packageName();
-        PackageManager packageManager = getPackageManager(context);
-
-        if (InstallerDelegate.isInstalled(packageManager, packageName)) {
-            // Open the app.
-            openApp(context, packageName);
-            return true;
-        } else {
-            // Try installing the app.  If the installation was kicked off, return false to prevent
-            // the infobar from disappearing.
-            // The supplied referrer is the URL of the page requesting the native app banner. It
-            // may be empty depending on that page's referrer policy. If it is non-empty, attach it
-            // to the installation intent as Intent.EXTRA_REFERRER.
-            Intent installIntent = appData.installIntent();
-            if (referrer.length() > 0) installIntent.putExtra(Intent.EXTRA_REFERRER, referrer);
-            return !tab.getWindowAndroid().showIntent(
-                    installIntent, createIntentCallback(appData), null);
-        }
-    }
-
-    void openApp(Context context, String packageName) {
-        Intent launchIntent = getPackageManager(context).getLaunchIntentForPackage(packageName);
-        if (launchIntent != null) {
-            try {
-                context.startActivity(launchIntent);
-            } catch (ActivityNotFoundException e) {
-                Log.e(TAG, "Failed to open app : %s!", packageName, e);
-                return;
-            }
-        }
-    }
-
-    private WindowAndroid.IntentCallback createIntentCallback(final AppData appData) {
-        return new WindowAndroid.IntentCallback() {
-            @Override
-            public void onIntentCompleted(WindowAndroid window, int resultCode, Intent data) {
-                boolean isInstalling = resultCode == Activity.RESULT_OK;
-                if (isInstalling) {
-                    // Start monitoring the install.
-                    PackageManager pm =
-                            getPackageManager(ContextUtils.getApplicationContext());
-                    mInstallTask = new InstallerDelegate(
-                            Looper.getMainLooper(), pm, createInstallerDelegateObserver(),
-                            appData.packageName());
-                    mInstallTask.start();
-                }
-
-                nativeOnInstallIntentReturned(mNativePointer, isInstalling);
-            }
-        };
-    }
-
-    private InstallerDelegate.Observer createInstallerDelegateObserver() {
-        return new InstallerDelegate.Observer() {
-            @Override
-            public void onInstallFinished(InstallerDelegate task, boolean success) {
-                if (mInstallTask != task) return;
-                mInstallTask = null;
-                nativeOnInstallFinished(mNativePointer, success);
-            }
-        };
+        return mInstallerDelegate.installOrOpenNativeApp(tab, appData, referrer);
     }
 
     @CalledByNative
-    private void openWebApk() {
-        Context context = ContextUtils.getApplicationContext();
-        PackageManager packageManager = getPackageManager(context);
-
-        if (InstallerDelegate.isInstalled(packageManager, mWebApkPackage)) {
-            openApp(context, mWebApkPackage);
-        }
+    private void openApp(String packageName) {
+        mInstallerDelegate.openApp(packageName);
     }
 
     @CalledByNative
@@ -165,33 +70,8 @@
     }
 
     @CalledByNative
-    private int determineInstallState(AppData data) {
-        if (mInstallTask != null || mIsInstallingWebApk) {
-            return AppBannerInfoBarAndroid.INSTALL_STATE_INSTALLING;
-        }
-
-        PackageManager pm = getPackageManager(ContextUtils.getApplicationContext());
-        String packageName = (data != null) ? data.packageName() : mWebApkPackage;
-        boolean isInstalled = InstallerDelegate.isInstalled(pm, packageName);
-        return isInstalled ? AppBannerInfoBarAndroid.INSTALL_STATE_INSTALLED
-                        : AppBannerInfoBarAndroid.INSTALL_STATE_NOT_INSTALLED;
-    }
-
-    @CalledByNative
-    /** Set the flag of whether the installation process has been started for the WebAPK. */
-    private void setWebApkInstallingState(boolean isInstalling) {
-        mIsInstallingWebApk = isInstalling;
-    }
-
-    @CalledByNative
-    /** Sets the WebAPK package name. */
-    private void setWebApkPackageName(String webApkPackage) {
-        mWebApkPackage = webApkPackage;
-    }
-
-    private PackageManager getPackageManager(Context context) {
-        if (sPackageManagerForTests != null) return sPackageManagerForTests;
-        return context.getPackageManager();
+    private int determineInstallState(String packageName) {
+        return mInstallerDelegate.determineInstallState(packageName);
     }
 
     @CalledByNative
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoBottomSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoBottomSheetContent.java
index 999eb3c..1550780 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoBottomSheetContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoBottomSheetContent.java
@@ -92,9 +92,4 @@
     public int getType() {
         return BottomSheetContentController.TYPE_INCOGNITO_HOME;
     }
-
-    @Override
-    public boolean applyDefaultTopPadding() {
-        return true;
-    }
 }
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 bcdd131e..ef702e6 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
@@ -384,16 +384,16 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent event) {
-        if (!mFocused) {
-            mGestureDetector.onTouchEvent(event);
-            return true;
-        }
-
         if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
             getLocationInWindow(mCachedLocation);
             mDownEventViewTop = mCachedLocation[1];
         }
 
+        if (!mFocused) {
+            mGestureDetector.onTouchEvent(event);
+            return true;
+        }
+
         Tab currentTab = mUrlBarDelegate.getCurrentTab();
         if (event.getAction() == MotionEvent.ACTION_DOWN && currentTab != null) {
             // Make sure to hide the current ContentView ActionBar.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java
index 3735ad3..c5e6adb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java
@@ -207,6 +207,10 @@
         updatePreferences();
     }
 
+    ManagedPreferenceDelegate getManagedPreferenceDelegateForTest() {
+        return mManagedPreferenceDelegate;
+    }
+
     private ManagedPreferenceDelegate createManagedPreferenceDelegate() {
         return new ManagedPreferenceDelegate() {
             @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoView.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoView.java
new file mode 100644
index 0000000..8b2b2db
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoView.java
@@ -0,0 +1,67 @@
+// Copyright 2017 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.signin;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+
+import org.chromium.chrome.R;
+import org.chromium.ui.widget.ButtonCompat;
+
+/**
+ * Container view for signin promos.
+ */
+public class SigninPromoView extends LinearLayout {
+    private ImageView mImage;
+    private ImageButton mDismissButton;
+    private ButtonCompat mSigninButton;
+    private Button mChooseAccountButton;
+
+    public SigninPromoView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        mImage = (ImageView) findViewById(R.id.signin_promo_image);
+        mDismissButton = (ImageButton) findViewById(R.id.signin_promo_close_button);
+        mSigninButton = (ButtonCompat) findViewById(R.id.signin_promo_signin_button);
+        mChooseAccountButton = (Button) findViewById(R.id.signin_promo_choose_account_button);
+    }
+
+    /**
+     * Returns a reference to the image of the promo.
+     */
+    public ImageView getImage() {
+        return mImage;
+    }
+
+    /**
+     * Returns a reference to the dismiss button.
+     */
+    public ImageButton getDismissButton() {
+        return mDismissButton;
+    }
+
+    /**
+     * Returns a reference to the signin button.
+     */
+    public ButtonCompat getSigninButton() {
+        return mSigninButton;
+    }
+
+    /**
+     * Returns a reference to the choose account button.
+     */
+    public Button getChooseAccountButton() {
+        return mChooseAccountButton;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
index b6444d8..d47a6b8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
@@ -30,7 +30,6 @@
 import org.chromium.chrome.browser.widget.FadingShadowView;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetContentController;
-import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetNewTabController;
 import org.chromium.chrome.browser.widget.displaystyle.UiConfig;
 import org.chromium.ui.widget.Toast;
 
@@ -40,8 +39,7 @@
 /**
  * Provides content to be displayed inside of the Home tab of bottom sheet.
  */
-public class SuggestionsBottomSheetContent
-        implements BottomSheet.BottomSheetContent, BottomSheetNewTabController.Observer {
+public class SuggestionsBottomSheetContent implements BottomSheet.BottomSheetContent {
     private final View mView;
     private final FadingShadowView mShadowView;
     private final SuggestionsRecyclerView mRecyclerView;
@@ -163,8 +161,6 @@
                 return false;
             }
         });
-
-        sheet.getNewTabController().addObserver(this);
     }
 
     @Override
@@ -204,17 +200,6 @@
         return BottomSheetContentController.TYPE_SUGGESTIONS;
     }
 
-    @Override
-    public boolean applyDefaultTopPadding() {
-        return false;
-    }
-
-    @Override
-    public void onNewTabShown() {}
-
-    @Override
-    public void onNewTabHidden() {}
-
     private void updateContextualSuggestions(String url) {
         mSuggestionsUiDelegate.getSuggestionsSource().fetchContextualSuggestions(
                 url, new Callback<List<SnippetArticle>>() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
index 7a38263..bc75575 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -295,11 +295,6 @@
          */
         @ContentType
         int getType();
-
-        /**
-         * @return Whether the default top padding should be applied to the content view.
-         */
-        boolean applyDefaultTopPadding();
     }
 
     /**
@@ -907,13 +902,6 @@
     }
 
     /**
-     * @return The {@link BottomSheetNewTabController} used to present the new tab UI.
-     */
-    public BottomSheetNewTabController getNewTabController() {
-        return mNtpController;
-    }
-
-    /**
      * Show content in the bottom sheet's content area.
      * @param content The {@link BottomSheetContent} to show.
      */
@@ -948,17 +936,11 @@
             }
         });
 
-        View contentView = content.getContentView();
-        if (content.applyDefaultTopPadding()) {
-            contentView.setPadding(contentView.getPaddingLeft(), mToolbarHolder.getHeight(),
-                    contentView.getPaddingRight(), contentView.getPaddingBottom());
-        }
-
         // For the toolbar transition, make sure we don't detach the default toolbar view.
         animators.add(getViewTransitionAnimator(
                 newToolbar, oldToolbar, mToolbarHolder, mDefaultToolbarView != oldToolbar));
         animators.add(getViewTransitionAnimator(
-                contentView, oldContent, mBottomSheetContentContainer, true));
+                content.getContentView(), oldContent, mBottomSheetContentContainer, true));
 
         // Temporarily make the background of the toolbar holder a solid color so the transition
         // doesn't appear to show a hole in the toolbar.
@@ -1099,11 +1081,14 @@
         // The max height ratio will be greater than 1 to account for the toolbar shadow.
         mStateRatios[2] = (mContainerHeight + mToolbarShadowHeight) / mContainerHeight;
 
+        // Compute the height that the content section of the bottom sheet.
+        float contentHeight = (mContainerHeight * getFullRatio()) - mToolbarHeight;
+
         MarginLayoutParams sheetContentParams =
                 (MarginLayoutParams) mBottomSheetContentContainer.getLayoutParams();
         sheetContentParams.width = (int) mContainerWidth;
-        sheetContentParams.height = (int) mContainerHeight;
-        sheetContentParams.topMargin = mToolbarShadowHeight;
+        sheetContentParams.height = (int) contentHeight;
+        sheetContentParams.topMargin = (int) mToolbarHeight;
 
         MarginLayoutParams toolbarShadowParams =
                 (MarginLayoutParams) findViewById(R.id.toolbar_shadow).getLayoutParams();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetNewTabController.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetNewTabController.java
index 04e7cbb..c324efd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetNewTabController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetNewTabController.java
@@ -13,26 +13,13 @@
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.toolbar.BottomToolbarPhone;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
- * A class that handles showing and hiding the bottom sheet new tab UI.
+ * A class that handles showing and hiding the Chrome Home new tab UI.
  */
 public class BottomSheetNewTabController extends EmptyBottomSheetObserver {
-    /** Observe events related to the bottom sheet new tab UI. **/
-    public interface Observer {
-        /** Called when the bottom sheet NTP UI is shown. */
-        void onNewTabShown();
-
-        /** Called when the bottom sheet NTP UI is hidden. */
-        void onNewTabHidden();
-    }
-
     private final BottomSheet mBottomSheet;
     private final BottomToolbarPhone mToolbar;
     private final ChromeActivity mActivity;
-    private final List<Observer> mObservers = new ArrayList<>();
 
     private LayoutManagerChrome mLayoutManager;
     private OverviewModeObserver mOverviewModeObserver;
@@ -59,20 +46,6 @@
     }
 
     /**
-     * @param observer An {@link Observer} to be notified of events related to the new tab UI.
-     */
-    public void addObserver(Observer observer) {
-        mObservers.add(observer);
-    }
-
-    /**
-     * @param observer The {@link Observer} to remove.
-     */
-    public void removeObserver(Observer observer) {
-        mObservers.remove(observer);
-    }
-
-    /**
      * @param tabModelSelector A TabModelSelector for getting the current tab and activity.
      */
     public void setTabModelSelector(TabModelSelector tabModelSelector) {
@@ -145,8 +118,6 @@
             mBottomSheet.getBottomSheetMetrics().recordSheetOpenReason(
                     BottomSheetMetrics.OPENED_BY_NEW_TAB_CREATION);
         }
-
-        for (Observer observer : mObservers) observer.onNewTabShown();
     }
 
     /**
@@ -224,8 +195,6 @@
         }
 
         mHideOverviewOnClose = false;
-
-        for (Observer observer : mObservers) observer.onNewTabHidden();
     }
 
     private void showTabSwitcherToolbarIfNecessary() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/PlaceholderSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/PlaceholderSheetContent.java
index a5f83c5..7a20a78 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/PlaceholderSheetContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/PlaceholderSheetContent.java
@@ -78,9 +78,4 @@
     public int getType() {
         return BottomSheetContentController.TYPE_PLACEHOLDER;
     }
-
-    @Override
-    public boolean applyDefaultTopPadding() {
-        return true;
-    }
 }
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index a845bb6..3b704f4 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -391,14 +391,6 @@
           other {<ph name="CONTACT_PREVIEW">%1$s<ex>Jerry, 438-123-1922</ex></ph>\u2026 and <ph name="NUMBER_OF_ADDITIONAL_CONTACTS">%2$s<ex>2</ex></ph> more}}
       </message>
 
-      <!-- Autofill/Wallet integration preferences -->
-      <message name="IDS_AUTOFILL_WALLET_MANAGEMENT_LINK_TEXT" desc="Text for link that allows users to see and edit their Wallet information.">
-        Edit
-      </message>
-      <message name="IDS_AUTOFILL_FROM_GOOGLE_ACCOUNT_LONG" desc="Text that indicates an address or credit card came from Google servers.">
-        From Google Payments
-      </message>
-
       <!-- Save passwords preferences -->
       <message name="IDS_PREFS_SAVED_PASSWORDS" desc="Title for the Saved Passwords preferences. [CHAR-LIMIT=32]">
         Save passwords
@@ -2235,6 +2227,15 @@
       <message name="IDS_SIGNIN_GMS_UPDATING" desc="Message notifying user that Google Play Services is still updating.">
         Waiting for Google Play Services to finish updating
       </message>
+      <message name="IDS_SIGNIN_PROMO_SETTINGS" desc="Text to inform the user that they can sign in to get personal settings.">
+        Sign in to Chrome to get your bookmarks, passwords, and more on all your devices.
+      </message>
+      <message name="IDS_SIGNIN_PROMO_CONTINUE_AS" desc="Button that the user can press to login without asking the password and continue using Chrome with this acccount.">
+        Continue as <ph name="USER_FULL_NAME">%1$s<ex>John Doe</ex></ph>
+     </message>
+      <message name="IDS_SIGNIN_PROMO_CHOOSE_ACCOUNT" desc="Button that the user can press if they are not the profile that Chrome found (opposite of 'Continue as Joe Doe').">
+        Not <ph name="EMAIL">%1$s<ex>john.doe@example.com</ex></ph>?
+      </message>
 
       <!-- Messages for remote media playback (casting) -->
       <message name="IDS_CAST_CASTING_VIDEO" desc="AtHome text to tell user which screen casting is happening. [CHAR LIMIT=40]">
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index a040b801..028a43f 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -1007,6 +1007,7 @@
   "java/src/org/chromium/chrome/browser/signin/SigninInvestigator.java",
   "java/src/org/chromium/chrome/browser/signin/SigninManager.java",
   "java/src/org/chromium/chrome/browser/signin/SigninPromoUtil.java",
+  "java/src/org/chromium/chrome/browser/signin/SigninPromoView.java",
   "java/src/org/chromium/chrome/browser/snackbar/BottomContainer.java",
   "java/src/org/chromium/chrome/browser/snackbar/DataReductionPromoSnackbarController.java",
   "java/src/org/chromium/chrome/browser/snackbar/DataUseSnackbarController.java",
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 9e3c250..7c25890 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
@@ -37,7 +37,6 @@
 import org.chromium.chrome.browser.ShortcutHelper;
 import org.chromium.chrome.browser.engagement.SiteEngagementService;
 import org.chromium.chrome.browser.infobar.AppBannerInfoBarAndroid;
-import org.chromium.chrome.browser.infobar.AppBannerInfoBarDelegateAndroid;
 import org.chromium.chrome.browser.infobar.InfoBar;
 import org.chromium.chrome.browser.infobar.InfoBarContainer;
 import org.chromium.chrome.browser.infobar.InfoBarContainer.InfoBarAnimationListener;
@@ -199,7 +198,7 @@
     public void setUp() throws Exception {
         mPackageManager = new TestPackageManager();
         AppBannerManager.setIsSupported(true);
-        AppBannerInfoBarDelegateAndroid.setPackageManagerForTesting(mPackageManager);
+        InstallerDelegate.setPackageManagerForTesting(mPackageManager);
         ShortcutHelper.setDelegateForTests(new ShortcutHelper.Delegate() {
             @Override
             public void addShortcutToHomescreen(String title, Bitmap icon, Intent shortcutIntent) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/banners/InstallerDelegateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/banners/InstallerDelegateTest.java
index e64a9c3b..300fe75d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/banners/InstallerDelegateTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/banners/InstallerDelegateTest.java
@@ -57,6 +57,11 @@
     private boolean mInstallStarted;
 
     @Override
+    public void onInstallIntentCompleted(InstallerDelegate delegate, boolean isInstalling) {
+        Assert.assertTrue(isInstalling);
+    }
+
+    @Override
     public void onInstallFinished(InstallerDelegate delegate, boolean success) {
         mResultDelegate = delegate;
         mResultSuccess = success;
@@ -64,16 +69,19 @@
         Assert.assertTrue(mInstallStarted);
     }
 
+    @Override
+    public void onApplicationStateChanged(InstallerDelegate delegate, int newState) {}
+
     @Before
     public void setUp() throws Exception {
         mPackageManager = new TestPackageManager();
+        InstallerDelegate.setPackageManagerForTesting(mPackageManager);
 
         // Create a thread for the InstallerDelegate to run on.  We need this thread because the
         // InstallerDelegate's handler fails to be processed otherwise.
         mThread = new HandlerThread("InstallerDelegateTest thread");
         mThread.start();
-        mTestDelegate = new InstallerDelegate(
-                mThread.getLooper(), mPackageManager, this, MOCK_PACKAGE_NAME);
+        mTestDelegate = new InstallerDelegate(mThread.getLooper(), this);
 
         // Clear out the results from last time.
         mResultDelegate = null;
@@ -87,7 +95,7 @@
     }
 
     private void startMonitoring() {
-        mTestDelegate.start();
+        mTestDelegate.startMonitoring(MOCK_PACKAGE_NAME);
         mInstallStarted = true;
     }
 
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 14fd9e8f..9811b3d 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
@@ -45,6 +45,7 @@
 import org.chromium.content.browser.test.util.DOMUtils;
 import org.chromium.content.browser.test.util.TestTouchUtils;
 import org.chromium.net.test.EmbeddedTestServer;
+import org.chromium.policy.test.annotations.Policies;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -395,6 +396,21 @@
     @Test
     @SmallTest
     @Feature({"Browser", "ContextMenu"})
+    @Policies.Add({ @Policies.Item(key = "DefaultSearchProviderEnabled", string = "false") })
+    @RetryOnFailure
+    public void testContextMenuRetrievesImageOptions_NoDefaultSearchEngine()
+            throws TimeoutException, InterruptedException {
+        Tab tab = mDownloadTestRule.getActivity().getActivityTab();
+        ContextMenu menu = ContextMenuUtils.openContextMenu(tab, "testImage");
+
+        Integer[] expectedItems = {R.id.contextmenu_save_image,
+                R.id.contextmenu_open_image_in_new_tab, R.id.contextmenu_share_image};
+        assertMenuItemsAreEqual(menu, expectedItems);
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Browser", "ContextMenu"})
     @RetryOnFailure
     public void testContextMenuRetrievesImageLinkOptions()
             throws TimeoutException, InterruptedException {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentManifestDownloaderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentManifestDownloaderTest.java
index 7b6e847..dbd2ba8e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentManifestDownloaderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentManifestDownloaderTest.java
@@ -124,7 +124,7 @@
     @Test
     @Feature({"Payments"})
     public void testDownloadWebAppManifest() throws Throwable {
-        final URI uri = new URI(mServer.getURL("/chrome/test/data/payments/app.json"));
+        final URI uri = new URI(mServer.getURL("/components/test/data/payments/app.json"));
         mRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
@@ -166,7 +166,7 @@
     @Test
     @Feature({"Payments"})
     public void testDownloadPaymentMethodManifest() throws Throwable {
-        final URI uri = new URI(mServer.getURL("/chrome/test/data/payments/webpay"));
+        final URI uri = new URI(mServer.getURL("/components/test/data/payments/webpay"));
         mRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
@@ -210,9 +210,10 @@
     @Feature({"Payments"})
     public void testSeveralDownloadsAtOnce() throws Throwable {
         final URI paymentMethodUri1 = new URI(mServer.getURL("/no-such-payment-method-name"));
-        final URI paymentMethodUri2 = new URI(mServer.getURL("/chrome/test/data/payments/webpay"));
+        final URI paymentMethodUri2 =
+                new URI(mServer.getURL("/components/test/data/payments/webpay"));
         final URI webAppUri1 = new URI(mServer.getURL("/no-such-app.json"));
-        final URI webAppUri2 = new URI(mServer.getURL("/chrome/test/data/payments/app.json"));
+        final URI webAppUri2 = new URI(mServer.getURL("/components/test/data/payments/app.json"));
         mRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
@@ -235,4 +236,4 @@
         Assert.assertEquals(PAYMENT_METHOD_MANIFEST, mPaymentMethodManifest);
         Assert.assertEquals(WEB_APP_MANIFEST, mWebAppManifest);
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestCommon.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestCommon.java
index e1c8ceb..e5e31b5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestCommon.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestCommon.java
@@ -132,7 +132,7 @@
         mTestFilePath = testFileName.startsWith("data:")
                 ? testFileName
                 : UrlUtils.getIsolatedTestFilePath(
-                          String.format("chrome/test/data/payments/%s", testFileName));
+                          String.format("components/test/data/payments/%s", testFileName));
     }
 
     public void startMainActivity() throws InterruptedException {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/PreferencesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/PreferencesTest.java
index e7fb6b3..566bb86 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/PreferencesTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/PreferencesTest.java
@@ -20,13 +20,14 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.ThreadUtils;
-import org.chromium.base.test.BaseJUnit4ClassRunner;
+import org.chromium.base.library_loader.ProcessInitException;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.RetryOnFailure;
 import org.chromium.chrome.browser.accessibility.FontSizePrefs;
+import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
 import org.chromium.chrome.browser.preferences.website.ContentSetting;
 import org.chromium.chrome.browser.preferences.website.GeolocationInfo;
 import org.chromium.chrome.browser.preferences.website.WebsitePreferenceBridge;
@@ -34,17 +35,24 @@
 import org.chromium.chrome.browser.search_engines.TemplateUrlService.LoadListener;
 import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrl;
 import org.chromium.chrome.browser.test.ChromeBrowserTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.util.ActivityUtils;
+import org.chromium.content.browser.test.util.Criteria;
+import org.chromium.content.browser.test.util.CriteriaHelper;
 import org.chromium.content.browser.test.util.UiUtils;
+import org.chromium.policy.test.annotations.Policies;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.text.NumberFormat;
 import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
 
 /**
  * Tests for the Settings menu.
  */
-@RunWith(BaseJUnit4ClassRunner.class)
+@RunWith(ChromeJUnit4ClassRunner.class)
 public class PreferencesTest {
     @Rule
     public final ChromeBrowserTestRule mBrowserTestRule = new ChromeBrowserTestRule();
@@ -155,6 +163,57 @@
         });
     }
 
+    @Test
+    @SmallTest
+    @Feature({"Preferences"})
+    @Policies.Add({ @Policies.Item(key = "DefaultSearchProviderEnabled", string = "false") })
+    public void testSearchEnginePreference_DisabledIfNoDefaultSearchEngine() throws Exception {
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    ChromeBrowserInitializer.getInstance(InstrumentationRegistry.getTargetContext())
+                            .handleSynchronousStartup();
+                } catch (ProcessInitException e) {
+                    Assert.fail("Unable to initialize process: " + e);
+                }
+            }
+        });
+
+        ensureTemplateUrlServiceLoaded();
+        CriteriaHelper.pollUiThread(Criteria.equals(true, new Callable<Boolean>() {
+            @Override
+            public Boolean call() throws Exception {
+                return TemplateUrlService.getInstance().isDefaultSearchManaged();
+            }
+        }));
+
+        Preferences preferenceActivity = ActivityUtils.waitForActivity(
+                InstrumentationRegistry.getInstrumentation(), Preferences.class);
+
+        final MainPreferences mainPreferences =
+                ActivityUtils.waitForFragmentToAttach(preferenceActivity, MainPreferences.class);
+
+        final Preference searchEnginePref =
+                waitForPreference(mainPreferences, MainPreferences.PREF_SEARCH_ENGINE);
+
+        CriteriaHelper.pollUiThread(Criteria.equals(null, new Callable<Object>() {
+            @Override
+            public Object call() throws Exception {
+                return searchEnginePref.getFragment();
+            }
+        }));
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                ManagedPreferenceDelegate managedPrefDelegate =
+                        mainPreferences.getManagedPreferenceDelegateForTest();
+                Assert.assertTrue(
+                        managedPrefDelegate.isPreferenceControlledByPolicy(searchEnginePref));
+            }
+        });
+    }
+
     /**
      * Make sure that when a user switches to a search engine that uses HTTP, the location
      * permission is not added.
@@ -336,4 +395,21 @@
             }
         });
     }
+
+    private static Preference waitForPreference(final PreferenceFragment prefFragment,
+            final String preferenceKey) throws ExecutionException {
+        CriteriaHelper.pollUiThread(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                return prefFragment.findPreference(preferenceKey) != null;
+            }
+        });
+
+        return ThreadUtils.runOnUiThreadBlocking(new Callable<Preference>() {
+            @Override
+            public Preference call() throws Exception {
+                return prefFragment.findPreference(preferenceKey);
+            }
+        });
+    }
 }
diff --git a/chrome/app/BUILD.gn b/chrome/app/BUILD.gn
index 71fc9b9..9b5f880 100644
--- a/chrome/app/BUILD.gn
+++ b/chrome/app/BUILD.gn
@@ -335,6 +335,7 @@
     "//printing/features",
     "//services/service_manager/embedder",
     "//ui/base",
+    "//v8:v8_headers",
   ]
 
   if (is_mac) {
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc
index 0371d51..978c2fd 100644
--- a/chrome/app/chrome_main_delegate.cc
+++ b/chrome/app/chrome_main_delegate.cc
@@ -138,6 +138,7 @@
 
 #if defined(OS_POSIX) && !defined(OS_MACOSX)
 #include "components/crash/content/app/breakpad_linux.h"
+#include "v8/include/v8.h"
 #endif
 
 #if defined(OS_LINUX)
@@ -570,6 +571,9 @@
 #if defined(OS_WIN) && !defined(CHROME_MULTIPLE_DLL_BROWSER)
   v8_breakpad_support::SetUp();
 #endif
+#if defined(OS_LINUX) && !defined(OS_ANDROID)
+  breakpad::SetFirstChanceExceptionHandler(v8::V8::TryHandleSignal);
+#endif
 
 #if defined(OS_POSIX)
   if (HandleVersionSwitches(command_line)) {
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index de25e2a3..4e857dbc 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -297,6 +297,8 @@
     "content_settings/local_shared_objects_container.h",
     "content_settings/mixed_content_settings_tab_helper.cc",
     "content_settings/mixed_content_settings_tab_helper.h",
+    "content_settings/sound_content_setting_observer.cc",
+    "content_settings/sound_content_setting_observer.h",
     "content_settings/tab_specific_content_settings.cc",
     "content_settings/tab_specific_content_settings.h",
     "content_settings/web_site_settings_uma_util.cc",
@@ -3917,8 +3919,8 @@
       "//components/exo/wayland",
     ]
     sources += [
-      "chrome_browser_main_extra_parts_exo.cc",
-      "chrome_browser_main_extra_parts_exo.h",
+      "exo_parts.cc",
+      "exo_parts.h",
     ]
   }
 
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index d2f4157a..323cf399 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3178,7 +3178,7 @@
      flag_descriptions::kDelayReloadStopButtonChangeName,
      flag_descriptions::kDelayReloadStopButtonChangeDescription,
      kOsCrOS | kOsWin | kOsLinux,
-     SINGLE_DISABLE_VALUE_TYPE(switches::kDelayReloadStopButtonChange)},
+     SINGLE_VALUE_TYPE(switches::kDelayReloadStopButtonChange)},
 #endif  // TOOLKIT_VIEWS
 
     {"enable-async-image-decoding", flag_descriptions::kAsyncImageDecodingName,
diff --git a/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc b/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc
index 6234b7d..d68dca1 100644
--- a/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc
+++ b/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc
@@ -82,10 +82,10 @@
     const base::string16& app_title,
     const base::android::ScopedJavaGlobalRef<jobject>& native_app_data,
     const SkBitmap& icon,
-    const std::string& native_app_package,
+    const std::string& native_app_package_name,
     const std::string& referrer) {
   auto infobar_delegate = base::WrapUnique(new AppBannerInfoBarDelegateAndroid(
-      app_title, native_app_data, icon, native_app_package, referrer));
+      app_title, native_app_data, icon, native_app_package_name, referrer));
   return InfoBarService::FromWebContents(web_contents)
       ->AddInfoBar(base::MakeUnique<AppBannerInfoBarAndroid>(
            std::move(infobar_delegate), native_app_data));
@@ -107,8 +107,8 @@
 
   if (TriggeredFromBanner())
     TrackDismissEvent(DISMISS_EVENT_DISMISSED);
-  JNIEnv* env = base::android::AttachCurrentThread();
-  Java_AppBannerInfoBarDelegateAndroid_destroy(env, java_delegate_);
+  Java_AppBannerInfoBarDelegateAndroid_destroy(
+      base::android::AttachCurrentThread(), java_delegate_);
   java_delegate_.Reset();
 }
 
@@ -118,10 +118,12 @@
   if (native_app_data_.is_null() && !is_webapk_)
     return;
 
+  ScopedJavaLocalRef<jstring> jpackage_name(
+      ConvertUTF8ToJavaString(env, package_name_));
   int newState = Java_AppBannerInfoBarDelegateAndroid_determineInstallState(
-      env, java_delegate_, native_app_data_);
-  static_cast<AppBannerInfoBarAndroid*>(infobar())
-      ->OnInstallStateChanged(newState);
+      env, java_delegate_, jpackage_name);
+  static_cast<AppBannerInfoBarAndroid*>(infobar())->OnInstallStateChanged(
+      newState);
 }
 
 void AppBannerInfoBarDelegateAndroid::OnInstallIntentReturned(
@@ -129,14 +131,13 @@
     const JavaParamRef<jobject>& obj,
     jboolean jis_installing) {
   DCHECK(infobar());
+  DCHECK(!package_name_.empty());
 
   content::WebContents* web_contents =
       InfoBarService::WebContentsFromInfoBar(infobar());
   if (jis_installing) {
     AppBannerSettingsHelper::RecordBannerEvent(
-        web_contents,
-        web_contents->GetURL(),
-        native_app_package_,
+        web_contents, web_contents->GetURL(), package_name_,
         AppBannerSettingsHelper::APP_BANNER_EVENT_DID_ADD_TO_HOMESCREEN,
         AppBannerManager::GetCurrentTime());
 
@@ -184,19 +185,6 @@
   return AcceptWebApp(web_contents);
 }
 
-void AppBannerInfoBarDelegateAndroid::UpdateStateForInstalledWebAPK(
-    const std::string& webapk_package_name) {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  ScopedJavaLocalRef<jstring> java_webapk_package_name =
-      base::android::ConvertUTF8ToJavaString(env, webapk_package_name);
-  Java_AppBannerInfoBarDelegateAndroid_setWebApkInstallingState(
-      env, java_delegate_, false);
-  Java_AppBannerInfoBarDelegateAndroid_setWebApkPackageName(
-      env, java_delegate_, java_webapk_package_name);
-  UpdateInstallState(env, nullptr);
-  install_state_ = INSTALLED;
-}
-
 AppBannerInfoBarDelegateAndroid::AppBannerInfoBarDelegateAndroid(
     base::WeakPtr<AppBannerManager> weak_manager,
     std::unique_ptr<ShortcutInfo> shortcut_info,
@@ -221,23 +209,24 @@
     const base::string16& app_title,
     const base::android::ScopedJavaGlobalRef<jobject>& native_app_data,
     const SkBitmap& icon,
-    const std::string& native_app_package,
+    const std::string& native_app_package_name,
     const std::string& referrer)
     : app_title_(app_title),
       native_app_data_(native_app_data),
       primary_icon_(icon),
-      native_app_package_(native_app_package),
+      package_name_(native_app_package_name),
       referrer_(referrer),
       has_user_interaction_(false),
+      is_webapk_(false),
       weak_ptr_factory_(this) {
   DCHECK(!native_app_data_.is_null());
+  DCHECK(!package_name_.empty());
   CreateJavaDelegate();
 }
 
 void AppBannerInfoBarDelegateAndroid::CreateJavaDelegate() {
   java_delegate_.Reset(Java_AppBannerInfoBarDelegateAndroid_create(
-      base::android::AttachCurrentThread(),
-      reinterpret_cast<intptr_t>(this)));
+      base::android::AttachCurrentThread(), reinterpret_cast<intptr_t>(this)));
 }
 
 bool AppBannerInfoBarDelegateAndroid::AcceptNativeApp(
@@ -285,7 +274,11 @@
   // If the WebAPK is installed and the "Open" button is clicked, open the
   // WebAPK. Do not send a BannerAccepted message.
   if (install_state_ == INSTALLED) {
-    Java_AppBannerInfoBarDelegateAndroid_openWebApk(env, java_delegate_);
+    DCHECK(!package_name_.empty());
+    ScopedJavaLocalRef<jstring> jpackage_name(
+        ConvertUTF8ToJavaString(env, package_name_));
+    Java_AppBannerInfoBarDelegateAndroid_openApp(env, java_delegate_,
+                                                 jpackage_name);
     webapk::TrackUserAction(webapk::USER_ACTION_INSTALLED_OPEN);
     return true;
   }
@@ -310,8 +303,6 @@
         AppBannerManager::GetCurrentTime());
   }
 
-  Java_AppBannerInfoBarDelegateAndroid_setWebApkInstallingState(
-      env, java_delegate_, true);
   UpdateInstallState(env, nullptr);
   WebApkInstallService::FinishCallback callback =
       base::Bind(&AppBannerInfoBarDelegateAndroid::OnWebApkInstallFinished,
@@ -352,7 +343,10 @@
     OnWebApkInstallFailed(result);
     return;
   }
-  UpdateStateForInstalledWebAPK(webapk_package_name);
+
+  install_state_ = INSTALLED;
+  package_name_ = webapk_package_name;
+  UpdateInstallState(base::android::AttachCurrentThread(), nullptr);
 }
 
 void AppBannerInfoBarDelegateAndroid::OnWebApkInstallFailed(
@@ -415,9 +409,10 @@
           AppBannerSettingsHelper::WEB);
     }
   } else {
+    DCHECK(!package_name_.empty());
     TrackUserResponse(USER_RESPONSE_NATIVE_APP_DISMISSED);
     AppBannerSettingsHelper::RecordBannerDismissEvent(
-        web_contents, native_app_package_, AppBannerSettingsHelper::NATIVE);
+        web_contents, package_name_, AppBannerSettingsHelper::NATIVE);
   }
 }
 
@@ -435,15 +430,14 @@
     return false;
 
   // Try to show the details for the native app.
-  JNIEnv* env = base::android::AttachCurrentThread();
-
   content::WebContents* web_contents =
       InfoBarService::WebContentsFromInfoBar(infobar());
   TabAndroid* tab = TabAndroid::FromWebContents(web_contents);
   DCHECK(tab);
 
   Java_AppBannerInfoBarDelegateAndroid_showAppDetails(
-      env, java_delegate_, tab->GetJavaObject(), native_app_data_);
+      base::android::AttachCurrentThread(), java_delegate_,
+      tab->GetJavaObject(), native_app_data_);
 
   TrackDismissEvent(DISMISS_EVENT_BANNER_CLICK);
   return true;
diff --git a/chrome/browser/android/banners/app_banner_infobar_delegate_android.h b/chrome/browser/android/banners/app_banner_infobar_delegate_android.h
index b62e5e3..e7dd249 100644
--- a/chrome/browser/android/banners/app_banner_infobar_delegate_android.h
+++ b/chrome/browser/android/banners/app_banner_infobar_delegate_android.h
@@ -52,7 +52,7 @@
       const base::string16& app_title,
       const base::android::ScopedJavaGlobalRef<jobject>& native_app_data,
       const SkBitmap& icon,
-      const std::string& native_app_package,
+      const std::string& native_app_package_name,
       const std::string& referrer);
 
   ~AppBannerInfoBarDelegateAndroid() override;
@@ -75,9 +75,6 @@
   // ConfirmInfoBarDelegate:
   bool Accept() override;
 
-  // Update the AppBannerInfoBarAndroid with installed WebAPK's information.
-  void UpdateStateForInstalledWebAPK(const std::string& webapk_package_name);
-
  private:
   // The states of a WebAPK installation, where the infobar is displayed during
   // the entire installation process. This state is used to correctly record
@@ -102,7 +99,7 @@
       const base::string16& app_title,
       const base::android::ScopedJavaGlobalRef<jobject>& native_app_data,
       const SkBitmap& icon,
-      const std::string& native_app_package,
+      const std::string& native_app_package_name,
       const std::string& referrer);
 
   void CreateJavaDelegate();
@@ -152,7 +149,7 @@
   const SkBitmap primary_icon_;
   const SkBitmap badge_icon_;
 
-  std::string native_app_package_;
+  std::string package_name_;
   std::string referrer_;
   bool has_user_interaction_;
 
diff --git a/chrome/browser/android/offline_pages/offline_page_request_job.cc b/chrome/browser/android/offline_pages/offline_page_request_job.cc
index 8278d6bb..26ebc675a 100644
--- a/chrome/browser/android/offline_pages/offline_page_request_job.cc
+++ b/chrome/browser/android/offline_pages/offline_page_request_job.cc
@@ -358,7 +358,13 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   // If the match is for original URL, trigger the redirect.
-  if (offline_page && url == offline_page->original_url) {
+  // Note: If the offline page has same orginal URL and final URL, don't trigger
+  // the redirect. Some websites might route the redirect finally back to itself
+  // after intermediate redirects for authentication. Previously this case was
+  // not handled and some pages might be saved with same URLs. Though we fixed
+  // the problem, we still need to support those pages already saved with this
+  if (offline_page && url == offline_page->original_url &&
+      url != offline_page->url) {
     ReportRequestResult(RequestResult::REDIRECTED, network_state);
     NotifyOfflineRedirectOnUI(job, offline_page->url);
     return;
diff --git a/chrome/browser/android/offline_pages/offline_page_request_job_unittest.cc b/chrome/browser/android/offline_pages/offline_page_request_job_unittest.cc
index ea6ff6d6..abc7d50 100644
--- a/chrome/browser/android/offline_pages/offline_page_request_job_unittest.cc
+++ b/chrome/browser/android/offline_pages/offline_page_request_job_unittest.cc
@@ -49,15 +49,18 @@
 const GURL kTestUrl3("http://test.org/page3");
 const GURL kTestUrl3WithFragment("http://test.org/page3#ref1");
 const GURL kTestUrl4("http://test.org/page4");
+const GURL kTestUrl5("http://test.org/page5");
 const GURL kTestOriginalUrl("http://test.org/first");
 const ClientId kTestClientId = ClientId(kBookmarkNamespace, "1234");
 const ClientId kTestClientId2 = ClientId(kDownloadNamespace, "1a2b3c4d");
 const ClientId kTestClientId3 = ClientId(kDownloadNamespace, "3456abcd");
 const ClientId kTestClientId4 = ClientId(kDownloadNamespace, "5678");
+const ClientId kTestClientId5 = ClientId(kDownloadNamespace, "9999");
 const int kTestFileSize = 444;
 const int kTestFileSize2 = 450;
 const int kTestFileSize3 = 450;
 const int kTestFileSize4 = 111;
+const int kTestFileSize5 = 450;
 const int kTabId = 1;
 const int kBufSize = 1024;
 const char kAggregatedRequestResultHistogram[] =
@@ -257,6 +260,8 @@
                 const GURL& original_url,
                 std::unique_ptr<OfflinePageArchiver> archiver);
 
+  OfflinePageItem GetPage(int64_t offline_id);
+
   void InterceptRequest(const GURL& url,
                         const std::string& method,
                         const std::string& extra_header_name,
@@ -289,6 +294,7 @@
   int64_t offline_id2() const { return offline_id2_; }
   int64_t offline_id3() const { return offline_id3_; }
   int64_t offline_id4() const { return offline_id4_; }
+  int64_t offline_id5() const { return offline_id5_; }
   int bytes_read() const { return bytes_read_; }
 
   TestPreviewsDecider* test_previews_decider() {
@@ -301,6 +307,7 @@
       const GURL& url,
       const std::string& method,
       content::ResourceType resource_type);
+  void OnGetPageByOfflineIdDone(const OfflinePageItem* pages);
   void ReadCompleted(int bytes_read);
 
   // Runs on IO thread.
@@ -331,7 +338,9 @@
   int64_t offline_id2_;
   int64_t offline_id3_;
   int64_t offline_id4_;
+  int64_t offline_id5_;
   int bytes_read_;
+  OfflinePageItem page_;
 
   DISALLOW_COPY_AND_ASSIGN(OfflinePageRequestJobTest);
 };
@@ -344,6 +353,7 @@
       offline_id2_(-1),
       offline_id3_(-1),
       offline_id4_(-1),
+      offline_id5_(-1),
       bytes_read_(0) {}
 
 void OfflinePageRequestJobTest::SetUp() {
@@ -363,13 +373,19 @@
       profile(), BuildTestOfflinePageModel);
   RunUntilIdle();
 
-  OfflinePageModel* model =
-      OfflinePageModelFactory::GetForBrowserContext(profile());
+  OfflinePageModelImpl* model = static_cast<OfflinePageModelImpl*>(
+      OfflinePageModelFactory::GetForBrowserContext(profile()));
 
   // Hook up a test clock such that we can control the time when the offline
   // page is created.
   clock_.SetNow(base::Time::Now());
-  static_cast<OfflinePageModelImpl*>(model)->set_testing_clock(&clock_);
+  model->set_testing_clock(&clock_);
+
+  // Skip the logic to clear the original URL if it is same as final URL.
+  // This is needed in order to test that offline page request handler can
+  // omit the redirect under this circumstance, for compatibility with the
+  // metadata already written to the store.
+  model->set_skip_clearing_original_url_for_testing();
 
   // All offline pages being created below will point to real archive files
   // residing in test data directory.
@@ -420,6 +436,20 @@
 
   SavePage(kTestUrl4, kTestClientId4, GURL(), std::move(archiver4));
 
+  // Save an offline page with same original URL and final URL.
+  base::FilePath archive_file_path5 =
+      test_data_dir_path.AppendASCII("offline_pages")
+          .AppendASCII("hello.mhtml");
+  std::unique_ptr<TestOfflinePageArchiver> archiver5(
+      new TestOfflinePageArchiver(kTestUrl5, archive_file_path5,
+                                  kTestFileSize5));
+
+  SavePage(kTestUrl5, kTestClientId5, kTestUrl5, std::move(archiver5));
+
+  // Check if the original URL is still present.
+  OfflinePageItem page = GetPage(offline_id5());
+  EXPECT_EQ(kTestUrl5, page.original_url);
+
   // Create a context with delayed initialization.
   test_url_request_context_.reset(new net::TestURLRequestContext(true));
 
@@ -532,6 +562,23 @@
     offline_id3_ = offline_id;
   else if (offline_id4_ == -1)
     offline_id4_ = offline_id;
+  else if (offline_id5_ == -1)
+    offline_id5_ = offline_id;
+}
+
+OfflinePageItem OfflinePageRequestJobTest::GetPage(int64_t offline_id) {
+  OfflinePageModelFactory::GetForBrowserContext(profile())->GetPageByOfflineId(
+      offline_id,
+      base::Bind(&OfflinePageRequestJobTest::OnGetPageByOfflineIdDone,
+                 base::Unretained(this)));
+  RunUntilIdle();
+  return page_;
+}
+
+void OfflinePageRequestJobTest::OnGetPageByOfflineIdDone(
+    const OfflinePageItem* page) {
+  ASSERT_TRUE(page);
+  page_ = *page;
 }
 
 void OfflinePageRequestJobTest::InterceptRequestOnIO(
@@ -895,6 +942,22 @@
           SHOW_OFFLINE_ON_DISCONNECTED_NETWORK);
 }
 
+TEST_F(OfflinePageRequestJobTest, NoRedirectForOfflinePageWithSameOriginalURL) {
+  SimulateHasNetworkConnectivity(false);
+
+  // No redirect should be triggered when original URL is same as final URL.
+  InterceptRequest(kTestUrl5, "GET", "", "", content::RESOURCE_TYPE_MAIN_FRAME);
+  base::RunLoop().Run();
+
+  EXPECT_EQ(kTestFileSize5, bytes_read());
+  ASSERT_TRUE(offline_page_tab_helper()->GetOfflinePageForTest());
+  EXPECT_EQ(offline_id5(),
+            offline_page_tab_helper()->GetOfflinePageForTest()->offline_id);
+  ExpectOneUniqueSampleForAggregatedRequestResult(
+      OfflinePageRequestJob::AggregatedRequestResult::
+          SHOW_OFFLINE_ON_DISCONNECTED_NETWORK);
+}
+
 TEST_F(OfflinePageRequestJobTest, LoadOfflinePageFromNonExistentFile) {
   SimulateHasNetworkConnectivity(false);
 
diff --git a/chrome/browser/android/vr_shell/vr_shell_delegate.cc b/chrome/browser/android/vr_shell/vr_shell_delegate.cc
index 33605a50..95ea24f 100644
--- a/chrome/browser/android/vr_shell/vr_shell_delegate.cc
+++ b/chrome/browser/android/vr_shell/vr_shell_delegate.cc
@@ -117,7 +117,7 @@
                                           jlong timebase_nanos,
                                           jlong interval_micros) {
   vsync_timebase_ = base::TimeTicks() +
-                    base::TimeDelta::FromMilliseconds(timebase_nanos / 1000);
+                    base::TimeDelta::FromMicroseconds(timebase_nanos / 1000);
   vsync_interval_ = base::TimeDelta::FromMicroseconds(interval_micros);
   if (gvr_delegate_) {
     gvr_delegate_->UpdateVSyncInterval(vsync_timebase_, vsync_interval_);
diff --git a/chrome/browser/android/vr_shell/vr_shell_gl.cc b/chrome/browser/android/vr_shell/vr_shell_gl.cc
index 83e8742..198524d6 100644
--- a/chrome/browser/android/vr_shell/vr_shell_gl.cc
+++ b/chrome/browser/android/vr_shell/vr_shell_gl.cc
@@ -1067,18 +1067,20 @@
     return;
 
   base::TimeTicks now = base::TimeTicks::Now();
-  base::TimeTicks target;
-  target = now + vsync_interval_;
-  int64_t intervals = (target - vsync_timebase_) / vsync_interval_;
+  base::TimeTicks target = now + vsync_interval_;
+  double intervalsF =
+      (target - vsync_timebase_).InSecondsF() / vsync_interval_.InSecondsF();
+  uint64_t intervals = std::llround(intervalsF);
   target = vsync_timebase_ + intervals * vsync_interval_;
   task_runner_->PostDelayedTask(FROM_HERE, vsync_task_.callback(),
                                 target - now);
-  base::TimeDelta current = target - vsync_interval_ - base::TimeTicks();
+
+  base::TimeDelta current_time = target - vsync_interval_ - base::TimeTicks();
   if (!callback_.is_null()) {
-    SendVSync(current, base::ResetAndReturn(&callback_));
+    SendVSync(current_time, base::ResetAndReturn(&callback_));
   } else {
     pending_vsync_ = true;
-    pending_time_ = current;
+    pending_time_ = current_time;
   }
   if (!ShouldDrawWebVr()) {
     DrawFrame(-1);
diff --git a/chrome/browser/chrome_browser_main_extra_parts_exo.h b/chrome/browser/chrome_browser_main_extra_parts_exo.h
deleted file mode 100644
index 0113c771..0000000
--- a/chrome/browser/chrome_browser_main_extra_parts_exo.h
+++ /dev/null
@@ -1,46 +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.
-
-#ifndef CHROME_BROWSER_CHROME_BROWSER_MAIN_EXTRA_PARTS_EXO_H_
-#define CHROME_BROWSER_CHROME_BROWSER_MAIN_EXTRA_PARTS_EXO_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "chrome/browser/chrome_browser_main_extra_parts.h"
-
-namespace exo {
-class Display;
-class WMHelper;
-namespace wayland {
-class Server;
-}
-}
-
-namespace arc {
-class ArcNotificationSurfaceManagerImpl;
-}
-
-class ChromeBrowserMainExtraPartsExo : public ChromeBrowserMainExtraParts {
- public:
-  ChromeBrowserMainExtraPartsExo();
-  ~ChromeBrowserMainExtraPartsExo() override;
-
-  // Overridden from ChromeBrowserMainExtraParts:
-  void PreProfileInit() override;
-  void PostMainMessageLoopRun() override;
-
- private:
-  std::unique_ptr<arc::ArcNotificationSurfaceManagerImpl>
-      arc_notification_surface_manager_;
-  std::unique_ptr<exo::WMHelper> wm_helper_;
-  std::unique_ptr<exo::Display> display_;
-  std::unique_ptr<exo::wayland::Server> wayland_server_;
-  class WaylandWatcher;
-  std::unique_ptr<WaylandWatcher> wayland_watcher_;
-
-  DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainExtraPartsExo);
-};
-
-#endif  // CHROME_BROWSER_CHROME_BROWSER_MAIN_EXTRA_PARTS_EXO_H_
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index dd0309b..d1be8fc 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -73,11 +73,11 @@
 #include "chrome/browser/renderer_host/chrome_render_message_filter.h"
 #include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h"
 #include "chrome/browser/resource_coordinator/background_tab_navigation_throttle.h"
-#include "chrome/browser/safe_browsing/browser_url_loader_throttle.h"
 #include "chrome/browser/safe_browsing/certificate_reporting_service.h"
 #include "chrome/browser/safe_browsing/certificate_reporting_service_factory.h"
-#include "chrome/browser/safe_browsing/mojo_safe_browsing_impl.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
+#include "chrome/browser/safe_browsing/ui_manager.h"
+#include "chrome/browser/safe_browsing/url_checker_delegate_impl.h"
 #include "chrome/browser/search/instant_service.h"
 #include "chrome/browser/search/instant_service_factory.h"
 #include "chrome/browser/search/search.h"
@@ -147,7 +147,11 @@
 #include "components/rappor/public/rappor_utils.h"
 #include "components/rappor/rappor_recorder_impl.h"
 #include "components/rappor/rappor_service_impl.h"
+#include "components/safe_browsing/browser/browser_url_loader_throttle.h"
+#include "components/safe_browsing/browser/mojo_safe_browsing_impl.h"
+#include "components/safe_browsing/browser/url_checker_delegate.h"
 #include "components/safe_browsing/common/safe_browsing_prefs.h"
+#include "components/safe_browsing_db/database_manager.h"
 #include "components/security_interstitials/core/ssl_error_ui.h"
 #include "components/signin/core/common/profile_management_switches.h"
 #include "components/spellcheck/spellcheck_build_features.h"
@@ -383,10 +387,6 @@
 #include "components/printing/service/public/interfaces/pdf_compositor.mojom.h"
 #endif
 
-#if BUILDFLAG(ENABLE_WAYLAND_SERVER)
-#include "chrome/browser/chrome_browser_main_extra_parts_exo.h"
-#endif
-
 #if BUILDFLAG(ENABLE_MOJO_MEDIA)
 #include "chrome/browser/media/output_protection_impl.h"
 #if BUILDFLAG(ENABLE_MOJO_CDM) && defined(OS_ANDROID)
@@ -904,10 +904,6 @@
   main_parts->AddParts(new ChromeBrowserMainExtraPartsX11());
 #endif
 
-#if BUILDFLAG(ENABLE_WAYLAND_SERVER)
-  main_parts->AddParts(new ChromeBrowserMainExtraPartsExo());
-#endif
-
   chrome::AddMetricsExtraParts(main_parts);
 
   return main_parts;
@@ -2871,10 +2867,12 @@
 
   if (base::FeatureList::IsEnabled(features::kNetworkService)) {
     registry->AddInterface(
-        base::Bind(&safe_browsing::MojoSafeBrowsingImpl::Create,
-                   safe_browsing_service_->database_manager(),
-                   safe_browsing_service_->ui_manager(),
-                   render_process_host->GetID()),
+        base::Bind(
+            &safe_browsing::MojoSafeBrowsingImpl::MaybeCreate,
+            render_process_host->GetID(),
+            base::Bind(
+                &ChromeContentBrowserClient::GetSafeBrowsingUrlCheckerDelegate,
+                base::Unretained(this))),
         BrowserThread::GetTaskRunnerForThread(BrowserThread::IO));
   }
 
@@ -3381,9 +3379,13 @@
   DCHECK(base::FeatureList::IsEnabled(features::kNetworkService));
 
   std::vector<std::unique_ptr<content::URLLoaderThrottle>> result;
-  result.push_back(base::MakeUnique<safe_browsing::BrowserURLLoaderThrottle>(
-      safe_browsing_service_->database_manager(),
-      safe_browsing_service_->ui_manager(), wc_getter));
+
+  auto safe_browsing_throttle =
+      safe_browsing::BrowserURLLoaderThrottle::MaybeCreate(
+          GetSafeBrowsingUrlCheckerDelegate(), wc_getter);
+  if (safe_browsing_throttle)
+    result.push_back(std::move(safe_browsing_throttle));
+
   return result;
 }
 
@@ -3439,3 +3441,18 @@
     const storage::QuotaSettings* settings) {
   g_default_quota_settings = settings;
 }
+
+safe_browsing::UrlCheckerDelegate*
+ChromeContentBrowserClient::GetSafeBrowsingUrlCheckerDelegate() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  // |safe_browsing_service_| may be unavailable in tests.
+  if (safe_browsing_service_ && !safe_browsing_url_checker_delegate_) {
+    safe_browsing_url_checker_delegate_ =
+        new safe_browsing::UrlCheckerDelegateImpl(
+            safe_browsing_service_->database_manager(),
+            safe_browsing_service_->ui_manager());
+  }
+
+  return safe_browsing_url_checker_delegate_.get();
+}
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index e45c8e2..c63110650 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -43,6 +43,7 @@
 
 namespace safe_browsing {
 class SafeBrowsingService;
+class UrlCheckerDelegate;
 }
 
 namespace user_prefs {
@@ -380,6 +381,8 @@
   static void SetDefaultQuotaSettingsForTesting(
       const storage::QuotaSettings *settings);
 
+  safe_browsing::UrlCheckerDelegate* GetSafeBrowsingUrlCheckerDelegate();
+
 #if BUILDFLAG(ENABLE_PLUGINS)
   // Set of origins that can use TCP/UDP private APIs from NaCl.
   std::set<std::string> allowed_socket_origins_;
@@ -397,6 +400,8 @@
   service_manager::BinderRegistry gpu_binder_registry_;
 
   scoped_refptr<safe_browsing::SafeBrowsingService> safe_browsing_service_;
+  scoped_refptr<safe_browsing::UrlCheckerDelegate>
+      safe_browsing_url_checker_delegate_;
 
   std::unique_ptr<service_manager::BinderRegistry> frame_interfaces_;
   std::unique_ptr<
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.cc b/chrome/browser/chromeos/arc/arc_session_manager.cc
index 92cd72c1..5b29c12 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager.cc
+++ b/chrome/browser/chromeos/arc/arc_session_manager.cc
@@ -173,6 +173,9 @@
   registry->RegisterBooleanPref(prefs::kArcTermsAccepted, false);
   registry->RegisterBooleanPref(prefs::kArcVoiceInteractionValuePropAccepted,
                                 false);
+  registry->RegisterBooleanPref(prefs::kVoiceInteractionEnabled, false);
+  registry->RegisterBooleanPref(prefs::kVoiceInteractionContextEnabled, false);
+  registry->RegisterBooleanPref(prefs::kVoiceInteractionPrefSynced, false);
   // Note that ArcBackupRestoreEnabled and ArcLocationServiceEnabled prefs have
   // to be off by default, until an explicit gesture from the user to enable
   // them is received. This is crucial in the cases when these prefs transition
diff --git a/chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.cc b/chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.cc
index 7ddad71..cc3b669 100644
--- a/chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.cc
+++ b/chrome/browser/chromeos/arc/intent_helper/arc_navigation_throttle.cc
@@ -228,7 +228,7 @@
     // iff there are ARC apps which can actually handle the given URL.
     DVLOG(1) << "There are no app candidates for this URL: "
              << navigation_handle()->GetURL();
-    navigation_handle()->Resume();
+    Resume();
     return;
   }
 
@@ -251,7 +251,7 @@
       navigation_handle()->GetWebContents()->GetBrowserContext());
   if (!intent_helper_bridge) {
     LOG(ERROR) << "Cannot get an instance of ArcIntentHelperBridge";
-    navigation_handle()->Resume();
+    Resume();
     return;
   }
   std::vector<ArcIntentHelperBridge::ActivityName> activities;
@@ -322,7 +322,7 @@
       // an error or if |selected_app_index| is not a valid index, then resume
       // the navigation in Chrome.
       DVLOG(1) << "User didn't select a valid option, resuming navigation.";
-      handle->Resume();
+      Resume();
       break;
     }
     case CloseReason::ALWAYS_PRESSED: {
@@ -341,10 +341,10 @@
     case CloseReason::PREFERRED_ACTIVITY_FOUND: {
       if (ArcIntentHelperBridge::IsIntentHelperPackage(
               handlers[selected_app_index]->package_name)) {
-        handle->Resume();
+        Resume();
       } else {
         instance->HandleUrl(url.spec(), selected_app_package);
-        handle->CancelDeferredNavigation(
+        CancelDeferredNavigation(
             content::NavigationThrottle::CANCEL_AND_IGNORE);
         if (handle->GetWebContents()->GetController().IsInitialNavigation())
           handle->GetWebContents()->Close();
diff --git a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_arc_home_service.cc b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_arc_home_service.cc
index c065a9ab..02800d5 100644
--- a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_arc_home_service.cc
+++ b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_arc_home_service.cc
@@ -191,6 +191,8 @@
   if (pai_starter)
     pai_starter->ReleaseLock();
   chromeos::first_run::MaybeLaunchDialogImmediately();
+  arc::ArcVoiceInteractionFrameworkService::GetForBrowserContext(context_)
+      ->UpdateVoiceInteractionPrefs();
 }
 
 // static
diff --git a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc
index 0547573..b2d0c9a 100644
--- a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc
+++ b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc
@@ -24,6 +24,7 @@
 #include "chrome/browser/chromeos/login/helper.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
@@ -190,6 +191,15 @@
   }
 };
 
+void SetVoiceInteractionPrefs(mojom::VoiceInteractionStatusPtr status) {
+  PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
+  prefs->SetBoolean(prefs::kVoiceInteractionPrefSynced, status->configured);
+  prefs->SetBoolean(prefs::kVoiceInteractionEnabled,
+                    status->configured && status->voice_interaction_enabled);
+  prefs->SetBoolean(prefs::kVoiceInteractionContextEnabled,
+                    status->configured && status->context_enabled);
+}
+
 }  // namespace
 
 // static
@@ -209,6 +219,7 @@
     ArcBridgeService* bridge_service)
     : context_(context), arc_bridge_service_(bridge_service), binding_(this) {
   arc_bridge_service_->voice_interaction_framework()->AddObserver(this);
+  ArcSessionManager::Get()->AddObserver(this);
 }
 
 ArcVoiceInteractionFrameworkService::~ArcVoiceInteractionFrameworkService() {
@@ -218,6 +229,8 @@
   // so do not touch it.
   if (ArcServiceManager::Get())
     arc_bridge_service_->voice_interaction_framework()->RemoveObserver(this);
+  ArcSessionManager::Get()->RemoveObserver(this);
+  ArcSessionManager::Get()->AddObserver(this);
 }
 
 void ArcVoiceInteractionFrameworkService::OnInstanceReady() {
@@ -234,6 +247,11 @@
   ash::Shell::Get()->accelerator_controller()->Register(
       {ui::Accelerator(ui::VKEY_A, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN)},
       this);
+
+  if (is_request_pending_) {
+    is_request_pending_ = false;
+    framework_instance->StartVoiceInteractionSession();
+  }
 }
 
 void ArcVoiceInteractionFrameworkService::OnInstanceClosed() {
@@ -365,6 +383,18 @@
   SetMetalayerVisibility(false);
 }
 
+void ArcVoiceInteractionFrameworkService::OnArcPlayStoreEnabledChanged(
+    bool enabled) {
+  if (enabled)
+    return;
+  mojom::VoiceInteractionStatusPtr status =
+      mojom::VoiceInteractionStatus::New();
+  status->configured = false;
+  status->voice_interaction_enabled = false;
+  status->context_enabled = false;
+  SetVoiceInteractionPrefs(std::move(status));
+}
+
 void ArcVoiceInteractionFrameworkService::StartVoiceInteractionSetupWizard() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   arc::mojom::VoiceInteractionFrameworkInstance* framework_instance =
@@ -423,6 +453,21 @@
   framework_instance->SetVoiceInteractionContextEnabled(enable);
 }
 
+void ArcVoiceInteractionFrameworkService::UpdateVoiceInteractionPrefs() {
+  if (ProfileManager::GetActiveUserProfile()->GetPrefs()->GetBoolean(
+          prefs::kVoiceInteractionPrefSynced)) {
+    return;
+  }
+  mojom::VoiceInteractionFrameworkInstance* framework_instance =
+      ARC_GET_INSTANCE_FOR_METHOD(
+          arc_bridge_service_->voice_interaction_framework(),
+          GetVoiceInteractionSettings);
+  if (!framework_instance)
+    return;
+  framework_instance->GetVoiceInteractionSettings(
+      base::Bind(&SetVoiceInteractionPrefs));
+}
+
 void ArcVoiceInteractionFrameworkService::StartSessionFromUserInteraction(
     const gfx::Rect& rect) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -444,6 +489,7 @@
 
   if (!arc_bridge_service_->voice_interaction_framework()->has_instance()) {
     SetArcCpuRestriction(false);
+    is_request_pending_ = true;
     return;
   }
 
diff --git a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.h b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.h
index eba6931..56fe5733 100644
--- a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.h
+++ b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.h
@@ -9,6 +9,8 @@
 
 #include "base/macros.h"
 #include "base/time/time.h"
+#include "chrome/browser/chromeos/arc/arc_session_manager.h"
+#include "components/arc/arc_service.h"
 #include "components/arc/common/voice_interaction_framework.mojom.h"
 #include "components/arc/instance_holder.h"
 #include "components/keyed_service/core/keyed_service.h"
@@ -38,8 +40,8 @@
       public mojom::VoiceInteractionFrameworkHost,
       public ui::AcceleratorTarget,
       public ui::EventHandler,
-      public InstanceHolder<
-          mojom::VoiceInteractionFrameworkInstance>::Observer {
+      public InstanceHolder<mojom::VoiceInteractionFrameworkInstance>::Observer,
+      public ArcSessionManager::Observer {
  public:
   // Returns singleton instance for the given BrowserContext,
   // or nullptr if the browser |context| is not allowed to use ARC.
@@ -76,6 +78,9 @@
   void ShowMetalayer(const base::Closure& closed);
   void HideMetalayer();
 
+  // ArcSessionManager::Observer overrides.
+  void OnArcPlayStoreEnabledChanged(bool enabled) override;
+
   // Starts a voice interaction session after user-initiated interaction.
   // Records a timestamp and sets number of allowed requests to 2 since by
   // design, there will be one request for screenshot and the other for
@@ -102,6 +107,13 @@
   // Start the voice interaction setup wizard in container.
   void StartVoiceInteractionSetupWizard();
 
+  // Updates voice interaction flags. These flags are set only once when ARC
+  // container is enabled.
+  void UpdateVoiceInteractionPrefs();
+
+  // For supporting ArcServiceManager::GetService<T>().
+  static const char kArcServiceName[];
+
  private:
   void SetMetalayerVisibility(bool visible);
 
@@ -115,6 +127,9 @@
   base::Closure metalayer_closed_callback_;
   bool metalayer_enabled_ = false;
 
+  // Whether there is a pending request to start voice interaction.
+  bool is_request_pending_ = false;
+
   // The time when a user initated an interaction.
   base::TimeTicks user_interaction_start_time_;
 
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index 42f3a31..1397e3db 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -553,10 +553,6 @@
     chrome::SetChannel(channel);
 #endif
 
-  // Start monitoring OOM kills.
-  memory_kills_monitor_ = base::MakeUnique<memory::MemoryKillsMonitor::Handle>(
-      memory::MemoryKillsMonitor::StartMonitoring());
-
   ChromeBrowserMainPartsLinux::PreEarlyInitialization();
 }
 
@@ -584,6 +580,9 @@
 
   dbus_services_.reset(new internal::DBusServices(parameters()));
 
+  // Need to be done after LoginState has been initialized in DBusServices().
+  memory_kills_monitor_ = memory::MemoryKillsMonitor::Initialize();
+
   ChromeBrowserMainPartsLinux::PostMainMessageLoopStart();
 }
 
diff --git a/chrome/browser/chromeos/locale_change_guard_unittest.cc b/chrome/browser/chromeos/locale_change_guard_unittest.cc
index 736340a9..a7c02802 100644
--- a/chrome/browser/chromeos/locale_change_guard_unittest.cc
+++ b/chrome/browser/chromeos/locale_change_guard_unittest.cc
@@ -53,6 +53,7 @@
     "haw",  // Hawaiian
     "he",   // Hebrew
     "hi",   // Hindi
+    "hmn",  // Hmong
     "hr",   // Croatian
     "hu",   // Hungarian
     "hy",   // Armenian
@@ -60,7 +61,7 @@
     "id",   // Indonesian
     "is",   // Icelandic
     "ja",   // Japanese
-    "jw",   // Javanese
+    "jv",   // Javanese
     "ka",   // Georgian
     "kk",   // Kazakh
     "km",   // Cambodian
@@ -69,6 +70,7 @@
     "ku",   // Kurdish
     "ky",   // Kyrgyz
     "la",   // Latin
+    "lb",   // Luxembourgish
     "ln",   // Lingala
     "lo",   // Laothian
     "lt",   // Lithuanian
@@ -101,6 +103,7 @@
     "si",   // Sinhalese
     "sk",   // Slovak
     "sl",   // Slovenian
+    "sm",   // Samoan
     "sn",   // Shona
     "so",   // Somali
     "sq",   // Albanian
diff --git a/chrome/browser/chromeos/login/signin/merge_session_navigation_throttle.cc b/chrome/browser/chromeos/login/signin/merge_session_navigation_throttle.cc
index 4f76f10b0..34907522 100644
--- a/chrome/browser/chromeos/login/signin/merge_session_navigation_throttle.cc
+++ b/chrome/browser/chromeos/login/signin/merge_session_navigation_throttle.cc
@@ -51,5 +51,5 @@
 
 void MergeSessionNavigationThrottle::OnBlockingPageComplete() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  navigation_handle()->Resume();
+  Resume();
 }
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_creation_browsertest.cc b/chrome/browser/chromeos/login/supervised/supervised_user_creation_browsertest.cc
index 4c5a1bb..5137172 100644
--- a/chrome/browser/chromeos/login/supervised/supervised_user_creation_browsertest.cc
+++ b/chrome/browser/chromeos/login/supervised/supervised_user_creation_browsertest.cc
@@ -5,8 +5,8 @@
 #include <string>
 
 #include "ash/system/status_area_widget.h"
+#include "ash/system/status_area_widget_test_helper.h"
 #include "ash/system/web_notification/web_notification_tray.h"
-#include "ash/test/status_area_widget_test_helper.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
diff --git a/chrome/browser/chromeos/net/network_state_notifier.cc b/chrome/browser/chromeos/net/network_state_notifier.cc
index ce2fc793..4d78006 100644
--- a/chrome/browser/chromeos/net/network_state_notifier.cc
+++ b/chrome/browser/chromeos/net/network_state_notifier.cc
@@ -83,6 +83,31 @@
           ash::system_notifier::kNotifierNetworkError, callback));
 }
 
+bool ShouldConnectFailedNotificationBeShown(const std::string& error_name,
+                                            const NetworkState* network_state) {
+  // Only show a notification for certain errors. Other failures are expected
+  // to be handled by the UI that initiated the connect request.
+  // Note: kErrorConnectFailed may also cause the configure dialog to be
+  // displayed, but we rely on the notification system to show additional
+  // details if available.
+  if (error_name != NetworkConnectionHandler::kErrorConnectFailed &&
+      error_name != NetworkConnectionHandler::kErrorNotFound &&
+      error_name != NetworkConnectionHandler::kErrorConfigureFailed &&
+      error_name != NetworkConnectionHandler::kErrorCertLoadTimeout) {
+    return false;
+  }
+
+  // When a connection to a Tether network fails, the Tether component shows its
+  // own error notification. If this is the case, there is no need to show an
+  // additional notification for the failure to connect to the underlying Wi-Fi
+  // network.
+  if (network_state && !network_state->tether_guid().empty())
+    return false;
+
+  // Otherwise, the connection failed notification should be shown.
+  return true;
+}
+
 }  // namespace
 
 const char NetworkStateNotifier::kNetworkConnectNotificationId[] =
@@ -127,18 +152,11 @@
 
 void NetworkStateNotifier::ConnectFailed(const std::string& service_path,
                                          const std::string& error_name) {
-  // Only show a notification for certain errors. Other failures are expected
-  // to be handled by the UI that initiated the connect request.
-  // Note: kErrorConnectFailed may also cause the configure dialog to be
-  // displayed, but we rely on the notification system to show additional
-  // details if available.
-  if (error_name != NetworkConnectionHandler::kErrorConnectFailed &&
-      error_name != NetworkConnectionHandler::kErrorNotFound &&
-      error_name != NetworkConnectionHandler::kErrorConfigureFailed &&
-      error_name != NetworkConnectionHandler::kErrorCertLoadTimeout) {
-    return;
-  }
-  ShowNetworkConnectError(error_name, service_path);
+  const NetworkState* network =
+      NetworkHandler::Get()->network_state_handler()->GetNetworkState(
+          service_path);
+  if (ShouldConnectFailedNotificationBeShown(error_name, network))
+    ShowNetworkConnectError(error_name, service_path);
 }
 
 void NetworkStateNotifier::DisconnectRequested(
diff --git a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
index 7f0ad07..bad1bfa 100644
--- a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
+++ b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
@@ -20,6 +20,7 @@
 #include "base/task_runner_util.h"
 #include "base/task_scheduler/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/printing/cups_print_job.h"
 #include "chrome/browser/chromeos/printing/synced_printers_manager.h"
@@ -59,6 +60,16 @@
   RESULT_MAX
 };
 
+// Container for results from CUPS queries.
+struct QueryResult {
+  QueryResult() = default;
+  QueryResult(const QueryResult& other) = default;
+  ~QueryResult() = default;
+
+  bool success;
+  std::vector<::printing::QueueStatus> queues;
+};
+
 // Returns the appropriate JobResultForHistogram for a given |state|.  Only
 // FINISHED and PRINTER_CANCEL are derived from CupsPrintJob::State.
 JobResultForHistogram ResultForHistogram(State state) {
@@ -208,15 +219,6 @@
 
 namespace chromeos {
 
-struct QueryResult {
-  QueryResult() = default;
-  QueryResult(const QueryResult& other) = default;
-  ~QueryResult() = default;
-
-  bool success;
-  std::vector<::printing::QueueStatus> queues;
-};
-
 // A wrapper around the CUPS connection to ensure that it's always accessed on
 // the same sequence.
 class CupsWrapper {
@@ -274,6 +276,8 @@
         cups_wrapper_(new CupsWrapper(),
                       base::OnTaskRunnerDeleter(query_runner_)),
         weak_ptr_factory_(this) {
+    timer_.SetTaskRunner(content::BrowserThread::GetTaskRunnerForThread(
+        content::BrowserThread::UI));
     registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT,
                    content::NotificationService::AllSources());
   }
@@ -364,29 +368,22 @@
     job->set_state(CupsPrintJob::State::STATE_WAITING);
     NotifyJobUpdated(job);
 
-    ScheduleQuery(base::TimeDelta());
+    // Run a query now.
+    content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI)
+        ->PostTask(FROM_HERE, base::Bind(&CupsPrintJobManagerImpl::PostQuery,
+                                         weak_ptr_factory_.GetWeakPtr()));
+    // Start the timer for ongoing queries.
+    ScheduleQuery();
 
     return true;
   }
 
-  // Schedule a query of CUPS for print job status with the default delay.
-  void ScheduleQuery() {
-    ScheduleQuery(base::TimeDelta::FromMilliseconds(kPollRate));
-  }
-
   // Schedule a query of CUPS for print job status with a delay of |delay|.
-  void ScheduleQuery(const base::TimeDelta& delay) {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
-    if (!in_query_) {
-      in_query_ = true;
-
-      content::BrowserThread::PostDelayedTask(
-          content::BrowserThread::UI, FROM_HERE,
-          base::Bind(&CupsPrintJobManagerImpl::PostQuery,
-                     weak_ptr_factory_.GetWeakPtr()),
-          delay);
-    }
+  void ScheduleQuery(int attempt_count = 1) {
+    const int delay_ms = kPollRate * attempt_count;
+    timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(delay_ms),
+                 base::Bind(&CupsPrintJobManagerImpl::PostQuery,
+                            weak_ptr_factory_.GetWeakPtr()));
   }
 
   // Schedule the CUPS query off the UI thread. Posts results back to UI thread
@@ -420,11 +417,6 @@
   void UpdateJobs(std::unique_ptr<QueryResult> result) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-    const std::vector<::printing::QueueStatus>& queues = result->queues;
-
-    // Query has completed.  Allow more queries.
-    in_query_ = false;
-
     // If the query failed, either retry or purge.
     if (!result->success) {
       retry_count_++;
@@ -432,12 +424,12 @@
                    << retry_count_ << ")";
       if (retry_count_ > kRetryMax) {
         LOG(ERROR) << "CUPS is unreachable.  Giving up on all jobs.";
+        timer_.Stop();
         PurgeJobs();
       } else {
-        // Schedule another query with a larger delay.
+        // Backoff the polling frequency. Give CUPS a chance to recover.
         DCHECK_GE(1, retry_count_);
-        ScheduleQuery(
-            base::TimeDelta::FromMilliseconds(kPollRate * retry_count_));
+        ScheduleQuery(retry_count_);
       }
       return;
     }
@@ -446,7 +438,7 @@
     retry_count_ = 0;
 
     std::vector<std::string> active_jobs;
-    for (const auto& queue : queues) {
+    for (const auto& queue : result->queues) {
       for (auto& job : queue.jobs) {
         std::string key = CupsPrintJob::GetUniqueId(job.printer_id, job.id);
         const auto& entry = jobs_.find(key);
@@ -475,15 +467,15 @@
       }
     }
 
-    // Keep polling until all jobs complete or error.
-    if (!active_jobs.empty()) {
-      // During normal operations, we poll at the default rate.
-      ScheduleQuery();
-    } else if (!jobs_.empty()) {
-      // We're tracking jobs that we didn't receive an update for.  Something
-      // bad has happened.
-      LOG(ERROR) << "Lost track of (" << jobs_.size() << ") jobs";
-      PurgeJobs();
+    if (active_jobs.empty()) {
+      // CUPS has stopped reporting jobs.  Stop polling.
+      timer_.Stop();
+      if (!jobs_.empty()) {
+        // We're tracking jobs that we didn't receive an update for.  Something
+        // bad has happened.
+        LOG(ERROR) << "Lost track of (" << jobs_.size() << ") jobs";
+        PurgeJobs();
+      }
     }
   }
 
@@ -540,12 +532,10 @@
   // Ongoing print jobs.
   std::map<std::string, std::unique_ptr<CupsPrintJob>> jobs_;
 
-  // Prevents multiple queries from being scheduled simultaneously.
-  bool in_query_ = false;
-
   // Records the number of consecutive times the GetJobs query has failed.
   int retry_count_ = 0;
 
+  base::RepeatingTimer timer_;
   content::NotificationRegistrar registrar_;
   // Task runner for queries to CUPS.
   scoped_refptr<base::SequencedTaskRunner> query_runner_;
diff --git a/chrome/browser/chromeos/printing/doc/README.md b/chrome/browser/chromeos/printing/doc/README.md
new file mode 100644
index 0000000..4a4fe09
--- /dev/null
+++ b/chrome/browser/chromeos/printing/doc/README.md
@@ -0,0 +1,23 @@
+# ChromeOS Printing
+
+This directory contains browser-side code for printing infrastructure in
+ChromeOS.  This directory primarily contains code dealing with local printing
+via the Common Unix Printing System (CUPS), *not* Cloud Print.
+
+## Other Related Directories
+
+(Paths are given from the git root):
+
+* `chromeos/printing/` - ChromeOS CUPS printing code that doesn't have
+  dependencies that require it to live in chrome/browser.
+* `chrome/browser/ui/webui/settings/chromeos/` - ChromeOS printing settings
+  dialog backend support
+* `chrome/browser/resources/settings/printing_page/` - Front end printer
+  settings code.
+* `chrome/browser/printing/` - Cloud print support, and common print dialog
+  support.
+
+## Printing Docs
+
+* [Cups Printer Management](cups_printer_management.md) - Overview of how CUPS
+  printers are managed in ChromeOS.
diff --git a/chrome/browser/chromeos/printing/doc/cups_printer_management.md b/chrome/browser/chromeos/printing/doc/cups_printer_management.md
new file mode 100644
index 0000000..7a093ea
--- /dev/null
+++ b/chrome/browser/chromeos/printing/doc/cups_printer_management.md
@@ -0,0 +1,158 @@
+# CUPS Printer Management in ChromeOS
+
+One of the goals of CUPS printing in ChromeOS is to provide as smooth an
+experience as possible to users who wish to print to CUPS printers.  This means
+we want to avoid extra setup steps where they are not necessary, and provide
+help to the user when setup steps are necessary.  This document covers several
+different ways we might discover printers, and how they integrate into the
+printing flows.
+
+Note that this doc is, at present, a design for the future instead of a
+description of the status quo.  For up-to-date information on the implementation
+refer to http://crbug.com/742487.
+
+## Categorizing printers
+The fact that CUPS supports many printing modalities means that we have a
+mishmash of ways we could print.  Within ChromeOS, we divide CUPS printers into
+4 categories:
+
+*  *Configured* printers - These are printers that are saved as a part of a users'
+   settings and are synced across devices.  They show up in the list of printers
+   in printer settings.
+
+*  *Enterprise* printers - Printers that are provided by an enterprise
+   environment.  These are synced one-way to ChromeOS devices.  If you work for
+   a company/attend a school using ChromeOS, these are the printers that your
+   administrator set up for you ahead of time.  (These are currently called
+   "Recommended" printers in some APIs).
+
+*  *Automatic* printers - Printers that this user has never printed to, but we
+   believe the user *could* print to without needing to go through any manual
+   setup steps.  Examples include Zeroconf printers and USB printers that either
+   do not need a PPD or for which we have identified with high confidence an
+   available PPD that can be installed if the user wants to print to this
+   device.  If a user uses one of these printers, we automatically migrate it to
+   be a Configured printer, as the user has shown that this is a printer of
+   interest to them.
+
+*  *Discovered* printers - Printers that have been detected, but that we believe
+   will need user intervention to set up properly.  Examples would be an
+   advertised zeroconf printer that can't be identified, or an unknown USB
+   printer.
+
+
+The flow of printers through theses states is illustrated here:
+![Printer Flow Chart](printer_flow_chart.png)
+
+In terms of usage, the categories combine in these ways:
+
+*Automatic* and *Discovered* printers appear in the settings Discovery dialog as
+available printers to be added.
+
+*Configured* printers appear in the list of printers in the settings dialog. The
+plan of record is that we do *not* support user-configurability for *Enterprise*
+printers, which means these will either not appear in settings, or appear there
+in an uneditable way.
+
+*Configured*, *Enterprise*, and *Automatic* printers appear in the print preview
+dialog as available targets for printing.
+
+
+## Code structure
+
+### CupsPrintersManager
+
+Defined in `chome/browser/chromeos/printing/cups_printers_manager.[cc|h]`.
+
+The `CupsPrintersManager` class is the top-level object responsible for
+providing information about available printers of all 4 types to all consumers.
+It is instantiated on demand, and is not intended to be a long-lived structure;
+it should be destroyed when its immediate usefulness is complete.
+
+It provides this information both via an Observer interface, for consumers that
+require live updates to changes in availability, and also via a simpler "Give me
+all the printers of this type" interface for simpler consumers that just need to
+know the state of the world at a given point in time.  `CupsPrinterManager` is
+also where the logic to determine whether a given detected printer is
+automatically configurable (and this belongs in the *Automatic* category) or not
+(and thus belongs in the *Discovered* category).
+
+There are 4 primary consumers of `CupsPrintersManager` information:
+
+* The ChromeOS Print Backend implementation
+  (`printing/backend/print_backend_chromeos.cc`).  This is the ChromeOS
+  implementation of the backend print API used by Chrome.
+* The PrintPreview dialog proxy
+  (`chrome/browser/ui/webui/print_preview/printer_backend_proxy_chromeos.cc`).
+  This is mostly a thread workaround to access the stuff in the print backend.
+* The ChromeOS printers settings
+  page. (`chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc`
+  and related code).  This is the primary place the user manages available
+  printers.
+* `CupsPrintJobManager`.  Requires printer information for the display and
+  management of print job notifications.
+
+Currently the needs of these sites are served by a combination of
+`PrintersManager` and direct access to `Detector` classes.  Going forward, we
+should make `CupsPrintersManager` the combined interface used by all of these
+sites.
+
+### SyncedPrintersManager
+
+`SyncedPrintersManager` (nee `PrintersManager`) is a KeyedService Defined in
+`chome/browser/chromeos/printing/printers_sync_manager.[cc|h]`.
+`SyncedPrintersManager` manages the persistent data about printers that is
+synced across devices.  It serves as a two-way bridge between the sync systems
+and `CupsPrintersManager` for both Configured and Enterprise printers.
+Essentially, when the user changes their Configured printers list,
+`SyncedPrintersManager` is what makes sure that propagates upstream, and when
+changes from upstream come in, `SyncedPrintersManager` is responsible for
+notifying `CupsPrintersManager` of the changes.
+
+`SyncedPrintersManager` carries the additional responsibility for caching which
+print destinations have been created in CUPS in the current session.  CrOS
+differs from most CUPS installations in that configuration information lives in
+the user profile, and is only made available to CUPS as needed.  In other words,
+when a user wants to print, at that point Chrome tells CUPS to create the
+relevant print queue, if needed.  Print queues don’t persist across logins, and
+are recreated as needed.
+
+Additionally, although recreating the same print queue with the same options is
+theoretically a null operation, cupsd can get somewhat unhappy if you attempt to
+create the same destination too many times quickly.  Thus, we need to cache
+which destinations have been created in the current session.
+
+This responsibility is given to `SyncedPrintersManager` because it is the only
+long-lived piece of the printer management system.  (NOTE: Is there any sort of
+session-persistent key-value store that can be used in the browser?  If so, we
+can and should shift this responsibility to `CupsPrintersManager` directly.  It
+appears the KeyedService is the preferred way to do this sort of thing.)
+
+### PrinterDetectors
+
+Defined in `chome/browser/chromeos/printing/printer_detector.h` `PrinterDetector`
+provides an interface implemented by subsystems that can automatically detect
+the existence of printers.
+
+These detections are used in two ways.  First, detected printers that are not
+previously-known Configured printers become either Automatic or Discovered
+printers, depending on whether or not we believe they can be configured
+automatically.
+
+Second, `CupsPrintersManager` uses the detectors to determine whether or not
+certain Configured printers are currently available.  This impacts whether or
+not they appear as print targets in the print UI.
+
+Details for the existing PrinterDetector implementations follow.
+
+#### USBPrinterDetector
+
+Defined in `chome/browser/chromeos/printing/usb_printer_detector.[cc|h]`, this
+interacts with the USB subsystem to turn USB device detection events into
+printers.  Both cold- and hot-plugged printers are supported.
+
+#### ZeroconfPrinterDetector
+
+Defined in `chome/browser/chromeos/printing/zeroconf_printer_detector.[cc|h]`,
+this interacts with the DNS-SD and mDNS systems to detect printers that
+advertise themselves on the local network.
diff --git a/chrome/browser/chromeos/printing/doc/printer_flow_chart.dot b/chrome/browser/chromeos/printing/doc/printer_flow_chart.dot
new file mode 100644
index 0000000..d9dfba0
--- /dev/null
+++ b/chrome/browser/chromeos/printing/doc/printer_flow_chart.dot
@@ -0,0 +1,64 @@
+// This is the source file for printer_flow_chart.svg.
+//
+// If you make changes, update the .png with this command:
+//
+// dot -Tpng printer_flow_chart.dot > printer_flow_chart.png
+
+strict digraph printer_flow {
+	 // Source nodes
+	 newrank=true;
+	 {
+	  rank=same;
+	  NEW_USB_PRINTER [label="A new USB\nprinter appears"];
+	  NEW_ZEROCONF_PRINTER [label="A new zeroconf\nprinter appears"];
+	  NEW_USER_PRINTER [label="User adds\nprinter in settings"];
+	  NEW_ENTERPRISE_PRINTER [label="A new enterprise\nprinter appears"];
+  }	 
+						 
+	// Ending nodes
+	{
+		rank=same;
+		node [shape=doublecircle; margin=0];
+		CONFIGURED_PRINTERS  [label="In CONFIGURED\nprinters list"];		
+		ENTERPRISE_PRINTERS [label="In ENTERPRISE\nprinters list"];
+		AUTOMATIC_PRINTERS [label="In AUTOMATIC\nprinters list"];
+		DISCOVERED_PRINTERS [label="In DISCOVERED\nprinters list"];
+		DELETED [label="Deleted"; margin=.1];
+	}
+
+	AVAILABLE_AS_DISCOVERED [label="Available in settings\ndiscovery dialog";
+                          	rank=2];
+
+	CAN_AUTOCONFIGURE [label="Can be configured\nautomatically?";
+	                   shape=diamond];
+	CAN_AUTOCONFIGURE_YES [label="Yes"];
+	CAN_AUTOCONFIGURE_NO [label="No"];
+
+	USER_PRINTS [label="User prints\nusing printer"];
+	USER_REMOVES_IN_SETTINGS [label="User removes\nin settings"];
+	
+	NEW_USB_PRINTER -> CAN_AUTOCONFIGURE;
+	NEW_ZEROCONF_PRINTER -> CAN_AUTOCONFIGURE;
+	NEW_ENTERPRISE_PRINTER -> ENTERPRISE_PRINTERS;
+
+	CAN_AUTOCONFIGURE -> CAN_AUTOCONFIGURE_YES;
+	CAN_AUTOCONFIGURE -> CAN_AUTOCONFIGURE_NO;
+
+	CAN_AUTOCONFIGURE_YES -> AUTOMATIC_PRINTERS;
+	CAN_AUTOCONFIGURE_NO -> DISCOVERED_PRINTERS;
+
+	AUTOMATIC_PRINTERS -> USER_PRINTS;
+	AUTOMATIC_PRINTERS -> AVAILABLE_AS_DISCOVERED;
+	DISCOVERED_PRINTERS -> AVAILABLE_AS_DISCOVERED;
+
+	AVAILABLE_AS_DISCOVERED -> NEW_USER_PRINTER;
+
+	USER_PRINTS -> CONFIGURED_PRINTERS;
+	NEW_USER_PRINTER -> CONFIGURED_PRINTERS;
+	CONFIGURED_PRINTERS -> USER_REMOVES_IN_SETTINGS;
+	USER_REMOVES_IN_SETTINGS -> NEW_ZEROCONF_PRINTER;
+	USER_REMOVES_IN_SETTINGS -> NEW_USB_PRINTER;
+	USER_REMOVES_IN_SETTINGS -> DELETED;
+}
+	
+	 
\ No newline at end of file
diff --git a/chrome/browser/chromeos/printing/doc/printer_flow_chart.png b/chrome/browser/chromeos/printing/doc/printer_flow_chart.png
new file mode 100644
index 0000000..babdbe962
--- /dev/null
+++ b/chrome/browser/chromeos/printing/doc/printer_flow_chart.png
Binary files differ
diff --git a/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc b/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc
index 9e568913..5b9a145 100644
--- a/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc
+++ b/chrome/browser/chromeos/system/tray_accessibility_browsertest.cc
@@ -6,10 +6,10 @@
 #include "ash/login_status.h"
 #include "ash/magnifier/magnification_controller.h"
 #include "ash/shell.h"
+#include "ash/shell_test_api.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_test_api.h"
 #include "ash/system/tray_accessibility.h"
-#include "ash/test/shell_test_api.h"
 #include "base/callback.h"
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
diff --git a/chrome/browser/content_settings/sound_content_setting_observer.cc b/chrome/browser/content_settings/sound_content_setting_observer.cc
new file mode 100644
index 0000000..5ffd0cc3
--- /dev/null
+++ b/chrome/browser/content_settings/sound_content_setting_observer.cc
@@ -0,0 +1,50 @@
+// Copyright 2017 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/content_settings/sound_content_setting_observer.h"
+
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "content/public/browser/navigation_handle.h"
+
+DEFINE_WEB_CONTENTS_USER_DATA_KEY(SoundContentSettingObserver);
+
+SoundContentSettingObserver::SoundContentSettingObserver(
+    content::WebContents* contents)
+    : content::WebContentsObserver(contents), observer_(this) {
+  host_content_settings_map_ = HostContentSettingsMapFactory::GetForProfile(
+      Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
+  observer_.Add(host_content_settings_map_);
+}
+
+SoundContentSettingObserver::~SoundContentSettingObserver() = default;
+
+void SoundContentSettingObserver::DidFinishNavigation(
+    content::NavigationHandle* navigation_handle) {
+  if (navigation_handle->IsInMainFrame() && navigation_handle->HasCommitted() &&
+      !navigation_handle->IsSameDocument()) {
+    MuteOrUnmuteIfNecessary();
+  }
+}
+
+void SoundContentSettingObserver::OnContentSettingChanged(
+    const ContentSettingsPattern& primary_pattern,
+    const ContentSettingsPattern& secondary_pattern,
+    ContentSettingsType content_type,
+    std::string resource_identifier) {
+  if (content_type == CONTENT_SETTINGS_TYPE_SOUND)
+    MuteOrUnmuteIfNecessary();
+}
+
+void SoundContentSettingObserver::MuteOrUnmuteIfNecessary() {
+  web_contents()->SetAudioMuted(GetCurrentContentSetting() ==
+                                CONTENT_SETTING_BLOCK);
+}
+
+ContentSetting SoundContentSettingObserver::GetCurrentContentSetting() {
+  GURL url = web_contents()->GetLastCommittedURL();
+  return host_content_settings_map_->GetContentSetting(
+      url, url, CONTENT_SETTINGS_TYPE_SOUND, std::string());
+}
diff --git a/chrome/browser/content_settings/sound_content_setting_observer.h b/chrome/browser/content_settings/sound_content_setting_observer.h
new file mode 100644
index 0000000..8590c26
--- /dev/null
+++ b/chrome/browser/content_settings/sound_content_setting_observer.h
@@ -0,0 +1,47 @@
+// Copyright 2017 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_CONTENT_SETTINGS_SOUND_CONTENT_SETTING_OBSERVER_H_
+#define CHROME_BROWSER_CONTENT_SETTINGS_SOUND_CONTENT_SETTING_OBSERVER_H_
+
+#include "base/scoped_observer.h"
+#include "components/content_settings/core/browser/content_settings_observer.h"
+#include "components/content_settings/core/common/content_settings.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+class HostContentSettingsMap;
+
+class SoundContentSettingObserver
+    : public content::WebContentsObserver,
+      public content::WebContentsUserData<SoundContentSettingObserver>,
+      public content_settings::Observer {
+ public:
+  ~SoundContentSettingObserver() override;
+
+  // content::WebContentsObserver implementation.
+  void DidFinishNavigation(
+      content::NavigationHandle* navigation_handle) override;
+
+  // content_settings::Observer implementation.
+  void OnContentSettingChanged(const ContentSettingsPattern& primary_pattern,
+                               const ContentSettingsPattern& secondary_pattern,
+                               ContentSettingsType content_type,
+                               std::string resource_identifier) override;
+
+ private:
+  explicit SoundContentSettingObserver(content::WebContents* web_contents);
+  friend class content::WebContentsUserData<SoundContentSettingObserver>;
+
+  void MuteOrUnmuteIfNecessary();
+  ContentSetting GetCurrentContentSetting();
+
+  HostContentSettingsMap* host_content_settings_map_;
+
+  ScopedObserver<HostContentSettingsMap, content_settings::Observer> observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(SoundContentSettingObserver);
+};
+
+#endif  // CHROME_BROWSER_CONTENT_SETTINGS_SOUND_CONTENT_SETTING_OBSERVER_H_
diff --git a/chrome/browser/content_settings/sound_content_setting_observer_unittest.cc b/chrome/browser/content_settings/sound_content_setting_observer_unittest.cc
new file mode 100644
index 0000000..452ddd0
--- /dev/null
+++ b/chrome/browser/content_settings/sound_content_setting_observer_unittest.cc
@@ -0,0 +1,99 @@
+// Copyright 2017 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/content_settings/sound_content_setting_observer.h"
+
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+constexpr char kURL1[] = "http://google.com";
+constexpr char kURL2[] = "http://youtube.com";
+
+}  // anonymous namespace
+
+class SoundContentSettingObserverTest : public ChromeRenderViewHostTestHarness {
+ public:
+  SoundContentSettingObserverTest() = default;
+  ~SoundContentSettingObserverTest() override = default;
+
+  void SetUp() override {
+    ChromeRenderViewHostTestHarness::SetUp();
+
+    SoundContentSettingObserver::CreateForWebContents(web_contents());
+    host_content_settings_map_ = HostContentSettingsMapFactory::GetForProfile(
+        Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
+
+    NavigateAndCommit(GURL(kURL1));
+  }
+
+ protected:
+  void ChangeSoundContentSettingTo(ContentSetting setting) {
+    GURL url = web_contents()->GetLastCommittedURL();
+    host_content_settings_map_->SetContentSettingDefaultScope(
+        url, url, CONTENT_SETTINGS_TYPE_SOUND, std::string(), setting);
+  }
+
+  void ChangeDefaultSoundContentSettingTo(ContentSetting setting) {
+    host_content_settings_map_->SetDefaultContentSetting(
+        CONTENT_SETTINGS_TYPE_SOUND, setting);
+  }
+
+ private:
+  HostContentSettingsMap* host_content_settings_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(SoundContentSettingObserverTest);
+};
+
+TEST_F(SoundContentSettingObserverTest, AudioMutingUpdatesWithContentSetting) {
+  EXPECT_FALSE(web_contents()->IsAudioMuted());
+
+  // Block site.
+  ChangeSoundContentSettingTo(CONTENT_SETTING_BLOCK);
+  EXPECT_TRUE(web_contents()->IsAudioMuted());
+
+  // Allow site.
+  ChangeSoundContentSettingTo(CONTENT_SETTING_ALLOW);
+  EXPECT_FALSE(web_contents()->IsAudioMuted());
+
+  // Set site to default.
+  ChangeSoundContentSettingTo(CONTENT_SETTING_DEFAULT);
+  EXPECT_FALSE(web_contents()->IsAudioMuted());
+
+  // Block by default.
+  ChangeDefaultSoundContentSettingTo(CONTENT_SETTING_BLOCK);
+  EXPECT_TRUE(web_contents()->IsAudioMuted());
+
+  // Should not affect site if explicitly allowed.
+  ChangeSoundContentSettingTo(CONTENT_SETTING_ALLOW);
+  EXPECT_FALSE(web_contents()->IsAudioMuted());
+
+  // Change site back to default.
+  ChangeSoundContentSettingTo(CONTENT_SETTING_DEFAULT);
+  EXPECT_TRUE(web_contents()->IsAudioMuted());
+
+  // Allow by default.
+  ChangeDefaultSoundContentSettingTo(CONTENT_SETTING_ALLOW);
+  EXPECT_FALSE(web_contents()->IsAudioMuted());
+}
+
+TEST_F(SoundContentSettingObserverTest, AudioMutingUpdatesWithNavigation) {
+  EXPECT_FALSE(web_contents()->IsAudioMuted());
+
+  // Block for kURL1.
+  ChangeSoundContentSettingTo(CONTENT_SETTING_BLOCK);
+  EXPECT_TRUE(web_contents()->IsAudioMuted());
+
+  // Should not be muted for kURL2.
+  NavigateAndCommit(GURL(kURL2));
+  EXPECT_FALSE(web_contents()->IsAudioMuted());
+
+  // Should be muted for kURL1.
+  NavigateAndCommit(GURL(kURL1));
+  EXPECT_TRUE(web_contents()->IsAudioMuted());
+}
diff --git a/chrome/browser/download/download_target_determiner.cc b/chrome/browser/download/download_target_determiner.cc
index 9a32c252..43bbb3a 100644
--- a/chrome/browser/download/download_target_determiner.cc
+++ b/chrome/browser/download/download_target_determiner.cc
@@ -11,6 +11,7 @@
 #include "base/rand_util.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
+#include "base/task_runner_util.h"
 #include "base/task_scheduler/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
@@ -559,8 +560,11 @@
     return CONTINUE;
   }
 
-  base::PostTaskWithTraitsAndReplyWithResult(
-      FROM_HERE, {base::MayBlock()}, base::Bind(&::IsAdobeReaderUpToDate),
+  // IsAdobeReaderUpToDate() needs to be run with COM as it makes COM calls via
+  // AssocQueryString() in IsAdobeReaderDefaultPDFViewer().
+  base::PostTaskAndReplyWithResult(
+      base::CreateCOMSTATaskRunnerWithTraits({base::MayBlock()}).get(),
+      FROM_HERE, base::Bind(&::IsAdobeReaderUpToDate),
       base::Bind(&DownloadTargetDeterminer::DetermineIfAdobeReaderUpToDateDone,
                  weak_ptr_factory_.GetWeakPtr()));
   return QUIT_DOLOOP;
diff --git a/chrome/browser/chrome_browser_main_extra_parts_exo.cc b/chrome/browser/exo_parts.cc
similarity index 87%
rename from chrome/browser/chrome_browser_main_extra_parts_exo.cc
rename to chrome/browser/exo_parts.cc
index 4927bbd..6e6f5d7 100644
--- a/chrome/browser/chrome_browser_main_extra_parts_exo.cc
+++ b/chrome/browser/exo_parts.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 "chrome/browser/chrome_browser_main_extra_parts_exo.h"
+#include "chrome/browser/exo_parts.h"
 
 #include "base/memory/ptr_util.h"
 
@@ -12,6 +12,7 @@
 
 #include "base/command_line.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "chrome/browser/ui/ash/ash_util.h"
 #include "chrome/common/chrome_switches.h"
@@ -56,7 +57,7 @@
 
 }  // namespace
 
-class ChromeBrowserMainExtraPartsExo::WaylandWatcher {
+class ExoParts::WaylandWatcher {
  public:
   explicit WaylandWatcher(exo::wayland::Server* server)
       : wayland_poll_(new GPollFD),
@@ -87,8 +88,7 @@
   DISALLOW_COPY_AND_ASSIGN(WaylandWatcher);
 };
 #else
-class ChromeBrowserMainExtraPartsExo::WaylandWatcher
-    : public base::MessagePumpLibevent::Watcher {
+class ExoParts::WaylandWatcher : public base::MessagePumpLibevent::Watcher {
  public:
   explicit WaylandWatcher(exo::wayland::Server* server)
       : controller_(FROM_HERE), server_(server) {
@@ -113,15 +113,24 @@
 };
 #endif
 
-ChromeBrowserMainExtraPartsExo::ChromeBrowserMainExtraPartsExo() {}
-
-ChromeBrowserMainExtraPartsExo::~ChromeBrowserMainExtraPartsExo() {}
-
-void ChromeBrowserMainExtraPartsExo::PreProfileInit() {
+// static
+std::unique_ptr<ExoParts> ExoParts::CreateIfNecessary() {
   if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kEnableWaylandServer))
-    return;
+          switches::kEnableWaylandServer)) {
+    return nullptr;
+  }
 
+  return base::WrapUnique(new ExoParts());
+}
+
+ExoParts::~ExoParts() {
+  wayland_watcher_.reset();
+  wayland_server_.reset();
+  exo::WMHelper::SetInstance(nullptr);
+  wm_helper_.reset();
+}
+
+ExoParts::ExoParts() {
   arc_notification_surface_manager_ =
       base::MakeUnique<arc::ArcNotificationSurfaceManagerImpl>();
   if (ash_util::IsRunningInMash())
@@ -136,12 +145,3 @@
   if (wayland_server_)
     wayland_watcher_ = base::MakeUnique<WaylandWatcher>(wayland_server_.get());
 }
-
-void ChromeBrowserMainExtraPartsExo::PostMainMessageLoopRun() {
-  wayland_watcher_.reset();
-  wayland_server_.reset();
-  if (wm_helper_) {
-    exo::WMHelper::SetInstance(nullptr);
-    wm_helper_.reset();
-  }
-}
diff --git a/chrome/browser/exo_parts.h b/chrome/browser/exo_parts.h
new file mode 100644
index 0000000..5c34364
--- /dev/null
+++ b/chrome/browser/exo_parts.h
@@ -0,0 +1,45 @@
+// 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.
+
+#ifndef CHROME_BROWSER_EXO_PARTS_H_
+#define CHROME_BROWSER_EXO_PARTS_H_
+
+#include <memory>
+
+#include "base/macros.h"
+
+namespace exo {
+class Display;
+class WMHelper;
+namespace wayland {
+class Server;
+}
+}  // namespace exo
+
+namespace arc {
+class ArcNotificationSurfaceManagerImpl;
+}
+
+class ExoParts {
+ public:
+  // Creates ExoParts. Returns null if exo should not be created.
+  static std::unique_ptr<ExoParts> CreateIfNecessary();
+
+  ~ExoParts();
+
+ private:
+  ExoParts();
+
+  std::unique_ptr<arc::ArcNotificationSurfaceManagerImpl>
+      arc_notification_surface_manager_;
+  std::unique_ptr<exo::WMHelper> wm_helper_;
+  std::unique_ptr<exo::Display> display_;
+  std::unique_ptr<exo::wayland::Server> wayland_server_;
+  class WaylandWatcher;
+  std::unique_ptr<WaylandWatcher> wayland_watcher_;
+
+  DISALLOW_COPY_AND_ASSIGN(ExoParts);
+};
+
+#endif  // CHROME_BROWSER_EXO_PARTS_H_
diff --git a/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc b/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc
index 2519c77..182858b9 100644
--- a/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc
+++ b/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc
@@ -69,12 +69,12 @@
 void FrameNavigationState::StartTrackingDocumentLoad(
     content::RenderFrameHost* frame_host,
     const GURL& url,
-    bool is_same_page,
+    bool is_same_document,
     bool is_error_page) {
   FrameState& frame_state = frame_host_state_map_[frame_host];
   frame_state.error_occurred = is_error_page;
   frame_state.url = url;
-  if (!is_same_page) {
+  if (!is_same_document) {
     frame_state.is_loading = true;
     frame_state.is_parsing = true;
   }
diff --git a/chrome/browser/extensions/api/web_navigation/frame_navigation_state.h b/chrome/browser/extensions/api/web_navigation/frame_navigation_state.h
index 97de022..22d1248e 100644
--- a/chrome/browser/extensions/api/web_navigation/frame_navigation_state.h
+++ b/chrome/browser/extensions/api/web_navigation/frame_navigation_state.h
@@ -41,7 +41,7 @@
   // Starts to track a document load in |frame_host| to |url|.
   void StartTrackingDocumentLoad(content::RenderFrameHost* frame_host,
                                  const GURL& url,
-                                 bool is_same_page,
+                                 bool is_same_document,
                                  bool is_error_page);
 
   // Adds the |frame_host| to the set of RenderFrameHosts associated with the
diff --git a/chrome/browser/extensions/content_script_apitest.cc b/chrome/browser/extensions/content_script_apitest.cc
index 242b99dd..5f761322 100644
--- a/chrome/browser/extensions/content_script_apitest.cc
+++ b/chrome/browser/extensions/content_script_apitest.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_with_management_policy_apitest.h"
 #include "chrome/browser/extensions/test_extension_dir.h"
+#include "chrome/browser/search/search.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/javascript_dialogs/javascript_dialog_tab_helper.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -622,6 +623,46 @@
   EXPECT_FALSE(content_script_listener.was_satisfied());
 }
 
+IN_PROC_BROWSER_TEST_P(ContentScriptApiTest, CannotScriptTheNewTabPage) {
+  ASSERT_TRUE(StartEmbeddedTestServer());
+
+  ExtensionTestMessageListener test_listener("ready", true);
+  LoadExtension(test_data_dir_.AppendASCII("content_scripts/ntp"));
+  ASSERT_TRUE(test_listener.WaitUntilSatisfied());
+
+  auto did_script_inject = [](content::WebContents* web_contents) {
+    bool did_inject = false;
+    EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+        web_contents,
+        "domAutomationController.send(document.title === 'injected');",
+        &did_inject));
+    return did_inject;
+  };
+
+  // First, test the executeScript() method.
+  ResultCatcher catcher;
+  test_listener.Reply(std::string());
+  ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
+  EXPECT_EQ(GURL("chrome://newtab"), browser()
+                                         ->tab_strip_model()
+                                         ->GetActiveWebContents()
+                                         ->GetLastCommittedURL());
+  EXPECT_FALSE(
+      did_script_inject(browser()->tab_strip_model()->GetActiveWebContents()));
+
+  // Next, check content script injection.
+  ui_test_utils::NavigateToURL(browser(), search::GetNewTabPageURL(profile()));
+  EXPECT_FALSE(
+      did_script_inject(browser()->tab_strip_model()->GetActiveWebContents()));
+
+  // The extension should inject on "normal" urls.
+  GURL unprotected_url = embedded_test_server()->GetURL(
+      "example.com", "/extensions/test_file.html");
+  ui_test_utils::NavigateToURL(browser(), unprotected_url);
+  EXPECT_TRUE(
+      did_script_inject(browser()->tab_strip_model()->GetActiveWebContents()));
+}
+
 INSTANTIATE_TEST_CASE_P(
     ContentScriptApiTests,
     ContentScriptApiTest,
diff --git a/chrome/browser/extensions/display_info_provider_chromeos_unittest.cc b/chrome/browser/extensions/display_info_provider_chromeos_unittest.cc
index 16ae823..6c8ca217 100644
--- a/chrome/browser/extensions/display_info_provider_chromeos_unittest.cc
+++ b/chrome/browser/extensions/display_info_provider_chromeos_unittest.cc
@@ -7,9 +7,9 @@
 #include <stdint.h>
 
 #include "ash/display/screen_orientation_controller_chromeos.h"
+#include "ash/display/screen_orientation_controller_test_api.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/screen_orientation_controller_test_api.h"
 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
 #include "base/command_line.h"
 #include "base/macros.h"
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 4ed6b413..dc683cdb 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -1910,7 +1910,8 @@
   for (const auto& extension : *all_extensions) {
     if (!settings->IsPermissionSetAllowed(
             extension.get(),
-            extension->permissions_data()->active_permissions())) {
+            extension->permissions_data()->active_permissions()) &&
+        CanBlockExtension(extension.get())) {
       extensions::PermissionsUpdater(profile()).RemovePermissionsUnsafe(
           extension.get(), *settings->GetBlockedPermissions(extension.get()));
     }
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index e154c55..5572d58 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -3640,6 +3640,45 @@
   EXPECT_TRUE(service()->GetExtensionById(good0, false));
 }
 
+// Tests that active permissions are not revoked from component extensions
+// by policy when the policy is updated. https://crbug.com/746017.
+TEST_F(ExtensionServiceTest, ComponentExtensionWhitelistedPermission) {
+  InitializeEmptyExtensionServiceWithTestingPrefs();
+
+  // Install a component extension.
+  base::FilePath path = data_dir()
+                            .AppendASCII("good")
+                            .AppendASCII("Extensions")
+                            .AppendASCII(good0)
+                            .AppendASCII("1.0.0.0");
+  std::string manifest;
+  ASSERT_TRUE(base::ReadFileToString(path.Append(extensions::kManifestFilename),
+                                     &manifest));
+  service()->component_loader()->Add(manifest, path);
+  service()->Init();
+
+  // Extension should have the "tabs" permission.
+  EXPECT_TRUE(service()
+                  ->GetExtensionById(good0, false)
+                  ->permissions_data()
+                  ->active_permissions()
+                  .HasAPIPermission(extensions::APIPermission::kTab));
+
+  // Component should not lose permissions on policy change.
+  {
+    ManagementPrefUpdater pref(profile_->GetTestingPrefService());
+    pref.AddBlockedPermission(good0, "tabs");
+  }
+
+  service()->OnExtensionManagementSettingsChanged();
+  content::RunAllBlockingPoolTasksUntilIdle();
+  EXPECT_TRUE(service()
+                  ->GetExtensionById(good0, false)
+                  ->permissions_data()
+                  ->active_permissions()
+                  .HasAPIPermission(extensions::APIPermission::kTab));
+}
+
 // Tests that policy-installed extensions are not blacklisted by policy.
 TEST_F(ExtensionServiceTest, PolicyInstalledExtensionsWhitelisted) {
   InitializeEmptyExtensionServiceWithTestingPrefs();
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index 523319e..846af32 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -782,9 +782,37 @@
   return pac_https_url_stripping_enabled_.GetValue();
 }
 
-void IOThread::ConstructSystemRequestContext() {
+void IOThread::SetUpProxyConfigService(
+    net::URLRequestContextBuilderMojo* builder,
+    std::unique_ptr<net::ProxyConfigService> proxy_config_service) const {
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
+
+  // TODO(eroman): Figure out why this doesn't work in single-process mode.
+  // Should be possible now that a private isolate is used.
+  // http://crbug.com/474654
+  if (!command_line.HasSwitch(switches::kWinHttpProxyResolver)) {
+    if (command_line.HasSwitch(switches::kSingleProcess)) {
+      LOG(ERROR) << "Cannot use V8 Proxy resolver in single process mode.";
+    } else {
+      builder->set_mojo_proxy_resolver_factory(
+          ChromeMojoProxyResolverFactory::GetInstance());
+#if defined(OS_CHROMEOS)
+      builder->set_dhcp_fetcher_factory(
+          base::MakeUnique<chromeos::DhcpProxyScriptFetcherFactoryChromeos>());
+#endif
+    }
+  }
+
+  builder->set_pac_quick_check_enabled(WpadQuickCheckEnabled());
+  builder->set_pac_sanitize_url_policy(
+      PacHttpsUrlStrippingEnabled()
+          ? net::ProxyService::SanitizeUrlPolicy::SAFE
+          : net::ProxyService::SanitizeUrlPolicy::UNSAFE);
+  builder->set_proxy_config_service(std::move(proxy_config_service));
+}
+
+void IOThread::ConstructSystemRequestContext() {
   std::unique_ptr<net::URLRequestContextBuilderMojo> builder =
       base::MakeUnique<net::URLRequestContextBuilderMojo>();
 
@@ -823,6 +851,8 @@
 #else
   cert_verifier = net::CertVerifier::CreateDefault();
 #endif
+  const base::CommandLine& command_line =
+      *base::CommandLine::ForCurrentProcess();
   builder->SetCertVerifier(
       content::IgnoreErrorsCertVerifier::MaybeWrapCertVerifier(
           command_line, switches::kUserDataDir, std::move(cert_verifier)));
@@ -840,28 +870,8 @@
 
   builder->set_ct_verifier(std::move(ct_verifier));
 
-  // TODO(eroman): Figure out why this doesn't work in single-process mode.
-  // Should be possible now that a private isolate is used.
-  // http://crbug.com/474654
-  if (!command_line.HasSwitch(switches::kWinHttpProxyResolver)) {
-    if (command_line.HasSwitch(switches::kSingleProcess)) {
-      LOG(ERROR) << "Cannot use V8 Proxy resolver in single process mode.";
-    } else {
-      builder->set_mojo_proxy_resolver_factory(
-          ChromeMojoProxyResolverFactory::GetInstance());
-    }
-  }
-
-  builder->set_pac_quick_check_enabled(WpadQuickCheckEnabled());
-  builder->set_pac_sanitize_url_policy(
-      PacHttpsUrlStrippingEnabled()
-          ? net::ProxyService::SanitizeUrlPolicy::SAFE
-          : net::ProxyService::SanitizeUrlPolicy::UNSAFE);
-#if defined(OS_CHROMEOS)
-  builder->set_dhcp_fetcher_factory(
-      base::MakeUnique<chromeos::DhcpProxyScriptFetcherFactoryChromeos>());
-#endif
-  builder->set_proxy_config_service(std::move(system_proxy_config_service_));
+  SetUpProxyConfigService(builder.get(),
+                          std::move(system_proxy_config_service_));
 
   builder->set_http_network_session_params(session_params_);
 
diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h
index 537d5fe1..bb3dbcc 100644
--- a/chrome/browser/io_thread.h
+++ b/chrome/browser/io_thread.h
@@ -88,6 +88,7 @@
 class RTTAndThroughputEstimatesObserver;
 class SSLConfigService;
 class URLRequestContext;
+class URLRequestContextBuilderMojo;
 class URLRequestContextGetter;
 
 namespace ct {
@@ -229,6 +230,13 @@
   bool WpadQuickCheckEnabled() const;
   bool PacHttpsUrlStrippingEnabled() const;
 
+  // Configures |builder|'s ProxyService to use the specified
+  // |proxy_config_service| and sets a number of proxy-related options based on
+  // prefs, policies, and the command line.
+  void SetUpProxyConfigService(
+      net::URLRequestContextBuilderMojo* builder,
+      std::unique_ptr<net::ProxyConfigService> proxy_config_service) const;
+
  private:
   friend class test::IOThreadPeer;
   friend class chrome::TestingIOThreadState;
diff --git a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
index 8e1a788d..f6e5880 100644
--- a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
+++ b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
@@ -374,6 +374,7 @@
     const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter,
     ResourceType resource_type) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  CHECK(!web_contents_getter.is_null());
   content::WebContents* web_contents = web_contents_getter.Run();
   if (!web_contents)
     return;
@@ -514,15 +515,18 @@
     safe_browsing_->OnResourceRequest(request);
 
   const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
+  // TODO(742370): remove when bug is resolved.
+  CHECK(info);
+  CHECK(!info->GetWebContentsGetterForRequest().is_null());
 
 #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
   // TODO(petewil): Unify the safe browsing request and the metrics observer
   // request if possible so we only have to cross to the main thread once.
   // http://crbug.com/712312.
   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
-                          base::Bind(&NotifyUIThreadOfRequestStarted,
-                                     info->GetWebContentsGetterForRequest(),
-                                     info->GetResourceType()));
+                          base::BindOnce(&NotifyUIThreadOfRequestStarted,
+                                         info->GetWebContentsGetterForRequest(),
+                                         info->GetResourceType()));
 #endif  // BUILDFLAG(ENABLE_OFFLINE_PAGES)
 
   ProfileIOData* io_data = ProfileIOData::FromResourceContext(
diff --git a/chrome/browser/media/router/discovery/dial/dial_service.cc b/chrome/browser/media/router/discovery/dial/dial_service.cc
index 5335738..c1cfa4a 100644
--- a/chrome/browser/media/router/discovery/dial/dial_service.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_service.cc
@@ -163,16 +163,10 @@
 
 }  // namespace
 
-DialServiceImpl::DialSocket::DialSocket(
-    const base::Closure& discovery_request_cb,
-    const base::Callback<void(const DialDeviceData&)>& device_discovered_cb,
-    const base::Closure& on_error_cb)
-    : discovery_request_cb_(discovery_request_cb),
-      device_discovered_cb_(device_discovered_cb),
-      on_error_cb_(on_error_cb),
-      is_writing_(false),
-      is_reading_(false) {
+DialServiceImpl::DialSocket::DialSocket(DialServiceImpl* dial_service)
+    : is_writing_(false), is_reading_(false), dial_service_(dial_service) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK(dial_service_);
 }
 
 DialServiceImpl::DialSocket::~DialSocket() {
@@ -243,7 +237,7 @@
     Close();
     std::string error_str(net::ErrorToString(result));
     VLOG(1) << "dial socket error: " << error_str;
-    on_error_cb_.Run();
+    dial_service_->NotifyOnError();
     return false;
   }
   return true;
@@ -266,7 +260,7 @@
     VLOG(1) << "Sent " << result << " chars, expected " << send_buffer_size
             << " chars";
   }
-  discovery_request_cb_.Run();
+  dial_service_->NotifyOnDiscoveryRequest();
 }
 
 bool DialServiceImpl::DialSocket::ReadSocket() {
@@ -328,7 +322,7 @@
   // Attempt to parse response, notify observers if successful.
   DialDeviceData parsed_device;
   if (ParseResponse(response, response_time, &parsed_device))
-    device_discovered_cb_.Run(parsed_device);
+    dial_service_->NotifyOnDeviceDiscovered(parsed_device);
 }
 
 // static
@@ -398,8 +392,7 @@
                                                 kDialRequestIntervalMillis) +
                     TimeDelta::FromSeconds(kDialResponseTimeoutSecs)),
       request_interval_(
-          TimeDelta::FromMilliseconds(kDialRequestIntervalMillis)),
-      weak_factory_(this) {
+          TimeDelta::FromMilliseconds(kDialRequestIntervalMillis)) {
   IPAddress address;
   bool success = address.AssignFromIPLiteral(kDialRequestAddress);
   DCHECK(success);
@@ -453,16 +446,17 @@
 #if defined(OS_CHROMEOS)
   auto task_runner =
       content::BrowserThread::GetTaskRunnerForThread(BrowserThread::UI);
-  base::PostTaskAndReplyWithResult(
+  task_tracker_.PostTaskAndReplyWithResult(
       task_runner.get(), FROM_HERE,
       base::BindOnce(&GetBestBindAddressOnUIThread),
       base::BindOnce(&DialServiceImpl::DiscoverOnAddresses,
-                     weak_factory_.GetWeakPtr()));
+                     base::Unretained(this)));
 #else
-  base::PostTaskWithTraitsAndReplyWithResult(
-      FROM_HERE, {base::MayBlock()}, base::BindOnce(&GetNetworkList),
+  auto task_runner = base::CreateTaskRunnerWithTraits({base::MayBlock()});
+  task_tracker_.PostTaskAndReplyWithResult(
+      task_runner.get(), FROM_HERE, base::BindOnce(&GetNetworkList),
       base::BindOnce(&DialServiceImpl::SendNetworkList,
-                     weak_factory_.GetWeakPtr()));
+                     base::Unretained(this)));
 #endif
 }
 
@@ -537,12 +531,7 @@
 
 std::unique_ptr<DialServiceImpl::DialSocket>
 DialServiceImpl::CreateDialSocket() {
-  return base::MakeUnique<DialServiceImpl::DialSocket>(
-      base::Bind(&DialServiceImpl::NotifyOnDiscoveryRequest,
-                 weak_factory_.GetWeakPtr()),
-      base::Bind(&DialServiceImpl::NotifyOnDeviceDiscovered,
-                 weak_factory_.GetWeakPtr()),
-      base::Bind(&DialServiceImpl::NotifyOnError, weak_factory_.GetWeakPtr()));
+  return base::MakeUnique<DialServiceImpl::DialSocket>(this);
 }
 
 void DialServiceImpl::SendOneRequest() {
diff --git a/chrome/browser/media/router/discovery/dial/dial_service.h b/chrome/browser/media/router/discovery/dial/dial_service.h
index 11935d7..de210557 100644
--- a/chrome/browser/media/router/discovery/dial/dial_service.h
+++ b/chrome/browser/media/router/discovery/dial/dial_service.h
@@ -11,8 +11,8 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
-#include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
+#include "base/task/cancelable_task_tracker.h"
 #include "base/timer/timer.h"
 #include "net/base/ip_address.h"
 #include "net/log/net_log_source.h"
@@ -111,13 +111,7 @@
   // DialSocket lives on the IO thread.
   class DialSocket {
    public:
-    // TODO(imcheng): Consider writing a DialSocket::Delegate interface that
-    // declares methods for these callbacks, and taking a ptr to the delegate
-    // here.
-    DialSocket(
-        const base::Closure& discovery_request_cb,
-        const base::Callback<void(const DialDeviceData&)>& device_discovered_cb,
-        const base::Closure& on_error_cb);
+    explicit DialSocket(DialServiceImpl* dial_service);
     ~DialSocket();
 
     // Creates a socket using |net_log| and |net_log_source| and binds it to
@@ -135,6 +129,11 @@
     bool IsClosed();
 
    private:
+    FRIEND_TEST_ALL_PREFIXES(DialServiceTest, TestNotifyOnError);
+    FRIEND_TEST_ALL_PREFIXES(DialServiceTest, TestOnDeviceDiscovered);
+    FRIEND_TEST_ALL_PREFIXES(DialServiceTest, TestOnDiscoveryRequest);
+    FRIEND_TEST_ALL_PREFIXES(DialServiceTest, TestResponseParsing);
+
     // Checks the result of a socket operation.  The name of the socket
     // operation is given by |operation| and the result of the operation is
     // given by |result|. If the result is an error, closes the socket,
@@ -174,25 +173,15 @@
     // The source of of the last socket read.
     net::IPEndPoint recv_address_;
 
-    // The callback to be invoked when a discovery request was made.
-    base::Closure discovery_request_cb_;
-
-    // The callback to be invoked when a device has been discovered.
-    base::Callback<void(const DialDeviceData&)> device_discovered_cb_;
-
-    // The callback to be invoked when there is an error with socket operations.
-    base::Closure on_error_cb_;
-
     // Marks whether there is an active write callback.
     bool is_writing_;
 
     // Marks whether there is an active read callback.
     bool is_reading_;
 
-    FRIEND_TEST_ALL_PREFIXES(DialServiceTest, TestNotifyOnError);
-    FRIEND_TEST_ALL_PREFIXES(DialServiceTest, TestOnDeviceDiscovered);
-    FRIEND_TEST_ALL_PREFIXES(DialServiceTest, TestOnDiscoveryRequest);
-    FRIEND_TEST_ALL_PREFIXES(DialServiceTest, TestResponseParsing);
+    // Pointer to the DialServiceImpl that owns this socket.
+    DialServiceImpl* const dial_service_;
+
     DISALLOW_COPY_AND_ASSIGN(DialSocket);
   };
 
@@ -277,7 +266,7 @@
   // List of observers.
   base::ObserverList<Observer> observer_list_;
 
-  base::WeakPtrFactory<DialServiceImpl> weak_factory_;
+  base::CancelableTaskTracker task_tracker_;
 
   friend class DialServiceTest;
   FRIEND_TEST_ALL_PREFIXES(DialServiceTest, TestSendMultipleRequests);
diff --git a/chrome/browser/media/router/discovery/dial/dial_service_unittest.cc b/chrome/browser/media/router/discovery/dial/dial_service_unittest.cc
index a90112f..045ee4b8 100644
--- a/chrome/browser/media/router/discovery/dial/dial_service_unittest.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_service_unittest.cc
@@ -15,6 +15,7 @@
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "net/base/ip_address.h"
 #include "net/base/ip_endpoint.h"
+#include "net/base/net_errors.h"
 #include "net/base/network_interfaces.h"
 #include "net/log/test_net_log.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -129,6 +130,12 @@
   dial_socket_->OnSocketWrite(num_bytes, num_bytes);
 }
 
+TEST_F(DialServiceTest, TestNotifyOnError) {
+  EXPECT_CALL(mock_observer_, OnError(A<DialService*>(),
+                                      DialService::DIAL_SERVICE_NO_INTERFACES));
+  dial_socket_->OnSocketWrite(0, net::ERR_CONNECTION_REFUSED);
+}
+
 TEST_F(DialServiceTest, TestOnDeviceDiscovered) {
   dial_service_.discovery_active_ = true;
   int response_size = arraysize(kValidResponse) - 1;
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_unittest.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_unittest.cc
index 963a24e..9a22f31 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_unittest.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_unittest.cc
@@ -194,11 +194,13 @@
   // Add dns services.
   DnsSdRegistry::DnsSdServiceList service_list{service1, service2};
 
-  cast_channel::CastSocket::OnOpenCallback callback1;
-  cast_channel::CastSocket::OnOpenCallback callback2;
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket(ip_endpoint1, _, _, _))
+  cast_channel::MockCastSocket::MockOnOpenCallback callback1;
+  cast_channel::MockCastSocket::MockOnOpenCallback callback2;
+  EXPECT_CALL(*mock_cast_socket_service_,
+              OpenSocketInternal(ip_endpoint1, _, _, _))
       .WillOnce(DoAll(SaveArg<2>(&callback1), Return(1)));
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket(ip_endpoint2, _, _, _))
+  EXPECT_CALL(*mock_cast_socket_service_,
+              OpenSocketInternal(ip_endpoint2, _, _, _))
       .WillOnce(DoAll(SaveArg<2>(&callback2), Return(2)));
 
   // Invoke CastSocketService::OpenSocket on the IO thread.
@@ -236,8 +238,10 @@
   media_sink_service_->OnDnsSdEvent(CastMediaSinkService::kCastServiceType,
                                     service_list1);
 
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket(ip_endpoint1, _, _, _));
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket(ip_endpoint2, _, _, _));
+  EXPECT_CALL(*mock_cast_socket_service_,
+              OpenSocketInternal(ip_endpoint1, _, _, _));
+  EXPECT_CALL(*mock_cast_socket_service_,
+              OpenSocketInternal(ip_endpoint2, _, _, _));
   base::RunLoop().RunUntilIdle();
 
   // Channel 2 opened.
@@ -248,8 +252,10 @@
   media_sink_service_->OnDnsSdEvent(CastMediaSinkService::kCastServiceType,
                                     service_list2);
 
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket(ip_endpoint2, _, _, _));
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket(ip_endpoint3, _, _, _));
+  EXPECT_CALL(*mock_cast_socket_service_,
+              OpenSocketInternal(ip_endpoint2, _, _, _));
+  EXPECT_CALL(*mock_cast_socket_service_,
+              OpenSocketInternal(ip_endpoint3, _, _, _));
   base::RunLoop().RunUntilIdle();
 
   // Channel 1 and 3 opened.
@@ -273,8 +279,10 @@
   media_sink_service_->OnDnsSdEvent(CastMediaSinkService::kCastServiceType,
                                     service_list1);
 
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket(ip_endpoint1, _, _, _));
-  EXPECT_CALL(*mock_cast_socket_service_, OpenSocket(ip_endpoint2, _, _, _));
+  EXPECT_CALL(*mock_cast_socket_service_,
+              OpenSocketInternal(ip_endpoint1, _, _, _));
+  EXPECT_CALL(*mock_cast_socket_service_,
+              OpenSocketInternal(ip_endpoint2, _, _, _));
   base::RunLoop().RunUntilIdle();
 
   // Channel 2 is opened.
diff --git a/chrome/browser/memory/memory_kills_monitor.cc b/chrome/browser/memory/memory_kills_monitor.cc
index 9e6da116..e9b989d 100644
--- a/chrome/browser/memory/memory_kills_monitor.cc
+++ b/chrome/browser/memory/memory_kills_monitor.cc
@@ -9,6 +9,8 @@
 #include <inttypes.h>
 #include <stdio.h>
 
+#include <fstream>
+#include <ios>
 #include <string>
 #include <vector>
 
@@ -27,8 +29,9 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/synchronization/atomic_flag.h"
-#include "base/time/time.h"
+#include "base/threading/platform_thread.h"
 #include "chrome/browser/memory/memory_kills_histogram.h"
+#include "content/public/browser/browser_thread.h"
 #include "third_party/re2/src/re2/re2.h"
 
 namespace memory {
@@ -38,6 +41,9 @@
 
 namespace {
 
+base::LazyInstance<MemoryKillsMonitor>::Leaky g_instance =
+    LAZY_INSTANCE_INITIALIZER;
+
 int64_t GetTimestamp(const std::string& line) {
   std::vector<std::string> fields = base::SplitString(
       line, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
@@ -53,9 +59,169 @@
   VLOG(1) << time_stamp.ToJavaTime() << ", " << event;
 }
 
-void LogOOMKill(int64_t time_stamp, int oom_badness) {
-  static int64_t last_kill_time = -1;
-  static int oom_kills = 0;
+}  // namespace
+
+MemoryKillsMonitor::Handle::Handle(MemoryKillsMonitor* outer) : outer_(outer) {
+  DCHECK(outer_);
+}
+
+MemoryKillsMonitor::Handle::~Handle() {
+  if (outer_) {
+    VLOG(2) << "Chrome is shutting down" << outer_;
+    outer_->is_shutting_down_.Set();
+  }
+}
+
+MemoryKillsMonitor::MemoryKillsMonitor()
+    : low_memory_kills_count_(0),
+      last_oom_kill_time_(-1),
+      oom_kills_count_(0) {}
+
+MemoryKillsMonitor::~MemoryKillsMonitor() {
+  // The instance has to be leaked on shutdown as it is referred to by a
+  // non-joinable thread but ~MemoryKillsMonitor() can't be explicitly deleted
+  // as it overrides ~SimpleThread(), it should nevertheless never be invoked.
+  NOTREACHED();
+}
+
+// static
+std::unique_ptr<MemoryKillsMonitor::Handle> MemoryKillsMonitor::Initialize() {
+  VLOG(2) << "MemoryKillsMonitor::Initializing on "
+          << base::PlatformThread::CurrentId();
+
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  auto* login_state = chromeos::LoginState::Get();
+  if (login_state)
+    login_state->AddObserver(g_instance.Pointer());
+  else
+    LOG(ERROR) << "LoginState is not initialized";
+
+  // The MemoryKillsMonitor::Handle will notify the MemoryKillsMonitor
+  // when it is destroyed so that the underlying thread can at a minimum not
+  // do extra work during shutdown.
+  return base::MakeUnique<Handle>(g_instance.Pointer());
+}
+
+// static
+void MemoryKillsMonitor::LogLowMemoryKill(
+    const std::string& type, int estimated_freed_kb) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  g_instance.Get().LogLowMemoryKillImpl(type, estimated_freed_kb);
+}
+
+// static
+void MemoryKillsMonitor::TryMatchOomKillLine(const std::string& line) {
+  // Sample OOM log line:
+  // 3,1362,97646497541,-;Out of memory: Kill process 29582 (android.vending)
+  // score 961 or sacrifice child.
+  int oom_badness;
+  if (RE2::PartialMatch(line,
+                        "Out of memory: Kill process .* score (\\d+)",
+                        &oom_badness)) {
+    int64_t time_stamp = GetTimestamp(line);
+    g_instance.Get().LogOOMKill(time_stamp, oom_badness);
+  }
+}
+
+// TODO(cylee): Consider adding a unit test for this fuction.
+void MemoryKillsMonitor::Run() {
+  VLOG(2) << "Started monitoring OOM kills on thread "
+          << base::PlatformThread::CurrentId();
+
+  std::ifstream kmsg_stream("/dev/kmsg", std::ifstream::in);
+  if (kmsg_stream.fail()) {
+    LOG(WARNING) << "Open /dev/kmsg failed: " << base::safe_strerror(errno);
+    return;
+  }
+  // Skip kernel messages prior to the instantiation of this object to avoid
+  // double reporting.
+  // Note: there's a small gap between login the fseek here, and events in that
+  // period will not be recorded.
+  kmsg_stream.seekg(0, std::ios_base::end);
+
+  std::string line;
+  while (std::getline(kmsg_stream, line)) {
+    if (is_shutting_down_.IsSet()) {
+      // Not guaranteed to execute when the process is shutting down,
+      // because the thread might be blocked in fgets().
+      VLOG(1) << "Chrome is shutting down, MemoryKillsMonitor exits.";
+      break;
+    }
+    TryMatchOomKillLine(line);
+  }
+}
+
+void MemoryKillsMonitor::LoggedInStateChanged() {
+  VLOG(2) << "LoggedInStateChanged";
+  auto* login_state = chromeos::LoginState::Get();
+  if (login_state) {
+    // Note: LoginState never fires a notification when logged out.
+    if (login_state->IsUserLoggedIn()) {
+      VLOG(2) << "User logged in";
+      StartMonitoring();
+    }
+  }
+}
+
+void MemoryKillsMonitor::StartMonitoring() {
+  VLOG(2) << "Starting monitor from thread "
+          << base::PlatformThread::CurrentId();
+
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  if (monitoring_started_.IsSet()) {
+    LOG(WARNING) << "Monitoring has been started";
+    return;
+  }
+
+  // Insert a zero kill record at the begining of each login session for easy
+  // comparison to those with non-zero kill sessions.
+  UMA_HISTOGRAM_CUSTOM_COUNTS("Arc.OOMKills.Count", 0, 1, 1000, 1001);
+  UMA_HISTOGRAM_CUSTOM_COUNTS("Arc.LowMemoryKiller.Count", 0, 1, 1000, 1001);
+
+  base::SimpleThread::Options non_joinable_options;
+  non_joinable_options.joinable = false;
+  non_joinable_worker_thread_ = base::MakeUnique<base::DelegateSimpleThread>(
+      this, "memory_kills_monitor", non_joinable_options);
+  non_joinable_worker_thread_->Start();
+  monitoring_started_.Set();
+}
+
+void MemoryKillsMonitor::LogLowMemoryKillImpl(const std::string& type,
+                                              int estimated_freed_kb) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  if (!monitoring_started_.IsSet()) {
+    LOG(WARNING) << "LogLowMemoryKill before monitoring started, "
+                    "skipped this log.";
+    return;
+  }
+
+  base::Time now = base::Time::Now();
+  LogEvent(now, "LOW_MEMORY_KILL_" + type);
+
+  const TimeDelta time_delta = last_low_memory_kill_time_.is_null()
+                                   ? kMaxMemoryKillTimeDelta
+                                   : (now - last_low_memory_kill_time_);
+  UMA_HISTOGRAM_MEMORY_KILL_TIME_INTERVAL("Arc.LowMemoryKiller.TimeDelta",
+                                          time_delta);
+  last_low_memory_kill_time_ = now;
+
+  ++low_memory_kills_count_;
+  UMA_HISTOGRAM_CUSTOM_COUNTS("Arc.LowMemoryKiller.Count",
+                              low_memory_kills_count_, 1, 1000, 1001);
+
+  UMA_HISTOGRAM_MEMORY_KB("Arc.LowMemoryKiller.FreedSize", estimated_freed_kb);
+}
+
+void MemoryKillsMonitor::LogOOMKill(int64_t time_stamp, int oom_badness) {
+  if (!monitoring_started_.IsSet()) {
+    LOG(WARNING) << "LogOOMKill before monitoring started, "
+                    "skipped this log.";
+    return;
+  }
 
   // Ideally the timestamp should be parsed from /dev/kmsg, but the timestamp
   // there is the elapsed time since system boot. So the timestamp |now| used
@@ -63,7 +229,7 @@
   base::Time now = base::Time::Now();
   LogEvent(now, "OOM_KILL");
 
-  ++oom_kills;
+  ++oom_kills_count_;
   // Report the cumulative count of killed process in one login session.
   // For example if there are 3 processes killed, it would report 1 for the
   // first kill, 2 for the second kill, then 3 for the final kill.
@@ -73,7 +239,8 @@
   // terminated brutally so there's no chance to execute a "final" block.
   // More specifically, code outside the main loop of MemoryKillsMonitor::Run()
   // are not guaranteed to be executed.
-  UMA_HISTOGRAM_CUSTOM_COUNTS("Arc.OOMKills.Count", oom_kills, 1, 1000, 1001);
+  UMA_HISTOGRAM_CUSTOM_COUNTS("Arc.OOMKills.Count", oom_kills_count_, 1, 1000,
+                              1001);
 
   // In practice most process has oom_badness < 1000, but
   // strictly speaking the number could be [1, 2000]. What it really
@@ -86,133 +253,19 @@
   if (time_stamp > 0) {
     // Sets to |kMaxMemoryKillTimeDelta| for the first kill event.
     const TimeDelta time_delta =
-        last_kill_time < 0 ? kMaxMemoryKillTimeDelta:
-        TimeDelta::FromMicroseconds(time_stamp - last_kill_time);
+        last_oom_kill_time_ < 0
+            ? kMaxMemoryKillTimeDelta
+            : TimeDelta::FromMicroseconds(time_stamp - last_oom_kill_time_);
 
-    last_kill_time = time_stamp;
+    last_oom_kill_time_ = time_stamp;
 
-    UMA_HISTOGRAM_MEMORY_KILL_TIME_INTERVAL(
-        "Arc.OOMKills.TimeDelta", time_delta);
+    UMA_HISTOGRAM_MEMORY_KILL_TIME_INTERVAL("Arc.OOMKills.TimeDelta",
+                                            time_delta);
   }
 }
 
-}  // namespace
-
-MemoryKillsMonitor::Handle::Handle(MemoryKillsMonitor* outer) : outer_(outer) {
-  DCHECK(outer_);
+MemoryKillsMonitor* MemoryKillsMonitor::GetForTesting() {
+  return g_instance.Pointer();
 }
 
-MemoryKillsMonitor::Handle::Handle(MemoryKillsMonitor::Handle&& other)
-    : outer_(nullptr) {
-  outer_ = other.outer_;
-  other.outer_ = nullptr;
-}
-
-MemoryKillsMonitor::Handle::~Handle() {
-  if (outer_) {
-    VLOG(2) << "Chrome is shutting down" << outer_;
-    outer_->is_shutting_down_.Set();
-  }
-}
-
-MemoryKillsMonitor::MemoryKillsMonitor() {
-  base::SimpleThread::Options non_joinable_options;
-  non_joinable_options.joinable = false;
-  non_joinable_worker_thread_ = base::MakeUnique<base::DelegateSimpleThread>(
-      this, "memory_kills_monitor", non_joinable_options);
-  non_joinable_worker_thread_->Start();
-}
-
-MemoryKillsMonitor::~MemoryKillsMonitor() {
-  // The instance has to be leaked on shutdown as it is referred to by a
-  // non-joinable thread but ~MemoryKillsMonitor() can't be explicitly deleted
-  // as it overrides ~SimpleThread(), it should nevertheless never be invoked.
-  NOTREACHED();
-}
-
-// static
-MemoryKillsMonitor::Handle MemoryKillsMonitor::StartMonitoring() {
-#if DCHECK_IS_ON()
-  static volatile bool monitoring_active = false;
-  DCHECK(!monitoring_active);
-  monitoring_active = true;
-#endif
-
-  // Instantiate the MemoryKillsMonitor and its underlying thread. The
-  // MemoryKillsMonitor itself has to be leaked on shutdown per having a
-  // non-joinable thread associated to its state. The MemoryKillsMonitor::Handle
-  // will notify the MemoryKillsMonitor when it is destroyed so that the
-  // underlying thread can at a minimum not do extra work during shutdown.
-  MemoryKillsMonitor* instance = new MemoryKillsMonitor();
-  ANNOTATE_LEAKING_OBJECT_PTR(instance);
-  return Handle(instance);
-}
-
-// static
-void MemoryKillsMonitor::LogLowMemoryKill(
-    const std::string& type, int estimated_freed_kb) {
-  static base::Time last_kill_time;
-  static int low_memory_kills = 0;
-
-  base::Time now = base::Time::Now();
-  LogEvent(now, "LOW_MEMORY_KILL_" + type);
-
-  const TimeDelta time_delta =
-      last_kill_time.is_null() ?
-      kMaxMemoryKillTimeDelta :
-      (now - last_kill_time);
-  UMA_HISTOGRAM_MEMORY_KILL_TIME_INTERVAL(
-            "Arc.LowMemoryKiller.TimeDelta", time_delta);
-  last_kill_time = now;
-
-  ++low_memory_kills;
-  UMA_HISTOGRAM_CUSTOM_COUNTS(
-      "Arc.LowMemoryKiller.Count", low_memory_kills, 1, 1000, 1001);
-
-  UMA_HISTOGRAM_MEMORY_KB("Arc.LowMemoryKiller.FreedSize",
-                          estimated_freed_kb);
-}
-
-// static
-void MemoryKillsMonitor::TryMatchOomKillLine(const std::string& line) {
-  // Sample OOM log line:
-  // 3,1362,97646497541,-;Out of memory: Kill process 29582 (android.vending)
-  // score 961 or sacrifice child.
-  int oom_badness;
-  TimeDelta time_delta;
-  if (RE2::PartialMatch(line,
-                        "Out of memory: Kill process .* score (\\d+)",
-                        &oom_badness)) {
-    int64_t time_stamp = GetTimestamp(line);
-    LogOOMKill(time_stamp, oom_badness);
-  }
-}
-
-void MemoryKillsMonitor::Run() {
-  VLOG(1) << "MemoryKillsMonitor started";
-  base::ScopedFILE kmsg_handle(
-      base::OpenFile(base::FilePath("/dev/kmsg"), "r"));
-  if (!kmsg_handle) {
-    LOG(WARNING) << "Open /dev/kmsg failed: " << base::safe_strerror(errno);
-    return;
-  }
-  // Skip kernel messages prior to the instantiation of this object to avoid
-  // double reporting.
-  fseek(kmsg_handle.get(), 0, SEEK_END);
-
-  static constexpr int kMaxBufSize = 512;
-  char buf[kMaxBufSize];
-
-  while (fgets(buf, kMaxBufSize, kmsg_handle.get())) {
-    if (is_shutting_down_.IsSet()) {
-      // Not guaranteed to execute when the process is shutting down,
-      // because the thread might be blocked in fgets().
-      VLOG(1) << "Chrome is shutting down, MemoryKillsMonitor exits.";
-      break;
-    }
-    TryMatchOomKillLine(buf);
-  }
-}
-
-
 }  // namespace memory
diff --git a/chrome/browser/memory/memory_kills_monitor.h b/chrome/browser/memory/memory_kills_monitor.h
index 8594f53..ecfa2f1 100644
--- a/chrome/browser/memory/memory_kills_monitor.h
+++ b/chrome/browser/memory/memory_kills_monitor.h
@@ -16,11 +16,14 @@
 #include "base/synchronization/lock.h"
 #include "base/threading/simple_thread.h"
 #include "base/time/time.h"
+#include "chromeos/login/login_state.h"
 
 namespace memory {
 
 // Traces kernel OOM kill events and Low memory kill events (by Chrome
-// TabManager).
+// TabManager). It starts logging when a user has logged in and stopped until
+// the chrome process has ended (usually because of a user log out). Thus it can
+// be deemed as a per user session logger.
 //
 // For OOM kill events, it listens to kernel message (/dev/kmsg) in a blocking
 // manner. It runs in a non-joinable thread in order to avoid blocking shutdown.
@@ -30,48 +33,64 @@
 // For Low memory kills events, chrome calls the single global instance of
 // MemoryKillsMonitor synchronously. Note that it would be from a browser thread
 // other than the listening thread.
-//
-// For every events, it reports to UMA and optionally a local file specified by
-// --memory-kills-log. The log file is useful if we want to analyze low memory
-// kills. If the flag is not given, it won't write to any file.
-class MemoryKillsMonitor : public base::DelegateSimpleThread::Delegate {
+class MemoryKillsMonitor : public base::DelegateSimpleThread::Delegate,
+                           public chromeos::LoginState::Observer {
  public:
-  // A handle representing the MemoryKillsMonitor's lifetime (the monitor itself
-  // can't be destroyed per being a non-joinable Thread).
   class Handle {
    public:
     // Constructs a handle that will flag |outer| as shutting down on
     // destruction.
     explicit Handle(MemoryKillsMonitor* outer);
 
-    Handle(Handle&& handle);
-
     ~Handle();
 
    private:
-    MemoryKillsMonitor* outer_;
+    MemoryKillsMonitor* const outer_;
+
     DISALLOW_COPY_AND_ASSIGN(Handle);
   };
 
-  // Instantiates the MemoryKillsMonitor instance and starts it. This must only
-  // be invoked once per process.
-  static Handle StartMonitoring();
-
-  // Logs a low memory kill event.
-  static void LogLowMemoryKill(const std::string& type, int estimated_freed_kb);
-
- private:
-  FRIEND_TEST_ALL_PREFIXES(MemoryKillsMonitorTest, TryMatchOomKillLine);
-
   MemoryKillsMonitor();
   ~MemoryKillsMonitor() override;
 
-  // Overridden from base::DelegateSimpleThread::Delegate:
-  void Run() override;
+  // Initializes the global instance, but do not start monitoring until user
+  // log in. The caller is responsible for deleting the returned handle to
+  // indicate the end of monitoring.
+  static std::unique_ptr<Handle> Initialize();
+
+  // A convenient function to log a low memory kill event. It only logs events
+  // after StartMonitoring() has been called.
+  static void LogLowMemoryKill(const std::string& type, int estimated_freed_kb);
+
+  // Gets the global instance for unit test.
+  static MemoryKillsMonitor* GetForTesting();
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(MemoryKillsMonitorTest, TestHistograms);
 
   // Try to match a line in kernel message which reports OOM.
   static void TryMatchOomKillLine(const std::string& line);
 
+  // Overridden from base::DelegateSimpleThread::Delegate:
+  void Run() override;
+
+  // LoginState::Observer overrides.
+  void LoggedInStateChanged() override;
+
+  // Starts a non-joinable thread to monitor OOM kills. This must only
+  // be invoked once per process.
+  void StartMonitoring();
+
+  // Logs low memory kill event.
+  void LogLowMemoryKillImpl(const std::string& type, int estimated_freed_kb);
+
+  // Logs OOM kill event.
+  void LogOOMKill(int64_t time_stamp, int oom_badness);
+
+  // A flag set when StartMonitoring() is called to indicate that monitoring has
+  // been started.
+  base::AtomicFlag monitoring_started_;
+
   // A flag set when MemoryKillsMonitor is shutdown so that its thread can poll
   // it and attempt to wind down from that point (to avoid unnecessary work, not
   // because it blocks shutdown).
@@ -81,6 +100,19 @@
   // shutdown.
   std::unique_ptr<base::DelegateSimpleThread> non_joinable_worker_thread_;
 
+  // The last time a low memory kill happens. Accessed from UI thread only.
+  base::Time last_low_memory_kill_time_;
+  // The number of low memory kills since monitoring is started. Accessed from
+  // UI thread only.
+  int low_memory_kills_count_;
+
+  // The last time an OOM kill happens. Accessed from
+  // |non_joinable_worker_thread_| only.
+  int64_t last_oom_kill_time_;
+  // The number of OOM kills since monitoring is started. Accessed from
+  // |non_joinable_worker_thread_| only.
+  int oom_kills_count_;
+
   DISALLOW_COPY_AND_ASSIGN(MemoryKillsMonitor);
 };
 
diff --git a/chrome/browser/memory/memory_kills_monitor_unittest.cc b/chrome/browser/memory/memory_kills_monitor_unittest.cc
index 6d32a694..09990cb0 100644
--- a/chrome/browser/memory/memory_kills_monitor_unittest.cc
+++ b/chrome/browser/memory/memory_kills_monitor_unittest.cc
@@ -10,49 +10,103 @@
 #include "base/metrics/statistics_recorder.h"
 #include "base/time/time.h"
 #include "chrome/browser/memory/memory_kills_histogram.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace memory {
 
-using MemoryKillsMonitorTest = testing::Test;
+namespace {
 
-TEST_F(MemoryKillsMonitorTest, LogLowMemoryKill) {
+base::HistogramBase* GetLowMemoryKillsCountHistogram() {
+  return base::StatisticsRecorder::FindHistogram("Arc.LowMemoryKiller.Count");
+}
+
+base::HistogramBase* GetOOMKillsCountHistogram() {
+  return base::StatisticsRecorder::FindHistogram("Arc.OOMKills.Count");
+}
+
+}  // namespace.
+
+class MemoryKillsMonitorTest : public testing::Test {
+ private:
+  content::TestBrowserThreadBundle test_browser_thread_bundle_;
+};
+
+TEST_F(MemoryKillsMonitorTest, TestHistograms) {
+  std::unique_ptr<base::StatisticsRecorder> statistic_recorder(
+      base::StatisticsRecorder::CreateTemporaryForTesting());
+
+  MemoryKillsMonitor* g_instance = MemoryKillsMonitor::GetForTesting();
+
   MemoryKillsMonitor::LogLowMemoryKill("APP", 123);
   MemoryKillsMonitor::LogLowMemoryKill("APP", 100);
   MemoryKillsMonitor::LogLowMemoryKill("TAB", 10000);
 
-  auto* histogram_count =
-      base::StatisticsRecorder::FindHistogram("Arc.LowMemoryKiller.Count");
-  ASSERT_TRUE(histogram_count);
-  auto count_samples = histogram_count->SnapshotSamples();
-  EXPECT_EQ(3, count_samples->TotalCount());
-  EXPECT_EQ(1, count_samples->GetCount(1));
-  EXPECT_EQ(1, count_samples->GetCount(2));
-  EXPECT_EQ(1, count_samples->GetCount(3));
+  auto* lmk_count_histogram = GetLowMemoryKillsCountHistogram();
+  auto* oom_count_histogram = GetOOMKillsCountHistogram();
+  // Before StartMonitoring() is called, nothing is recorded.
+  ASSERT_FALSE(lmk_count_histogram);
+  ASSERT_FALSE(oom_count_histogram);
 
-  auto* histogram_freed_size =
-      base::StatisticsRecorder::FindHistogram("Arc.LowMemoryKiller.FreedSize");
-  ASSERT_TRUE(histogram_freed_size);
-  auto freed_size_samples = histogram_freed_size->SnapshotSamples();
-  EXPECT_EQ(3, freed_size_samples->TotalCount());
-  // 123 and 100 are in the same bucket.
-  EXPECT_EQ(2, freed_size_samples->GetCount(123));
-  EXPECT_EQ(2, freed_size_samples->GetCount(100));
-  EXPECT_EQ(1, freed_size_samples->GetCount(10000));
+  // Start monitoring.
+  g_instance->StartMonitoring();
+  lmk_count_histogram = GetLowMemoryKillsCountHistogram();
+  oom_count_histogram = GetOOMKillsCountHistogram();
+  ASSERT_TRUE(lmk_count_histogram);
+  ASSERT_TRUE(oom_count_histogram);
+  {
+    auto count_samples = lmk_count_histogram->SnapshotSamples();
+    EXPECT_EQ(1, count_samples->TotalCount());
+    EXPECT_EQ(1, count_samples->GetCount(0));
+  }
+  {
+    auto count_samples = oom_count_histogram->SnapshotSamples();
+    EXPECT_EQ(1, count_samples->TotalCount());
+    EXPECT_EQ(1, count_samples->GetCount(0));
+  }
 
-  auto* histogram_time_delta =
-      base::StatisticsRecorder::FindHistogram("Arc.LowMemoryKiller.TimeDelta");
-  ASSERT_TRUE(histogram_time_delta);
-  auto time_delta_samples = histogram_time_delta->SnapshotSamples();
-  EXPECT_EQ(3, time_delta_samples->TotalCount());
-  // First time delta is set to kMaxMemoryKillTimeDelta.
-  EXPECT_EQ(1, time_delta_samples->GetCount(
-      kMaxMemoryKillTimeDelta.InMilliseconds()));
-  // Time delta for the other 2 events depends on Now() so we skip testing it
-  // here.
-}
+  // Low memory kills.
+  MemoryKillsMonitor::LogLowMemoryKill("APP", 123);
+  MemoryKillsMonitor::LogLowMemoryKill("APP", 100);
+  MemoryKillsMonitor::LogLowMemoryKill("TAB", 10000);
+  lmk_count_histogram = GetLowMemoryKillsCountHistogram();
+  ASSERT_TRUE(lmk_count_histogram);
+  {
+    auto count_samples = lmk_count_histogram->SnapshotSamples();
+    EXPECT_EQ(4, count_samples->TotalCount());
+    // The zero count is implicitly added when StartMonitoring() is called.
+    EXPECT_EQ(1, count_samples->GetCount(0));
+    EXPECT_EQ(1, count_samples->GetCount(1));
+    EXPECT_EQ(1, count_samples->GetCount(2));
+    EXPECT_EQ(1, count_samples->GetCount(3));
+  }
 
-TEST_F(MemoryKillsMonitorTest, TryMatchOomKillLine) {
+  {
+    auto* histogram_freed_size = base::StatisticsRecorder::FindHistogram(
+        "Arc.LowMemoryKiller.FreedSize");
+    ASSERT_TRUE(histogram_freed_size);
+    auto freed_size_samples = histogram_freed_size->SnapshotSamples();
+    EXPECT_EQ(3, freed_size_samples->TotalCount());
+    // 123 and 100 are in the same bucket.
+    EXPECT_EQ(2, freed_size_samples->GetCount(123));
+    EXPECT_EQ(2, freed_size_samples->GetCount(100));
+    EXPECT_EQ(1, freed_size_samples->GetCount(10000));
+  }
+
+  {
+    auto* histogram_time_delta = base::StatisticsRecorder::FindHistogram(
+        "Arc.LowMemoryKiller.TimeDelta");
+    ASSERT_TRUE(histogram_time_delta);
+    auto time_delta_samples = histogram_time_delta->SnapshotSamples();
+    EXPECT_EQ(3, time_delta_samples->TotalCount());
+    // First time delta is set to kMaxMemoryKillTimeDelta.
+    EXPECT_EQ(1, time_delta_samples->GetCount(
+                     kMaxMemoryKillTimeDelta.InMilliseconds()));
+    // Time delta for the other 2 events depends on Now() so we skip testing it
+    // here.
+  }
+
+  // OOM kills.
   const char* sample_lines[] = {
       "3,3429,812967386,-;Out of memory: Kill process 8291 (handle-watcher-) "
       "score 674 or sacrifice child",
@@ -66,34 +120,62 @@
     MemoryKillsMonitor::TryMatchOomKillLine(sample_lines[i]);
   }
 
-  auto* histogram_count =
-      base::StatisticsRecorder::FindHistogram("Arc.OOMKills.Count");
-  ASSERT_TRUE(histogram_count);
-  auto count_samples = histogram_count->SnapshotSamples();
-  EXPECT_EQ(3, count_samples->TotalCount());
-  EXPECT_EQ(1, count_samples->GetCount(1));
-  EXPECT_EQ(1, count_samples->GetCount(2));
-  EXPECT_EQ(1, count_samples->GetCount(3));
+  oom_count_histogram = GetOOMKillsCountHistogram();
+  ASSERT_TRUE(oom_count_histogram);
+  {
+    auto count_samples = oom_count_histogram->SnapshotSamples();
+    EXPECT_EQ(4, count_samples->TotalCount());
+    // The zero count is implicitly added when StartMonitoring() is called.
+    EXPECT_EQ(1, count_samples->GetCount(0));
+    EXPECT_EQ(1, count_samples->GetCount(1));
+    EXPECT_EQ(1, count_samples->GetCount(2));
+    EXPECT_EQ(1, count_samples->GetCount(3));
+  }
 
-  auto* histogram_score =
-      base::StatisticsRecorder::FindHistogram("Arc.OOMKills.Score");
-  ASSERT_TRUE(histogram_score);
-  auto score_samples = histogram_score->SnapshotSamples();
-  EXPECT_EQ(3, score_samples->TotalCount());
-  EXPECT_EQ(1, score_samples->GetCount(674));
-  EXPECT_EQ(1, score_samples->GetCount(652));
-  EXPECT_EQ(1, score_samples->GetCount(653));
+  {
+    auto* histogram_score =
+        base::StatisticsRecorder::FindHistogram("Arc.OOMKills.Score");
+    ASSERT_TRUE(histogram_score);
+    auto score_samples = histogram_score->SnapshotSamples();
+    EXPECT_EQ(3, score_samples->TotalCount());
+    EXPECT_EQ(1, score_samples->GetCount(674));
+    EXPECT_EQ(1, score_samples->GetCount(652));
+    EXPECT_EQ(1, score_samples->GetCount(653));
+  }
 
-  auto* histogram_time_delta =
-      base::StatisticsRecorder::FindHistogram("Arc.OOMKills.TimeDelta");
-  ASSERT_TRUE(histogram_time_delta);
-  auto time_delta_samples = histogram_time_delta->SnapshotSamples();
-  EXPECT_EQ(3, time_delta_samples->TotalCount());
-  // First time delta is set to kMaxMemoryKillTimeDelta.
-  EXPECT_EQ(1, time_delta_samples->GetCount(
-      kMaxMemoryKillTimeDelta.InMilliseconds()));
-  EXPECT_EQ(1, time_delta_samples->GetCount(11));
-  EXPECT_EQ(1, time_delta_samples->GetCount(13));
+  {
+    auto* histogram_time_delta =
+        base::StatisticsRecorder::FindHistogram("Arc.OOMKills.TimeDelta");
+    ASSERT_TRUE(histogram_time_delta);
+    auto time_delta_samples = histogram_time_delta->SnapshotSamples();
+    EXPECT_EQ(3, time_delta_samples->TotalCount());
+    // First time delta is set to kMaxMemoryKillTimeDelta.
+    EXPECT_EQ(1, time_delta_samples->GetCount(
+                     kMaxMemoryKillTimeDelta.InMilliseconds()));
+    EXPECT_EQ(1, time_delta_samples->GetCount(11));
+    EXPECT_EQ(1, time_delta_samples->GetCount(13));
+  }
+
+  // Call StartMonitoring multiple times.
+  base::PlatformThreadId tid1 = g_instance->non_joinable_worker_thread_->tid();
+  g_instance->StartMonitoring();
+  base::PlatformThreadId tid2 = g_instance->non_joinable_worker_thread_->tid();
+  EXPECT_EQ(tid1, tid2);
+
+  lmk_count_histogram = GetLowMemoryKillsCountHistogram();
+  ASSERT_TRUE(lmk_count_histogram);
+  {
+    auto count_samples = lmk_count_histogram->SnapshotSamples();
+    // Ensure zero count is not increased.
+    EXPECT_EQ(1, count_samples->GetCount(0));
+  }
+  oom_count_histogram = GetOOMKillsCountHistogram();
+  ASSERT_TRUE(oom_count_histogram);
+  {
+    auto count_samples = oom_count_histogram->SnapshotSamples();
+    // Ensure zero count is not increased.
+    EXPECT_EQ(1, count_samples->GetCount(0));
+  }
 }
 
 }  // namespace memory
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter.cc b/chrome/browser/metrics/process_memory_metrics_emitter.cc
index 620ac406..62cfb48 100644
--- a/chrome/browser/metrics/process_memory_metrics_emitter.cc
+++ b/chrome/browser/metrics/process_memory_metrics_emitter.cc
@@ -43,6 +43,8 @@
   UMA_HISTOGRAM_MEMORY_LARGE_MB(
       "Memory.Experimental.Browser2.PrivateMemoryFootprint",
       pmd->os_dump->private_footprint_kb / 1024);
+  UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Browser.PrivateMemoryFootprint",
+                                pmd->os_dump->private_footprint_kb / 1024);
   TryAddMetric(builder, "PrivateMemoryFootprint",
                pmd->os_dump->private_footprint_kb / 1024);
 }
@@ -64,6 +66,8 @@
   UMA_HISTOGRAM_MEMORY_LARGE_MB(
       "Memory.Experimental.Renderer2.PrivateMemoryFootprint",
       pmd->os_dump->private_footprint_kb / 1024);
+  UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Renderer.PrivateMemoryFootprint",
+                                pmd->os_dump->private_footprint_kb / 1024);
   TryAddMetric(builder, "PrivateMemoryFootprint",
                pmd->os_dump->private_footprint_kb / 1024);
 
@@ -105,6 +109,8 @@
   UMA_HISTOGRAM_MEMORY_LARGE_MB(
       "Memory.Experimental.Gpu2.PrivateMemoryFootprint",
       pmd->os_dump->private_footprint_kb / 1024);
+  UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Gpu.PrivateMemoryFootprint",
+                                pmd->os_dump->private_footprint_kb / 1024);
   TryAddMetric(builder, "PrivateMemoryFootprint",
                pmd->os_dump->private_footprint_kb / 1024);
 }
@@ -180,6 +186,8 @@
   UMA_HISTOGRAM_MEMORY_LARGE_MB(
       "Memory.Experimental.Total2.PrivateMemoryFootprint",
       private_footprint_total_kb / 1024);
+  UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Total.PrivateMemoryFootprint",
+                                private_footprint_total_kb / 1024);
 
   std::unique_ptr<ukm::UkmEntryBuilder> builder =
       CreateUkmBuilder("Memory.Experimental");
diff --git a/chrome/browser/nacl_host/OWNERS b/chrome/browser/nacl_host/OWNERS
index fc1180e..4d29309 100644
--- a/chrome/browser/nacl_host/OWNERS
+++ b/chrome/browser/nacl_host/OWNERS
@@ -1,6 +1,5 @@
 bradnelson@chromium.org
 dschuff@chromium.org
 mseaborn@chromium.org
-sehr@chromium.org
 
 # COMPONENT: Platform>NaCl
diff --git a/chrome/browser/net/proxy_service_factory.cc b/chrome/browser/net/proxy_service_factory.cc
index f53dc2f..17c0e53 100644
--- a/chrome/browser/net/proxy_service_factory.cc
+++ b/chrome/browser/net/proxy_service_factory.cc
@@ -4,31 +4,13 @@
 
 #include "chrome/browser/net/proxy_service_factory.h"
 
-#include <stddef.h>
-#include <string>
-#include <utility>
-
-#include "base/command_line.h"
-#include "base/metrics/field_trial.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/threading/thread.h"
 #include "build/build_config.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/io_thread.h"
-#include "chrome/browser/net/chrome_mojo_proxy_resolver_factory.h"
-#include "chrome/common/chrome_switches.h"
 #include "components/proxy_config/pref_proxy_config_tracker_impl.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/common/content_switches.h"
-#include "net/proxy/dhcp_proxy_script_fetcher_factory.h"
 #include "net/proxy/proxy_config_service.h"
-#include "net/proxy/proxy_script_fetcher_impl.h"
 #include "net/proxy/proxy_service.h"
-#include "net/proxy/proxy_service_mojo.h"
-#include "net/url_request/url_request_context.h"
 
 #if defined(OS_CHROMEOS)
-#include "chromeos/network/dhcp_proxy_script_fetcher_chromeos.h"
 #include "chromeos/network/proxy/proxy_config_service_impl.h"
 #endif  // defined(OS_CHROMEOS)
 
@@ -88,53 +70,3 @@
       BrowserThread::GetTaskRunnerForThread(BrowserThread::IO));
 #endif  // defined(OS_CHROMEOS)
 }
-
-// static
-std::unique_ptr<net::ProxyService> ProxyServiceFactory::CreateProxyService(
-    net::NetLog* net_log,
-    net::URLRequestContext* context,
-    net::NetworkDelegate* network_delegate,
-    std::unique_ptr<net::ProxyConfigService> proxy_config_service,
-    const base::CommandLine& command_line,
-    bool quick_check_enabled,
-    bool pac_https_url_stripping_enabled) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  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.
-  // http://crbug.com/474654
-  if (use_v8 && command_line.HasSwitch(switches::kSingleProcess)) {
-    LOG(ERROR) << "Cannot use V8 Proxy resolver in single process mode.";
-    use_v8 = false;  // Fallback to non-v8 implementation.
-  }
-
-  std::unique_ptr<net::ProxyService> proxy_service;
-  if (use_v8) {
-    std::unique_ptr<net::DhcpProxyScriptFetcher> dhcp_proxy_script_fetcher;
-#if defined(OS_CHROMEOS)
-    dhcp_proxy_script_fetcher.reset(
-        new chromeos::DhcpProxyScriptFetcherChromeos(context));
-#else
-    net::DhcpProxyScriptFetcherFactory dhcp_factory;
-    dhcp_proxy_script_fetcher = dhcp_factory.Create(context);
-#endif
-
-    proxy_service = net::CreateProxyServiceUsingMojoFactory(
-        ChromeMojoProxyResolverFactory::GetInstance(),
-        std::move(proxy_config_service),
-        new net::ProxyScriptFetcherImpl(context),
-        std::move(dhcp_proxy_script_fetcher), context->host_resolver(), net_log,
-        network_delegate);
-  } else {
-    proxy_service = net::ProxyService::CreateUsingSystemProxyResolver(
-        std::move(proxy_config_service), net_log);
-  }
-
-  proxy_service->set_quick_check_enabled(quick_check_enabled);
-  proxy_service->set_sanitize_url_policy(
-      pac_https_url_stripping_enabled
-          ? net::ProxyService::SanitizeUrlPolicy::SAFE
-          : net::ProxyService::SanitizeUrlPolicy::UNSAFE);
-
-  return proxy_service;
-}
diff --git a/chrome/browser/net/proxy_service_factory.h b/chrome/browser/net/proxy_service_factory.h
index aea984f..4bc76b7 100644
--- a/chrome/browser/net/proxy_service_factory.h
+++ b/chrome/browser/net/proxy_service_factory.h
@@ -12,16 +12,8 @@
 class PrefProxyConfigTracker;
 class PrefService;
 
-namespace base {
-class CommandLine;
-}
-
 namespace net {
-class NetLog;
-class NetworkDelegate;
 class ProxyConfigService;
-class ProxyService;
-class URLRequestContext;
 }
 
 class ProxyServiceFactory {
@@ -45,16 +37,6 @@
   static PrefProxyConfigTracker* CreatePrefProxyConfigTrackerOfLocalState(
       PrefService* local_state_prefs);
 
-  // Create a proxy service according to the options on command line.
-  static std::unique_ptr<net::ProxyService> CreateProxyService(
-      net::NetLog* net_log,
-      net::URLRequestContext* context,
-      net::NetworkDelegate* network_delegate,
-      std::unique_ptr<net::ProxyConfigService> proxy_config_service,
-      const base::CommandLine& command_line,
-      bool quick_check_enabled,
-      bool pac_https_url_stripping_enabled);
-
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(ProxyServiceFactory);
 };
diff --git a/chrome/browser/page_load_metrics/experiments/delay_navigation_throttle.cc b/chrome/browser/page_load_metrics/experiments/delay_navigation_throttle.cc
index d83213d..2d6cc4a 100644
--- a/chrome/browser/page_load_metrics/experiments/delay_navigation_throttle.cc
+++ b/chrome/browser/page_load_metrics/experiments/delay_navigation_throttle.cc
@@ -137,5 +137,5 @@
                                         actual_delay);
   }
 
-  navigation_handle()->Resume();
+  Resume();
 }
diff --git a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_unittest.cc
index 73b94614..272261f 100644
--- a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_unittest.cc
@@ -72,9 +72,7 @@
     return "DelayWillProcessResponseThrottle";
   }
 
-  void CancelDeferredNavigation() {
-    navigation_handle()->CancelDeferredNavigation(NavigationThrottle::CANCEL);
-  }
+  void Cancel() { CancelDeferredNavigation(NavigationThrottle::CANCEL); }
 
  private:
   DISALLOW_COPY_AND_ASSIGN(DelayWillProcessResponseThrottle);
@@ -114,7 +112,7 @@
         nullptr /* data_reduction_proxy */, 10 * 1024 /* raw_body_bytes */,
         0 /* original_network_content_length */, base::TimeTicks::Now(), 0);
 
-    throttle_->CancelDeferredNavigation();
+    throttle_->Cancel();
   }
 
  private:
diff --git a/chrome/browser/payments/site_per_process_payments_browsertest.cc b/chrome/browser/payments/site_per_process_payments_browsertest.cc
index 3891334..2e427cdc 100644
--- a/chrome/browser/payments/site_per_process_payments_browsertest.cc
+++ b/chrome/browser/payments/site_per_process_payments_browsertest.cc
@@ -43,7 +43,8 @@
     host_resolver()->AddRule("*", "127.0.0.1");
     ASSERT_TRUE(https_server_->InitializeAndListen());
     content::SetupCrossSiteRedirector(https_server_.get());
-    https_server_->ServeFilesFromSourceDirectory("chrome/test/data/payments");
+    https_server_->ServeFilesFromSourceDirectory(
+        "components/test/data/payments");
     https_server_->StartAcceptingConnections();
   }
 
diff --git a/chrome/browser/profiles/off_the_record_profile_io_data.cc b/chrome/browser/profiles/off_the_record_profile_io_data.cc
index d08c5fe..6909b93 100644
--- a/chrome/browser/profiles/off_the_record_profile_io_data.cc
+++ b/chrome/browser/profiles/off_the_record_profile_io_data.cc
@@ -35,7 +35,8 @@
 #include "net/http/http_server_properties_impl.h"
 #include "net/ssl/channel_id_service.h"
 #include "net/ssl/default_channel_id_store.h"
-#include "net/url_request/url_request_context_storage.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_builder.h"
 #include "net/url_request/url_request_job_factory_impl.h"
 #include "storage/browser/database/database_tracker.h"
 
@@ -192,45 +193,40 @@
 }
 
 void OffTheRecordProfileIOData::InitializeInternal(
+    net::URLRequestContextBuilder* builder,
     ProfileParams* profile_params,
     content::ProtocolHandlerMap* protocol_handlers,
     content::URLRequestInterceptorScopedVector request_interceptors) const {
-  net::URLRequestContext* main_context = main_request_context();
-  net::URLRequestContextStorage* main_context_storage =
-      main_request_context_storage();
-
-  // For incognito, we use the default non-persistent HttpServerPropertiesImpl.
-  main_context_storage->set_http_server_properties(
-      base::MakeUnique<net::HttpServerPropertiesImpl>());
-
   // For incognito, we use a non-persistent channel ID store.
-  main_context_storage->set_channel_id_service(
+  std::unique_ptr<net::ChannelIDService> channel_id_service(
       base::MakeUnique<net::ChannelIDService>(
           new net::DefaultChannelIDStore(nullptr)));
 
   using content::CookieStoreConfig;
-  main_context_storage->set_cookie_store(CreateCookieStore(CookieStoreConfig(
-      base::FilePath(), CookieStoreConfig::EPHEMERAL_SESSION_COOKIES, NULL,
-      profile_params->cookie_monster_delegate.get())));
+  std::unique_ptr<net::CookieStore> cookie_store(
+      CreateCookieStore(CookieStoreConfig(
+          base::FilePath(), CookieStoreConfig::EPHEMERAL_SESSION_COOKIES, NULL,
+          profile_params->cookie_monster_delegate.get())));
+  cookie_store->SetChannelIDServiceID(channel_id_service->GetUniqueID());
 
-  main_context->cookie_store()->SetChannelIDServiceID(
-      main_context->channel_id_service()->GetUniqueID());
+  builder->SetCookieAndChannelIdStores(std::move(cookie_store),
+                                       std::move(channel_id_service));
 
-  main_context_storage->set_http_network_session(
-      CreateHttpNetworkSession(*profile_params));
-  main_context_storage->set_http_transaction_factory(
-      CreateMainHttpFactory(main_context_storage->http_network_session(),
-                            net::HttpCache::DefaultBackend::InMemory(0)));
+  // Create an in memory cache using the default size.
+  net::URLRequestContextBuilder::HttpCacheParams cache_params;
+  cache_params.type = net::URLRequestContextBuilder::HttpCacheParams::IN_MEMORY;
+  builder->EnableHttpCache(cache_params);
 
-  std::unique_ptr<net::URLRequestJobFactoryImpl> main_job_factory(
-      new net::URLRequestJobFactoryImpl());
-
-  InstallProtocolHandlers(main_job_factory.get(), protocol_handlers);
-  main_context_storage->set_job_factory(SetUpJobFactoryDefaults(
-      std::move(main_job_factory), std::move(request_interceptors),
+  AddProtocolHandlersToBuilder(builder, protocol_handlers);
+  SetUpJobFactoryDefaultsForBuilder(
+      builder, std::move(request_interceptors),
       std::move(profile_params->protocol_handler_interceptor),
-      main_context->network_delegate(), main_context->host_resolver()));
+      profile_params->io_thread->globals()
+          ->system_request_context->host_resolver());
+}
 
+void OffTheRecordProfileIOData::OnMainRequestContextCreated(
+    ProfileParams* profile_params) const {
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   InitializeExtensionsRequestContext(profile_params);
 #endif
@@ -272,13 +268,12 @@
   context->SetCookieStore(std::move(cookie_store));
 
   // Build a new HttpNetworkSession that uses the new ChannelIDService.
-  net::HttpNetworkSession::Context session_context =
-      main_request_context_storage()->http_network_session()->context();
+  net::HttpNetworkSession* network_session =
+      main_request_context()->http_transaction_factory()->GetSession();
+  net::HttpNetworkSession::Context session_context = network_session->context();
   session_context.channel_id_service = channel_id_service.get();
   std::unique_ptr<net::HttpNetworkSession> http_network_session(
-      new net::HttpNetworkSession(
-          main_request_context_storage()->http_network_session()->params(),
-          session_context));
+      new net::HttpNetworkSession(network_session->params(), session_context));
 
   // Use a separate in-memory cache for the app.
   std::unique_ptr<net::HttpCache> app_http_cache = CreateMainHttpFactory(
diff --git a/chrome/browser/profiles/off_the_record_profile_io_data.h b/chrome/browser/profiles/off_the_record_profile_io_data.h
index eb287e0..9aeabff7 100644
--- a/chrome/browser/profiles/off_the_record_profile_io_data.h
+++ b/chrome/browser/profiles/off_the_record_profile_io_data.h
@@ -23,6 +23,7 @@
 namespace net {
 class CookieStore;
 class URLRequestContext;
+class URLRequestContextBuilder;
 }  // namespace net
 
 // OffTheRecordProfile owns a OffTheRecordProfileIOData::Handle, which holds a
@@ -107,11 +108,13 @@
   explicit OffTheRecordProfileIOData(Profile::ProfileType profile_type);
   ~OffTheRecordProfileIOData() override;
 
-  void InitializeInternal(
-      ProfileParams* profile_params,
-      content::ProtocolHandlerMap* protocol_handlers,
-      content::URLRequestInterceptorScopedVector request_interceptors)
-      const override;
+  void InitializeInternal(net::URLRequestContextBuilder* builder,
+                          ProfileParams* profile_params,
+                          content::ProtocolHandlerMap* protocol_handlers,
+                          content::URLRequestInterceptorScopedVector
+                              request_interceptors) const override;
+  void OnMainRequestContextCreated(
+      ProfileParams* profile_params) const override;
   void InitializeExtensionsRequestContext(
       ProfileParams* profile_params) const override;
   net::URLRequestContext* InitializeAppRequestContext(
diff --git a/chrome/browser/profiles/profile_impl_io_data.cc b/chrome/browser/profiles/profile_impl_io_data.cc
index e308fd6..61d21fe 100644
--- a/chrome/browser/profiles/profile_impl_io_data.cc
+++ b/chrome/browser/profiles/profile_impl_io_data.cc
@@ -68,7 +68,7 @@
 #include "net/reporting/reporting_policy.h"
 #include "net/reporting/reporting_service.h"
 #include "net/ssl/channel_id_service.h"
-#include "net/url_request/url_request_context_storage.h"
+#include "net/url_request/url_request_context_builder.h"
 #include "net/url_request/url_request_intercepting_job_factory.h"
 #include "net/url_request/url_request_job_factory_impl.h"
 #include "storage/browser/quota/special_storage_policy.h"
@@ -79,7 +79,9 @@
 
 namespace {
 
-net::BackendType ChooseCacheBackendType() {
+// Returns the URLRequestContextBuilder::HttpCacheParams::Type that the disk
+// cache should use.
+net::URLRequestContextBuilder::HttpCacheParams::Type ChooseCacheType() {
 #if !defined(OS_ANDROID)
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
@@ -87,29 +89,48 @@
     const std::string opt_value =
         command_line.GetSwitchValueASCII(switches::kUseSimpleCacheBackend);
     if (base::LowerCaseEqualsASCII(opt_value, "off"))
-      return net::CACHE_BACKEND_BLOCKFILE;
+      return net::URLRequestContextBuilder::HttpCacheParams::DISK_BLOCKFILE;
     if (opt_value.empty() || base::LowerCaseEqualsASCII(opt_value, "on"))
-      return net::CACHE_BACKEND_SIMPLE;
+      return net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE;
   }
   const std::string experiment_name =
       base::FieldTrialList::FindFullName("SimpleCacheTrial");
   if (base::StartsWith(experiment_name, "Disable",
                        base::CompareCase::INSENSITIVE_ASCII)) {
-    return net::CACHE_BACKEND_BLOCKFILE;
+    return net::URLRequestContextBuilder::HttpCacheParams::DISK_BLOCKFILE;
   }
   if (base::StartsWith(experiment_name, "ExperimentYes",
                        base::CompareCase::INSENSITIVE_ASCII)) {
-    return net::CACHE_BACKEND_SIMPLE;
+    return net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE;
   }
 #endif  // #if !defined(OS_ANDROID)
 
 #if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
-  return net::CACHE_BACKEND_SIMPLE;
+  return net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE;
 #else
-  return net::CACHE_BACKEND_BLOCKFILE;
+  return net::URLRequestContextBuilder::HttpCacheParams::DISK_BLOCKFILE;
 #endif
 }
 
+// Returns the BackendType that the disk cache should use.
+// TODO(mmenke): Once all URLRequestContexts are set up using
+// URLRequestContextBuilders, and the media URLRequestContext is take care of
+// (In one way or another), this should be removed.
+net::BackendType ChooseCacheBackendType() {
+  switch (ChooseCacheType()) {
+    case net::URLRequestContextBuilder::HttpCacheParams::DISK_BLOCKFILE:
+      return net::CACHE_BACKEND_BLOCKFILE;
+    case net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE:
+      return net::CACHE_BACKEND_SIMPLE;
+    case net::URLRequestContextBuilder::HttpCacheParams::DISK:
+      return net::CACHE_BACKEND_DEFAULT;
+    case net::URLRequestContextBuilder::HttpCacheParams::IN_MEMORY:
+      NOTREACHED();
+      break;
+  }
+  return net::CACHE_BACKEND_DEFAULT;
+}
+
 }  // namespace
 
 using content::BrowserThread;
@@ -459,23 +480,20 @@
 }
 
 void ProfileImplIOData::InitializeInternal(
+    net::URLRequestContextBuilder* builder,
     ProfileParams* profile_params,
     content::ProtocolHandlerMap* protocol_handlers,
     content::URLRequestInterceptorScopedVector request_interceptors) const {
-  net::URLRequestContext* main_context = main_request_context();
-  net::URLRequestContextStorage* main_context_storage =
-      main_request_context_storage();
-
   IOThread* const io_thread = profile_params->io_thread;
   IOThread::Globals* const io_thread_globals = io_thread->globals();
 
   if (lazy_params_->http_server_properties_manager) {
     lazy_params_->http_server_properties_manager->InitializeOnNetworkSequence();
-    main_context_storage->set_http_server_properties(
+    builder->SetHttpServerProperties(
         std::move(lazy_params_->http_server_properties_manager));
   }
 
-  main_context->set_network_quality_estimator(
+  builder->set_network_quality_estimator(
       io_thread_globals->network_quality_estimator.get());
 
   // Create a single task runner to use with the CookieStore and ChannelIDStore.
@@ -490,7 +508,7 @@
       new QuotaPolicyChannelIDStore(lazy_params_->channel_id_path,
                                     cookie_background_task_runner,
                                     lazy_params_->special_storage_policy.get());
-  main_context_storage->set_channel_id_service(
+  std::unique_ptr<net::ChannelIDService> channel_id_service(
       base::MakeUnique<net::ChannelIDService>(
           new net::DefaultChannelIDStore(channel_id_db.get())));
 
@@ -502,27 +520,25 @@
       lazy_params_->special_storage_policy.get(),
       profile_params->cookie_monster_delegate.get());
   cookie_config.crypto_delegate = cookie_config::GetCookieCryptoDelegate();
-  cookie_config.channel_id_service = main_context->channel_id_service();
+  cookie_config.channel_id_service = channel_id_service.get();
   cookie_config.background_task_runner = cookie_background_task_runner;
-  main_context_storage->set_cookie_store(
+  std::unique_ptr<net::CookieStore> cookie_store(
       content::CreateCookieStore(cookie_config));
 
-  main_context->cookie_store()->SetChannelIDServiceID(
-      main_context->channel_id_service()->GetUniqueID());
+  cookie_store->SetChannelIDServiceID(channel_id_service->GetUniqueID());
 
-  std::unique_ptr<net::HttpCache::BackendFactory> main_backend(
-      new net::HttpCache::DefaultBackend(
-          net::DISK_CACHE, ChooseCacheBackendType(), lazy_params_->cache_path,
-          lazy_params_->cache_max_size,
-          BrowserThread::GetTaskRunnerForThread(BrowserThread::CACHE)));
-  main_context_storage->set_http_network_session(
-      CreateHttpNetworkSession(*profile_params));
-  main_context_storage->set_http_transaction_factory(CreateMainHttpFactory(
-      main_context_storage->http_network_session(), std::move(main_backend)));
+  builder->SetCookieAndChannelIdStores(std::move(cookie_store),
+                                       std::move(channel_id_service));
 
-  std::unique_ptr<net::URLRequestJobFactoryImpl> main_job_factory(
-      new net::URLRequestJobFactoryImpl());
-  InstallProtocolHandlers(main_job_factory.get(), protocol_handlers);
+  net::URLRequestContextBuilder::HttpCacheParams cache_params;
+  cache_params.type = ChooseCacheType();
+  cache_params.path = lazy_params_->cache_path;
+  cache_params.max_size = lazy_params_->cache_max_size;
+  builder->EnableHttpCache(cache_params);
+  builder->SetCacheThreadTaskRunner(
+      BrowserThread::GetTaskRunnerForThread(BrowserThread::CACHE));
+
+  AddProtocolHandlersToBuilder(builder, protocol_handlers);
 
   // Install the Offline Page Interceptor.
 #if defined(OS_ANDROID)
@@ -538,24 +554,27 @@
       data_reduction_proxy_io_data()->CreateInterceptor());
   data_reduction_proxy_io_data()->SetDataUseAscriber(
       io_thread_globals->data_use_ascriber.get());
-  main_context_storage->set_job_factory(SetUpJobFactoryDefaults(
-      std::move(main_job_factory), std::move(request_interceptors),
+  SetUpJobFactoryDefaultsForBuilder(
+      builder, std::move(request_interceptors),
       std::move(profile_params->protocol_handler_interceptor),
-      main_context->network_delegate(),
-      io_thread_globals->system_request_context->host_resolver()));
+      io_thread_globals->system_request_context->host_resolver());
+
+  builder->set_reporting_policy(MaybeCreateReportingPolicy());
+}
+
+void ProfileImplIOData::OnMainRequestContextCreated(
+    ProfileParams* profile_params) const {
+  DCHECK(lazy_params_);
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   InitializeExtensionsRequestContext(profile_params);
 #endif
 
-  main_context_storage->set_reporting_service(
-      MaybeCreateReportingService(main_context));
-
   // Create a media request context based on the main context, but using a
   // media cache.  It shares the same job factory as the main context.
   StoragePartitionDescriptor details(profile_path_, false);
-  media_request_context_.reset(
-      InitializeMediaRequestContext(main_context, details, "main_media"));
+  media_request_context_.reset(InitializeMediaRequestContext(
+      main_request_context(), details, "main_media"));
   lazy_params_.reset();
 }
 
@@ -643,13 +662,12 @@
   // main_request_context_storage() objects and the argumet to this method,
   // |main_context|.  Remove |main_context| as an argument, and just use
   // main_context() instead.
-  net::HttpNetworkSession::Context session_context =
-      main_request_context_storage()->http_network_session()->context();
+  net::HttpNetworkSession* network_session =
+      main_context->http_transaction_factory()->GetSession();
+  net::HttpNetworkSession::Context session_context = network_session->context();
   session_context.channel_id_service = channel_id_service.get();
   std::unique_ptr<net::HttpNetworkSession> http_network_session(
-      new net::HttpNetworkSession(
-          main_request_context_storage()->http_network_session()->params(),
-          session_context));
+      new net::HttpNetworkSession(network_session->params(), session_context));
   std::unique_ptr<net::HttpCache> app_http_cache =
       CreateMainHttpFactory(http_network_session.get(), std::move(app_backend));
 
@@ -771,11 +789,20 @@
 std::unique_ptr<net::ReportingService>
 ProfileImplIOData::MaybeCreateReportingService(
     net::URLRequestContext* url_request_context) const {
-  if (!base::FeatureList::IsEnabled(features::kReporting))
+  std::unique_ptr<net::ReportingPolicy> reporting_policy(
+      MaybeCreateReportingPolicy());
+  if (!reporting_policy)
     return std::unique_ptr<net::ReportingService>();
 
-  return net::ReportingService::Create(net::ReportingPolicy(),
-                                       url_request_context);
+  return net::ReportingService::Create(*reporting_policy, url_request_context);
+}
+
+std::unique_ptr<net::ReportingPolicy>
+ProfileImplIOData::MaybeCreateReportingPolicy() {
+  if (!base::FeatureList::IsEnabled(features::kReporting))
+    return std::unique_ptr<net::ReportingPolicy>();
+
+  return base::MakeUnique<net::ReportingPolicy>();
 }
 
 void ProfileImplIOData::ClearNetworkingHistorySinceOnIOThread(
diff --git a/chrome/browser/profiles/profile_impl_io_data.h b/chrome/browser/profiles/profile_impl_io_data.h
index 6ba3a12..0041436 100644
--- a/chrome/browser/profiles/profile_impl_io_data.h
+++ b/chrome/browser/profiles/profile_impl_io_data.h
@@ -26,6 +26,9 @@
 namespace net {
 class CookieStore;
 class HttpServerPropertiesManager;
+struct ReportingPolicy;
+class ReportingService;
+class URLRequestContextBuilder;
 }  // namespace net
 
 namespace storage {
@@ -161,11 +164,13 @@
       std::unique_ptr<ChromeNetworkDelegate> chrome_network_delegate)
       const override;
 
-  void InitializeInternal(
-      ProfileParams* profile_params,
-      content::ProtocolHandlerMap* protocol_handlers,
-      content::URLRequestInterceptorScopedVector request_interceptors)
-      const override;
+  void InitializeInternal(net::URLRequestContextBuilder* builder,
+                          ProfileParams* profile_params,
+                          content::ProtocolHandlerMap* protocol_handlers,
+                          content::URLRequestInterceptorScopedVector
+                              request_interceptors) const override;
+  void OnMainRequestContextCreated(
+      ProfileParams* profile_params) const override;
   void InitializeExtensionsRequestContext(
       ProfileParams* profile_params) const override;
   net::URLRequestContext* InitializeAppRequestContext(
@@ -194,9 +199,17 @@
       const StoragePartitionDescriptor& partition_descriptor) const override;
   chrome_browser_net::Predictor* GetPredictor() override;
 
+  // Returns a net::ReportingService, if reporting should be enabled. Otherwise,
+  // returns nullptr.
+  // TODO(mmenke): Remove once URLRequestContextBuilders are always used to
+  // create URLRequestContexts.
   std::unique_ptr<net::ReportingService> MaybeCreateReportingService(
       net::URLRequestContext* url_request_context) const;
 
+  // Returns a net::ReportingPolicy, if reporting should be enabled. Otherwise,
+  // returns nullptr.
+  static std::unique_ptr<net::ReportingPolicy> MaybeCreateReportingPolicy();
+
   // Deletes all network related data since |time|. It deletes transport
   // security state since |time| and also deletes HttpServerProperties data.
   // Works asynchronously, however if the |completion| callback is non-null,
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index 95cc04a9..0795a96 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -106,6 +106,7 @@
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_builder.h"
+#include "net/url_request/url_request_context_builder_mojo.h"
 #include "net/url_request/url_request_context_storage.h"
 #include "net/url_request/url_request_file_job.h"
 #include "net/url_request/url_request_intercepting_job_factory.h"
@@ -369,6 +370,15 @@
     chrome_context_getter->NotifyContextShuttingDown();
 }
 
+// Wraps |inner_job_factory| with |protocol_handler_interceptor|.
+std::unique_ptr<net::URLRequestJobFactory> CreateURLRequestJobFactory(
+    std::unique_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>
+        protocol_handler_interceptor,
+    std::unique_ptr<net::URLRequestJobFactory> inner_job_factory) {
+  protocol_handler_interceptor->Chain(std::move(inner_job_factory));
+  return std::move(protocol_handler_interceptor);
+}
+
 }  // namespace
 
 void ProfileIOData::InitializeOnUIThread(Profile* profile) {
@@ -677,20 +687,10 @@
 
     main_request_context_->transport_security_state()->SetRequireCTDelegate(
         nullptr);
-
-    // And the same for the ReportingService.
-    main_request_context_storage()->set_reporting_service(
-        std::unique_ptr<net::ReportingService>());
-
-    // This should be shut down last, as any other requests may initiate more
-    // activity when the ProxyService aborts lookups.
-    main_request_context_->proxy_service()->OnShutdown();
   }
 
   // TODO(ajwong): These AssertNoURLRequests() calls are unnecessary since they
   // are already done in the URLRequestContext destructor.
-  if (main_request_context_)
-    main_request_context_->AssertNoURLRequests();
   if (extensions_request_context_)
     extensions_request_context_->AssertNoURLRequests();
 
@@ -787,6 +787,18 @@
 }
 
 // static
+void ProfileIOData::AddProtocolHandlersToBuilder(
+    net::URLRequestContextBuilder* builder,
+    content::ProtocolHandlerMap* protocol_handlers) {
+  for (auto& protocol_handler : *protocol_handlers) {
+    builder->SetProtocolHandler(
+        protocol_handler.first,
+        base::WrapUnique(protocol_handler.second.release()));
+  }
+  protocol_handlers->clear();
+}
+
+// static
 void ProfileIOData::SetCertVerifierForTesting(
     net::CertVerifier* cert_verifier) {
   g_cert_verifier_for_testing = cert_verifier;
@@ -945,11 +957,12 @@
   // here. Instead, it will inherit its QUIC enablement from IOThread on
   // construction, which is fine, as NetHttpSessionParamsObserver also disables
   // QUIC there.
-  if (!main_request_context_storage_ ||
-      !main_request_context_storage_->http_network_session())
+  if (!main_request_context_)
     return;
 
-  main_request_context_storage_->http_network_session()->DisableQuic();
+  main_request_context_->http_transaction_factory()
+      ->GetSession()
+      ->DisableQuic();
 }
 
 void ProfileIOData::set_data_reduction_proxy_io_data(
@@ -996,23 +1009,21 @@
 
   IOThread* const io_thread = profile_params_->io_thread;
   IOThread::Globals* const io_thread_globals = io_thread->globals();
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
 
   // Create extension request context.  Only used for cookies.
   extensions_request_context_.reset(new net::URLRequestContext());
   extensions_request_context_->set_name("extensions");
 
   // Create the main request context.
-  main_request_context_.reset(new net::URLRequestContext());
-  main_request_context_storage_.reset(
-      new net::URLRequestContextStorage(main_request_context_.get()));
-  main_request_context_->set_name("main");
+  net::URLRequestContextBuilderMojo builder;
+  builder.set_name("main");
 
-  ApplyProfileParamsToContext(main_request_context_.get());
-  main_request_context_->set_net_log(io_thread->net_log());
+  builder.set_net_log(io_thread->net_log());
+  builder.set_shared_http_user_agent_settings(
+      chrome_http_user_agent_settings_.get());
+  builder.set_ssl_config_service(profile_params_->ssl_config_service);
 
-  main_request_context_->set_enable_brotli(io_thread_globals->enable_brotli);
+  builder.set_enable_brotli(io_thread_globals->enable_brotli);
 
   std::unique_ptr<ChromeNetworkDelegate> chrome_network_delegate(
       new ChromeNetworkDelegate(
@@ -1025,7 +1036,8 @@
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   chrome_network_delegate->set_extension_info_map(
       profile_params_->extension_info_map.get());
-  if (!command_line.HasSwitch(switches::kDisableExtensionsHttpThrottling)) {
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisableExtensionsHttpThrottling)) {
     extension_throttle_manager_.reset(
         new extensions::ExtensionThrottleManager());
   }
@@ -1050,33 +1062,19 @@
       ConfigureNetworkDelegate(profile_params_->io_thread,
                                std::move(chrome_network_delegate));
 
-  main_request_context_->set_host_resolver(
+  builder.set_shared_host_resolver(
       io_thread_globals->system_request_context->host_resolver());
 
-  main_request_context_->set_http_auth_handler_factory(
+  builder.set_shared_http_auth_handler_factory(
       io_thread_globals->system_request_context->http_auth_handler_factory());
 
-  main_request_context_storage_->set_proxy_service(
-      ProxyServiceFactory::CreateProxyService(
-          io_thread->net_log(), main_request_context_.get(),
-          network_delegate.get(),
-          std::move(profile_params_->proxy_config_service), command_line,
-          io_thread->WpadQuickCheckEnabled(),
-          io_thread->PacHttpsUrlStrippingEnabled()));
+  io_thread->SetUpProxyConfigService(
+      &builder, std::move(profile_params_->proxy_config_service));
 
-  main_request_context_storage_->set_network_delegate(
-      std::move(network_delegate));
+  builder.set_network_delegate(std::move(network_delegate));
 
-  std::unique_ptr<net::TransportSecurityState> transport_security_state(
-      base::MakeUnique<net::TransportSecurityState>());
-  transport_security_persister_.reset(new net::TransportSecurityPersister(
-      transport_security_state.get(), profile_params_->path,
-      base::CreateSequencedTaskRunnerWithTraits(
-          {base::MayBlock(), base::TaskPriority::BACKGROUND,
-           base::TaskShutdownBehavior::BLOCK_SHUTDOWN}),
-      IsOffTheRecord()));
-  main_request_context_storage_->set_transport_security_state(
-      std::move(transport_security_state));
+  builder.set_transport_security_persister_path(profile_params_->path);
+  builder.set_transport_security_persister_readonly(IsOffTheRecord());
 
   // Take ownership over these parameters.
   cookie_settings_ = profile_params_->cookie_settings;
@@ -1085,10 +1083,6 @@
   extension_info_map_ = profile_params_->extension_info_map;
 #endif
 
-  resource_context_->host_resolver_ =
-      io_thread_globals->system_request_context->host_resolver();
-  resource_context_->request_context_ = main_request_context_.get();
-
   if (profile_params_->loading_predictor_observer_) {
     loading_predictor_observer_ =
         std::move(profile_params_->loading_predictor_observer_);
@@ -1104,7 +1098,7 @@
 #endif
 
   if (g_cert_verifier_for_testing) {
-    main_request_context_->set_cert_verifier(g_cert_verifier_for_testing);
+    builder.set_shared_cert_verifier(g_cert_verifier_for_testing);
   } else {
 #if defined(OS_CHROMEOS)
     crypto::ScopedPK11Slot public_slot =
@@ -1120,9 +1114,9 @@
       cert_verifier_ = base::MakeUnique<net::CachingCertVerifier>(
           base::MakeUnique<net::MultiThreadedCertVerifier>(verify_proc.get()));
     }
-    main_request_context_->set_cert_verifier(cert_verifier_.get());
+    builder.set_shared_cert_verifier(cert_verifier_.get());
 #else
-    main_request_context_->set_cert_verifier(
+    builder.set_shared_cert_verifier(
         io_thread_globals->system_request_context->cert_verifier());
 #endif
   }
@@ -1141,20 +1135,29 @@
       io_thread_globals->ct_logs, io_thread->net_log()));
   ct_verifier->SetObserver(ct_tree_tracker_.get());
 
-  main_request_context_storage_->set_cert_transparency_verifier(
-      std::move(ct_verifier));
+  builder.set_ct_verifier(std::move(ct_verifier));
 
   io_thread->RegisterSTHObserver(ct_tree_tracker_.get());
   ct_tree_tracker_unregistration_ =
       base::Bind(&IOThread::UnregisterSTHObserver, base::Unretained(io_thread),
                  ct_tree_tracker_.get());
 
-  main_request_context_storage_->set_ct_policy_enforcer(
-      base::MakeUnique<net::CTPolicyEnforcer>());
+  builder.set_http_network_session_params(
+      profile_params_->io_thread->NetworkSessionParams());
+  if (data_reduction_proxy_io_data_.get()) {
+    builder.set_shared_proxy_delegate(
+        data_reduction_proxy_io_data_->proxy_delegate());
+  }
 
-  InitializeInternal(profile_params_.get(), protocol_handlers,
+  InitializeInternal(&builder, profile_params_.get(), protocol_handlers,
                      std::move(request_interceptors));
 
+  main_request_context_ = builder.Build();
+
+  // Attach some things to the URLRequestContextBuilder's
+  // TransportSecurityState.  Since no requests have been made yet, safe to do
+  // this even after the call to Build().
+
   net::NetworkTrafficAnnotationTag traffic_annotation =
       net::DefineNetworkTrafficAnnotation("domain_security_policy", R"(
         semantics {
@@ -1196,17 +1199,16 @@
   main_request_context_->transport_security_state()->SetRequireCTDelegate(
       ct_policy_manager_->GetDelegate());
 
+  resource_context_->host_resolver_ =
+      io_thread_globals->system_request_context->host_resolver();
+  resource_context_->request_context_ = main_request_context_.get();
+
+  OnMainRequestContextCreated(profile_params_.get());
+
   profile_params_.reset();
   initialized_ = true;
 }
 
-void ProfileIOData::ApplyProfileParamsToContext(
-    net::URLRequestContext* context) const {
-  context->set_http_user_agent_settings(
-      chrome_http_user_agent_settings_.get());
-  context->set_ssl_config_service(profile_params_->ssl_config_service.get());
-}
-
 std::unique_ptr<net::URLRequestJobFactory>
 ProfileIOData::SetUpJobFactoryDefaults(
     std::unique_ptr<net::URLRequestJobFactoryImpl> job_factory,
@@ -1286,6 +1288,69 @@
   }
 }
 
+void ProfileIOData::SetUpJobFactoryDefaultsForBuilder(
+    net::URLRequestContextBuilder* builder,
+    content::URLRequestInterceptorScopedVector request_interceptors,
+    std::unique_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>
+        protocol_handler_interceptor,
+    net::HostResolver* host_resolver) const {
+  // NOTE(willchan): Keep these protocol handlers in sync with
+  // ProfileIOData::IsHandledProtocol().
+  builder->SetProtocolHandler(
+      url::kFileScheme,
+      base::MakeUnique<net::FileProtocolHandler>(
+          base::CreateTaskRunnerWithTraits(
+              {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
+               base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})));
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+  DCHECK(extension_info_map_.get());
+  // Check only for incognito (and not Chrome OS guest mode GUEST_PROFILE).
+  bool is_incognito = profile_type() == Profile::INCOGNITO_PROFILE;
+  builder->SetProtocolHandler(extensions::kExtensionScheme,
+                              extensions::CreateExtensionProtocolHandler(
+                                  is_incognito, extension_info_map_.get()));
+#endif
+  builder->SetProtocolHandler(url::kDataScheme,
+                              base::MakeUnique<net::DataProtocolHandler>());
+#if defined(OS_CHROMEOS)
+  if (profile_params_) {
+    builder->SetProtocolHandler(
+        content::kExternalFileScheme,
+        base::MakeUnique<chromeos::ExternalFileProtocolHandler>(
+            profile_params_->profile));
+  }
+#endif  // defined(OS_CHROMEOS)
+#if defined(OS_ANDROID)
+  builder->SetProtocolHandler(
+      url::kContentScheme,
+      content::ContentProtocolHandler::Create(base::CreateTaskRunnerWithTraits(
+          {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
+           base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})));
+#endif
+
+  builder->SetProtocolHandler(
+      url::kAboutScheme,
+      base::MakeUnique<about_handler::AboutProtocolHandler>());
+
+#if !BUILDFLAG(DISABLE_FTP_SUPPORT)
+  builder->SetProtocolHandler(url::kFtpScheme,
+                              net::FtpProtocolHandler::Create(host_resolver));
+#endif  // !BUILDFLAG(DISABLE_FTP_SUPPORT)
+
+#if BUILDFLAG(DEBUG_DEVTOOLS)
+  request_interceptors.push_back(base::MakeUnique<DebugDevToolsInterceptor>());
+#endif
+
+  builder->SetInterceptors(std::move(request_interceptors));
+
+  if (protocol_handler_interceptor) {
+    builder->set_create_intercepting_job_factory(
+        base::BindOnce(&CreateURLRequestJobFactory,
+                       base::Passed(std::move(protocol_handler_interceptor))));
+  }
+}
+
 void ProfileIOData::ShutdownOnUIThread(
     std::unique_ptr<ChromeURLRequestContextGetterVector> context_getters) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -1328,25 +1393,6 @@
   resource_context_.reset();
 }
 
-std::unique_ptr<net::HttpNetworkSession>
-ProfileIOData::CreateHttpNetworkSession(
-    const ProfileParams& profile_params) const {
-  net::URLRequestContext* context = main_request_context();
-
-  IOThread* const io_thread = profile_params.io_thread;
-
-  net::HttpNetworkSession::Context session_context;
-  net::URLRequestContextBuilder::SetHttpNetworkSessionComponents(
-      context, &session_context);
-  if (data_reduction_proxy_io_data_.get()) {
-    session_context.proxy_delegate =
-        data_reduction_proxy_io_data_->proxy_delegate();
-  }
-
-  return std::unique_ptr<net::HttpNetworkSession>(new net::HttpNetworkSession(
-      io_thread->NetworkSessionParams(), session_context));
-}
-
 std::unique_ptr<net::HttpCache> ProfileIOData::CreateMainHttpFactory(
     net::HttpNetworkSession* session,
     std::unique_ptr<net::HttpCache::BackendFactory> main_backend) const {
diff --git a/chrome/browser/profiles/profile_io_data.h b/chrome/browser/profiles/profile_io_data.h
index d626a45..d4cf4d4 100644
--- a/chrome/browser/profiles/profile_io_data.h
+++ b/chrome/browser/profiles/profile_io_data.h
@@ -82,8 +82,7 @@
 class ReportingService;
 class ReportSender;
 class SSLConfigService;
-class TransportSecurityPersister;
-class URLRequestContextStorage;
+class URLRequestContextBuilder;
 class URLRequestJobFactoryImpl;
 }  // namespace net
 
@@ -122,10 +121,17 @@
   // Utility to install additional WebUI handlers into the |job_factory|.
   // Ownership of the handlers is transfered from |protocol_handlers|
   // to the |job_factory|.
+  // TODO(mmenke): Remove this, once only AddProtocolHandlersToBuilder is used.
   static void InstallProtocolHandlers(
       net::URLRequestJobFactoryImpl* job_factory,
       content::ProtocolHandlerMap* protocol_handlers);
 
+  // Utility to install additional WebUI handlers into |builder|. Ownership of
+  // the handlers is transfered from |protocol_handlers| to |builder|.
+  static void AddProtocolHandlersToBuilder(
+      net::URLRequestContextBuilder* builder,
+      content::ProtocolHandlerMap* protocol_handlers);
+
   // Sets a global CertVerifier to use when initializing all profiles.
   static void SetCertVerifierForTesting(net::CertVerifier* cert_verifier);
 
@@ -343,7 +349,6 @@
   explicit ProfileIOData(Profile::ProfileType profile_type);
 
   void InitializeOnUIThread(Profile* profile);
-  void ApplyProfileParamsToContext(net::URLRequestContext* context) const;
 
   // Does common setup of the URLRequestJobFactories. Adds default
   // ProtocolHandlers to |job_factory|, adds URLRequestInterceptors in front of
@@ -352,6 +357,9 @@
   // |protocol_handler_interceptor| is configured to intercept URLRequests
   //     before all other URLRequestInterceptors, if non-null.
   // |host_resolver| is needed to set up the FtpProtocolHandler.
+  //
+  // TODO(mmenke): Remove this once all URLRequestContexts are set up using
+  // URLRequestContextBuilders.
   std::unique_ptr<net::URLRequestJobFactory> SetUpJobFactoryDefaults(
       std::unique_ptr<net::URLRequestJobFactoryImpl> job_factory,
       content::URLRequestInterceptorScopedVector request_interceptors,
@@ -360,6 +368,20 @@
       net::NetworkDelegate* network_delegate,
       net::HostResolver* host_resolver) const;
 
+  // Does common setup of the URLRequestJobFactories. Adds default
+  // ProtocolHandlers to |builder|, and adds URLRequestInterceptors in front of
+  // them as needed.
+  //
+  // |protocol_handler_interceptor| is configured to intercept URLRequests
+  //     before all other URLRequestInterceptors, if non-null.
+  // |host_resolver| is needed to set up the FtpProtocolHandler.
+  void SetUpJobFactoryDefaultsForBuilder(
+      net::URLRequestContextBuilder* builder,
+      content::URLRequestInterceptorScopedVector request_interceptors,
+      std::unique_ptr<ProtocolHandlerRegistry::JobInterceptorFactory>
+          protocol_handler_interceptor,
+      net::HostResolver* host_resolver) const;
+
   // Called when the Profile is destroyed. |context_getters| must include all
   // URLRequestContextGetters that refer to the ProfileIOData's
   // URLRequestContexts. Triggers destruction of the ProfileIOData and shuts
@@ -380,13 +402,6 @@
     return main_request_context_.get();
   }
 
-  // Storage for |main_request_context_|, to allow objects created by subclasses
-  // to live until the ProfileIOData destructor is invoked, so it can safely
-  // cancel URLRequests.
-  net::URLRequestContextStorage* main_request_context_storage() const {
-    return main_request_context_storage_.get();
-  }
-
   bool initialized() const {
     return initialized_;
   }
@@ -396,9 +411,6 @@
   // URLRequests may be accessing.
   void DestroyResourceContext();
 
-  std::unique_ptr<net::HttpNetworkSession> CreateHttpNetworkSession(
-      const ProfileParams& profile_params) const;
-
   // Creates main network transaction factory.
   std::unique_ptr<net::HttpCache> CreateMainHttpFactory(
       net::HttpNetworkSession* session,
@@ -448,14 +460,21 @@
       IOThread* io_thread,
       std::unique_ptr<ChromeNetworkDelegate> chrome_network_delegate) const;
 
-  // Does the actual initialization of the ProfileIOData subtype. Subtypes
-  // should use the static helper functions above to implement this.
+  // Does the initialization of the URLRequestContextBuilder for a ProfileIOData
+  // subclass. Subclasseses should use the static helper functions above to
+  // implement this.
   virtual void InitializeInternal(
+      net::URLRequestContextBuilder* builder,
       ProfileParams* profile_params,
       content::ProtocolHandlerMap* protocol_handlers,
       content::URLRequestInterceptorScopedVector request_interceptors)
       const = 0;
 
+  // Called after the main URLRequestContext has been initialized, just after
+  // InitializeInternal().
+  virtual void OnMainRequestContextCreated(
+      ProfileParams* profile_params) const = 0;
+
   // Initializes the RequestContext for extensions.
   virtual void InitializeExtensionsRequestContext(
       ProfileParams* profile_params) const = 0;
@@ -564,19 +583,11 @@
   mutable std::unique_ptr<chromeos::CertificateProvider> certificate_provider_;
 #endif
 
-  // Owns the subset of URLRequestContext's elements that are created by
-  // subclasses of ProfileImplIOData, to ensure proper destruction ordering.
-  // TODO(mmenke):  Move ownship of net objects owned by the ProfileIOData
-  // itself to this class, to improve destruction ordering.
-  mutable std::unique_ptr<net::URLRequestContextStorage>
-      main_request_context_storage_;
   mutable std::unique_ptr<net::URLRequestContext> main_request_context_;
 
   // Pointed to by the TransportSecurityState (owned by
   // URLRequestContextStorage), and must be disconnected from it before it's
   // destroyed.
-  mutable std::unique_ptr<net::TransportSecurityPersister>
-      transport_security_persister_;
   mutable std::unique_ptr<net::ReportSender> certificate_report_sender_;
   mutable std::unique_ptr<certificate_transparency::CTPolicyManager>
       ct_policy_manager_;
diff --git a/chrome/browser/resource_coordinator/background_tab_navigation_throttle.cc b/chrome/browser/resource_coordinator/background_tab_navigation_throttle.cc
index 88a87ca..25a2e43 100644
--- a/chrome/browser/resource_coordinator/background_tab_navigation_throttle.cc
+++ b/chrome/browser/resource_coordinator/background_tab_navigation_throttle.cc
@@ -58,8 +58,11 @@
 
 content::NavigationThrottle::ThrottleCheckResult
 BackgroundTabNavigationThrottle::WillStartRequest() {
-  return g_browser_process->GetTabManager()->MaybeThrottleNavigation(
-      navigation_handle());
+  return g_browser_process->GetTabManager()->MaybeThrottleNavigation(this);
+}
+
+void BackgroundTabNavigationThrottle::ResumeNavigation() {
+  Resume();
 }
 
 }  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/background_tab_navigation_throttle.h b/chrome/browser/resource_coordinator/background_tab_navigation_throttle.h
index abcb1fb..df3f43a 100644
--- a/chrome/browser/resource_coordinator/background_tab_navigation_throttle.h
+++ b/chrome/browser/resource_coordinator/background_tab_navigation_throttle.h
@@ -28,6 +28,9 @@
   const char* GetNameForLogging() override;
   content::NavigationThrottle::ThrottleCheckResult WillStartRequest() override;
 
+  // Virtual to allow unit tests to make this a no-op.
+  virtual void ResumeNavigation();
+
  private:
   DISALLOW_COPY_AND_ASSIGN(BackgroundTabNavigationThrottle);
 };
diff --git a/chrome/browser/resource_coordinator/tab_manager.cc b/chrome/browser/resource_coordinator/tab_manager.cc
index 53c2d86..dd27468 100644
--- a/chrome/browser/resource_coordinator/tab_manager.cc
+++ b/chrome/browser/resource_coordinator/tab_manager.cc
@@ -30,6 +30,7 @@
 #include "chrome/browser/media/webrtc/media_stream_capture_indicator.h"
 #include "chrome/browser/memory/oom_memory_details.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/resource_coordinator/background_tab_navigation_throttle.h"
 #include "chrome/browser/resource_coordinator/resource_coordinator_web_contents_observer.h"
 #include "chrome/browser/resource_coordinator/tab_manager_grc_tab_signal_observer.h"
 #include "chrome/browser/resource_coordinator/tab_manager_observer.h"
@@ -1004,8 +1005,8 @@
 }
 
 content::NavigationThrottle::ThrottleCheckResult
-TabManager::MaybeThrottleNavigation(
-    content::NavigationHandle* navigation_handle) {
+TabManager::MaybeThrottleNavigation(BackgroundTabNavigationThrottle* throttle) {
+  content::NavigationHandle* navigation_handle = throttle->navigation_handle();
   if (!ShouldDelayNavigation(navigation_handle)) {
     loading_contents_.insert(navigation_handle->GetWebContents());
     return content::NavigationThrottle::PROCEED;
@@ -1015,8 +1016,7 @@
   // navigation will be delayed.
   GetWebContentsData(navigation_handle->GetWebContents())
       ->SetTabLoadingState(TAB_IS_NOT_LOADING);
-  pending_navigations_.push_back(navigation_handle);
-
+  pending_navigations_.push_back(throttle);
   return content::NavigationThrottle::DEFER;
 }
 
@@ -1033,8 +1033,8 @@
     content::NavigationHandle* navigation_handle) {
   auto it = pending_navigations_.begin();
   while (it != pending_navigations_.end()) {
-    content::NavigationHandle* pending_handle = *it;
-    if (pending_handle == navigation_handle) {
+    BackgroundTabNavigationThrottle* throttle = *it;
+    if (throttle->navigation_handle() == navigation_handle) {
       pending_navigations_.erase(it);
       break;
     }
@@ -1063,41 +1063,39 @@
   if (pending_navigations_.empty())
     return;
 
-  content::NavigationHandle* navigation_handle = pending_navigations_.front();
+  BackgroundTabNavigationThrottle* throttle = pending_navigations_.front();
   pending_navigations_.erase(pending_navigations_.begin());
-  ResumeNavigation(navigation_handle);
+  ResumeNavigation(throttle);
 }
 
 void TabManager::ResumeTabNavigationIfNeeded(content::WebContents* contents) {
-  content::NavigationHandle* navigation_handle =
+  BackgroundTabNavigationThrottle* throttle =
       RemovePendingNavigationIfNeeded(contents);
-  if (navigation_handle)
-    ResumeNavigation(navigation_handle);
+  if (throttle)
+    ResumeNavigation(throttle);
 }
 
-void TabManager::ResumeNavigation(
-    content::NavigationHandle* navigation_handle) {
+void TabManager::ResumeNavigation(BackgroundTabNavigationThrottle* throttle) {
+  content::NavigationHandle* navigation_handle = throttle->navigation_handle();
   GetWebContentsData(navigation_handle->GetWebContents())
       ->SetTabLoadingState(TAB_IS_LOADING);
   loading_contents_.insert(navigation_handle->GetWebContents());
 
-  navigation_handle->Resume();
+  throttle->ResumeNavigation();
 }
 
-content::NavigationHandle* TabManager::RemovePendingNavigationIfNeeded(
+BackgroundTabNavigationThrottle* TabManager::RemovePendingNavigationIfNeeded(
     content::WebContents* contents) {
-  content::NavigationHandle* navigation_handle = nullptr;
   auto it = pending_navigations_.begin();
   while (it != pending_navigations_.end()) {
-    navigation_handle = *it;
-    if ((*it)->GetWebContents() == contents) {
-      navigation_handle = *it;
+    BackgroundTabNavigationThrottle* throttle = *it;
+    if (throttle->navigation_handle()->GetWebContents() == contents) {
       pending_navigations_.erase(it);
-      break;
+      return throttle;
     }
     it++;
   }
-  return navigation_handle;
+  return nullptr;
 }
 
 bool TabManager::IsTabLoadingForTest(content::WebContents* contents) const {
@@ -1113,8 +1111,8 @@
 
 bool TabManager::IsNavigationDelayedForTest(
     const content::NavigationHandle* navigation_handle) const {
-  for (const auto* nav : pending_navigations_) {
-    if (nav == navigation_handle)
+  for (const auto* it : pending_navigations_) {
+    if (it->navigation_handle() == navigation_handle)
       return true;
   }
   return false;
diff --git a/chrome/browser/resource_coordinator/tab_manager.h b/chrome/browser/resource_coordinator/tab_manager.h
index 83dcd12..3a0e3b0d 100644
--- a/chrome/browser/resource_coordinator/tab_manager.h
+++ b/chrome/browser/resource_coordinator/tab_manager.h
@@ -44,6 +44,8 @@
 
 namespace resource_coordinator {
 
+class BackgroundTabNavigationThrottle;
+
 #if defined(OS_CHROMEOS)
 class TabManagerDelegate;
 #endif
@@ -160,7 +162,7 @@
 
   // Maybe throttle a tab's navigation based on current system status.
   content::NavigationThrottle::ThrottleCheckResult MaybeThrottleNavigation(
-      content::NavigationHandle* navigation_handle);
+      BackgroundTabNavigationThrottle* throttle);
 
   // Notifies TabManager that one navigation has finished (committed, aborted or
   // replaced). TabManager should clean up the NavigationHandle objects bookkept
@@ -380,11 +382,11 @@
   void ResumeTabNavigationIfNeeded(content::WebContents* contents);
 
   // Resume navigation.
-  void ResumeNavigation(content::NavigationHandle* navigation_handle);
+  void ResumeNavigation(BackgroundTabNavigationThrottle* throttle);
 
   // Remove the pending navigation for the provided WebContents. Return the
-  // removed navigation handle. Return nullptr if it doesn't exists.
-  content::NavigationHandle* RemovePendingNavigationIfNeeded(
+  // removed NavigationThrottle. Return nullptr if it doesn't exists.
+  BackgroundTabNavigationThrottle* RemovePendingNavigationIfNeeded(
       content::WebContents* contents);
 
   // Check if the tab is loading. Use only in tests.
@@ -463,8 +465,8 @@
   class TabManagerSessionRestoreObserver;
   std::unique_ptr<TabManagerSessionRestoreObserver> session_restore_observer_;
 
-  // The list of navigation handles that are delayed.
-  std::vector<content::NavigationHandle*> pending_navigations_;
+  // The list of navigations that are delayed.
+  std::vector<BackgroundTabNavigationThrottle*> pending_navigations_;
 
   // The tabs that are currently loading. We will consider loading the next
   // background tab when these tabs have finished loading or a background tab
diff --git a/chrome/browser/resource_coordinator/tab_manager_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
index 2c94819..8674175 100644
--- a/chrome/browser/resource_coordinator/tab_manager_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
@@ -20,6 +20,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/resource_coordinator/background_tab_navigation_throttle.h"
 #include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
 #include "chrome/browser/resource_coordinator/tab_stats.h"
 #include "chrome/browser/sessions/tab_loader.h"
@@ -48,6 +49,19 @@
 
 const char kTestUrl[] = "http://www.example.com";
 
+class NonResumingBackgroundTabNavigationThrottle
+    : public BackgroundTabNavigationThrottle {
+ public:
+  explicit NonResumingBackgroundTabNavigationThrottle(
+      content::NavigationHandle* handle)
+      : BackgroundTabNavigationThrottle(handle) {}
+
+  void ResumeNavigation() override {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NonResumingBackgroundTabNavigationThrottle);
+};
+
 class TabStripDummyDelegate : public TestTabStripModelDelegate {
  public:
   TabStripDummyDelegate() {}
@@ -134,12 +148,19 @@
     contents2_ = nav_handle2_->GetWebContents();
     contents3_ = nav_handle3_->GetWebContents();
 
+    throttle1_ = base::MakeUnique<NonResumingBackgroundTabNavigationThrottle>(
+        nav_handle1_.get());
+    throttle2_ = base::MakeUnique<NonResumingBackgroundTabNavigationThrottle>(
+        nav_handle2_.get());
+    throttle3_ = base::MakeUnique<NonResumingBackgroundTabNavigationThrottle>(
+        nav_handle3_.get());
+
     NavigationThrottle::ThrottleCheckResult result1 =
-        tab_manager->MaybeThrottleNavigation(nav_handle1_.get());
+        tab_manager->MaybeThrottleNavigation(throttle1_.get());
     NavigationThrottle::ThrottleCheckResult result2 =
-        tab_manager->MaybeThrottleNavigation(nav_handle2_.get());
+        tab_manager->MaybeThrottleNavigation(throttle2_.get());
     NavigationThrottle::ThrottleCheckResult result3 =
-        tab_manager->MaybeThrottleNavigation(nav_handle3_.get());
+        tab_manager->MaybeThrottleNavigation(throttle3_.get());
 
     // First tab starts navigation right away because there is no tab loading.
     EXPECT_EQ(content::NavigationThrottle::PROCEED, result1);
@@ -150,6 +171,9 @@
   }
 
  protected:
+  std::unique_ptr<BackgroundTabNavigationThrottle> throttle1_;
+  std::unique_ptr<BackgroundTabNavigationThrottle> throttle2_;
+  std::unique_ptr<BackgroundTabNavigationThrottle> throttle3_;
   std::unique_ptr<NavigationHandle> nav_handle1_;
   std::unique_ptr<NavigationHandle> nav_handle2_;
   std::unique_ptr<NavigationHandle> nav_handle3_;
diff --git a/chrome/browser/resources/chromeos/arc_support/main.html b/chrome/browser/resources/chromeos/arc_support/main.html
index 7c9000f..c6dc50b3 100644
--- a/chrome/browser/resources/chromeos/arc_support/main.html
+++ b/chrome/browser/resources/chromeos/arc_support/main.html
@@ -8,8 +8,8 @@
   <link rel="stylesheet" href="chrome://resources/css/overlay.css">
   <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
   <link rel="import" href="chrome://resources/polymer/v1_0/paper-progress/paper-progress.html">
-  <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html">
-  <style is="custom-style">
+  <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
+  <style is="custom-style" include="iron-flex iron-flex-alignment">
     paper-progress {
       display: block;
       margin: auto;
diff --git a/chrome/browser/resources/chromeos/emulator/audio_settings.html b/chrome/browser/resources/chromeos/emulator/audio_settings.html
index eacb65eb..7dc3553 100644
--- a/chrome/browser/resources/chromeos/emulator/audio_settings.html
+++ b/chrome/browser/resources/chromeos/emulator/audio_settings.html
@@ -19,8 +19,8 @@
     <style include="device-emulator-shared-styles cr-shared-style iron-flex iron-flex-alignment iron-positioning">
     </style>
     <dialog is="cr-dialog" id="editDialog">
-      <div class="title">[[currentEditableObject.deviceName]]</div>
-      <div class="body">
+      <div class="title" slot="title">[[currentEditableObject.deviceName]]</div>
+      <div class="body" slot="body">
         <form>
           <div class="form-field-section">
             <paper-input value="{{currentEditableObject.deviceName}}"
@@ -54,7 +54,7 @@
           </div>
         </form>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button class="action-button" on-click="insertEditedAudioNode">
           Done
         </paper-button>
diff --git a/chrome/browser/resources/chromeos/emulator/bluetooth_settings.html b/chrome/browser/resources/chromeos/emulator/bluetooth_settings.html
index b64ecf6..ed00c159 100644
--- a/chrome/browser/resources/chromeos/emulator/bluetooth_settings.html
+++ b/chrome/browser/resources/chromeos/emulator/bluetooth_settings.html
@@ -19,8 +19,8 @@
     <style include="device-emulator-shared-styles cr-shared-style iron-flex iron-flex-alignment iron-positioning">
     </style>
     <dialog is="cr-dialog" id="editDialog">
-      <div class="title">[[currentEditableObject.alias]]</div>
-      <div class="body">
+      <div class="title" slot="title">[[currentEditableObject.alias]]</div>
+      <div class="body" slot="body">
         <form>
           <div class="form-field-section">
             <paper-input value="{{currentEditableObject.alias}}"
@@ -94,7 +94,7 @@
           </div>
         </form>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button class="action-button" on-tap="onCloseTap_">
           Close
         </paper-button>
diff --git a/chrome/browser/resources/chromeos/login/offline_gaia.html b/chrome/browser/resources/chromeos/login/offline_gaia.html
index 7d95d1f..7687bb2 100644
--- a/chrome/browser/resources/chromeos/login/offline_gaia.html
+++ b/chrome/browser/resources/chromeos/login/offline_gaia.html
@@ -172,8 +172,9 @@
 
     <dialog is="cr-dialog" id="forgotPasswordDlg"
         on-close="onDialogOverlayClosed_">
-      <div class="body" i18n-content="offlineLoginForgotPasswordDlg"></div>
-      <div class="button-container">
+      <div class="body" slot="body"
+          i18n-content="offlineLoginForgotPasswordDlg"></div>
+      <div class="button-container" slot="button-container">
         <paper-button autofocus on-tap="onForgotPasswordCloseTap_"
             i18n-content="offlineLoginCloseBtn" class="action-button">
         </paper-button>
diff --git a/chrome/browser/resources/chromeos/login/saml_confirm_password.html b/chrome/browser/resources/chromeos/login/saml_confirm_password.html
index f03a62b..66d92f6a 100644
--- a/chrome/browser/resources/chromeos/login/saml_confirm_password.html
+++ b/chrome/browser/resources/chromeos/login/saml_confirm_password.html
@@ -79,8 +79,9 @@
 
     <dialog is="cr-dialog" id="cancelConfirmDlg"
         on-close="onDialogOverlayClosed_">
-      <div class="body" i18n-content="accountSetupCancelDialogTitle"></div>
-      <div class="button-container">
+      <div class="body" slot="body"
+          i18n-content="accountSetupCancelDialogTitle"></div>
+      <div class="button-container" slot="button-container">
         <paper-button class="action-button"
             i18n-content="accountSetupCancelDialogNo" on-tap="onCancelNo_">
         </paper-button>
diff --git a/chrome/browser/resources/chromeos/network_ui/network_ui.css b/chrome/browser/resources/chromeos/network_ui/network_ui.css
index 935ae84..242254f 100644
--- a/chrome/browser/resources/chromeos/network_ui/network_ui.css
+++ b/chrome/browser/resources/chromeos/network_ui/network_ui.css
@@ -2,6 +2,11 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
 
+body {
+  display: flex;
+  flex-direction: column;
+}
+
 div {
   margin: 10px 0;
 }
@@ -12,6 +17,7 @@
 }
 
 #select-div {
+  display: flex;
   height: 100px;
   width: 500px;
 }
@@ -51,3 +57,7 @@
   height: 32px;
   width: 32px;
 }
+
+cr-network-select {
+  flex: 1;
+}
diff --git a/chrome/browser/resources/chromeos/network_ui/network_ui.html b/chrome/browser/resources/chromeos/network_ui/network_ui.html
index 09b377c..7ecbf37f 100644
--- a/chrome/browser/resources/chromeos/network_ui/network_ui.html
+++ b/chrome/browser/resources/chromeos/network_ui/network_ui.html
@@ -9,7 +9,6 @@
   <link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_network_icon.html">
   <link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_network_select.html">
   <link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_onc_types.html">
-  <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/paper-button/paper-button.html">
 
   <script src="chrome://resources/js/load_time_data.js"></script>
@@ -19,71 +18,69 @@
 </head>
 
 <body>
-  <div class="layout vertical">
-    <div i18n-content="autoRefreshText"></div>
-    <span i18n-values=".innerHTML:deviceLogLinkText"></span>
+  <div i18n-content="autoRefreshText"></div>
+  <span i18n-values=".innerHTML:deviceLogLinkText"></span>
 
-    <h3 i18n-content="globalPolicyLabel"></h3>
-    <div id="global-policy"></div>
+  <h3 i18n-content="globalPolicyLabel"></h3>
+  <div id="global-policy"></div>
 
-    <h3>CrNetworkSelect</h3>
-    <div id="select-div" class="layout vertical">
-      <cr-network-select class="flex" handle-network-item-selected>
-      </cr-network-select>
-    </div>
-    <div>
-      <paper-button raised class="colored" id="refresh"
-          i18n-content="networkRefreshText">
-      </paper-button>
-    </div>
-
-    <h3 i18n-content="visibleNetworksLabel"></h3>
-    <div i18n-content="clickToExpandText"></div>
-    <div>
-      <span i18n-content="propertyFormatText"></span>
-      <select id="get-property-format">
-        <option value="normal" i18n-content="normalFormatOption"></option>
-        <option value="managed" i18n-content="managedFormatOption"></option>
-        <option value="state" i18n-content="stateFormatOption"></option>
-        <option value="shill" i18n-content="shillFormatOption"></option>
-      </select>
-    </div>
-
-    <table id="network-state-table" class="state-table">
-      <tr class="state-table-header">
-        <td></td>
-        <td></td>
-        <td>GUID</td>
-        <td>Path</td>
-        <td>Name</td>
-        <td>Type</td>
-        <td>State</td>
-        <td>Connect?</td>
-        <td>Error</td>
-        <td>Security</td>
-        <td>Tech</td>
-        <td>Activation</td>
-        <td>Roam</td>
-        <td>Frequency</td>
-        <td>Strength</td>
-      </tr>
-    </table>
-
-    <h3 i18n-content="favoriteNetworksLabel"></h3>
-    <table id="favorite-state-table" class="state-table">
-      <tr class="state-table-header">
-        <td></td>
-        <td></td>
-        <td>GUID</td>
-        <td>Path</td>
-        <td>Name</td>
-        <td>Type</td>
-        <td>Profile</td>
-        <td>Visible</td>
-        <td>ONC Source</td>
-      </tr>
-    </table>
+  <h3>CrNetworkSelect</h3>
+  <div id="select-div">
+    <cr-network-select handle-network-item-selected>
+    </cr-network-select>
   </div>
+  <div>
+    <paper-button raised class="colored" id="refresh"
+        i18n-content="networkRefreshText">
+    </paper-button>
+  </div>
+
+  <h3 i18n-content="visibleNetworksLabel"></h3>
+  <div i18n-content="clickToExpandText"></div>
+  <div>
+    <span i18n-content="propertyFormatText"></span>
+    <select id="get-property-format">
+      <option value="normal" i18n-content="normalFormatOption"></option>
+      <option value="managed" i18n-content="managedFormatOption"></option>
+      <option value="state" i18n-content="stateFormatOption"></option>
+      <option value="shill" i18n-content="shillFormatOption"></option>
+    </select>
+  </div>
+
+  <table id="network-state-table" class="state-table">
+    <tr class="state-table-header">
+      <td></td>
+      <td></td>
+      <td>GUID</td>
+      <td>Path</td>
+      <td>Name</td>
+      <td>Type</td>
+      <td>State</td>
+      <td>Connect?</td>
+      <td>Error</td>
+      <td>Security</td>
+      <td>Tech</td>
+      <td>Activation</td>
+      <td>Roam</td>
+      <td>Frequency</td>
+      <td>Strength</td>
+    </tr>
+  </table>
+
+  <h3 i18n-content="favoriteNetworksLabel"></h3>
+  <table id="favorite-state-table" class="state-table">
+    <tr class="state-table-header">
+      <td></td>
+      <td></td>
+      <td>GUID</td>
+      <td>Path</td>
+      <td>Name</td>
+      <td>Type</td>
+      <td>Profile</td>
+      <td>Visible</td>
+      <td>ONC Source</td>
+    </tr>
+  </table>
 
   <script src="chrome://resources/js/i18n_template.js"></script>
 </body>
diff --git a/chrome/browser/resources/md_bookmarks/command_manager.html b/chrome/browser/resources/md_bookmarks/command_manager.html
index 2586135..728e518 100644
--- a/chrome/browser/resources/md_bookmarks/command_manager.html
+++ b/chrome/browser/resources/md_bookmarks/command_manager.html
@@ -52,9 +52,9 @@
     </template>
     <template is="cr-lazy-render" id="openDialog">
       <dialog is="cr-dialog">
-        <div class="title">$i18n{openDialogTitle}</div>
-        <div class="body"></div>
-        <div class="button-container">
+        <div class="title" slot="title">$i18n{openDialogTitle}</div>
+        <div class="body" slot="body"></div>
+        <div class="button-container" slot="button-container">
           <paper-button class="cancel-button" on-tap="onOpenCancelTap_">
             $i18n{cancel}
           </paper-button>
diff --git a/chrome/browser/resources/md_bookmarks/edit_dialog.html b/chrome/browser/resources/md_bookmarks/edit_dialog.html
index 733b76e2..8daaaeda 100644
--- a/chrome/browser/resources/md_bookmarks/edit_dialog.html
+++ b/chrome/browser/resources/md_bookmarks/edit_dialog.html
@@ -11,8 +11,10 @@
   <template>
     <style include="cr-shared-style"></style>
     <dialog is="cr-dialog" id="dialog">
-      <div class="title">[[getDialogTitle_(isFolder_, isEdit_)]]</div>
-      <div class="body">
+      <div class="title" slot="title">
+        [[getDialogTitle_(isFolder_, isEdit_)]]
+      </div>
+      <div class="body" slot="body">
         <paper-input always-float-label id="name"
             label="$i18n{editDialogNameInput}"
             value="{{titleValue_}}"
@@ -27,7 +29,7 @@
             required>
         </paper-input>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button class="cancel-button" on-tap="onCancelButtonTap_">
           $i18n{cancel}
         </paper-button>
diff --git a/chrome/browser/resources/md_extensions/load_error.html b/chrome/browser/resources/md_extensions/load_error.html
index f1fd855..37cd559 100644
--- a/chrome/browser/resources/md_extensions/load_error.html
+++ b/chrome/browser/resources/md_extensions/load_error.html
@@ -29,8 +29,8 @@
       }
     </style>
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
-      <div class="title">$i18n{loadErrorHeading}</div>
-      <div class="body">
+      <div class="title" slot="title">$i18n{loadErrorHeading}</div>
+      <div class="body" slot="body">
         <div id="info">
           <div id="file" class="description-row">
             <span class="row-label">$i18n{loadErrorFileLabel}</span>
@@ -45,7 +45,7 @@
             could-not-display-code="$i18n{loadErrorCouldNotLoadManifest}">
         </extensions-code-section>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button class="cancel-button" on-tap="close">
           $i18n{loadErrorCancel}
         </paper-button>
diff --git a/chrome/browser/resources/md_extensions/options_dialog.html b/chrome/browser/resources/md_extensions/options_dialog.html
index a01b3e7..c00b200d 100644
--- a/chrome/browser/resources/md_extensions/options_dialog.html
+++ b/chrome/browser/resources/md_extensions/options_dialog.html
@@ -27,13 +27,13 @@
     </style>
 
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
-      <div class="title">
+      <div class="title" slot="title">
         <div id="icon-and-name-wrapper">
           <img id="icon" src="[[data_.iconUrl]]"></img>
           <span>[[data_.name]]</span>
         </div>
       </div>
-      <div class="body" id="body">
+      <div class="body" slot="body" id="body">
       </div>
     </dialog>
   </template>
diff --git a/chrome/browser/resources/md_extensions/pack_dialog.html b/chrome/browser/resources/md_extensions/pack_dialog.html
index f276ea1..5bdcf1c6 100644
--- a/chrome/browser/resources/md_extensions/pack_dialog.html
+++ b/chrome/browser/resources/md_extensions/pack_dialog.html
@@ -38,8 +38,8 @@
     </style>
 
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
-      <div class="title">$i18n{packDialogTitle}</div>
-      <div class="body">
+      <div class="title" slot="title">$i18n{packDialogTitle}</div>
+      <div class="body" slot="body">
         <div>$i18n{packDialogContent}</div>
         <div class="file-input">
           <paper-input id="root-dir" label="$i18n{packDialogExtensionRoot}"
@@ -58,7 +58,7 @@
           </paper-button>
         </div>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button class="cancel-button" on-tap="close">
           $i18n{packDialogCancel}
         </paper-button>
diff --git a/chrome/browser/resources/md_history/history_list.html b/chrome/browser/resources/md_history/history_list.html
index 1d73ed2..a9c4b640 100644
--- a/chrome/browser/resources/md_history/history_list.html
+++ b/chrome/browser/resources/md_history/history_list.html
@@ -59,9 +59,9 @@
 
     <template is="cr-lazy-render" id="dialog">
       <dialog is="cr-dialog">
-        <div class="title">$i18n{removeSelected}</div>
-        <div class="body">$i18n{deleteWarning}</div>
-        <div class="button-container">
+        <div class="title" slot="title">$i18n{removeSelected}</div>
+        <div class="body" slot="body">$i18n{deleteWarning}</div>
+        <div class="button-container" slot="button-container">
           <paper-button class="cancel-button" on-tap="onDialogCancelTap_">
             $i18n{cancel}
           </paper-button>
diff --git a/chrome/browser/resources/md_user_manager/error_dialog.html b/chrome/browser/resources/md_user_manager/error_dialog.html
index f7964ca..6c1bd29 100644
--- a/chrome/browser/resources/md_user_manager/error_dialog.html
+++ b/chrome/browser/resources/md_user_manager/error_dialog.html
@@ -16,7 +16,7 @@
       }
     </style>
     <dialog is="cr-dialog" id="dialog">
-      <div class="body">
+      <div class="body" slot="body">
         <div id="message">[[message_]]</div>
       </div>
     </dialog>
diff --git a/chrome/browser/resources/md_user_manager/import_supervised_user.html b/chrome/browser/resources/md_user_manager/import_supervised_user.html
index dea9538..89fc1966 100644
--- a/chrome/browser/resources/md_user_manager/import_supervised_user.html
+++ b/chrome/browser/resources/md_user_manager/import_supervised_user.html
@@ -62,8 +62,8 @@
       }
     </style>
     <dialog is="cr-dialog" id="dialog">
-      <div class="title">$i18n{supervisedUserImportTitle}</div>
-      <div class="body">
+      <div class="title" slot="title">$i18n{supervisedUserImportTitle}</div>
+      <div class="body" slot="body">
         <div id="message">$i18n{supervisedUserImportText}</div>
         <paper-listbox class="no-padding" selected="{{supervisedUserIndex_}}">
           <template is="dom-repeat" items="[[supervisedUsers_]]">
@@ -77,7 +77,7 @@
           </template>
         </paper-listbox>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button id="cancel" class="cancel-button" on-tap="onCancelTap_">
           $i18n{cancel}
         </paper-button>
diff --git a/chrome/browser/resources/options/options_polymer.html b/chrome/browser/resources/options/options_polymer.html
index e20838d1..afbf9fd 100644
--- a/chrome/browser/resources/options/options_polymer.html
+++ b/chrome/browser/resources/options/options_polymer.html
@@ -8,5 +8,4 @@
 <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-checkbox/paper-checkbox.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html">
 <link rel="import" href="chrome://settings-frame/people_page/lock_screen.html">
diff --git a/chrome/browser/resources/pdf/elements/viewer-error-screen/viewer-error-screen.html b/chrome/browser/resources/pdf/elements/viewer-error-screen/viewer-error-screen.html
index 3dccd91..10a850ee 100644
--- a/chrome/browser/resources/pdf/elements/viewer-error-screen/viewer-error-screen.html
+++ b/chrome/browser/resources/pdf/elements/viewer-error-screen/viewer-error-screen.html
@@ -7,13 +7,14 @@
   <template>
     <style include="cr-shared-style"></style>
     <dialog is="cr-dialog" id="dialog" no-cancel>
-      <div class="title">
+      <div class="title" slot="title">
         [[strings.errorDialogTitle]]
       </div>
-      <div class="body">
+      <div class="body" slot="body">
         [[strings.pageLoadFailed]]
       </div>
-      <div class="button-container" hidden$="[[!reloadFn]]">
+      <div class="button-container" slot="button-container"
+          hidden$="[[!reloadFn]]">
         <paper-button class="action-button" on-click="reload">
           [[strings.pageReload]]
         </paper-button>
diff --git a/chrome/browser/resources/pdf/elements/viewer-password-screen/viewer-password-screen.html b/chrome/browser/resources/pdf/elements/viewer-password-screen/viewer-password-screen.html
index fe925120..76351c2e 100644
--- a/chrome/browser/resources/pdf/elements/viewer-password-screen/viewer-password-screen.html
+++ b/chrome/browser/resources/pdf/elements/viewer-password-screen/viewer-password-screen.html
@@ -16,8 +16,8 @@
       }
     </style>
     <dialog is="cr-dialog" id="dialog" no-cancel>
-      <div class="title">[[strings.passwordDialogTitle]]</div>
-      <div class="body">
+      <div class="title" slot="title">[[strings.passwordDialogTitle]]</div>
+      <div class="body" slot="body">
         <div id="message">[[strings.passwordPrompt]]</div>
         <paper-input id="password"
             type="password"
@@ -27,7 +27,7 @@
             autofocus>
         </paper-input>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button id="submit" class="action-button" on-click="submit">
           [[strings.passwordSubmit]]
         </paper-button>
diff --git a/chrome/browser/resources/settings/about_page/channel_switcher_dialog.html b/chrome/browser/resources/settings/about_page/channel_switcher_dialog.html
index 8c9db5b..11845c1 100644
--- a/chrome/browser/resources/settings/about_page/channel_switcher_dialog.html
+++ b/chrome/browser/resources/settings/about_page/channel_switcher_dialog.html
@@ -12,8 +12,8 @@
   <template>
     <style include="settings-shared"></style>
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
-      <div class="title">$i18n{aboutChangeChannel}</div>
-      <div class="body">
+      <div class="title" slot="title">$i18n{aboutChangeChannel}</div>
+      <div class="body" slot="body">
         <!-- TODO(dbeam): this can be policy-controlled. Show this in the UI.
              https://www.chromium.org/administrators/policy-list-3#ChromeOsReleaseChannel
         -->
@@ -34,7 +34,7 @@
           <div>[[warning_.description]]</div>
         </div>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button class="cancel-button" on-tap="onCancelTap_"
             id="cancel">$i18n{cancel}</paper-button>
         <paper-button id="changeChannel" class="action-button"
diff --git a/chrome/browser/resources/settings/about_page/update_warning_dialog.html b/chrome/browser/resources/settings/about_page/update_warning_dialog.html
index 734b20d6..1ad1bd61 100644
--- a/chrome/browser/resources/settings/about_page/update_warning_dialog.html
+++ b/chrome/browser/resources/settings/about_page/update_warning_dialog.html
@@ -10,11 +10,11 @@
   <template>
     <style include="settings-shared"></style>
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
-      <div class="title">$i18n{aboutUpdateWarningTitle}</div>
-      <div class="body">
+      <div class="title" slot="title">$i18n{aboutUpdateWarningTitle}</div>
+      <div class="body" slot="body">
         <div id="update-warning-message"></div>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button id="cancel" class="cancel-button"
             on-tap="onCancelTap_">$i18n{cancel}</paper-button>
         <paper-button id="continue" class="action-button"
diff --git a/chrome/browser/resources/settings/android_apps_page/android_apps_subpage.html b/chrome/browser/resources/settings/android_apps_page/android_apps_subpage.html
index bfedd2a..87b6511 100644
--- a/chrome/browser/resources/settings/android_apps_page/android_apps_subpage.html
+++ b/chrome/browser/resources/settings/android_apps_page/android_apps_subpage.html
@@ -33,9 +33,9 @@
     <dialog is="cr-dialog" id="confirmDisableDialog" close-text="$i18n{close}"
         on-cancel="onConfirmDisableDialogCancel_"
         on-close="onConfirmDisableDialogClose_">
-      <div class="title">$i18n{androidAppsDisableDialogTitle}</div>
-      <div class="body" inner-h-t-m-l="[[dialogBody_]]"></div>
-      <div class="button-container">
+      <div class="title" slot="title">$i18n{androidAppsDisableDialogTitle}</div>
+      <div class="body" slot="body" inner-h-t-m-l="[[dialogBody_]]"></div>
+      <div class="button-container" slot="button-container">
         <paper-button class="cancel-button"
             on-tap="onConfirmDisableDialogCancel_">
           $i18n{cancel}
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_dialog.html b/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_dialog.html
index 7fc49f2..7c27747 100644
--- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_dialog.html
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_dialog.html
@@ -70,8 +70,8 @@
     </style>
     <dialog is="cr-dialog" id="dialog" on-cancel="onDialogCanceled_"
         close-text="$i18n{close}" on-closed="onDialogCanceled_">
-      <div class="title">$i18n{bluetoothPairDevicePageTitle}</div>
-      <div class="body">
+      <div class="title" slot="title">$i18n{bluetoothPairDevicePageTitle}</div>
+      <div class="body" slot="body">
         <div class="contents layout vertical center center-justified">
           <template is="dom-if" if="[[isDialogType_(dialogId, 'pairDevice')]]">
             <div id="pairing" class="settings-box first layout vertical center
@@ -112,7 +112,7 @@
           </template>
         </div>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <template is="dom-if" if="[[isDialogType_('pairDevice', dialogId)]]">
           <paper-button hidden$="[[!showAcceptReject_(pairingEvent_)]]"
               on-tap="onAcceptTap_">$i18n{bluetoothAccept}</paper-button>
diff --git a/chrome/browser/resources/settings/certificate_manager_page/ca_trust_edit_dialog.html b/chrome/browser/resources/settings/certificate_manager_page/ca_trust_edit_dialog.html
index 5c2dcd9..59062f7 100644
--- a/chrome/browser/resources/settings/certificate_manager_page/ca_trust_edit_dialog.html
+++ b/chrome/browser/resources/settings/certificate_manager_page/ca_trust_edit_dialog.html
@@ -22,8 +22,10 @@
     </style>
 
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
-      <div class="title">$i18n{certificateManagerCaTrustEditDialogTitle}</div>
-      <div class="body">
+      <div class="title" slot="title">
+        $i18n{certificateManagerCaTrustEditDialogTitle}
+      </div>
+      <div class="body" slot="body">
         <div>[[explanationText_]]</div>
         <div id="description">
           $i18n{certificateManagerCaTrustEditDialogDescription}
@@ -38,7 +40,7 @@
           $i18n{certificateManagerCaTrustEditDialogObjSign}
         </paper-checkbox>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-spinner id="spinner"></paper-spinner>
         <paper-button class="cancel-button" on-tap="onCancelTap_">
           $i18n{cancel}
diff --git a/chrome/browser/resources/settings/certificate_manager_page/certificate_delete_confirmation_dialog.html b/chrome/browser/resources/settings/certificate_manager_page/certificate_delete_confirmation_dialog.html
index 3679a58d..e27c9db 100644
--- a/chrome/browser/resources/settings/certificate_manager_page/certificate_delete_confirmation_dialog.html
+++ b/chrome/browser/resources/settings/certificate_manager_page/certificate_delete_confirmation_dialog.html
@@ -10,11 +10,13 @@
   <template>
     <style include="settings-shared"></style>
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
-      <div class="title">[[getTitleText_(model, certificateType)]]</div>
-      <div class="body">
+      <div class="title" slot="title">
+        [[getTitleText_(model, certificateType)]]
+      </div>
+      <div class="body" slot="body">
         <div>[[getDescriptionText_(model, certificateType)]]</div>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button class="cancel-button" on-tap="onCancelTap_">
           $i18n{cancel}
         </paper-button>
diff --git a/chrome/browser/resources/settings/certificate_manager_page/certificate_password_decryption_dialog.html b/chrome/browser/resources/settings/certificate_manager_page/certificate_password_decryption_dialog.html
index 68e869e..6dffa38e 100644
--- a/chrome/browser/resources/settings/certificate_manager_page/certificate_password_decryption_dialog.html
+++ b/chrome/browser/resources/settings/certificate_manager_page/certificate_password_decryption_dialog.html
@@ -11,13 +11,15 @@
   <template>
     <style include="settings-shared"></style>
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
-      <div class="title">$i18n{certificateManagerDecryptPasswordTitle}</div>
-      <div class="body">
+      <div class="title" slot="title">
+        $i18n{certificateManagerDecryptPasswordTitle}
+      </div>
+      <div class="body" slot="body">
         <paper-input type="password" id="password"
             label="$i18n{certificateManagerPassword}" value="{{password_}}">
         </paper-input>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button class="cancel-button" on-tap="onCancelTap_">
           $i18n{cancel}
         </paper-button>
diff --git a/chrome/browser/resources/settings/certificate_manager_page/certificate_password_encryption_dialog.html b/chrome/browser/resources/settings/certificate_manager_page/certificate_password_encryption_dialog.html
index 9d0904b..035727e 100644
--- a/chrome/browser/resources/settings/certificate_manager_page/certificate_password_encryption_dialog.html
+++ b/chrome/browser/resources/settings/certificate_manager_page/certificate_password_encryption_dialog.html
@@ -15,8 +15,10 @@
       }
     </style>
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
-      <div class="title">$i18n{certificateManagerEncryptPasswordTitle}</div>
-      <div class="body">
+      <div class="title" slot="title">
+        $i18n{certificateManagerEncryptPasswordTitle}
+      </div>
+      <div class="body" slot="body">
         <div>$i18n{certificateManagerEncryptPasswordDescription}</div>
         <div class="password-buttons">
           <paper-input type="password" value="{{password_}}" id="password"
@@ -28,7 +30,7 @@
               on-input="validate_"></paper-input>
         </div>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button class="cancel-button" on-tap="onCancelTap_">
           $i18n{cancel}
         </paper-button>
diff --git a/chrome/browser/resources/settings/certificate_manager_page/certificates_error_dialog.html b/chrome/browser/resources/settings/certificate_manager_page/certificates_error_dialog.html
index 56ef73ae..b7d519d 100644
--- a/chrome/browser/resources/settings/certificate_manager_page/certificates_error_dialog.html
+++ b/chrome/browser/resources/settings/certificate_manager_page/certificates_error_dialog.html
@@ -9,8 +9,8 @@
   <template>
     <style include="settings-shared"></style>
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
-      <div class="title">[[model.title]]</div>
-      <div class="body">
+      <div class="title" slot="title">[[model.title]]</div>
+      <div class="body" slot="body">
         <div>[[model.description]]</div>
         <template is="dom-if" if="[[model.certificateErrors]]">
           <template is="dom-repeat" items="[[model.certificateErrors]]">
@@ -18,7 +18,7 @@
           </template>
         </template>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button id="ok" class="action-button" on-tap="onOkTap_">
           $i18n{ok}
         </paper-button>
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html
index dc95636..bcff338 100644
--- a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html
+++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html
@@ -114,8 +114,8 @@
     <dialog is="cr-dialog" id="clearBrowsingDataDialog"
         on-close="onClearBrowsingDataDialogClose_"
         close-text="$i18n{close}" ignore-popstate>
-      <div class="title">$i18n{clearBrowsingData}</div>
-      <div class="body">
+      <div class="title" slot="title">$i18n{clearBrowsingData}</div>
+      <div class="body" slot="body">
         <div class="row">
           $i18n{clearFollowingItemsFrom}
           <settings-dropdown-menu id="clearFrom"
@@ -179,7 +179,7 @@
             disabled="[[clearingInProgress_]]">
         </settings-checkbox>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-spinner active="[[clearingInProgress_]]"></paper-spinner>
         <paper-button class="cancel-button" disabled="[[clearingInProgress_]]"
             on-tap="onCancelTap_">$i18n{cancel}</paper-button>
@@ -189,7 +189,7 @@
             $i18n{clearBrowsingData}
         </paper-button>
       </div>
-      <div class="footer">
+      <div class="footer" slot="footer">
         <div id="googleFooter" class="clear-browsing-data-footer">
           <iron-icon icon="settings:googleg"></iron-icon>
           <div class="footer-text">$i18nRaw{otherFormsOfBrowsingHistory}</div>
@@ -210,7 +210,7 @@
     <template is="dom-if" if="[[showImportantSitesDialog_]]">
       <dialog is="cr-dialog" id="importantSitesDialog" close-text="$i18n{close}"
           show-scroll-borders ignore-popstate>
-        <div class="title">
+        <div class="title" slot="title">
           $i18n{clearBrowsingData}
           <div class="secondary">
             <template is="dom-if"
@@ -222,7 +222,7 @@
             </template>
           </div>
         </div>
-        <div class="body">
+        <div class="body" slot="body">
           <template is="dom-repeat" items="[[importantSites_]]">
             <div class="row">
               <important-site-checkbox
@@ -232,7 +232,7 @@
             </div>
           </template>
         </div>
-        <div class="button-container">
+        <div class="button-container" slot="button-container">
           <paper-spinner active="[[clearingInProgress_]]"></paper-spinner>
           <paper-button class="cancel-button" disabled="[[clearingInProgress_]]"
               on-tap="onImportantSitesCancelTap_">$i18n{cancel}</paper-button>
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/history_deletion_dialog.html b/chrome/browser/resources/settings/clear_browsing_data_dialog/history_deletion_dialog.html
index a3af86b..eee0bad 100644
--- a/chrome/browser/resources/settings/clear_browsing_data_dialog/history_deletion_dialog.html
+++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/history_deletion_dialog.html
@@ -8,9 +8,9 @@
     <style include="settings-shared"></style>
 
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
-      <div class="title">$i18n{historyDeletionDialogTitle}</div>
-      <div class="body">$i18nRaw{historyDeletionDialogBody}</div>
-      <div class="button-container">
+      <div class="title" slot="title">$i18n{historyDeletionDialogTitle}</div>
+      <div class="body" slot="body">$i18nRaw{historyDeletionDialogBody}</div>
+      <div class="button-container" slot="button-container">
         <paper-button class="action-button" on-tap="onOkTap_">
           $i18n{historyDeletionDialogOK}
         </paper-button>
diff --git a/chrome/browser/resources/settings/device_page/display_overscan_dialog.html b/chrome/browser/resources/settings/device_page/display_overscan_dialog.html
index a0bf0909..d4f6cf4 100644
--- a/chrome/browser/resources/settings/device_page/display_overscan_dialog.html
+++ b/chrome/browser/resources/settings/device_page/display_overscan_dialog.html
@@ -45,8 +45,8 @@
     </style>
     <dialog is="cr-dialog" id="dialog" on-close="close"
         close-text="$i18n{close}">
-      <div class="title">$i18n{displayOverscanPageTitle}</div>
-      <div class="body">
+      <div class="title" slot="title">$i18n{displayOverscanPageTitle}</div>
+      <div class="body" slot="body">
         <div class="subtitle" >$i18n{displayOverscanSubtitle}</div>
         <div class="instructions" >$i18n{displayOverscanInstructions}</div>
         <div class="details layout horizontal around-justified self-stretch">
@@ -73,7 +73,7 @@
           </div>
         </div>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button id="reset" class="cancel-button" on-tap="onResetTap_">
           $i18n{displayOverscanReset}
         </paper-button>
diff --git a/chrome/browser/resources/settings/device_page/drive_cache_dialog.html b/chrome/browser/resources/settings/device_page/drive_cache_dialog.html
index 57d3fc1..b142f56 100644
--- a/chrome/browser/resources/settings/device_page/drive_cache_dialog.html
+++ b/chrome/browser/resources/settings/device_page/drive_cache_dialog.html
@@ -9,11 +9,13 @@
   <template>
     <style include="settings-shared"></style>
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
-      <div class="title">$i18n{storageClearDriveCacheDialogTitle}</div>
-      <div class="body">
+      <div class="title" slot="title">
+        $i18n{storageClearDriveCacheDialogTitle}
+      </div>
+      <div class="body" slot="body">
         <span>$i18n{storageClearDriveCacheDialogDescription}</span>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button id="cancelButton" class="cancel-button"
             on-tap="onCancelTap_">
           $i18n{cancel}
diff --git a/chrome/browser/resources/settings/internet_page/network_proxy.html b/chrome/browser/resources/settings/internet_page/network_proxy.html
index d6da26b..e6f9e298 100644
--- a/chrome/browser/resources/settings/internet_page/network_proxy.html
+++ b/chrome/browser/resources/settings/internet_page/network_proxy.html
@@ -21,7 +21,7 @@
 <link rel="import" href="../prefs/prefs_behavior.html">
 <link rel="import" href="../settings_vars_css.html">
 <link rel="import" href="internet_shared_css.html">
-<link rel="import" href="network_proxy_exclusions.html">
+link rel="import" href="network_proxy_exclusions.html">
 <link rel="import" href="network_proxy_input.html">
 
 <dom-module id="network-proxy">
@@ -210,9 +210,13 @@
     <dialog is="cr-dialog" id="confirmAllowSharedDialog"
         close-text="$i18n{close}" on-cancel="onAllowSharedDialogCancel_"
         on-close="onAllowSharedDialogClose_">
-      <div class="title">$i18n{networkProxyAllowSharedWarningTitle}</div>
-      <div class="body">$i18n{networkProxyAllowSharedWarningMessage}</div>
-      <div class="button-container">
+      <div class="title" slot="title">
+        $i18n{networkProxyAllowSharedWarningTitle}
+      </div>
+      <div class="body" slot="body">
+        $i18n{networkProxyAllowSharedWarningMessage}
+      </div>
+      <div class="button-container" slot="button-container">
         <paper-button class="cancel-button"
             on-tap="onAllowSharedDialogCancel_">
           $i18n{cancel}
diff --git a/chrome/browser/resources/settings/internet_page/network_siminfo.html b/chrome/browser/resources/settings/internet_page/network_siminfo.html
index e2849cc..071e045 100644
--- a/chrome/browser/resources/settings/internet_page/network_siminfo.html
+++ b/chrome/browser/resources/settings/internet_page/network_siminfo.html
@@ -96,8 +96,8 @@
     <dialog is="cr-dialog" id="enterPinDialog" close-text="$i18n{close}"
         on-cancel="onEnterPinDialogCancel_"
         on-close="onEnterPinDialogClose_">
-      <div class="title">$i18n{networkSimEnterPinTitle}</div>
-      <div class="body">
+      <div class="title" slot="title">$i18n{networkSimEnterPinTitle}</div>
+      <div class="body" slot="body">
         <paper-input id="enterPin" class="pin" no-label-float autofocus
             label="$i18n{networkSimEnterPin}">
           <iron-a11y-keys keys="enter" on-keys-pressed="sendEnterPin_">
@@ -107,7 +107,7 @@
           [[getErrorMsg_(error_, networkProperties)]]
         </div>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button on-tap="sendEnterPin_">
           $i18n{networkSimEnter}
         </paper-button>
@@ -117,8 +117,8 @@
     <!-- Change PIN dialog -->
     <dialog is="cr-dialog" id="changePinDialog" close-text="$i18n{close}"
         on-close="onChangePinDialogClose_">
-      <div class="title">$i18n{networkSimChangePinTitle}</div>
-      <div class="body">
+      <div class="title" slot="title">$i18n{networkSimChangePinTitle}</div>
+      <div class="body" slot="body">
         <paper-input id="changePinOld" class="pin" no-label-float autofocus
             label="$i18n{networkSimEnterOldPin}">
         </paper-input>
@@ -134,7 +134,7 @@
           [[getErrorMsg_(error_, networkProperties)]]
         </div>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button on-tap="sendChangePin_">
           $i18n{networkSimChange}
         </paper-button>
@@ -144,8 +144,8 @@
     <!-- Unlock PIN dialog -->
     <dialog is="cr-dialog" id="unlockPinDialog" close-text="$i18n{close}"
         on-close="onUnlockPinDialogClose_">
-      <div class="title">$i18n{networkSimLockedTitle}</div>
-      <div class="body">
+      <div class="title" slot="title">$i18n{networkSimLockedTitle}</div>
+      <div class="body" slot="body">
         <paper-input id="unlockPin" class="pin" no-label-float autofocus
             label="$i18n{networkSimEnterPin}">
           <iron-a11y-keys keys="enter" on-keys-pressed="sendUnlockPin_">
@@ -155,7 +155,7 @@
           [[getErrorMsg_(error_, networkProperties)]]
         </div>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button on-tap="sendUnlockPin_">
           $i18n{networkSimUnlock}
         </paper-button>
@@ -165,8 +165,8 @@
     <!-- Unlock PUK dialog -->
     <dialog is="cr-dialog" id="unlockPukDialog" close-text="$i18n{close}"
         on-close="onUnlockPinDialogClose_">
-      <div class="title">$i18n{networkSimLockedTitle}</div>
-      <div class="body">
+      <div class="title" slot="title">$i18n{networkSimLockedTitle}</div>
+      <div class="body" slot="body">
         <div>
           Enter the 8-digit PIN Unblocking Key provided by your carrier
         </div>
@@ -188,7 +188,7 @@
           [[getErrorMsg_(error_, networkProperties)]]
         </div>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button on-tap="sendUnlockPuk_">
           $i18n{networkSimUnlock}
         </paper-button>
diff --git a/chrome/browser/resources/settings/internet_page/tether_connection_dialog.html b/chrome/browser/resources/settings/internet_page/tether_connection_dialog.html
index 518637b..1424885a 100644
--- a/chrome/browser/resources/settings/internet_page/tether_connection_dialog.html
+++ b/chrome/browser/resources/settings/internet_page/tether_connection_dialog.html
@@ -67,8 +67,8 @@
     </style>
     <dialog is="cr-dialog" id="dialog" on-cancel="onDialogCanceled_"
         close-text="$i18n{close}" on-closed="onDialogCanceled_">
-      <div class="title">$i18n{tetherConnectionDialogTitle}</div>
-      <div class="body">
+      <div class="title" slot="title">$i18n{tetherConnectionDialogTitle}</div>
+      <div class="body" slot="body">
         <span id="availability-title">
           $i18n{tetherConnectionAvailableDeviceTitle}
         </span>
@@ -102,7 +102,7 @@
           </li>
         </ul>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button class="cancel-button" on-tap="onNotNowTap_">
           $i18n{tetherConnectionNotNowButton}
         </paper-button>
diff --git a/chrome/browser/resources/settings/languages_page/add_languages_dialog.html b/chrome/browser/resources/settings/languages_page/add_languages_dialog.html
index b56c185..d3591dd 100644
--- a/chrome/browser/resources/settings/languages_page/add_languages_dialog.html
+++ b/chrome/browser/resources/settings/languages_page/add_languages_dialog.html
@@ -40,8 +40,8 @@
       }
     </style>
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
-      <div class="title">$i18n{addLanguagesDialogTitle}</div>
-      <div class="body" scrollable>
+      <div class="title" slot="title">$i18n{addLanguagesDialogTitle}</div>
+      <div class="body" slot="body" scrollable>
         <settings-subpage-search label="[[searchLabel]]"
             on-search-changed="onSearchChanged_" autofocus>
         </settings-subpage-search>
@@ -58,7 +58,7 @@
           </template>
         </iron-list>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <div class="action-buttons">
           <paper-button class="cancel-button" on-tap="onCancelButtonTap_">
             $i18n{cancel}
diff --git a/chrome/browser/resources/settings/on_startup_page/startup_url_dialog.html b/chrome/browser/resources/settings/on_startup_page/startup_url_dialog.html
index 997fdfb3..dc36820 100644
--- a/chrome/browser/resources/settings/on_startup_page/startup_url_dialog.html
+++ b/chrome/browser/resources/settings/on_startup_page/startup_url_dialog.html
@@ -10,13 +10,13 @@
   <template>
     <style include="settings-shared"></style>
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
-      <div class="title">[[dialogTitle_]]</div>
-      <div class="body">
+      <div class="title" slot="title">[[dialogTitle_]]</div>
+      <div class="body" slot="body">
         <paper-input always-float-label id="url" label="$i18n{onStartupSiteUrl}"
             value="{{url_}}" on-input="validate_" autofocus>
         </paper-input>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <div class="action-buttons">
           <paper-button class="cancel-button" on-tap="onCancelTap_"
               id="cancel">$i18n{cancel}</paper-button>
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/address_edit_dialog.html b/chrome/browser/resources/settings/passwords_and_forms_page/address_edit_dialog.html
index c7e24a8..32684422 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/address_edit_dialog.html
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/address_edit_dialog.html
@@ -89,8 +89,8 @@
       }
     </style>
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
-      <div class="title">[[title_]]</div>
-      <div class="body">
+      <div class="title" slot="title">[[title_]]</div>
+      <div class="body" slot="body">
         <template is="dom-repeat" items="[[addressWrapper_]]">
           <div class="address-row">
             <template is="dom-repeat" items="[[item]]">
@@ -138,7 +138,7 @@
           </paper-input>
         </div>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button id="cancelButton" class="cancel-button"
             on-tap="onCancelTap_">
           $i18n{cancel}
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/credit_card_edit_dialog.html b/chrome/browser/resources/settings/passwords_and_forms_page/credit_card_edit_dialog.html
index d230f3a..abd53ae 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/credit_card_edit_dialog.html
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/credit_card_edit_dialog.html
@@ -50,8 +50,8 @@
       }
     </style>
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
-      <div class="title">[[title_]]</div>
-      <div class="body">
+      <div class="title" slot="title">[[title_]]</div>
+      <div class="body" slot="body">
         <paper-input id="nameInput" label="$i18n{creditCardName}"
             value="{{creditCard.name}}" always-float-label autofocus
             on-input="onCreditCardNameOrNumberChanged_">
@@ -81,11 +81,13 @@
           </select>
           <span class="md-select-underline"></span>
         </span>
-        <span id="expired" hidden="[[!checkIfCardExpired_(expirationMonth_, expirationYear_)]]">
+        <span id="expired"
+            hidden="[[!checkIfCardExpired_(expirationMonth_, expirationYear_)]]"
+            >
           $i18n{creditCardExpired}
         </span>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button id="cancelButton" class="cancel-button"
             on-tap="onCancelButtonTap_">$i18n{cancel}</paper-button>
         <paper-button id="saveButton" class="action-button"
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.html b/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.html
index 00db6769d..4c8f585a 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.html
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/password_edit_dialog.html
@@ -39,8 +39,8 @@
       }
     </style>
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
-      <div class="title">$i18n{passwordDetailsTitle}</div>
-      <div class="body">
+      <div class="title" slot="title">$i18n{passwordDetailsTitle}</div>
+      <div class="body" slot="body">
         <paper-input id="websiteInput" label="$i18n{editPasswordWebsiteLabel}"
             value="[[item.loginPair.urls.link]]" readonly always-float-label
             on-tap="onReadonlyInputTap_">
@@ -65,7 +65,7 @@
           </button>
         </div>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button class="action-button" on-tap="onActionButtonTap_">
           $i18n{passwordsDone}
         </paper-button>
diff --git a/chrome/browser/resources/settings/people_page/easy_unlock_turn_off_dialog.html b/chrome/browser/resources/settings/people_page/easy_unlock_turn_off_dialog.html
index c2ebdbd4..0bc4943 100644
--- a/chrome/browser/resources/settings/people_page/easy_unlock_turn_off_dialog.html
+++ b/chrome/browser/resources/settings/people_page/easy_unlock_turn_off_dialog.html
@@ -13,11 +13,12 @@
   <template>
     <style include="settings-shared"></style>
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
-      <div class="title">[[getTitleText_(status_)]]</div>
-      <div class="body">
+      <div class="title" slot="title">[[getTitleText_(status_)]]</div>
+      <div class="body" slot="body">
         [[getDescriptionText_(status_)]]
       </div>
-      <div class="button-container" hidden="[[isButtonBarHidden_(status_)]]">
+      <div class="button-container" slot="button-container"
+          hidden="[[isButtonBarHidden_(status_)]]">
         <paper-spinner active="[[isSpinnerActive_(status_)]]">
         </paper-spinner>
         <paper-button class="cancel-button" on-tap="onCancelTap_"
diff --git a/chrome/browser/resources/settings/people_page/import_data_dialog.html b/chrome/browser/resources/settings/people_page/import_data_dialog.html
index 72b1de0..df42eaa 100644
--- a/chrome/browser/resources/settings/people_page/import_data_dialog.html
+++ b/chrome/browser/resources/settings/people_page/import_data_dialog.html
@@ -35,9 +35,10 @@
         width: 100%;
       }
     </style>
-    <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}" ignore-popstate>
-      <div class="title">$i18n{importTitle}</div>
-      <div class="body">
+    <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}"
+        ignore-popstate>
+      <div class="title" slot="title">$i18n{importTitle}</div>
+      <div class="body" slot="body">
         <div hidden$="[[!hasImportStatus_(
             importStatusEnum_.SUCCEEDED, importStatus_)]]">
           <iron-icon id="successIcon" icon="settings:check-circle">
@@ -91,7 +92,7 @@
           </settings-checkbox>
         </div>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-spinner
             active="[[hasImportStatus_(
                 importStatusEnum_.IN_PROGRESS, importStatus_)]]"
@@ -123,4 +124,4 @@
     </dialog>
   </template>
   <script src="import_data_dialog.js"></script>
-</dom-module>
+:</dom-module>
diff --git a/chrome/browser/resources/settings/people_page/password_prompt_dialog.html b/chrome/browser/resources/settings/people_page/password_prompt_dialog.html
index f7c1547..ca3cc858 100644
--- a/chrome/browser/resources/settings/people_page/password_prompt_dialog.html
+++ b/chrome/browser/resources/settings/people_page/password_prompt_dialog.html
@@ -20,8 +20,8 @@
 
     <dialog is="cr-dialog" id="dialog" on-close="onClose_"
         close-text="$i18n{close}">
-      <div class="title">$i18n{passwordPromptTitle}</div>
-      <div class="body">
+      <div class="title" slot="title">$i18n{passwordPromptTitle}</div>
+      <div class="body" slot="body">
 
         <div class="settings-box first">$i18n{passwordPromptEnterPassword}</div>
 
@@ -33,7 +33,7 @@
             aria-disabled="false">
         </paper-input>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button class="cancel-button" on-tap="onCancelTap_">
           $i18n{cancel}
         </paper-button>
diff --git a/chrome/browser/resources/settings/people_page/people_page.html b/chrome/browser/resources/settings/people_page/people_page.html
index 902f806b..76a5007 100644
--- a/chrome/browser/resources/settings/people_page/people_page.html
+++ b/chrome/browser/resources/settings/people_page/people_page.html
@@ -289,13 +289,13 @@
       <dialog is="cr-dialog" id="disconnectDialog"
           ignore-popstate ignore-enter-key
           on-close="onDisconnectClosed_" close-text="$i18n{close}">
-        <div class="title">$i18n{syncDisconnectTitle}</div>
-        <div class="body">
+        <div class="title" slot="title">$i18n{syncDisconnectTitle}</div>
+        <div class="body" slot="body">
           <div inner-h-t-m-l="[[
               getDisconnectExplanationHtml_(syncStatus.domain)]]">
           </div>
         </div>
-        <div class="button-container">
+        <div class="button-container" slot="button-container">
           <paper-button on-tap="onDisconnectCancel_" class="cancel-button">
             $i18n{cancel}
           </paper-button>
@@ -311,7 +311,7 @@
         </div>
 <if expr="(not chromeos and is_posix) or is_win or is_macosx">
         <template is="dom-if" if="[[!syncStatus.domain]]">
-          <div class="footer border-top-divider">
+          <div class="footer border-top-divider" slot="footer">
             <div class="settings-box first">
               <paper-checkbox id="deleteProfile" class="start"
                   checked="{{deleteProfile_}}">
diff --git a/chrome/browser/resources/settings/people_page/setup_fingerprint_dialog.html b/chrome/browser/resources/settings/people_page/setup_fingerprint_dialog.html
index 3d7a97ea..a815334 100644
--- a/chrome/browser/resources/settings/people_page/setup_fingerprint_dialog.html
+++ b/chrome/browser/resources/settings/people_page/setup_fingerprint_dialog.html
@@ -54,8 +54,8 @@
 
     <dialog is="cr-dialog" id="dialog" on-close="close"
         close-text="$i18n{close}">
-      <div class="title">$i18n{configureFingerprintTitle}</div>
-      <div class="body">
+      <div class="title" slot="title">$i18n{configureFingerprintTitle}</div>
+      <div class="body" slot="body">
         <div class="settings-box first">
           <span class="middle">[[getInstructionMessage_(step_)]]</span>
         </div>
@@ -71,7 +71,7 @@
           <span class="middle">[[problemMessage_]]</span>
         </div>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button id="addAnotherButton" on-tap="onAddAnotherFingerprint_"
             hidden$="[[hideAddAnother_(step_)]]">
           $i18n{configureFingerprintAddAnotherButton}
diff --git a/chrome/browser/resources/settings/people_page/setup_pin_dialog.html b/chrome/browser/resources/settings/people_page/setup_pin_dialog.html
index ef5d2bb..801dc1e9 100644
--- a/chrome/browser/resources/settings/people_page/setup_pin_dialog.html
+++ b/chrome/browser/resources/settings/people_page/setup_pin_dialog.html
@@ -45,8 +45,8 @@
 
     <dialog is="cr-dialog" id="dialog" on-close="close"
         close-text="$i18n{close}">
-      <div class="title">[[getTitleMessage_(isConfirmStep_)]]</div>
-      <div class="body">
+      <div class="title" slot="title">[[getTitleMessage_(isConfirmStep_)]]</div>
+      <div class="body" slot="body">
         <!-- Pin keyboard -->
         <div id="pinKeyboardDiv" class="settings-box continuation">
           <pin-keyboard id="pinKeyboard" on-pin-change="onPinChange_"
@@ -61,7 +61,7 @@
           </pin-keyboard>
         </div>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button class="cancel-button" on-tap="onCancelTap_">
           $i18n{cancel}
         </paper-button>
diff --git a/chrome/browser/resources/settings/people_page/users_add_user_dialog.html b/chrome/browser/resources/settings/people_page/users_add_user_dialog.html
index 4b02f20..9fd1e6c 100644
--- a/chrome/browser/resources/settings/people_page/users_add_user_dialog.html
+++ b/chrome/browser/resources/settings/people_page/users_add_user_dialog.html
@@ -18,13 +18,13 @@
       }
     </style>
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
-      <div class="title">$i18n{addUsers}</div>
-      <div class="body">
+      <div class="title" slot="title">$i18n{addUsers}</div>
+      <div class="body" slot="body">
         <paper-input id="addUserInput" label="$i18n{addUsersEmail}" autofocus
             on-input="validate_" invalid="[[!isValid_]]">
         </paper-input>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button class="cancel-button" on-tap="onCancelTap_">
           $i18n{cancel}
         </paper-button>
diff --git a/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog_util.html b/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog_util.html
index 30fd218..611578d3 100644
--- a/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog_util.html
+++ b/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog_util.html
@@ -116,13 +116,13 @@
     </style>
 
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
-      <div class="title">
+      <div class="title" slot="title">
         <content select=".dialog-title"></content>
       </div>
-      <div class="body">
+      <div class="body" slot="body">
         <content select=".dialog-body"></content>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <content select=".dialog-buttons"></content>
       </div>
     </dialog>
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html
index e2ef551..e4555fd9 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -49,9 +49,9 @@
       <dialog is="cr-dialog" id="confirmDoNotTrackDialog"
           close-text="$i18n{close}" on-cancel="onDoNotTrackDialogCancel_"
           on-close="onDoNotTrackDialogClosed_">
-        <div class="title">$i18n{doNotTrackDialogTitle}</div>
-        <div class="body">$i18nRaw{doNotTrackDialogMessage}</div>
-        <div class="button-container">
+        <div class="title" slot="title">$i18n{doNotTrackDialogTitle}</div>
+        <div class="body" slot="body">$i18nRaw{doNotTrackDialogMessage}</div>
+        <div class="button-container" slot="button-container">
           <paper-button class="cancel-button"
               on-tap="onDoNotTrackDialogCancel_">
             $i18n{cancel}
diff --git a/chrome/browser/resources/settings/reset_page/powerwash_dialog.html b/chrome/browser/resources/settings/reset_page/powerwash_dialog.html
index 3156d93..bd42375 100644
--- a/chrome/browser/resources/settings/reset_page/powerwash_dialog.html
+++ b/chrome/browser/resources/settings/reset_page/powerwash_dialog.html
@@ -12,8 +12,8 @@
     </style>
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}"
         ignore-enter-key>
-      <div class="title">$i18n{powerwashDialogTitle}</div>
-      <div class="body">
+      <div class="title" slot="title">$i18n{powerwashDialogTitle}</div>
+      <div class="body" slot="body">
         <span>
           $i18n{powerwashDialogExplanation}
           <a href="$i18nRaw{powerwashLearnMoreUrl}" target="_blank">
@@ -21,7 +21,7 @@
           </a>
         </span>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button class="cancel-button" on-tap="onCancelTap_"
             id="cancel">$i18n{cancel}</paper-button>
         <paper-button class="action-button" id="powerwash"
diff --git a/chrome/browser/resources/settings/reset_page/reset_profile_banner.html b/chrome/browser/resources/settings/reset_page/reset_profile_banner.html
index fe6d5e5..31741b41 100644
--- a/chrome/browser/resources/settings/reset_page/reset_profile_banner.html
+++ b/chrome/browser/resources/settings/reset_page/reset_profile_banner.html
@@ -9,8 +9,8 @@
   <template>
     <style include="settings-shared"></style>
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}" ignore-popstate>
-      <div class="title">$i18n{resetAutomatedDialogTitle}</div>
-      <div class="body">
+      <div class="title" slot="title">$i18n{resetAutomatedDialogTitle}</div>
+      <div class="body" slot="body">
         <span id="description">
           $i18n{resetProfileBannerDescription}
           <a id="learnMore"
@@ -18,7 +18,7 @@
              target="_blank">$i18n{learnMore}</a>
         </span>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button class="cancel-button" on-tap="onOkTap_" id="ok">
           $i18n{ok}
         </paper-button>
diff --git a/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html b/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html
index 898da72..520a2e0 100644
--- a/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html
+++ b/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html
@@ -21,10 +21,10 @@
     </style>
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}"
         ignore-popstate ignore-enter-key>
-      <div class="title">
+      <div class="title" slot="title">
         [[getPageTitle_(isTriggered_, triggeredResetToolName_)]]
       </div>
-      <div class="body">
+      <div class="body" slot="body">
         <span>
           [[getExplanationText_(isTriggered_, triggeredResetToolName_)]]
           <a href="$i18nRaw{resetPageLearnMoreUrl}" target="_blank">
@@ -32,7 +32,7 @@
           </a>
         </span>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-spinner id="resetSpinner" active="[[clearingInProgress_]]">
         </paper-spinner>
         <paper-button class="cancel-button" on-tap="onCancelTap_"
@@ -44,7 +44,7 @@
           $i18n{resetPageCommit}
         </paper-button>
       </div>
-      <div class="footer border-top-divider">
+      <div class="footer border-top-divider" slot="footer">
         <paper-checkbox id="sendSettings" checked>
           $i18nRaw{resetPageFeedback}</paper-checkbox>
       </div>
diff --git a/chrome/browser/resources/settings/search_engines_page/search_engine_dialog.html b/chrome/browser/resources/settings/search_engines_page/search_engine_dialog.html
index 0b0db50..f9ee6494 100644
--- a/chrome/browser/resources/settings/search_engines_page/search_engine_dialog.html
+++ b/chrome/browser/resources/settings/search_engines_page/search_engine_dialog.html
@@ -23,8 +23,8 @@
       }
     </style>
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
-      <div class="title">[[dialogTitle_]]</div>
-      <div class="body">
+      <div class="title" slot="title">[[dialogTitle_]]</div>
+      <div class="body" slot="body">
         <paper-input always-float-label id="searchEngine"
             label="$i18n{searchEnginesSearchEngine}"
             error-message="$i18n{notValid}"
@@ -43,7 +43,7 @@
             disabled$="[[model.urlLocked]]">
         </paper-input>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button class="cancel-button" on-tap="cancel_" id="cancel">
             $i18n{cancel}</paper-button>
         <paper-button id="actionButton" class="action-button"
diff --git a/chrome/browser/resources/settings/site_settings/add_site_dialog.html b/chrome/browser/resources/settings/site_settings/add_site_dialog.html
index b8c97a3..7e0080c 100644
--- a/chrome/browser/resources/settings/site_settings/add_site_dialog.html
+++ b/chrome/browser/resources/settings/site_settings/add_site_dialog.html
@@ -22,8 +22,8 @@
       }
     </style>
     <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
-      <div class="title">$i18n{addSiteTitle}</div>
-      <div class="body">
+      <div class="title" slot="title">$i18n{addSiteTitle}</div>
+      <div class="body" slot="body">
         <paper-input id="site" always-float-label label="$i18n{addSite}"
             placeholder="$i18n{addSiteExceptionPlaceholder}"
             value="{{site_}}" on-input="validate_"
@@ -33,7 +33,7 @@
           $i18n{incognitoSiteOnly}
         </paper-checkbox>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <paper-button class="cancel-button" on-tap="onCancelTap_">
           $i18n{cancel}
         </paper-button>
diff --git a/chrome/browser/resources/settings/site_settings/edit_exception_dialog.html b/chrome/browser/resources/settings/site_settings/edit_exception_dialog.html
index ffbfd7c7..44430ca 100644
--- a/chrome/browser/resources/settings/site_settings/edit_exception_dialog.html
+++ b/chrome/browser/resources/settings/site_settings/edit_exception_dialog.html
@@ -10,15 +10,15 @@
   <template>
     <style include="settings-shared"></style>
     <dialog is="cr-dialog" id="dialog">
-      <div class="title">$i18n{editSiteTitle}</div>
-      <div class="body">
+      <div class="title" slot="title">$i18n{editSiteTitle}</div>
+      <div class="body" slot="body">
         <paper-input always-float-label label="$i18n{addSite}"
             placeholder="$i18n{addSiteExceptionPlaceholder}" value="{{origin_}}"
             on-input="validate_" error-message="$i18n{notValidWebAddress}"
             invalid="[[invalid_]]" autofocus>
         </paper-input>
       </div>
-      <div class="button-container">
+      <div class="button-container" slot="button-container">
         <div class="action-buttons">
           <paper-button class="cancel-button" on-tap="onCancelTap_"
               id="cancel">$i18n{cancel}</paper-button>
diff --git a/chrome/browser/resources/settings/site_settings/site_data.html b/chrome/browser/resources/settings/site_settings/site_data.html
index a956e50bf..e2a4304 100644
--- a/chrome/browser/resources/settings/site_settings/site_data.html
+++ b/chrome/browser/resources/settings/site_settings/site_data.html
@@ -68,9 +68,11 @@
     <!-- Confirm Delete dialog -->
     <dialog is="cr-dialog" id="confirmDeleteDialog" close-text="$i18n{close}"
         on-close="onConfirmDeleteDialogClosed_">
-      <div class="title">$i18n{siteSettingsCookieRemoveDialogTitle}</div>
-      <div class="body">[[confirmationDeleteMsg_]]</div>
-      <div class="button-container">
+      <div class="title" slot="title">
+        $i18n{siteSettingsCookieRemoveDialogTitle}
+      </div>
+      <div class="body" slot="body">[[confirmationDeleteMsg_]]</div>
+      <div class="button-container" slot="button-container">
         <paper-button class="cancel-button" on-tap="onCloseDialog_">
           $i18n{cancel}
         </paper-button>
diff --git a/chrome/browser/resources/settings/site_settings/site_details.html b/chrome/browser/resources/settings/site_settings/site_details.html
index 6fd3fcf..01f017a8 100644
--- a/chrome/browser/resources/settings/site_settings/site_details.html
+++ b/chrome/browser/resources/settings/site_settings/site_details.html
@@ -25,9 +25,11 @@
     </style>
     <!-- Confirm Delete dialog -->
     <dialog is="cr-dialog" id="confirmDeleteDialog" close-text="$i18n{close}">
-      <div class="title">$i18n{siteSettingsSiteRemoveDialogTitle}</div>
-      <div class="body">[[confirmationDeleteMsg_]]</div>
-      <div class="button-container">
+      <div class="title" slot="title">
+        $i18n{siteSettingsSiteRemoveDialogTitle}
+      </div>
+      <div class="body" slot="body">[[confirmationDeleteMsg_]]</div>
+      <div class="button-container" slot="button-container">
         <paper-button class="cancel-button" on-tap="onCloseDialog_">
           $i18n{cancel}
         </paper-button>
diff --git a/chrome/browser/safe_browsing/BUILD.gn b/chrome/browser/safe_browsing/BUILD.gn
index d5dc53b..d48eab04 100644
--- a/chrome/browser/safe_browsing/BUILD.gn
+++ b/chrome/browser/safe_browsing/BUILD.gn
@@ -13,8 +13,6 @@
 
 static_library("safe_browsing") {
   sources = [
-    "browser_url_loader_throttle.cc",
-    "browser_url_loader_throttle.h",
     "chrome_cleaner/chrome_cleaner_controller_win.cc",
     "chrome_cleaner/chrome_cleaner_controller_win.h",
     "chrome_cleaner/chrome_cleaner_fetcher_win.cc",
@@ -23,6 +21,8 @@
     "chrome_cleaner/chrome_cleaner_navigation_util_win.h",
     "chrome_cleaner/chrome_cleaner_runner_win.cc",
     "chrome_cleaner/chrome_cleaner_runner_win.h",
+    "chrome_cleaner/chrome_cleaner_state_change_observer_win.cc",
+    "chrome_cleaner/chrome_cleaner_state_change_observer_win.h",
     "chrome_cleaner/reporter_runner_win.cc",
     "chrome_cleaner/reporter_runner_win.h",
     "chrome_cleaner/settings_resetter_win.cc",
@@ -35,12 +35,10 @@
     "chrome_cleaner/srt_field_trial_win.h",
     "chrome_cleaner/srt_global_error_win.cc",
     "chrome_cleaner/srt_global_error_win.h",
-    "mojo_safe_browsing_impl.cc",
-    "mojo_safe_browsing_impl.h",
     "safe_browsing_tab_observer.cc",
     "safe_browsing_tab_observer.h",
-    "safe_browsing_url_checker_impl.cc",
-    "safe_browsing_url_checker_impl.h",
+    "url_checker_delegate_impl.cc",
+    "url_checker_delegate_impl.h",
   ]
 
   deps = [
diff --git a/chrome/browser/safe_browsing/certificate_reporting_service_test_utils.cc b/chrome/browser/safe_browsing/certificate_reporting_service_test_utils.cc
index 85ce984..b713c29 100644
--- a/chrome/browser/safe_browsing/certificate_reporting_service_test_utils.cc
+++ b/chrome/browser/safe_browsing/certificate_reporting_service_test_utils.cc
@@ -71,6 +71,7 @@
 
 RequestObserver::RequestObserver()
     : num_events_to_wait_for_(0u), num_received_events_(0u) {}
+
 RequestObserver::~RequestObserver() {}
 
 void RequestObserver::Wait(unsigned int num_events_to_wait_for) {
@@ -220,10 +221,11 @@
     ReportSendingResult expected_report_result,
     const uint8_t* server_private_key)
     : expected_report_result_(expected_report_result),
-      server_private_key_(server_private_key),
-      weak_factory_(this) {}
+      server_private_key_(server_private_key) {}
 
-CertReportJobInterceptor::~CertReportJobInterceptor() {}
+CertReportJobInterceptor::~CertReportJobInterceptor() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+}
 
 net::URLRequestJob* CertReportJobInterceptor::MaybeInterceptRequest(
     net::URLRequest* request,
@@ -232,11 +234,7 @@
 
   const std::string serialized_report =
       GetReportContents(request, server_private_key_);
-  content::BrowserThread::PostTask(
-      content::BrowserThread::UI, FROM_HERE,
-      base::BindOnce(&CertReportJobInterceptor::RequestCreated,
-                     weak_factory_.GetWeakPtr(), serialized_report,
-                     expected_report_result_));
+  RequestCreated(serialized_report, expected_report_result_);
 
   if (expected_report_result_ == REPORTS_FAIL) {
     return new DelayableCertReportURLRequestJob(
@@ -270,7 +268,7 @@
   content::BrowserThread::PostTask(
       content::BrowserThread::IO, FROM_HERE,
       base::BindOnce(&CertReportJobInterceptor::SetFailureModeOnIOThread,
-                     weak_factory_.GetWeakPtr(), expected_report_result));
+                     base::Unretained(this), expected_report_result));
 }
 
 void CertReportJobInterceptor::Resume() {
@@ -307,8 +305,11 @@
 void CertReportJobInterceptor::RequestCreated(
     const std::string& serialized_report,
     ReportSendingResult expected_report_result) const {
-  request_created_observer_.OnRequest(serialized_report,
-                                      expected_report_result);
+  content::BrowserThread::PostTask(
+      content::BrowserThread::UI, FROM_HERE,
+      base::BindOnce(&RequestObserver::OnRequest,
+                     base::Unretained(&request_created_observer_),
+                     serialized_report, expected_report_result));
 }
 
 void CertReportJobInterceptor::RequestDestructed(
diff --git a/chrome/browser/safe_browsing/certificate_reporting_service_test_utils.h b/chrome/browser/safe_browsing/certificate_reporting_service_test_utils.h
index c6172da..dc55a10 100644
--- a/chrome/browser/safe_browsing/certificate_reporting_service_test_utils.h
+++ b/chrome/browser/safe_browsing/certificate_reporting_service_test_utils.h
@@ -137,6 +137,8 @@
 
 // A job interceptor that returns a failed, succesful or delayed request job.
 // Used to simulate report uploads that fail, succeed or hang.
+// The caller is responsible for guaranteeing that |this| is kept alive for
+// all posted tasks and URLRequestJob objects.
 class CertReportJobInterceptor : public net::URLRequestInterceptor {
  public:
   CertReportJobInterceptor(ReportSendingResult expected_report_result,
@@ -177,9 +179,7 @@
   mutable RequestObserver request_created_observer_;
   mutable RequestObserver request_destroyed_observer_;
 
-  mutable base::WeakPtr<DelayableCertReportURLRequestJob> delayed_request_ =
-      nullptr;
-  mutable base::WeakPtrFactory<CertReportJobInterceptor> weak_factory_;
+  mutable base::WeakPtr<DelayableCertReportURLRequestJob> delayed_request_;
 
   DISALLOW_COPY_AND_ASSIGN(CertReportJobInterceptor);
 };
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_state_change_observer_win.cc b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_state_change_observer_win.cc
new file mode 100644
index 0000000..1b3dedc
--- /dev/null
+++ b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_state_change_observer_win.cc
@@ -0,0 +1,74 @@
+// Copyright (c) 2017 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/safe_browsing/chrome_cleaner/chrome_cleaner_state_change_observer_win.h"
+
+#include "base/threading/thread_checker.h"
+#include "content/public/browser/browser_thread.h"
+
+using content::BrowserThread;
+
+namespace safe_browsing {
+
+ChromeCleanerStateChangeObserver::ChromeCleanerStateChangeObserver(
+    const OnShowCleanupUIChangeCallback& on_show_cleanup_ui_change)
+    : on_show_cleanup_ui_change_(on_show_cleanup_ui_change),
+      controller_(ChromeCleanerController::GetInstance()),
+      cached_should_show_cleanup_in_settings_ui_(
+          controller_->ShouldShowCleanupInSettingsUI()),
+      cached_cleanup_powered_by_partner_(controller_->IsPoweredByPartner()) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  controller_->AddObserver(this);
+}
+
+ChromeCleanerStateChangeObserver::~ChromeCleanerStateChangeObserver() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  controller_->RemoveObserver(this);
+}
+
+void ChromeCleanerStateChangeObserver::OnCleanupStateChange() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  bool show_cleanup = controller_->ShouldShowCleanupInSettingsUI();
+  bool powered_by_partner = controller_->IsPoweredByPartner();
+
+  // Avoid calling the observer if nothing changed.
+  if (show_cleanup == cached_should_show_cleanup_in_settings_ui_ &&
+      powered_by_partner == cached_cleanup_powered_by_partner_) {
+    return;
+  }
+
+  cached_should_show_cleanup_in_settings_ui_ = show_cleanup;
+  cached_cleanup_powered_by_partner_ = powered_by_partner;
+  on_show_cleanup_ui_change_.Run(show_cleanup, powered_by_partner);
+}
+
+void ChromeCleanerStateChangeObserver::OnIdle(
+    ChromeCleanerController::IdleReason idle_reason) {
+  OnCleanupStateChange();
+}
+
+void ChromeCleanerStateChangeObserver::OnScanning() {
+  OnCleanupStateChange();
+}
+
+void ChromeCleanerStateChangeObserver::OnInfected(
+    const std::set<base::FilePath>& files) {
+  OnCleanupStateChange();
+}
+
+void ChromeCleanerStateChangeObserver::OnCleaning(
+    const std::set<base::FilePath>& files) {
+  OnCleanupStateChange();
+}
+
+void ChromeCleanerStateChangeObserver::OnRebootRequired() {
+  OnCleanupStateChange();
+}
+
+void ChromeCleanerStateChangeObserver::OnLogsEnabledChanged(bool logs_enabled) {
+  OnCleanupStateChange();
+}
+
+}  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_state_change_observer_win.h b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_state_change_observer_win.h
new file mode 100644
index 0000000..a8d2c1e
--- /dev/null
+++ b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_state_change_observer_win.h
@@ -0,0 +1,53 @@
+// Copyright 2017 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_SAFE_BROWSING_CHROME_CLEANER_CHROME_CLEANER_STATE_CHANGE_OBSERVER_WIN_H_
+#define CHROME_BROWSER_SAFE_BROWSING_CHROME_CLEANER_CHROME_CLEANER_STATE_CHANGE_OBSERVER_WIN_H_
+
+#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h"
+
+namespace safe_browsing {
+
+// A helper class which automatically starts observing |ChromeCleanerController|
+// when instantiated and calls the given callback with new |show_cleanup| and
+// |powered_by_partner| values if either of them changed.
+// Un-registerers itself as an observer on deletion.
+// Since ChromeCleanupController lives and has its methods called on the UI
+// thread, this class should live on and be destroyed on the UI thread as well
+// to guarantee that a state change does not race the destructor.
+class ChromeCleanerStateChangeObserver
+    : public ChromeCleanerController::Observer {
+ public:
+  typedef base::RepeatingCallback<void(bool showCleanup, bool partnerPowered)>
+      OnShowCleanupUIChangeCallback;
+
+  ChromeCleanerStateChangeObserver(
+      const OnShowCleanupUIChangeCallback& on_state_change);
+  ~ChromeCleanerStateChangeObserver() override;
+
+  // ChromeCleanerController::Observer implementation.
+  void OnIdle(ChromeCleanerController::IdleReason idle_reason) override;
+  void OnScanning() override;
+  void OnInfected(const std::set<base::FilePath>& files) override;
+  void OnCleaning(const std::set<base::FilePath>& files) override;
+  void OnRebootRequired() override;
+  void OnLogsEnabledChanged(bool logs_enabled) override;
+
+ private:
+  OnShowCleanupUIChangeCallback on_show_cleanup_ui_change_;
+
+  // Will be called when any of the Observer override methods are called.
+  void OnCleanupStateChange();
+
+  // Raw pointer to a singleton. Must outlive this object.
+  ChromeCleanerController* controller_;
+  bool cached_should_show_cleanup_in_settings_ui_;
+  bool cached_cleanup_powered_by_partner_;
+
+  DISALLOW_COPY_AND_ASSIGN(ChromeCleanerStateChangeObserver);
+};
+
+}  // namespace safe_browsing
+
+#endif  // CHROME_BROWSER_SAFE_BROWSING_CHROME_CLEANER_CHROME_CLEANER_STATE_CHANGE_OBSERVER_WIN_H_
diff --git a/chrome/browser/safe_browsing/url_checker_delegate_impl.cc b/chrome/browser/safe_browsing/url_checker_delegate_impl.cc
new file mode 100644
index 0000000..d813cb9
--- /dev/null
+++ b/chrome/browser/safe_browsing/url_checker_delegate_impl.cc
@@ -0,0 +1,93 @@
+// Copyright 2017 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/safe_browsing/url_checker_delegate_impl.h"
+
+#include "base/bind.h"
+#include "chrome/browser/prerender/prerender_contents.h"
+#include "chrome/browser/prerender/prerender_final_status.h"
+#include "chrome/browser/safe_browsing/ui_manager.h"
+#include "components/safe_browsing_db/database_manager.h"
+#include "components/safe_browsing_db/v4_protocol_manager_util.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/web_contents.h"
+
+namespace safe_browsing {
+namespace {
+
+// Destroys the prerender contents associated with the web_contents, if any.
+void DestroyPrerenderContents(
+    const base::Callback<content::WebContents*()>& web_contents_getter) {
+  content::WebContents* web_contents = web_contents_getter.Run();
+  if (web_contents) {
+    prerender::PrerenderContents* prerender_contents =
+        prerender::PrerenderContents::FromWebContents(web_contents);
+    if (prerender_contents)
+      prerender_contents->Destroy(prerender::FINAL_STATUS_SAFE_BROWSING);
+  }
+}
+
+void StartDisplayingBlockingPage(
+    scoped_refptr<BaseUIManager> ui_manager,
+    const security_interstitials::UnsafeResource& resource) {
+  content::WebContents* web_contents = resource.web_contents_getter.Run();
+  if (web_contents) {
+    prerender::PrerenderContents* prerender_contents =
+        prerender::PrerenderContents::FromWebContents(web_contents);
+    if (prerender_contents) {
+      prerender_contents->Destroy(prerender::FINAL_STATUS_SAFE_BROWSING);
+    } else {
+      ui_manager->DisplayBlockingPage(resource);
+      return;
+    }
+  }
+
+  // Tab is gone or it's being prerendered.
+  content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
+                                   base::Bind(resource.callback, false));
+}
+
+}  // namespace
+
+UrlCheckerDelegateImpl::UrlCheckerDelegateImpl(
+    scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
+    scoped_refptr<SafeBrowsingUIManager> ui_manager)
+    : database_manager_(std::move(database_manager)),
+      ui_manager_(std::move(ui_manager)),
+      threat_types_(
+          CreateSBThreatTypeSet({safe_browsing::SB_THREAT_TYPE_URL_MALWARE,
+                                 safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
+                                 safe_browsing::SB_THREAT_TYPE_URL_UNWANTED})) {
+}
+
+UrlCheckerDelegateImpl::~UrlCheckerDelegateImpl() = default;
+
+void UrlCheckerDelegateImpl::MaybeDestroyPrerenderContents(
+    const base::Callback<content::WebContents*()>& web_contents_getter) {
+  // Destroy the prefetch with FINAL_STATUS_SAFEBROSWING.
+  content::BrowserThread::PostTask(
+      content::BrowserThread::UI, FROM_HERE,
+      base::BindOnce(&DestroyPrerenderContents, web_contents_getter));
+}
+
+void UrlCheckerDelegateImpl::StartDisplayingBlockingPageHelper(
+    const security_interstitials::UnsafeResource& resource) {
+  content::BrowserThread::PostTask(
+      content::BrowserThread::UI, FROM_HERE,
+      base::BindOnce(&StartDisplayingBlockingPage, ui_manager_, resource));
+}
+
+const SBThreatTypeSet& UrlCheckerDelegateImpl::GetThreatTypes() {
+  return threat_types_;
+}
+
+SafeBrowsingDatabaseManager* UrlCheckerDelegateImpl::GetDatabaseManager() {
+  return database_manager_.get();
+}
+
+BaseUIManager* UrlCheckerDelegateImpl::GetUIManager() {
+  return ui_manager_.get();
+}
+
+}  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/url_checker_delegate_impl.h b/chrome/browser/safe_browsing/url_checker_delegate_impl.h
new file mode 100644
index 0000000..43a30da
--- /dev/null
+++ b/chrome/browser/safe_browsing/url_checker_delegate_impl.h
@@ -0,0 +1,44 @@
+// Copyright 2017 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_SAFE_BROWSING_URL_CHECKER_DELEGATE_IMPL_H_
+#define CHROME_BROWSER_SAFE_BROWSING_URL_CHECKER_DELEGATE_IMPL_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "components/safe_browsing/browser/url_checker_delegate.h"
+
+namespace safe_browsing {
+
+class SafeBrowsingUIManager;
+
+class UrlCheckerDelegateImpl : public UrlCheckerDelegate {
+ public:
+  UrlCheckerDelegateImpl(
+      scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
+      scoped_refptr<SafeBrowsingUIManager> ui_manager);
+
+ private:
+  ~UrlCheckerDelegateImpl() override;
+
+  // Implementation of UrlCheckerDelegate:
+  void MaybeDestroyPrerenderContents(
+      const base::Callback<content::WebContents*()>& web_contents_getter)
+      override;
+  void StartDisplayingBlockingPageHelper(
+      const security_interstitials::UnsafeResource& resource) override;
+  const SBThreatTypeSet& GetThreatTypes() override;
+  SafeBrowsingDatabaseManager* GetDatabaseManager() override;
+  BaseUIManager* GetUIManager() override;
+
+  scoped_refptr<SafeBrowsingDatabaseManager> database_manager_;
+  scoped_refptr<SafeBrowsingUIManager> ui_manager_;
+  SBThreatTypeSet threat_types_;
+
+  DISALLOW_COPY_AND_ASSIGN(UrlCheckerDelegateImpl);
+};
+
+}  // namespace safe_browsing
+
+#endif  // CHROME_BROWSER_SAFE_BROWSING_URL_CHECKER_DELEGATE_IMPL_H_
diff --git a/chrome/browser/signin/easy_unlock_service.cc b/chrome/browser/signin/easy_unlock_service.cc
index 157ac8cd2..1137cc55 100644
--- a/chrome/browser/signin/easy_unlock_service.cc
+++ b/chrome/browser/signin/easy_unlock_service.cc
@@ -254,9 +254,7 @@
   registry->RegisterDictionaryPref(prefs::kEasyUnlockPairing,
                                    base::MakeUnique<base::DictionaryValue>());
 
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery))
-    proximity_auth::ProximityAuthPrefManager::RegisterPrefs(registry);
+  proximity_auth::ProximityAuthPrefManager::RegisterPrefs(registry);
 }
 
 // static
diff --git a/chrome/browser/signin/easy_unlock_service_regular.cc b/chrome/browser/signin/easy_unlock_service_regular.cc
index bcbedd07..f94be93 100644
--- a/chrome/browser/signin/easy_unlock_service_regular.cc
+++ b/chrome/browser/signin/easy_unlock_service_regular.cc
@@ -41,6 +41,7 @@
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/proximity_auth/logging/logging.h"
 #include "components/proximity_auth/proximity_auth_pref_manager.h"
+#include "components/proximity_auth/proximity_auth_pref_names.h"
 #include "components/proximity_auth/proximity_auth_system.h"
 #include "components/proximity_auth/screenlock_bridge.h"
 #include "components/proximity_auth/switches.h"
@@ -454,6 +455,9 @@
       prefs::kEasyUnlockAllowed,
       base::Bind(&EasyUnlockServiceRegular::OnPrefsChanged,
                  base::Unretained(this)));
+  registrar_.Add(proximity_auth::prefs::kEasyUnlockProximityThreshold,
+                 base::Bind(&EasyUnlockServiceRegular::OnPrefsChanged,
+                            base::Unretained(this)));
 
   OnPrefsChanged();
 
@@ -615,6 +619,10 @@
   // items in the dictionary are the same profile prefs used for Easy Unlock.
   std::unique_ptr<base::DictionaryValue> user_prefs_dict(
       new base::DictionaryValue());
+  user_prefs_dict->SetIntegerWithoutPathExpansion(
+      proximity_auth::prefs::kEasyUnlockProximityThreshold,
+      profile_prefs->GetInteger(
+          proximity_auth::prefs::kEasyUnlockProximityThreshold));
 
   DictionaryPrefUpdate update(local_state,
                               prefs::kEasyUnlockLocalStateUserPrefs);
diff --git a/chrome/browser/ssl/ssl_browser_tests.cc b/chrome/browser/ssl/ssl_browser_tests.cc
index 9b93a337..1c717778 100644
--- a/chrome/browser/ssl/ssl_browser_tests.cc
+++ b/chrome/browser/ssl/ssl_browser_tests.cc
@@ -2414,7 +2414,6 @@
   ASSERT_TRUE(content::ExecuteScript(
       tab,
       "var loaded = function () {"
-      "  window.domAutomationController.setAutomationId(0);"
       "  window.domAutomationController.send('mixed-image-loaded');"
       "};"
       "var img = document.createElement('img');"
diff --git a/chrome/browser/subresource_filter/subresource_filter_browsertest.cc b/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
index c9fa183..3061780 100644
--- a/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
+++ b/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
@@ -260,8 +260,13 @@
     PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
     embedded_test_server()->ServeFilesFromDirectory(test_data_dir);
     host_resolver()->AddSimulatedFailure("host-with-dns-lookup-failure");
+
     host_resolver()->AddRule("*", "127.0.0.1");
     content::SetupCrossSiteRedirector(embedded_test_server());
+
+    // Add content/test/data for cross_site_iframe_factory.html
+    embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data");
+
     ASSERT_TRUE(embedded_test_server()->Start());
     ResetConfigurationToEnableOnPhishingSites();
 
@@ -735,6 +740,67 @@
   }
 }
 
+// Tests that navigations to special URLs (e.g. about:blank, data URLs, etc)
+// which do not trigger ReadyToCommitNavigation (and therefore our activation
+// IPC), properly inherit the activation of their parent frame.
+IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
+                       NavigationsWithNoIPC_HaveActivation) {
+  const GURL url(GetTestUrl("subresource_filter/frame_set_special_urls.html"));
+  const std::vector<const char*> subframe_names{"blank", "js", "data",
+                                                "srcdoc"};
+  ConfigureAsPhishingURL(url);
+
+  ui_test_utils::NavigateToURL(browser(), url);
+  ASSERT_NO_FATAL_FAILURE(ExpectParsedScriptElementLoadedStatusInFrames(
+      subframe_names, {true, true, true, true}));
+
+  // Disallow included_script.js, and all frames should filter it in subsequent
+  // navigations.
+  ASSERT_NO_FATAL_FAILURE(
+      SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
+  ui_test_utils::NavigateToURL(browser(), url);
+  ASSERT_NO_FATAL_FAILURE(ExpectParsedScriptElementLoadedStatusInFrames(
+      subframe_names, {false, false, false, false}));
+}
+
+// Navigate to a site with site hierarchy a(b(c)). Let a navigate c to a data
+// URL, and expect that the resulting frame has activation. We expect to fail in
+// --site-per-process because c is navigated to a's process. Therefore we can't
+// sniff b's activation state from c. See crbug.com/739777.
+IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
+                       NavigateCrossProcessDataUrl_MaintainsActivation) {
+  const GURL main_url(embedded_test_server()->GetURL(
+      "a.com", "/cross_site_iframe_factory.html?a(b(c))"));
+  ConfigureAsPhishingURL(main_url);
+  ASSERT_NO_FATAL_FAILURE(
+      SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
+  const GURL included_url(embedded_test_server()->GetURL(
+      "a.com", "/subresource_filter/included_script.js"));
+
+  ui_test_utils::NavigateToURL(browser(), main_url);
+
+  // The root node will initiate the navigation; its grandchild node will be the
+  // target of the navigation.
+  content::TestNavigationObserver navigation_observer(web_contents(), 1);
+  EXPECT_TRUE(content::ExecuteScript(
+      web_contents()->GetMainFrame(),
+      base::StringPrintf(
+          "var data_url = 'data:text/html,<script src=\"%s\"></script>';"
+          "window.frames[0][0].location.href = data_url;",
+          included_url.spec().c_str())));
+  navigation_observer.Wait();
+
+  content::RenderFrameHost* target = content::FrameMatchingPredicate(
+      web_contents(), base::Bind([](content::RenderFrameHost* rfh) {
+        return rfh->GetLastCommittedURL().scheme_piece() == url::kDataScheme;
+      }));
+  ASSERT_NE(target, nullptr);
+  EXPECT_TRUE(target->GetLastCommittedOrigin().unique());
+
+  EXPECT_EQ(content::AreAllSitesIsolatedForTesting(),
+            WasParsedScriptElementLoaded(target));
+}
+
 IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
                        HistoryNavigationActivation) {
   content::ConsoleObserverDelegate console_observer(web_contents(),
@@ -962,34 +1028,6 @@
   receiver.ExpectReceivedOnce(ActivationState(ActivationLevel::DISABLED));
 }
 
-// Schemes 'about:' and 'chrome-native:' are loaded synchronously as empty
-// documents in Blink, so there is no chance (or need) to send an activation
-// IPC message. Make sure that histograms are not polluted with these loads.
-IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, NoActivationOnAboutBlank) {
-  GURL url(GetTestUrl("subresource_filter/frame_set_sync_loads.html"));
-  ASSERT_NO_FATAL_FAILURE(
-      SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
-  ConfigureAsPhishingURL(url);
-
-  base::HistogramTester histogram_tester;
-  ui_test_utils::NavigateToURL(browser(), url);
-
-  content::RenderFrameHost* frame = FindFrameByName("initially_blank");
-  ASSERT_TRUE(frame);
-  EXPECT_FALSE(WasParsedScriptElementLoaded(frame));
-
-  // Support both pre-/post-PersistentHistograms worlds. The latter is enabled
-  // through field trials, so the former is still used on offical builders.
-  content::FetchHistogramsFromChildProcesses();
-  SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
-
-  // The only frames where filtering was (even considered to be) activated
-  // should be the main frame, and the child that was navigated to an HTTP URL.
-  histogram_tester.ExpectUniqueSample(
-      kDocumentLoadActivationLevel,
-      static_cast<base::Histogram::Sample>(ActivationLevel::ENABLED), 2);
-}
-
 IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, PageLoadMetrics) {
   GURL url(GetTestUrl("subresource_filter/frame_with_included_script.html"));
   ConfigureAsPhishingURL(url);
diff --git a/chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.cc b/chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.cc
index b14fdfb..ba725f4 100644
--- a/chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.cc
+++ b/chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.cc
@@ -93,12 +93,12 @@
   switch (result) {
     case content::NavigationThrottle::PROCEED: {
       google_auth_state_subscription_.reset();
-      navigation_handle()->Resume();
+      Resume();
       break;
     }
     case content::NavigationThrottle::CANCEL:
     case content::NavigationThrottle::CANCEL_AND_IGNORE: {
-      navigation_handle()->CancelDeferredNavigation(result);
+      CancelDeferredNavigation(result);
       break;
     }
     case content::NavigationThrottle::DEFER: {
@@ -150,6 +150,5 @@
   }
 
   // Otherwise cancel immediately.
-  navigation_handle()->CancelDeferredNavigation(
-      content::NavigationThrottle::CANCEL_AND_IGNORE);
+  CancelDeferredNavigation(content::NavigationThrottle::CANCEL_AND_IGNORE);
 }
diff --git a/chrome/browser/supervised_user/supervised_user_navigation_throttle.cc b/chrome/browser/supervised_user/supervised_user_navigation_throttle.cc
index f3b535a8..e6207ffa 100644
--- a/chrome/browser/supervised_user/supervised_user_navigation_throttle.cc
+++ b/chrome/browser/supervised_user/supervised_user_navigation_throttle.cc
@@ -237,17 +237,5 @@
   if (continue_request)
     Resume();
   else
-    Cancel();
-}
-
-void SupervisedUserNavigationThrottle::Resume() {
-  DCHECK(deferred_);
-  deferred_ = false;
-  navigation_handle()->Resume();
-}
-
-void SupervisedUserNavigationThrottle::Cancel() {
-  DCHECK(deferred_);
-  deferred_ = false;
-  navigation_handle()->CancelDeferredNavigation(CANCEL);
+    CancelDeferredNavigation(CANCEL);
 }
diff --git a/chrome/browser/supervised_user/supervised_user_navigation_throttle.h b/chrome/browser/supervised_user/supervised_user_navigation_throttle.h
index f97163a..ad751764 100644
--- a/chrome/browser/supervised_user/supervised_user_navigation_throttle.h
+++ b/chrome/browser/supervised_user/supervised_user_navigation_throttle.h
@@ -52,10 +52,6 @@
 
   void OnInterstitialResult(bool continue_request);
 
-  void Resume();
-
-  void Cancel();
-
   const SupervisedUserURLFilter* url_filter_;
   bool deferred_;
   SupervisedUserURLFilter::FilteringBehavior behavior_;
diff --git a/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.cc b/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.cc
index 38572e5..a9a7e75 100644
--- a/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.cc
+++ b/chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.cc
@@ -34,6 +34,9 @@
   REQUEST_RESULT_MAX = 5
 };
 
+constexpr char kSearchAnswerHasResult[] = "SearchAnswer-HasResult";
+constexpr char kSearchAnswerOpenResultUrl[] = "SearchAnswer-OpenResultUrl";
+
 void RecordRequestResult(SearchAnswerRequestResult request_result) {
   UMA_HISTOGRAM_ENUMERATION("SearchAnswer.RequestResult", request_result,
                             SearchAnswerRequestResult::REQUEST_RESULT_MAX);
@@ -133,13 +136,21 @@
 void AnswerCardSearchProvider::DidFinishNavigation(
     content::NavigationHandle* navigation_handle) {
   if (navigation_handle->GetURL() != current_request_url_) {
+    // TODO(vadimt): Remove this and similar logging once testing is complete if
+    // we think this is not useful after release or happens too frequently.
+    VLOG(1) << "DidFinishNavigation: Another request started";
     RecordRequestResult(
         SearchAnswerRequestResult::REQUEST_RESULT_ANOTHER_REQUEST_STARTED);
     return;
   }
 
+  VLOG(1) << "DidFinishNavigation: Latest request completed";
   if (!navigation_handle->HasCommitted() || navigation_handle->IsErrorPage() ||
       !navigation_handle->IsInMainFrame()) {
+    LOG(ERROR) << "Failed to navigate: HasCommitted="
+               << navigation_handle->HasCommitted()
+               << ", IsErrorPage=" << navigation_handle->IsErrorPage()
+               << ", IsInMainFrame=" << navigation_handle->IsInMainFrame();
     RecordRequestResult(
         SearchAnswerRequestResult::REQUEST_RESULT_REQUEST_FAILED);
     return;
@@ -180,8 +191,14 @@
   if (features::IsAnswerCardDarkRunEnabled())
     return true;
 
-  return preferred_size_.width() <= features::AnswerCardMaxWidth() &&
-         preferred_size_.height() <= features::AnswerCardMaxHeight();
+  if (preferred_size_.width() <= features::AnswerCardMaxWidth() &&
+      preferred_size_.height() <= features::AnswerCardMaxHeight()) {
+    return true;
+  }
+
+  LOG(ERROR) << "Card is too large: width=" << preferred_size_.width()
+             << ", height=" << preferred_size_.height();
+  return false;
 }
 
 void AnswerCardSearchProvider::RecordReceivedAnswerFinalResult() {
@@ -211,14 +228,30 @@
 
 bool AnswerCardSearchProvider::ParseResponseHeaders(
     const net::HttpResponseHeaders* headers) {
-  if (!headers || headers->response_code() != net::HTTP_OK)
+  if (!headers) {
+    LOG(ERROR) << "Failed to parse response headers: no headers";
     return false;
-  if (!headers->HasHeaderValue("SearchAnswer-HasResult", "true"))
+  }
+  if (headers->response_code() != net::HTTP_OK) {
+    LOG(ERROR) << "Failed to parse response headers: response code="
+               << headers->response_code();
     return false;
-  if (!headers->GetNormalizedHeader("SearchAnswer-OpenResultUrl", &result_url_))
+  }
+  if (!headers->HasHeaderValue(kSearchAnswerHasResult, "true")) {
+    VLOG(1) << "Failed to parse response headers: " << kSearchAnswerHasResult
+            << " header != true";
     return false;
-  if (!headers->GetNormalizedHeader("SearchAnswer-Title", &result_title_))
+  }
+  if (!headers->GetNormalizedHeader(kSearchAnswerOpenResultUrl, &result_url_)) {
+    LOG(ERROR) << "Failed to parse response headers: "
+               << kSearchAnswerOpenResultUrl << " header is not present";
     return false;
+  }
+  if (!headers->GetNormalizedHeader("SearchAnswer-Title", &result_title_)) {
+    LOG(ERROR) << "Failed to parse response headers: SearchAnswer-Title header "
+                  "is not present";
+    return false;
+  }
   return true;
 }
 
diff --git a/chrome/browser/ui/app_list/search/search_controller_factory.cc b/chrome/browser/ui/app_list/search/search_controller_factory.cc
index ab3a5226..30740cd 100644
--- a/chrome/browser/ui/app_list/search/search_controller_factory.cc
+++ b/chrome/browser/ui/app_list/search/search_controller_factory.cc
@@ -43,7 +43,7 @@
 constexpr size_t kMaxSuggestionsResults = 6;
 constexpr size_t kMaxLauncherSearchResults = 2;
 #if defined(OS_CHROMEOS)
-constexpr size_t kMaxPlayStoreResults = 2;
+constexpr size_t kMaxPlayStoreResults = 6;
 #endif
 
 // Constants related to the SuggestionsService in AppList field trial.
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
index 6668d76d..6af548a 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
@@ -14,9 +14,9 @@
 #include "ash/shelf/shelf_button.h"
 #include "ash/shelf/shelf_constants.h"
 #include "ash/shelf/shelf_view.h"
+#include "ash/shelf/shelf_view_test_api.h"
 #include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
-#include "ash/test/shelf_view_test_api.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "base/macros.h"
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
index 22ccec7..33b9f491 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
@@ -24,9 +24,9 @@
 #include "ash/shelf/shelf_constants.h"
 #include "ash/shelf/shelf_controller.h"
 #include "ash/shell.h"
+#include "ash/shell_test_api.h"
 #include "ash/test/ash_test_helper.h"
-#include "ash/test/shell_test_api.h"
-#include "ash/test/test_shell_delegate.h"
+#include "ash/test_shell_delegate.h"
 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/wm/window_util.h"
 #include "base/command_line.h"
diff --git a/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc b/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc
index d7cf021..f89f3788 100644
--- a/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/launcher_context_menu_unittest.cc
@@ -9,10 +9,10 @@
 #include "ash/public/cpp/shelf_item.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
+#include "ash/shell_test_api.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/ash_test_helper.h"
-#include "ash/test/shell_test_api.h"
-#include "ash/test/test_shell_delegate.h"
+#include "ash/test_shell_delegate.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "chrome/app/chrome_command_ids.h"
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc
index 525ae64d..76fe8bcd 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc
@@ -7,7 +7,7 @@
 #include "ash/shell.h"
 #include "ash/system/system_notifier.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/test_shell_delegate.h"
+#include "ash/test_shell_delegate.h"
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
index 3db3bc1..8ac5e6a1 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
@@ -16,7 +16,7 @@
 #include "ash/test/ash_test_base.h"
 #include "ash/test/ash_test_environment_content.h"
 #include "ash/test/ash_test_helper.h"
-#include "ash/test/test_shell_delegate.h"
+#include "ash/test_shell_delegate.h"
 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/wm/maximize_mode/maximize_mode_window_manager.h"
 #include "ash/wm/mru_window_tracker.h"
diff --git a/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc b/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc
index 57111b5..5733ea0 100644
--- a/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc
+++ b/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc
@@ -5,10 +5,10 @@
 #include <vector>
 
 #include "ash/shell.h"
+#include "ash/system/cast/tray_cast_test_api.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_delegate.h"
 #include "ash/system/tray/system_tray_test_api.h"
-#include "ash/test/tray_cast_test_api.h"
 #include "base/macros.h"
 #include "chrome/browser/media/router/media_routes_observer.h"
 #include "chrome/browser/media/router/media_sinks_observer.h"
diff --git a/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc b/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc
index 84dbea72..104ffbf 100644
--- a/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc
+++ b/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc
@@ -44,6 +44,10 @@
 #include "ui/keyboard/keyboard_controller.h"
 #include "ui/views/mus/mus_client.h"
 
+#if BUILDFLAG(ENABLE_WAYLAND_SERVER)
+#include "chrome/browser/exo_parts.h"
+#endif
+
 ChromeBrowserMainExtraPartsAsh::ChromeBrowserMainExtraPartsAsh() {}
 
 ChromeBrowserMainExtraPartsAsh::~ChromeBrowserMainExtraPartsAsh() {}
@@ -117,9 +121,19 @@
   keyboard::InitializeKeyboard();
 
   ui::SelectFileDialog::SetFactory(new SelectFileDialogExtensionFactory);
+
+#if BUILDFLAG(ENABLE_WAYLAND_SERVER)
+  exo_parts_ = ExoParts::CreateIfNecessary();
+#endif
 }
 
 void ChromeBrowserMainExtraPartsAsh::PostProfileInit() {
+#if BUILDFLAG(ENABLE_WAYLAND_SERVER)
+  // ExoParts uses state from ash, delete it before ash so that exo can
+  // uninstall correctly.
+  exo_parts_.reset();
+#endif
+
   if (ash_util::IsRunningInMash()) {
     DCHECK(!ash::Shell::HasInstance());
     DCHECK(!ChromeLauncherController::instance());
diff --git a/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.h b/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.h
index 8b297d5b..790cbc1b 100644
--- a/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.h
+++ b/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.h
@@ -9,6 +9,7 @@
 
 #include "base/macros.h"
 #include "chrome/browser/chrome_browser_main_extra_parts.h"
+#include "chrome/common/features.h"
 
 namespace ash {
 class ShelfModel;
@@ -37,6 +38,10 @@
 class VolumeController;
 class VpnListForwarder;
 
+#if BUILDFLAG(ENABLE_WAYLAND_SERVER)
+class ExoParts;
+#endif
+
 // Browser initialization for Ash. Only runs on Chrome OS.
 // TODO(jamescook): Fold this into ChromeBrowserMainPartsChromeOS.
 class ChromeBrowserMainExtraPartsAsh : public ChromeBrowserMainExtraParts {
@@ -75,6 +80,10 @@
   std::unique_ptr<ui::UserActivityDetector> user_activity_detector_;
   std::unique_ptr<aura::UserActivityForwarder> user_activity_forwarder_;
 
+#if BUILDFLAG(ENABLE_WAYLAND_SERVER)
+  std::unique_ptr<ExoParts> exo_parts_;
+#endif
+
   DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainExtraPartsAsh);
 };
 
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
index a3f03e3..43fa04ef 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
@@ -7,8 +7,8 @@
 #include "ash/ash_constants.h"
 #include "ash/frame/caption_buttons/frame_caption_button_container_view.h"
 #include "ash/frame/header_painter.h"
+#include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h"
 #include "ash/shell.h"
-#include "ash/test/immersive_fullscreen_controller_test_api.h"
 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
 #include "base/command_line.h"
 #include "build/build_config.h"
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc
index d9894e6..2880f02 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc
@@ -4,12 +4,12 @@
 
 #include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h"
 
+#include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h"
 #include "ash/public/cpp/shelf_types.h"
 #include "ash/root_window_controller.h"
 #include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/immersive_fullscreen_controller_test_api.h"
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "chrome/app/chrome_command_ids.h"
diff --git a/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc b/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc
index bbfa013d..42535dd 100644
--- a/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc
@@ -16,7 +16,7 @@
 typedef InProcessBrowserTest ZoomBubbleBrowserTest;
 
 #if defined(USE_ASH)
-#include "ash/test/immersive_fullscreen_controller_test_api.h"
+#include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h"
 #include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h"
 #endif
 
diff --git a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc b/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc
index 7b55d15..ae740ce5 100644
--- a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc
+++ b/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc
@@ -17,6 +17,9 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "chrome/browser/ui/autofill/autofill_dialog_models.h"
+#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
+#include "chrome/browser/ui/singleton_tabs.h"
+#include "chrome/browser/ui/views/harmony/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/payments/payment_request_dialog_view.h"
 #include "chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h"
 #include "chrome/browser/ui/views/payments/payment_request_views_util.h"
@@ -28,6 +31,7 @@
 #include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/payments/payments_service_url.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/validation.h"
 #include "components/autofill/core/common/autofill_clock.h"
@@ -43,6 +47,7 @@
 #include "ui/views/controls/button/md_text_button.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
+#include "ui/views/controls/styled_label.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/fill_layout.h"
@@ -188,8 +193,7 @@
   constexpr int kRowBottomPadding = 6;
   views::BoxLayout* layout = new views::BoxLayout(
       views::BoxLayout::kVertical,
-      gfx::Insets(kRowBottomPadding,
-                  payments::kPaymentRequestRowHorizontalInsets),
+      gfx::Insets(kRowBottomPadding, kPaymentRequestRowHorizontalInsets),
       kRowVerticalSpacing);
   layout->set_main_axis_alignment(views::BoxLayout::MAIN_AXIS_ALIGNMENT_START);
   layout->set_cross_axis_alignment(
@@ -238,6 +242,35 @@
   }
   view->AddChildView(icons_row.release());
 
+  // If dealing with a server card, we add "From Google Payments" with an edit
+  // link.
+  if (IsEditingServerCard()) {
+    std::unique_ptr<views::View> data_source = base::MakeUnique<views::View>();
+    auto data_source_layout = base::MakeUnique<views::BoxLayout>(
+        views::BoxLayout::kHorizontal, gfx::Insets(), kPaddingBetweenCardIcons);
+    data_source->SetLayoutManager(data_source_layout.release());
+
+    // "From Google Payments".
+    data_source->AddChildView(
+        CreateHintLabel(
+            l10n_util::GetStringUTF16(IDS_AUTOFILL_FROM_GOOGLE_ACCOUNT_LONG))
+            .release());
+
+    // "Edit" link.
+    base::string16 link_text =
+        l10n_util::GetStringUTF16(IDS_AUTOFILL_WALLET_MANAGEMENT_LINK_TEXT);
+    auto edit_link = base::MakeUnique<views::StyledLabel>(link_text, this);
+    edit_link->set_id(
+        static_cast<int>(DialogViewID::GOOGLE_PAYMENTS_EDIT_LINK_LABEL));
+    edit_link->AddStyleRange(
+        gfx::Range(0, link_text.size()),
+        views::StyledLabel::RangeStyleInfo::CreateForLink());
+    edit_link->SizeToFit(0);
+    data_source->AddChildView(edit_link.release());
+
+    view->AddChildView(data_source.release());
+  }
+
   return view;
 }
 
@@ -502,6 +535,17 @@
   return std::unique_ptr<ui::ComboboxModel>();
 }
 
+void CreditCardEditorViewController::StyledLabelLinkClicked(
+    views::StyledLabel* label,
+    const gfx::Range& range,
+    int event_flags) {
+  // The only thing that can trigger this is the user clicking on the "edit"
+  // link for a server card.
+  chrome::ScopedTabbedBrowserDisplayer displayer(dialog()->GetProfile());
+  chrome::ShowSingletonTab(displayer.browser(),
+                           autofill::payments::GetManageAddressesUrl(0));
+}
+
 void CreditCardEditorViewController::SelectBasicCardNetworkIcon(
     const std::string& basic_card_network) {
   // If empty string was passed or if the icon representing |basic_card_network|
diff --git a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.h b/chrome/browser/ui/views/payments/credit_card_editor_view_controller.h
index a83064d..c774419 100644
--- a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.h
+++ b/chrome/browser/ui/views/payments/credit_card_editor_view_controller.h
@@ -15,6 +15,7 @@
 #include "chrome/browser/ui/views/payments/editor_view_controller.h"
 #include "chrome/browser/ui/views/payments/validation_delegate.h"
 #include "ui/base/models/simple_combobox_model.h"
+#include "ui/views/controls/styled_label_listener.h"
 
 namespace autofill {
 class AutofillProfile;
@@ -28,7 +29,8 @@
 class PaymentRequestDialogView;
 
 // Credit card editor screen of the Payment Request flow.
-class CreditCardEditorViewController : public EditorViewController {
+class CreditCardEditorViewController : public EditorViewController,
+                                       public views::StyledLabelListener {
  public:
   // Does not take ownership of the arguments (except for the |on_edited| and
   // |on_added| callbacks), which should outlive this object. Additionally,
@@ -65,6 +67,11 @@
   std::unique_ptr<ui::ComboboxModel> GetComboboxModelForType(
       const autofill::ServerFieldType& type) override;
 
+  // views::StyledLabelListener:
+  void StyledLabelLinkClicked(views::StyledLabel* label,
+                              const gfx::Range& range,
+                              int event_flags) override;
+
   // Selects the icon in the UI corresponding to |basic_card_network| with
   // higher opacity. If empty string, selects none of them (all full opacity).
   void SelectBasicCardNetworkIcon(const std::string& basic_card_network);
diff --git a/chrome/browser/ui/views/payments/credit_card_editor_view_controller_browsertest.cc b/chrome/browser/ui/views/payments/credit_card_editor_view_controller_browsertest.cc
index d3ac129f..b35781d 100644
--- a/chrome/browser/ui/views/payments/credit_card_editor_view_controller_browsertest.cc
+++ b/chrome/browser/ui/views/payments/credit_card_editor_view_controller_browsertest.cc
@@ -15,6 +15,7 @@
 #include "components/autofill/core/browser/address_combobox_model.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/payments/payments_service_url.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/test_autofill_clock.h"
 #include "components/autofill/core/browser/test_region_data_loader.h"
@@ -26,6 +27,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/views/controls/combobox/combobox.h"
+#include "ui/views/controls/styled_label.h"
 
 namespace payments {
 
@@ -298,6 +300,51 @@
 }
 
 IN_PROC_BROWSER_TEST_F(PaymentRequestCreditCardEditorTest,
+                       EditingMaskedCard_ClickOnPaymentsLink) {
+  autofill::TestAutofillClock test_clock;
+  test_clock.SetNow(kJune2017);
+
+  autofill::AutofillProfile billing_profile(autofill::test::GetFullProfile());
+  AddAutofillProfile(billing_profile);
+  // Add a second address profile to the DB.
+  autofill::AutofillProfile additional_profile =
+      autofill::test::GetFullProfile2();
+  AddAutofillProfile(additional_profile);
+  autofill::CreditCard card = autofill::test::GetMaskedServerCard();
+  card.set_billing_address_id(billing_profile.guid());
+  AddCreditCard(card);
+
+  InvokePaymentRequestUI();
+
+  OpenPaymentMethodScreen();
+
+  views::View* list_view = dialog_view()->GetViewByID(
+      static_cast<int>(DialogViewID::PAYMENT_METHOD_SHEET_LIST_VIEW));
+  EXPECT_TRUE(list_view);
+  EXPECT_EQ(1, list_view->child_count());
+
+  views::View* edit_button = list_view->child_at(0)->GetViewByID(
+      static_cast<int>(DialogViewID::EDIT_ITEM_BUTTON));
+
+  ResetEventObserver(DialogEvent::CREDIT_CARD_EDITOR_OPENED);
+  ClickOnDialogViewAndWait(edit_button);
+
+  views::StyledLabel* styled_label =
+      static_cast<views::StyledLabel*>(dialog_view()->GetViewByID(
+          static_cast<int>(DialogViewID::GOOGLE_PAYMENTS_EDIT_LINK_LABEL)));
+  EXPECT_TRUE(styled_label);
+
+  content::WebContentsAddedObserver web_contents_added_observer;
+  styled_label->LinkClicked(nullptr, 0);
+  content::WebContents* new_tab_contents =
+      web_contents_added_observer.GetWebContents();
+
+  // A tab has opened at the Google Payments link.
+  EXPECT_EQ(autofill::payments::GetManageAddressesUrl(0),
+            new_tab_contents->GetVisibleURL());
+}
+
+IN_PROC_BROWSER_TEST_F(PaymentRequestCreditCardEditorTest,
                        EnteringNothingInARequiredField) {
   autofill::TestAutofillClock test_clock;
   test_clock.SetNow(kJune2017);
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc b/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
index 4b1c622..612dca1 100644
--- a/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
+++ b/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
@@ -97,7 +97,7 @@
   host_resolver()->AddRule("a.com", "127.0.0.1");
   host_resolver()->AddRule("b.com", "127.0.0.1");
   ASSERT_TRUE(https_server_->InitializeAndListen());
-  https_server_->ServeFilesFromSourceDirectory("chrome/test/data/payments");
+  https_server_->ServeFilesFromSourceDirectory("components/test/data/payments");
   https_server_->StartAcceptingConnections();
 
   NavigateTo(test_file_path_);
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest_base.h b/chrome/browser/ui/views/payments/payment_request_browsertest_base.h
index 98dfb427..3beed20 100644
--- a/chrome/browser/ui/views/payments/payment_request_browsertest_base.h
+++ b/chrome/browser/ui/views/payments/payment_request_browsertest_base.h
@@ -87,7 +87,7 @@
 
  protected:
   // Test will open a browser window to |test_file_path| (relative to
-  // chrome/test/data/payments).
+  // components/test/data/payments).
   explicit PaymentRequestBrowserTestBase(const std::string& test_file_path);
   ~PaymentRequestBrowserTestBase() override;
 
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h b/chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h
index e0211d8f7..b4d4a13 100644
--- a/chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h
+++ b/chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h
@@ -48,6 +48,7 @@
   ORDER_SUMMARY_LINE_ITEM_2,
   ORDER_SUMMARY_LINE_ITEM_3,
   DATA_SOURCE_LABEL,
+  GOOGLE_PAYMENTS_EDIT_LINK_LABEL,
 
   // This is the title used at the top of each sheet.
   SHEET_TITLE,
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index abea6e3..5190d53 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -63,9 +63,9 @@
 
 #if defined(USE_ASH)
 #include "ash/ash_switches.h"
+#include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h"
 #include "ash/shell.h"
-#include "ash/test/cursor_manager_test_api.h"
-#include "ash/test/immersive_fullscreen_controller_test_api.h"
+#include "ash/wm/cursor_manager_test_api.h"
 #include "ash/wm/root_window_finder.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
diff --git a/chrome/browser/ui/webui/net_export_ui.cc b/chrome/browser/ui/webui/net_export_ui.cc
index 55d0b12..d5b8661 100644
--- a/chrome/browser/ui/webui/net_export_ui.cc
+++ b/chrome/browser/ui/webui/net_export_ui.cc
@@ -149,10 +149,12 @@
                  net_log::NetExportFileWriter::StateObserver>
       state_observer_manager_;
 
-  // The capture mode the user chose in the UI when logging started is cached
-  // here and is read after a file path is chosen in the save dialog.
-  // Its value is only valid while the save dialog is open on the desktop UI.
+  // The capture mode and file size bound that the user chose in the UI when
+  // logging started is cached here and is read after a file path is chosen in
+  // the save dialog. Their values are only valid while the save dialog is open
+  // on the desktop UI.
   net::NetLogCaptureMode capture_mode_;
+  size_t max_log_file_size_;
 
   scoped_refptr<ui::SelectFileDialog> select_file_dialog_;
 
@@ -217,12 +219,21 @@
 
 void NetExportMessageHandler::OnStartNetLog(const base::ListValue* list) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  std::string capture_mode_string;
-  bool result = list->GetString(0, &capture_mode_string);
-  DCHECK(result);
 
-  capture_mode_ =
-      net_log::NetExportFileWriter::CaptureModeFromString(capture_mode_string);
+  const base::Value::ListStorage& params = list->GetList();
+
+  // Determine the capture mode.
+  capture_mode_ = net::NetLogCaptureMode::Default();
+  if (params.size() > 0 && params[0].is_string()) {
+    capture_mode_ = net_log::NetExportFileWriter::CaptureModeFromString(
+        params[0].GetString());
+  }
+
+  // Determine the max file size.
+  max_log_file_size_ = net_log::NetExportFileWriter::kNoLimit;
+  if (params.size() > 1 && params[1].is_int() && params[1].GetInt() > 0) {
+    max_log_file_size_ = params[1].GetInt();
+  }
 
   if (UsingMobileUI()) {
     StartNetLog(base::FilePath());
@@ -321,7 +332,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   file_writer_->StartNetLog(
-      path, capture_mode_,
+      path, capture_mode_, max_log_file_size_,
       base::CommandLine::ForCurrentProcess()->GetCommandLineString(),
       chrome::GetChannelString(), GetURLRequestContexts());
 }
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.cc b/chrome/browser/ui/webui/settings/md_settings_ui.cc
index b29198f5..7ee8b992 100644
--- a/chrome/browser/ui/webui/settings/md_settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_ui.cc
@@ -278,6 +278,16 @@
 
   content::WebUIDataSource::Add(web_ui->GetWebContents()->GetBrowserContext(),
                                 html_source);
+
+#if defined(OS_WIN)
+  // This needs to be below content::WebUIDataSource::Add to make sure there
+  // is a WebUIDataSource to update if the observer is immediately notified.
+  if (base::FeatureList::IsEnabled(safe_browsing::kInBrowserCleanerUIFeature)) {
+    cleanup_observer_.reset(
+        new safe_browsing::ChromeCleanerStateChangeObserver(base::Bind(
+            &MdSettingsUI::UpdateCleanupDataSource, base::Unretained(this))));
+  }
+#endif  // defined(OS_WIN)
 }
 
 MdSettingsUI::~MdSettingsUI() {
@@ -309,4 +319,19 @@
                       base::Time::Now() - load_start_time_);
 }
 
+#if defined(OS_WIN)
+void MdSettingsUI::UpdateCleanupDataSource(bool cleanupEnabled,
+                                           bool partnerPowered) {
+  DCHECK(web_ui());
+  Profile* profile = Profile::FromWebUI(web_ui());
+
+  std::unique_ptr<base::DictionaryValue> update(new base::DictionaryValue);
+  update->SetBoolean("chromeCleanupEnabled", cleanupEnabled);
+  update->SetBoolean("cleanupPoweredByPartner", partnerPowered);
+
+  content::WebUIDataSource::Update(profile, chrome::kChromeUISettingsHost,
+                                   std::move(update));
+}
+#endif  // defined(OS_WIN)
+
 }  // namespace settings
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.h b/chrome/browser/ui/webui/settings/md_settings_ui.h
index 7aef511..1ca22c6 100644
--- a/chrome/browser/ui/webui/settings/md_settings_ui.h
+++ b/chrome/browser/ui/webui/settings/md_settings_ui.h
@@ -9,9 +9,14 @@
 
 #include "base/macros.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_ui_controller.h"
 
+#if defined(OS_WIN)
+#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_state_change_observer_win.h"
+#endif
+
 class GURL;
 
 namespace user_prefs {
@@ -49,6 +54,12 @@
 
   base::Time load_start_time_;
 
+#if defined(OS_WIN)
+  void UpdateCleanupDataSource(bool cleanupEnabled, bool partnerPowered);
+  std::unique_ptr<safe_browsing::ChromeCleanerStateChangeObserver>
+      cleanup_observer_;
+#endif
+
   DISALLOW_COPY_AND_ASSIGN(MdSettingsUI);
 };
 
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 01dead6..5e05740 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -63,6 +63,11 @@
 // voice interaction services.
 const char kVoiceInteractionContextEnabled[] =
     "settings.voice_interaction.context.enabled";
+// A preference indicating whether voice interaction settings have been read
+// from ARC. This synchronization only happens when user goes through the flow
+// to set up voice interaction.
+const char kVoiceInteractionPrefSynced[] =
+    "settings.voice_interaction.context.synced";
 #endif
 
 // A bool pref that keeps whether the child status for this profile was already
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 25fe0b6..59e8ed3 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -36,6 +36,7 @@
 extern const char kArcVoiceInteractionValuePropAccepted[];
 extern const char kVoiceInteractionEnabled[];
 extern const char kVoiceInteractionContextEnabled[];
+extern const char kVoiceInteractionPrefSynced[];
 #endif
 extern const char kChildAccountStatusKnown[];
 extern const char kDefaultApps[];
diff --git a/chrome/common/safe_browsing/BUILD.gn b/chrome/common/safe_browsing/BUILD.gn
index b75bb1d..6c375d5 100644
--- a/chrome/common/safe_browsing/BUILD.gn
+++ b/chrome/common/safe_browsing/BUILD.gn
@@ -38,7 +38,6 @@
       "pe_image_reader_win.cc",
       "pe_image_reader_win.h",
       "protobuf_message_log_macros.h",
-      "protobuf_message_param_traits.h",
       "protobuf_message_read_macros.h",
       "protobuf_message_size_macros.h",
       "protobuf_message_write_macros.h",
diff --git a/chrome/common/safe_browsing/ipc_protobuf_message_test_messages.h b/chrome/common/safe_browsing/ipc_protobuf_message_test_messages.h
index 4a86ff0..822262b 100644
--- a/chrome/common/safe_browsing/ipc_protobuf_message_test_messages.h
+++ b/chrome/common/safe_browsing/ipc_protobuf_message_test_messages.h
@@ -5,8 +5,8 @@
 // Multiply-included message file, so no include guard.
 
 #include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_message_protobuf_utils.h"
 #include "chrome/common/safe_browsing/ipc_protobuf_message_macros.h"
-#include "chrome/common/safe_browsing/protobuf_message_param_traits.h"
 
 IPC_PROTOBUF_MESSAGE_TRAITS_BEGIN(SubMessage)
   IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_FUNDAMENTAL_MEMBER(foo)
diff --git a/chrome/common/safe_browsing/protobuf_message_param_traits.h b/chrome/common/safe_browsing/protobuf_message_param_traits.h
deleted file mode 100644
index 76613ce..0000000
--- a/chrome/common/safe_browsing/protobuf_message_param_traits.h
+++ /dev/null
@@ -1,66 +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.
-
-#ifndef CHROME_COMMON_SAFE_BROWSING_PROTOBUF_MESSAGE_PARAM_TRAITS_H_
-#define CHROME_COMMON_SAFE_BROWSING_PROTOBUF_MESSAGE_PARAM_TRAITS_H_
-
-#include <limits.h>
-
-#include <string>
-
-#include "base/pickle.h"
-#include "ipc/ipc_message.h"
-#include "ipc/ipc_param_traits.h"
-#include "third_party/protobuf/src/google/protobuf/repeated_field.h"
-
-namespace IPC {
-
-template <class Element>
-struct ParamTraits<google::protobuf::RepeatedPtrField<Element>> {
-  typedef google::protobuf::RepeatedPtrField<Element> param_type;
-
-  static void GetSize(base::PickleSizer* s, const param_type& p) {
-    GetParamSize(s, p.size());
-    for (const auto& element : p)
-      GetParamSize(s, element);
-  }
-
-  static void Write(base::Pickle* m, const param_type& p) {
-    WriteParam(m, p.size());
-    for (const auto& element : p)
-      WriteParam(m, element);
-  }
-
-  static bool Read(const base::Pickle* m,
-                   base::PickleIterator* iter,
-                   param_type* p) {
-    int size;
-    if (!iter->ReadLength(&size) || size < 0)
-      return false;
-    if (INT_MAX / static_cast<int>(sizeof(void*)) <= size)
-      return false;
-    p->Clear();
-    p->Reserve(size);
-    while (size--) {
-      if (!ReadParam(m, iter, p->Add()))
-        return false;
-    }
-    return true;
-  }
-
-  static void Log(const param_type& p, std::string* l) {
-    bool logged_first = false;
-    for (const auto& element : p) {
-      if (logged_first)
-        l->push_back(' ');
-      else
-        logged_first = true;
-      LogParam(element, l);
-    }
-  }
-};
-
-}  // namespace IPC
-
-#endif  // CHROME_COMMON_SAFE_BROWSING_PROTOBUF_MESSAGE_PARAM_TRAITS_H_
diff --git a/chrome/common/safe_browsing/safe_archive_analyzer_param_traits.h b/chrome/common/safe_browsing/safe_archive_analyzer_param_traits.h
index 95f428c5f..70e1cf399 100644
--- a/chrome/common/safe_browsing/safe_archive_analyzer_param_traits.h
+++ b/chrome/common/safe_browsing/safe_archive_analyzer_param_traits.h
@@ -11,8 +11,8 @@
 #include "build/build_config.h"
 #include "chrome/common/safe_browsing/archive_analyzer_results.h"
 #include "chrome/common/safe_browsing/ipc_protobuf_message_macros.h"
-#include "chrome/common/safe_browsing/protobuf_message_param_traits.h"
 #include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_message_protobuf_utils.h"
 
 IPC_ENUM_TRAITS_VALIDATE(
     safe_browsing::ClientDownloadRequest_DownloadType,
diff --git a/chrome/nacl/OWNERS b/chrome/nacl/OWNERS
index fc1180e..4d29309 100644
--- a/chrome/nacl/OWNERS
+++ b/chrome/nacl/OWNERS
@@ -1,6 +1,5 @@
 bradnelson@chromium.org
 dschuff@chromium.org
 mseaborn@chromium.org
-sehr@chromium.org
 
 # COMPONENT: Platform>NaCl
diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn
index 3f4c2ae..56914c5 100644
--- a/chrome/renderer/BUILD.gn
+++ b/chrome/renderer/BUILD.gn
@@ -74,6 +74,8 @@
     "page_load_metrics/renderer_page_track_decider.h",
     "plugins/non_loadable_plugin_placeholder.cc",
     "plugins/non_loadable_plugin_placeholder.h",
+    "plugins/pdf_plugin_placeholder.cc",
+    "plugins/pdf_plugin_placeholder.h",
     "plugins/plugin_uma.cc",
     "plugins/plugin_uma.h",
     "prerender/prerender_dispatcher.cc",
@@ -194,8 +196,6 @@
       "pepper/pepper_uma_host.h",
       "plugins/chrome_plugin_placeholder.cc",
       "plugins/chrome_plugin_placeholder.h",
-      "plugins/pdf_plugin_placeholder.cc",
-      "plugins/pdf_plugin_placeholder.h",
       "plugins/plugin_preroller.cc",
       "plugins/plugin_preroller.h",
       "plugins/power_saver_info.cc",
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index c6f47b0a..bb13e36 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -655,6 +655,12 @@
   if (orig_mime_type == kPDFMimeType) {
     ReportPDFLoadStatus(
         PDFLoadStatus::kShowedDisabledPluginPlaceholderForEmbeddedPdf);
+    if (base::FeatureList::IsEnabled(features::kClickToOpenPDFPlaceholder)) {
+      PDFPluginPlaceholder* placeholder =
+          PDFPluginPlaceholder::CreatePDFPlaceholder(render_frame, params);
+      *plugin = placeholder->plugin();
+      return true;
+    }
   }
   auto* placeholder = NonLoadablePluginPlaceholder::CreateNotSupportedPlugin(
       render_frame, params);
diff --git a/chrome/renderer/extensions/renderer_permissions_policy_delegate.cc b/chrome/renderer/extensions/renderer_permissions_policy_delegate.cc
index 240da30..e7042d3 100644
--- a/chrome/renderer/extensions/renderer_permissions_policy_delegate.cc
+++ b/chrome/renderer/extensions/renderer_permissions_policy_delegate.cc
@@ -5,6 +5,7 @@
 #include "chrome/renderer/extensions/renderer_permissions_policy_delegate.h"
 
 #include "chrome/common/extensions/extension_constants.h"
+#include "chrome/renderer/searchbox/search_bouncer.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extensions_client.h"
 #include "extensions/common/manifest_constants.h"
@@ -37,6 +38,12 @@
     return false;
   }
 
+  if (SearchBouncer::GetInstance()->IsNewTabPage(document_url)) {
+    if (error)
+      *error = errors::kCannotScriptNtp;
+    return false;
+  }
+
   return true;
 }
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 8f0a534..541dd835 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -253,7 +253,7 @@
 
     public_deps += [
       "//ash",
-      "//ash/test:test_support_with_content",
+      "//ash:test_support_with_content",
       "//ui/aura",
       "//ui/aura:test_support",
     ]
@@ -839,7 +839,7 @@
         # Use only the _chromeos version on Ash / Chrome OS.
         "base/view_event_test_platform_part_default.cc",
       ]
-      deps += [ "//ash/test:interactive_ui_test_support" ]
+      deps += [ "//ash:interactive_ui_test_support" ]
     }
 
     if (is_android) {
@@ -1701,6 +1701,7 @@
       "//chrome/browser/policy/test/policy_testserver.py",
       "//chrome/common/extensions/docs/examples/apps/calculator/",
       "//chrome/third_party/mock4js/",
+      "//components/test/data/payments/",
       "//components/test/data/update_client/",
       "//content/test/data/",
       "//google_apis/test/",
@@ -2047,7 +2048,7 @@
         "../browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc",
       ]
       deps += [
-        "//ash/test:test_support_with_content",
+        "//ash:test_support_with_content",
         "//ui/keyboard:test_support",
       ]
 
@@ -3089,6 +3090,7 @@
     "../browser/content_settings/host_content_settings_map_unittest.cc",
     "../browser/content_settings/mock_settings_observer.cc",
     "../browser/content_settings/mock_settings_observer.h",
+    "../browser/content_settings/sound_content_setting_observer_unittest.cc",
     "../browser/content_settings/tab_specific_content_settings_unittest.cc",
     "../browser/custom_handlers/protocol_handler_registry_unittest.cc",
     "../browser/data_usage/tab_id_annotator_unittest.cc",
@@ -4245,9 +4247,9 @@
       "../browser/ui/window_sizer/window_sizer_ash_unittest.cc",
     ]
     deps += [
+      "//ash:test_support_with_content",
       "//ash/resources",
       "//ash/strings",
-      "//ash/test:test_support_with_content",
     ]
 
     # Chrome OS uses window_sizer_ash_unittest.cc
diff --git a/chrome/test/base/view_event_test_platform_part_chromeos.cc b/chrome/test/base/view_event_test_platform_part_chromeos.cc
index b9e4a9f..f8759bd 100644
--- a/chrome/test/base/view_event_test_platform_part_chromeos.cc
+++ b/chrome/test/base/view_event_test_platform_part_chromeos.cc
@@ -6,11 +6,11 @@
 
 #include <memory>
 
+#include "ash/session/test_session_controller_client.h"
 #include "ash/shell.h"
 #include "ash/shell_init_params.h"
 #include "ash/test/ash_test_helper.h"
-#include "ash/test/test_session_controller_client.h"
-#include "ash/test/test_shell_delegate.h"
+#include "ash/test_shell_delegate.h"
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "chromeos/audio/cras_audio_handler.h"
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index e5a0d54e..9f14c70f 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -222,6 +222,7 @@
         'ChromeDriverLogTest.testDisablingDriverLogsSuppressesChromeDriverLog',
         'ChromeDriverTest.testCookiePath',
         'ChromeDriverTest.testGetHttpOnlyCookie',
+        'ChromeDriverTest.testGetNamedCookie',
     ]
 )
 
diff --git a/chrome/test/chromedriver/test/test_expectations b/chrome/test/chromedriver/test/test_expectations
index 9ebb12d..b11d11d 100644
--- a/chrome/test/chromedriver/test/test_expectations
+++ b/chrome/test/chromedriver/test/test_expectations
@@ -284,6 +284,10 @@
         'ClickScrollingTest.testShouldBeAbleToClickElementThatIsOutOfViewInANestedFrameThatIsOutOfView',
         # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1878
         'CombinedInputActionsTest.testSelectingMultipleItems',
+        'CombinedInputActionsTest.testHoldingDownShiftKeyWhileClicking',
+        'BasicMouseInterfaceTest.testDoubleClick',
+        'BasicMouseInterfaceTest.testContextClick',
+        'CorrectEventFiringTest.testShouldFireMouseUpEventWhenClicking',
     ]
 )
 _OS_NEGATIVE_FILTER['android:chrome_beta'] = (
diff --git a/chrome/test/data/extensions/api_test/content_scripts/ntp/background.js b/chrome/test/data/extensions/api_test/content_scripts/ntp/background.js
new file mode 100644
index 0000000..b1f8ea2
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/content_scripts/ntp/background.js
@@ -0,0 +1,26 @@
+// Copyright 2017 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.
+
+function testExecuteScriptInNewTab() {
+  // Create a new tab to chrome://newtab and wait for the loading to complete.
+  // Then, try to inject a script into that tab. The injection should fail.
+  chrome.tabs.onUpdated.addListener(function listener(tabId, changeInfo, tab) {
+    if (tab.url != 'chrome://newtab/' || changeInfo.status != 'complete')
+      return;
+    chrome.tabs.onUpdated.removeListener(listener);
+    chrome.tabs.executeScript(tab.id, {file: 'script.js'}, function() {
+      chrome.test.assertTrue(!!chrome.runtime.lastError);
+      chrome.test.assertTrue(
+          chrome.runtime.lastError.message.indexOf(
+              'Cannot access contents of') != -1,
+          chrome.runtime.lastError.message);
+      chrome.test.succeed();
+    });
+  });
+  chrome.tabs.create({url: 'chrome://newtab'});
+}
+
+chrome.test.sendMessage('ready', function() {
+  chrome.test.runTests([testExecuteScriptInNewTab]);
+});
diff --git a/chrome/test/data/extensions/api_test/content_scripts/ntp/manifest.json b/chrome/test/data/extensions/api_test/content_scripts/ntp/manifest.json
new file mode 100644
index 0000000..0eef9ce
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/content_scripts/ntp/manifest.json
@@ -0,0 +1,13 @@
+{
+  "name": "New Tab Page Injector",
+  "version": "0.1",
+  "manifest_version": 2,
+  "description": "Injects in the NTP",
+  "content_scripts": [{
+    "matches": ["*://*/*"],
+    "js": ["script.js"],
+    "run_at": "document_end"
+  }],
+  "background": {"scripts": ["background.js"]},
+  "permissions": ["tabs", "*://*/*"]
+}
diff --git a/chrome/test/data/extensions/api_test/content_scripts/ntp/script.js b/chrome/test/data/extensions/api_test/content_scripts/ntp/script.js
new file mode 100644
index 0000000..60ccce34
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/content_scripts/ntp/script.js
@@ -0,0 +1,5 @@
+// Copyright 2017 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.
+
+document.title = 'injected';
\ No newline at end of file
diff --git a/chrome/test/data/nacl/load_util.js b/chrome/test/data/nacl/load_util.js
index a133c5cf..bdf5dd6 100644
--- a/chrome/test/data/nacl/load_util.js
+++ b/chrome/test/data/nacl/load_util.js
@@ -4,7 +4,6 @@
 
 var load_util = {
   report: function(msg) {
-    domAutomationController.setAutomationId(0);
     // The automation controller seems to choke on Objects, so turn them into
     // strings.
     domAutomationController.send(JSON.stringify(msg));
diff --git a/chrome/test/data/nacl/nonsfi/libc_free.html b/chrome/test/data/nacl/nonsfi/libc_free.html
index e6ad59d..0ca9e22 100644
--- a/chrome/test/data/nacl/nonsfi/libc_free.html
+++ b/chrome/test/data/nacl/nonsfi/libc_free.html
@@ -17,7 +17,6 @@
 <script>
 
 function report(msg) {
-  domAutomationController.setAutomationId(0);
   // The automation controller seems to choke on Objects, so turn them into
   // strings.
   domAutomationController.send(JSON.stringify(msg));
diff --git a/chrome/test/data/nacl/pnacl_mime_type/pnacl_mime_type.html b/chrome/test/data/nacl/pnacl_mime_type/pnacl_mime_type.html
index 41a924b..1d0a3d3 100644
--- a/chrome/test/data/nacl/pnacl_mime_type/pnacl_mime_type.html
+++ b/chrome/test/data/nacl/pnacl_mime_type/pnacl_mime_type.html
@@ -15,7 +15,6 @@
 <script type="text/javascript">
 //<![CDATA[
 function report(msg) {
-  domAutomationController.setAutomationId(0);
   // The automation controller seems to choke on Objects, so turn them into
   // strings.
   domAutomationController.send(JSON.stringify(msg));
diff --git a/chrome/test/data/nacl/pnacl_url_loader/pnacl_url_loader.html b/chrome/test/data/nacl/pnacl_url_loader/pnacl_url_loader.html
index 6f186ec..0420ab5 100644
--- a/chrome/test/data/nacl/pnacl_url_loader/pnacl_url_loader.html
+++ b/chrome/test/data/nacl/pnacl_url_loader/pnacl_url_loader.html
@@ -6,7 +6,6 @@
 function init() {
   var embed = document.createElement('embed');
   embed.addEventListener('message', function(message) {
-      window.domAutomationController.setAutomationId(0);
       window.domAutomationController.send(message.data);
     }, false);
   embed.addEventListener('load', function() {
diff --git a/chrome/test/data/payments/blob_url.js b/chrome/test/data/payments/blob_url.js
deleted file mode 100644
index 5e6715de..0000000
--- a/chrome/test/data/payments/blob_url.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright 2017 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.
- */
-
-/** Requests payment via a blob URL. */
-function buy() { // eslint-disable-line no-unused-vars
-  const spoof = function() {
-    const payload = 'PGh0bWw+PGhlYWQ+PG1ldGEgbmFtZT0idmlld3BvcnQiIGNvbnRlbnQ9IndpZHRoPWRldmljZS13aWR0aCwgaW5pdGlhbC1zY2FsZT0yLCBtYXhpbXVtLXNjYWxlPTIiPjwvaGVhZD48Ym9keT48ZGl2IGlkPSJyZXN1bHQiPjwvZGl2PjxzY3JpcHQ+dHJ5IHsgIG5ldyBQYXltZW50UmVxdWVzdChbe3N1cHBvcnRlZE1ldGhvZHM6IFsiYmFzaWMtY2FyZCJdfV0sICAgIHt0b3RhbDoge2xhYmVsOiAiVCIsIGFtb3VudDoge2N1cnJlbmN5OiAiVVNEIiwgdmFsdWU6ICIxLjAwIn19fSkgIC5zaG93KCkgIC50aGVuKGZ1bmN0aW9uKGluc3RydW1lbnRSZXNwb25zZSkgeyAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgicmVzdWx0IikuaW5uZXJIVE1MID0gIlJlc29sdmVkIjsgIH0pLmNhdGNoKGZ1bmN0aW9uKGUpIHsgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoInJlc3VsdCIpLmlubmVySFRNTCA9ICJSZWplY3RlZDogIiArIGU7ICB9KTt9IGNhdGNoKGUpIHsgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCJyZXN1bHQiKS5pbm5lckhUTUwgPSAiRXhjZXB0aW9uOiAiICsgZTt9PC9zY3JpcHQ+PC9ib2R5PjwvaHRtbD4=';
-    document.write(atob(payload));
-  };
-  window.location.href =
-    URL.createObjectURL(new Blob(['<script>(', spoof, ')();</script>'], {
-      type: 'text/html',
-    }));
-}
diff --git a/chrome/test/data/payments/bobpay_ui_skip_preload.js b/chrome/test/data/payments/bobpay_ui_skip_preload.js
deleted file mode 100644
index 3b1fb0a2..0000000
--- a/chrome/test/data/payments/bobpay_ui_skip_preload.js
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2017 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.
- */
-
-/**
- * Builds PaymentRequest for Bob Pay, but does not show any UI yet.
- *
- * @return {PaymentRequest} The PaymentRequest object.
- */
-function initPaymentRequest() {
-  let supportedInstruments = [{
-    supportedMethods: ['https://bobpay.com'],
-  }];
-
-  let details = {
-    total: {
-      label: 'Donation',
-      amount: {
-        currency: 'USD',
-        value: '55.00',
-      },
-    },
-    displayItems: [{
-      label: 'Original donation amount',
-      amount: {
-        currency: 'USD',
-        value: '65.00',
-      },
-    }, {
-      label: 'Friends and family discount',
-      amount: {
-        currency: 'USD',
-        value: '-10.00',
-      },
-    }],
-  };
-
-  return new PaymentRequest(supportedInstruments, details);
-}
-
-/**
- * Launches the PaymentRequest UI with Bob Pay as the only payment method.
- * Preloads the second instance of PaymentRequest while the first instance is
- * showing.
- */
-function buy() { // eslint-disable-line no-unused-vars
-  let request = initPaymentRequest();
-  request.show()
-    .then(function(instrumentResponse) {
-      window.setTimeout(function() {
-        instrumentResponse.complete('success')
-          .then(function() {
-            print(JSON.stringify(instrumentResponse, undefined, 2));
-          })
-          .catch(function(err) {
-            print(err);
-          });
-      }, 500);
-    })
-    .catch(function(err) {
-      print(err);
-    });
-  request = initPaymentRequest();
-}
diff --git a/chrome/test/data/payments/contact_details_and_free_shipping.js b/chrome/test/data/payments/contact_details_and_free_shipping.js
deleted file mode 100644
index afddf27..0000000
--- a/chrome/test/data/payments/contact_details_and_free_shipping.js
+++ /dev/null
@@ -1,52 +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.
- */
-
-/* global PaymentRequest:false */
-
-/**
- * Launches the PaymentRequest UI that requests an email address and a phone
- * number and offers free shipping worldwide.
- */
-function buy() {  // eslint-disable-line no-unused-vars
-  try {
-    var details = {
-        total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}},
-        shippingOptions: [{
-          id: 'freeShippingOption',
-          label: 'Free global shipping',
-          amount: {currency: 'USD', value: '0'},
-          selected: true
-        }]
-      };
-    var request = new PaymentRequest(
-        [{supportedMethods: ['visa', 'https://bobpay.com']}], details,
-        {requestPayerName: true, requestPayerEmail: true,
-         requestPayerPhone: true, requestShipping: true});
-
-    request.addEventListener('shippingaddresschange', function(e) {
-      e.updateWith(new Promise(function(resolve) {
-        // No changes in price based on shipping address change.
-        resolve(details);
-      }));
-    });
-
-    request.show()
-        .then(function(resp) {
-          resp.complete('success')
-              .then(function() {
-                print(JSON.stringify(resp, undefined, 2));
-              })
-              .catch(function(error) {
-                print(error);
-              });
-        })
-        .catch(function(error) {
-          print(error);
-        });
-  } catch (error) {
-    print(error.message);
-  }
-}
diff --git a/chrome/test/data/payments/debit.js b/chrome/test/data/payments/debit.js
deleted file mode 100644
index f8f293c2c..0000000
--- a/chrome/test/data/payments/debit.js
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2017 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.
- */
-
-/**
- * Builds a payment request for a debit card.
- * @return {!PaymentRequest} A payment request for a debit card.
- * @private
- */
-function buildPaymentRequest() {
-  return new PaymentRequest([{
-    supportedMethods: ['basic-card'],
-    data: {
-      supportedTypes: ['debit'],
-    },
-  }], {
-    total: {
-      label: 'Total',
-      amount: {
-        currency: 'USD',
-        value: '1.00',
-      },
-    },
-  });
-}
-
-/** Requests payment via a debit card. */
-function buy() { // eslint-disable-line no-unused-vars
-  try {
-    buildPaymentRequest()
-      .show()
-      .then(function(response) {
-        response.complete()
-          .then(function() {
-            print(JSON.stringify(response, undefined, 2));
-          })
-          .catch(function(error) {
-            print(error);
-          });
-      })
-      .catch(function(error) {
-        print(error);
-      });
-  } catch (error) {
-    print(error);
-  }
-}
-
-/** Checks whether payment via a debit card is possible. */
-function canMakePayment() { // eslint-disable-line no-unused-vars
-  try {
-    buildPaymentRequest()
-      .canMakePayment()
-      .then(function(result) {
-        print(result);
-      })
-      .catch(function(error) {
-        print(error);
-      });
-  } catch (error) {
-    print(error);
-  }
-}
diff --git a/chrome/test/data/payments/email_and_free_shipping.js b/chrome/test/data/payments/email_and_free_shipping.js
deleted file mode 100644
index a3eeee9..0000000
--- a/chrome/test/data/payments/email_and_free_shipping.js
+++ /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.
- */
-
-/* global PaymentRequest:false */
-
-/**
- * Launches the PaymentRequest UI that requests an email address and offers free
- * shipping worldwide.
- */
-function buy() { // eslint-disable-line no-unused-vars
-  try {
-    const details = {
-      total: {
-        label: 'Total',
-        amount: {
-          currency: 'USD',
-          value: '5.00'
-        }
-      },
-      shippingOptions: [{
-        id: 'freeShippingOption',
-        label: 'Free global shipping',
-        amount: {
-          currency: 'USD',
-          value: '0'
-        },
-        selected: true
-      }]
-    };
-    const request = new PaymentRequest(
-      [{
-        supportedMethods: ['visa']
-      }], details, {
-        requestPayerEmail: true,
-        requestShipping: true
-      });
-    request.addEventListener('shippingaddresschange', function(e) {
-      e.updateWith(details);
-    });
-    request.show()
-      .then(function(resp) {
-        resp.complete('success')
-          .then(function() {
-            print(JSON.stringify(resp, undefined, 2));
-          })
-          .catch(function(error) {
-            print(error);
-          });
-      })
-      .catch(function(error) {
-        print(error);
-      });
-  } catch (error) {
-    print(error.message);
-  }
-}
diff --git a/chrome/test/data/payments/long_id.js b/chrome/test/data/payments/long_id.js
deleted file mode 100644
index 426874f..0000000
--- a/chrome/test/data/payments/long_id.js
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2017 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.
- */
-
-/** Invokes PaymentRequest with a very long request identifier. */
-function buy() { // eslint-disable-line no-unused-vars
-  const foo = Object.freeze({
-    supportedMethods: ['basic-card']
-  });
-  const defaultMethods = Object.freeze([foo]);
-  const defaultDetails = Object.freeze({
-    total: {
-      label: 'Label',
-      amount: {
-        currency: 'USD',
-        value: '1.00',
-      },
-    },
-  });
-  const newDetails = Object.assign({}, defaultDetails, {
-    id: ''.padStart(100000000, '\n very long id \t \n '),
-  });
-  try {
-    const request = new PaymentRequest(defaultMethods, newDetails);
-  } catch (error) {
-    print(error);
-  }
-}
diff --git a/chrome/test/data/payments/metrics.js b/chrome/test/data/payments/metrics.js
deleted file mode 100644
index 753e387..0000000
--- a/chrome/test/data/payments/metrics.js
+++ /dev/null
@@ -1,244 +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.
- */
-
-/* global PaymentRequest:false */
-
-let request;
-
-/**
- * Launches the PaymentRequest UI that accepts credit cards.
- */
-function ccBuy() { // eslint-disable-line no-unused-vars
-  try {
-    let details = {
-      total: {
-        label: 'Total',
-        amount: {
-          currency: 'USD',
-          value: '5.00',
-        },
-      },
-      shippingOptions: [{
-        id: 'freeShippingOption',
-        label: 'Free global shipping',
-        amount: {
-          currency: 'USD',
-          value: '0',
-        },
-        selected: true,
-      }],
-    };
-    request = new PaymentRequest(
-      [{
-        supportedMethods: ['visa'],
-      }], {
-        total: {
-          label: 'Total',
-          amount: {
-            currency: 'USD',
-            value: '5.00',
-          },
-        },
-        shippingOptions: [{
-          id: 'freeShippingOption',
-          label: 'Free global shipping',
-          amount: {
-            currency: 'USD',
-            value: '0',
-          },
-          selected: true,
-        }],
-      }, {
-        requestShipping: true,
-      });
-    request.show()
-      .then(function(resp) {
-        return resp.complete('success');
-      }).then(function() {
-        print(JSON.stringify(resp, undefined, 2));
-      }).catch(function(error) {
-        print(error);
-      });
-    request.addEventListener('shippingaddresschange', function(e) {
-      e.updateWith(new Promise(function(resolve) {
-        // No changes in price based on shipping address change.
-        resolve(details);
-      }));
-    });
-  } catch (error) {
-    print(error.message);
-  }
-}
-
-/**
- * Launches the PaymentRequest UI which accepts only Android Pay.
- */
-function androidPayBuy() { // eslint-disable-line no-unused-vars
-  try {
-    request = new PaymentRequest(
-      [{
-        supportedMethods: ['https://android.com/pay'],
-      }], {
-        total: {
-          label: 'Total',
-          amount: {
-            currency: 'USD',
-            value: '5.00',
-          },
-        },
-        shippingOptions: [{
-          id: 'freeShippingOption',
-          label: 'Free global shipping',
-          amount: {
-            currency: 'USD',
-            value: '0',
-          },
-          selected: true,
-        }],
-      }, {
-        requestShipping: true,
-      });
-    request.show()
-      .then(function(resp) {
-        return resp.complete('success');
-      }).then(function() {
-        print(JSON.stringify(resp, undefined, 2));
-      }).catch(function(error) {
-        print(error);
-      });
-  } catch (error) {
-    print(error.message);
-  }
-}
-
-/**
- * Launches the PaymentRequest UI which accepts only Android Pay and does not
- * require any other information.
- */
-function androidPaySkipUiBuy() { // eslint-disable-line no-unused-vars
-  try {
-    request = new PaymentRequest(
-      [{
-        supportedMethods: ['https://android.com/pay'],
-      }], {
-        total: {
-          label: 'Total',
-          amount: {
-            currency: 'USD',
-            value: '5.00',
-          },
-        },
-      });
-    request.show()
-      .then(function(resp) {
-        return resp.complete('success');
-      }).then(function() {
-        print(JSON.stringify(resp, undefined, 2));
-      }).catch(function(error) {
-        print(error);
-      });
-  } catch (error) {
-    print(error.message);
-  }
-}
-
-/**
- * Launches the PaymentRequest UI which accepts only an unsupported payment
- * method.
- */
-function noSupported() { // eslint-disable-line no-unused-vars
-  try {
-    request = new PaymentRequest(
-      [{
-        supportedMethods: ['https://randompay.com'],
-      }], {
-        total: {
-          label: 'Total',
-          amount: {
-            currency: 'USD',
-            value: '5.00',
-          },
-        },
-        shippingOptions: [{
-          id: 'freeShippingOption',
-          label: 'Free global shipping',
-          amount: {
-            currency: 'USD',
-            value: '0',
-          },
-          selected: true,
-        }],
-      }, {
-        requestShipping: true,
-      });
-    request.show()
-      .then(function(resp) {
-        return resp.complete('success');
-      }).then(function() {
-        print(JSON.stringify(resp, undefined, 2));
-      }).catch(function(error) {
-        print(error);
-      });
-  } catch (error) {
-    print(error.message);
-  }
-}
-
-/**
- * Launches the PaymentRequest UI which accepts credit cards and Bob Pay.
- */
-function cardsAndBobPayBuy() { // eslint-disable-line no-unused-vars
-  try {
-    request = new PaymentRequest(
-      [{
-        supportedMethods: ['visa', 'https://bobpay.com'],
-      }], {
-        total: {
-          label: 'Total',
-          amount: {
-            currency: 'USD',
-            value: '5.00',
-          },
-        },
-        shippingOptions: [{
-          id: 'freeShippingOption',
-          label: 'Free global shipping',
-          amount: {
-            currency: 'USD',
-            value: '0',
-          },
-          selected: true,
-        }],
-      }, {
-        requestShipping: true,
-      });
-    request.show()
-      .then(function(resp) {
-        return resp.complete('success');
-      }).then(function() {
-        print(JSON.stringify(resp, undefined, 2));
-      }).catch(function(error) {
-        print(error);
-      });
-  } catch (error) {
-    print(error.message);
-  }
-}
-
-/**
- * Aborts the current PaymentRequest.
- */
-function abort() { // eslint-disable-line no-unused-vars
-  try {
-    request.abort().then(function() {
-      print('Aborted');
-    }).catch(function() {
-      print('Cannot abort');
-    });
-  } catch (error) {
-    print(error.message);
-  }
-}
diff --git a/chrome/test/data/subresource_filter/frame_set_special_urls.html b/chrome/test/data/subresource_filter/frame_set_special_urls.html
new file mode 100644
index 0000000..46acbf0
--- /dev/null
+++ b/chrome/test/data/subresource_filter/frame_set_special_urls.html
@@ -0,0 +1,33 @@
+<html>
+  <body>
+    <iframe name="blank" src="about:blank"></iframe>
+    <iframe name="js" src="javascript:'<html><\/html>'"></iframe>
+    <iframe name="srcdoc" srcdoc="<script src='included_script.js'></script>"></iframe>
+  </body>
+  <script>
+    // Inject content into the blank frames.
+    let blankFrame = document.getElementsByName("blank")[0];
+    let script = document.createElement("script");
+    script.src = "included_script.js";
+    blankFrame.contentDocument.body.appendChild(script);
+
+    let jsFrame = document.getElementsByName("js")[0];
+    let script2 = document.createElement("script");
+    script2.src = "included_script.js";
+    jsFrame.contentDocument.body.appendChild(script2);
+
+    // Add a frame with a data URL, making sure it loads a script pointing to
+    // the right host and port.
+    let dataFrame = document.createElement('iframe');
+    dataFrame.name = "data";
+
+    let scriptPath = location.pathname.split("/");
+    scriptPath[scriptPath.length - 1] = "included_script.js";
+    scriptPath = scriptPath.join("/");
+
+    let url = new URL(location.href);
+    url.pathname = scriptPath;
+    dataFrame.src = "data:text/html,<script src='" + url + "'><\/script>";
+    document.body.appendChild(dataFrame);
+  </script>
+</html>
diff --git a/chrome/test/data/subresource_filter/frame_set_sync_loads.html b/chrome/test/data/subresource_filter/frame_set_sync_loads.html
deleted file mode 100644
index 4420cff..0000000
--- a/chrome/test/data/subresource_filter/frame_set_sync_loads.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<html>
-  <body>
-    <iframe name="blank_one" src="about:blank"></iframe>
-    <iframe name="blank_two" src="data:text/html,<h1>Content</h1>"></iframe>
-    <iframe id="initially_blank" name="initially_blank" src="about:blank"></iframe>
-  </body>
-  <script>
-    let f = document.getElementById("initially_blank");
-    f.src = "frame_with_included_script.html";
-  </script>
-</html>
diff --git a/chrome/test/data/webui/cr_elements/cr_dialog_test.js b/chrome/test/data/webui/cr_elements/cr_dialog_test.js
index 4a6e84ee..ad0a8689 100644
--- a/chrome/test/data/webui/cr_elements/cr_dialog_test.js
+++ b/chrome/test/data/webui/cr_elements/cr_dialog_test.js
@@ -14,8 +14,8 @@
   test('focuses title on show', function() {
     document.body.innerHTML = `
       <dialog is="cr-dialog">
-        <div class="title">title</div>
-        <div class="body"><button>button</button></div>
+        <div slot="title">title</div>
+        <div slot="body"><button>button</button></div>
       </dialog>`;
 
     var dialog = document.body.querySelector('dialog');
@@ -33,8 +33,8 @@
   test('enter keys should trigger action buttons once', function() {
     document.body.innerHTML = `
       <dialog is="cr-dialog">
-        <div class="title">title</div>
-        <div class="body">
+        <div slot="title">title</div>
+        <div slot="body">
           <button class="action-button">button</button>
           <button id="other-button">other button</button>
         </div>
@@ -70,8 +70,8 @@
   test('enter keys find the first non-hidden non-disabled button', function() {
     document.body.innerHTML = `
       <dialog is="cr-dialog">
-        <div class="title">title</div>
-        <div class="body">
+        <div slot="title">title</div>
+        <div slot="body">
           <button id="hidden" class="action-button" hidden>hidden</button>
           <button class="action-button" disabled>disabled</button>
           <button class="action-button" disabled hidden>disabled hidden</button>
@@ -100,8 +100,8 @@
   test('enter keys from paper-inputs (only) are processed', function() {
     document.body.innerHTML = `
       <dialog is="cr-dialog">
-        <div class="title">title</div>
-        <div class="body">
+        <div slot="title">title</div>
+        <div slot="body">
           <paper-input></paper-input>
           <foobar></foobar>
           <button class="action-button">active</button>
@@ -133,8 +133,8 @@
   test('focuses [autofocus] instead of title when present', function() {
     document.body.innerHTML = `
       <dialog is="cr-dialog">
-        <div class="title">title</div>
-        <div class="body"><button autofocus>button</button></div>
+        <div slot="title">title</div>
+        <div slot="body"><button autofocus>button</button></div>
       </dialog>`;
 
     var dialog = document.body.querySelector('dialog');
@@ -154,8 +154,8 @@
   test('body scrollable border not added before modal shown', function(done) {
     document.body.innerHTML = `
       <dialog is="cr-dialog">
-        <div class="title">title</div>
-        <div class="body">body</div>
+        <div slot="title">title</div>
+        <div slot="body">body</div>
       </dialog>`;
 
     var dialog = document.body.querySelector('dialog');
@@ -175,8 +175,8 @@
   test('dialog body scrollable border when appropriate', function(done) {
     document.body.innerHTML = `
       <dialog is="cr-dialog">
-        <div class="title">title</div>
-        <div class="body">
+        <div slot="title">title</div>
+        <div slot="body">
           <div style="height: 100px">tall content</div>
         </div>
       </dialog>`;
@@ -226,7 +226,7 @@
   test('dialog cannot be cancelled when `no-cancel` is set', function() {
     document.body.innerHTML = `
       <dialog is="cr-dialog" no-cancel>
-        <div class="title">title</div>
+        <div slot="title">title</div>
       </dialog>`;
 
     var dialog = document.body.querySelector('dialog');
diff --git a/chromecast/BUILD.gn b/chromecast/BUILD.gn
index ac22671..77e939ec 100644
--- a/chromecast/BUILD.gn
+++ b/chromecast/BUILD.gn
@@ -266,6 +266,17 @@
   }
   filters += [ media_unittests_filter ]
 
+  midi_unittests_filter = {
+    test_name = "midi_unittests"
+    if (!is_cast_desktop_build && !is_cast_audio_only) {
+      # Disable MidiTaskServiceTest.RunBoundTasks. This is failing on v1
+      # devices. Temporarily disable to get dashboards green again while the
+      # failure is investigated. (crbug/744777)
+      gtest_excludes = [ "MidiTaskServiceTest.RunBoundTasks" ]
+    }
+  }
+  filters += [ midi_unittests_filter ]
+
   net_unittests_filter = {
     test_name = "net_unittests"
     if (using_sanitizer) {
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsComponent.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsComponent.java
index 198f614..70f8272b 100644
--- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsComponent.java
+++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsComponent.java
@@ -137,6 +137,7 @@
     private OnKeyDownHandler mKeyDownHandler;
     private Receiver mReceiver;
     private String mInstanceId;
+    private boolean mStarted = false;
 
     public CastWebContentsComponent(String instanceId,
             OnComponentClosedHandler onComponentClosedHandler, OnKeyDownHandler onKeyDownHandler) {
@@ -164,13 +165,17 @@
         LocalBroadcastManager.getInstance(context).registerReceiver(mReceiver, filter);
 
         mDelegate.start(context, webContents);
+
+        mStarted = true;
     }
 
     public void stop(Context context) {
         if (DEBUG) Log.d(TAG, "stop");
-
-        LocalBroadcastManager.getInstance(context).unregisterReceiver(mReceiver);
-        mDelegate.stop(context);
+        if (mStarted) {
+            LocalBroadcastManager.getInstance(context).unregisterReceiver(mReceiver);
+            mDelegate.stop(context);
+            mStarted = false;
+        }
     }
 
     public static void onComponentClosed(Context context, String instanceId) {
diff --git a/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsComponentTest.java b/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsComponentTest.java
index 4c3709c..2a5371c 100644
--- a/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsComponentTest.java
+++ b/chromecast/browser/android/junit/src/org/chromium/chromecast/shell/CastWebContentsComponentTest.java
@@ -6,6 +6,7 @@
 
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
 import android.app.Activity;
@@ -141,4 +142,13 @@
 
         verify(callback).onKeyDown(42);
     }
+
+    @Test
+    public void testStopDoesNotUnbindServiceIfStartWasNotCalled() {
+        CastWebContentsComponent component = new CastWebContentsComponent(INSTANCE_ID, null, null);
+
+        component.stop(mActivity);
+
+        verify(mActivity, never()).unbindService(any(ServiceConnection.class));
+    }
 }
\ No newline at end of file
diff --git a/chromecast/renderer/cast_content_renderer_client.cc b/chromecast/renderer/cast_content_renderer_client.cc
index bf0002b..3ac1cfd4 100644
--- a/chromecast/renderer/cast_content_renderer_client.cc
+++ b/chromecast/renderer/cast_content_renderer_client.cc
@@ -216,7 +216,7 @@
   new CastRenderFrameActionDeferrer(render_frame, closure);
 }
 
-bool CastContentRendererClient::AllowMediaSuspend() {
+bool CastContentRendererClient::AllowIdleMediaSuspend() {
   return false;
 }
 
diff --git a/chromecast/renderer/cast_content_renderer_client.h b/chromecast/renderer/cast_content_renderer_client.h
index f72a97f..85e432d 100644
--- a/chromecast/renderer/cast_content_renderer_client.h
+++ b/chromecast/renderer/cast_content_renderer_client.h
@@ -46,7 +46,7 @@
   void DeferMediaLoad(content::RenderFrame* render_frame,
                       bool render_frame_has_played_media_before,
                       const base::Closure& closure) override;
-  bool AllowMediaSuspend() override;
+  bool AllowIdleMediaSuspend() override;
   void SetRuntimeFeaturesDefaultsBeforeBlinkInitialization() override;
 
  protected:
diff --git a/chromeos/network/network_connect.cc b/chromeos/network/network_connect.cc
index c3553e2b6..f4823e7 100644
--- a/chromeos/network/network_connect.cc
+++ b/chromeos/network/network_connect.cc
@@ -124,8 +124,12 @@
   }
 
   if (network->type() == shill::kTypeWifi) {
-    // Only show the config view for secure networks, otherwise do nothing.
-    if (network->security_class() != shill::kSecurityNone) {
+    // If the network does not require a password, do not show the dialog since
+    // there is nothing to configure. Likewise, if the network is the underlying
+    // Wi-Fi hotspot for a Tether network, do not show the dialog since the
+    // Tether component handles this case itself.
+    if (network->security_class() != shill::kSecurityNone &&
+        network->tether_guid().empty()) {
       delegate_->ShowNetworkConfigure(network_id);
     }
     return;
diff --git a/chromeos/network/network_connect_unittest.cc b/chromeos/network/network_connect_unittest.cc
index fccdbc0a..c07691ff 100644
--- a/chromeos/network/network_connect_unittest.cc
+++ b/chromeos/network/network_connect_unittest.cc
@@ -229,6 +229,20 @@
       kWiFi1Guid, NetworkConnectionHandler::kErrorConnectFailed);
 }
 
+TEST_F(NetworkConnectTest, ConfigureUINotShownForTetherAssociatedWifiNetwork) {
+  // The configure UI should *not* be shown for Wi-Fi networks which serve as
+  // the underlying Wi-Fi hotspot for a Tether network.
+  EXPECT_CALL(*mock_delegate_, ShowNetworkConfigure(kWiFi1Guid)).Times(0);
+
+  AddTetherNetwork(false /* has_connected_to_host */);
+  NetworkHandler::Get()
+      ->network_state_handler()
+      ->AssociateTetherNetworkStateWithWifiNetwork(kTetherGuid, kWiFi1Guid);
+
+  NetworkConnect::Get()->MaybeShowConfigureUI(
+      kWiFi1Guid, NetworkConnectionHandler::kErrorConnectFailed);
+}
+
 TEST_F(NetworkConnectTest, ShowConfigureUI_BadErrorCode) {
   EXPECT_CALL(*mock_delegate_, ShowNetworkConfigure(kWiFi1Guid)).Times(0);
 
diff --git a/components/arc/common/voice_interaction_framework.mojom b/components/arc/common/voice_interaction_framework.mojom
index c5129a6a..ad26b90 100644
--- a/components/arc/common/voice_interaction_framework.mojom
+++ b/components/arc/common/voice_interaction_framework.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Next MinVersion: 7
+// Next MinVersion: 8
 
 module arc.mojom;
 
@@ -30,8 +30,20 @@
   [MinVersion=6]SetVoiceInteractionRunning@4(bool running);
 };
 
+// Indicates voice interaction configuration status.
+struct VoiceInteractionStatus {
+  // Whether voice interaction is configured during OOBE flow. |false| if
+  // OOBE flow has been skipped.
+  bool configured;
+  // Whether voice interaction service is enabled.
+  bool voice_interaction_enabled;
+  // Whether allow voice interaction service to request screenshot
+  // and screen context.
+  bool context_enabled;
+};
+
 // Connects with Android system server.
-// Next method ID: 7
+// Next method ID: 8
 interface VoiceInteractionFrameworkInstance {
   Init@0(VoiceInteractionFrameworkHost host_ptr);
 
@@ -55,4 +67,8 @@
 
   // Starts the voice interaction setup wizard in container.
   [MinVersion=5] StartVoiceInteractionSetupWizard@6();
-};
+
+  // Queries voice interaction settings status.
+  [MinVersion=7] GetVoiceInteractionSettings@7() => 
+    (VoiceInteractionStatus status);
+};
\ No newline at end of file
diff --git a/components/autofill_strings.grdp b/components/autofill_strings.grdp
index bea84fe..16fd554 100644
--- a/components/autofill_strings.grdp
+++ b/components/autofill_strings.grdp
@@ -371,4 +371,12 @@
   <message name="IDS_AUTOFILL_NO_SAVED_ADDRESS" desc="The string to display in comboboxes when no addresses are available.">
     No saved addresses
   </message>
+
+  <!-- Autofill/Wallet integration preferences -->
+  <message name="IDS_AUTOFILL_WALLET_MANAGEMENT_LINK_TEXT" desc="Text for link that allows users to see and edit their Wallet information." formatter_data="android_java">
+    Edit
+  </message>
+  <message name="IDS_AUTOFILL_FROM_GOOGLE_ACCOUNT_LONG" desc="Text that indicates an address or credit card came from Google servers." formatter_data="android_java">
+    From Google Payments
+  </message>
 </grit-part>
diff --git a/components/cast_channel/cast_socket.cc b/components/cast_channel/cast_socket.cc
index 4039ade..20effac 100644
--- a/components/cast_channel/cast_socket.cc
+++ b/components/cast_channel/cast_socket.cc
@@ -137,7 +137,7 @@
   CloseInternal();
 
   for (auto& connect_callback : connect_callbacks_)
-    connect_callback.Run(channel_id_, ChannelError::UNKNOWN);
+    std::move(connect_callback).Run(channel_id_, ChannelError::UNKNOWN);
   connect_callbacks_.clear();
 }
 
@@ -241,20 +241,20 @@
   transport_ = std::move(transport);
 }
 
-void CastSocketImpl::Connect(const OnOpenCallback& callback) {
+void CastSocketImpl::Connect(OnOpenCallback callback) {
   switch (ready_state_) {
     case ReadyState::NONE:
-      connect_callbacks_.push_back(callback);
+      connect_callbacks_.push_back(std::move(callback));
       Connect();
       break;
     case ReadyState::CONNECTING:
-      connect_callbacks_.push_back(callback);
+      connect_callbacks_.push_back(std::move(callback));
       break;
     case ReadyState::OPEN:
-      callback.Run(channel_id_, ChannelError::NONE);
+      std::move(callback).Run(channel_id_, ChannelError::NONE);
       break;
     case ReadyState::CLOSED:
-      callback.Run(channel_id_, ChannelError::CONNECT_ERROR);
+      std::move(callback).Run(channel_id_, ChannelError::CONNECT_ERROR);
       break;
     default:
       NOTREACHED() << "Unknown ReadyState: "
@@ -573,7 +573,7 @@
   }
 
   for (auto& connect_callback : connect_callbacks_)
-    connect_callback.Run(channel_id_, error_state_);
+    std::move(connect_callback).Run(channel_id_, error_state_);
   connect_callbacks_.clear();
 }
 
diff --git a/components/cast_channel/cast_socket.h b/components/cast_channel/cast_socket.h
index 31d829ee..de1792b3 100644
--- a/components/cast_channel/cast_socket.h
+++ b/components/cast_channel/cast_socket.h
@@ -57,7 +57,7 @@
 class CastSocket {
  public:
   using OnOpenCallback =
-      base::Callback<void(int channel_id, ChannelError error_state)>;
+      base::OnceCallback<void(int channel_id, ChannelError error_state)>;
 
   class Observer {
    public:
@@ -85,7 +85,7 @@
   // If the CastSocket is destroyed while the connection is pending, |callback|
   // will be invoked with CHANNEL_ERROR_UNKNOWN. In this case, invoking
   // |callback| must not result in any re-entrancy behavior.
-  virtual void Connect(const OnOpenCallback& callback) = 0;
+  virtual void Connect(OnOpenCallback callback) = 0;
 
   // Closes the channel if not already closed. On completion, the channel will
   // be in READY_STATE_CLOSED.
@@ -173,7 +173,7 @@
   ~CastSocketImpl() override;
 
   // CastSocket interface.
-  void Connect(const OnOpenCallback& callback) override;
+  void Connect(OnOpenCallback callback) override;
   CastTransport* transport() const override;
   void Close(const net::CompletionCallback& callback) override;
   const net::IPEndPoint& ip_endpoint() const override;
diff --git a/components/cast_channel/cast_socket_service.cc b/components/cast_channel/cast_socket_service.cc
index 7932395..478dd55 100644
--- a/components/cast_channel/cast_socket_service.cc
+++ b/components/cast_channel/cast_socket_service.cc
@@ -94,7 +94,7 @@
                                   const base::TimeDelta& liveness_timeout,
                                   const base::TimeDelta& ping_interval,
                                   uint64_t device_capabilities,
-                                  const CastSocket::OnOpenCallback& open_cb,
+                                  CastSocket::OnOpenCallback open_cb,
                                   CastSocket::Observer* observer) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(observer);
@@ -113,21 +113,21 @@
   }
 
   socket->AddObserver(observer);
-  socket->Connect(open_cb);
+  socket->Connect(std::move(open_cb));
   return socket->id();
 }
 
 int CastSocketService::OpenSocket(const net::IPEndPoint& ip_endpoint,
                                   net::NetLog* net_log,
-                                  const CastSocket::OnOpenCallback& open_cb,
+                                  CastSocket::OnOpenCallback open_cb,
                                   CastSocket::Observer* observer) {
   auto connect_timeout = base::TimeDelta::FromSeconds(kConnectTimeoutSecs);
   auto ping_interval = base::TimeDelta::FromSeconds(kPingIntervalInSecs);
   auto liveness_timeout =
       base::TimeDelta::FromSeconds(kConnectLivenessTimeoutSecs);
   return OpenSocket(ip_endpoint, net_log, connect_timeout, liveness_timeout,
-                    ping_interval, CastDeviceCapability::NONE, open_cb,
-                    observer);
+                    ping_interval, CastDeviceCapability::NONE,
+                    std::move(open_cb), observer);
 }
 
 void CastSocketService::RemoveObserver(CastSocket::Observer* observer) {
diff --git a/components/cast_channel/cast_socket_service.h b/components/cast_channel/cast_socket_service.h
index d7dc8c2..e93ead0 100644
--- a/components/cast_channel/cast_socket_service.h
+++ b/components/cast_channel/cast_socket_service.h
@@ -61,7 +61,7 @@
                  const base::TimeDelta& liveness_timeout,
                  const base::TimeDelta& ping_interval,
                  uint64_t device_capabilities,
-                 const CastSocket::OnOpenCallback& open_cb,
+                 CastSocket::OnOpenCallback open_cb,
                  CastSocket::Observer* observer);
 
   // Opens cast socket with |ip_endpoint| and invokes |open_cb| when opening
@@ -74,7 +74,7 @@
   // Does not take ownership of |observer|.
   virtual int OpenSocket(const net::IPEndPoint& ip_endpoint,
                          net::NetLog* net_log,
-                         const CastSocket::OnOpenCallback& open_cb,
+                         CastSocket::OnOpenCallback open_cb,
                          CastSocket::Observer* observer);
 
   // Remove |observer| from each socket in |sockets_|
diff --git a/components/cast_channel/cast_socket_service_unittest.cc b/components/cast_channel/cast_socket_service_unittest.cc
index 1c2abbc..f2c0ce02 100644
--- a/components/cast_channel/cast_socket_service_unittest.cc
+++ b/components/cast_channel/cast_socket_service_unittest.cc
@@ -80,9 +80,9 @@
   mock_socket->SetIPEndpoint(ip_endpoint);
   cast_socket_service_->SetSocketForTest(base::WrapUnique(mock_socket));
 
-  EXPECT_CALL(*mock_socket, Connect(_))
-      .WillOnce(
-          WithArgs<0>(Invoke([&](const CastSocket::OnOpenCallback& callback) {
+  EXPECT_CALL(*mock_socket, ConnectInternal(_))
+      .WillOnce(WithArgs<0>(
+          Invoke([&](const MockCastSocket::MockOnOpenCallback& callback) {
             callback.Run(mock_socket->id(), ChannelError::NONE);
           })));
   EXPECT_CALL(mock_on_open_callback_, Run(_, ChannelError::NONE));
diff --git a/components/cast_channel/cast_test_util.h b/components/cast_channel/cast_test_util.h
index 7e37ca4..fbf0cc7 100644
--- a/components/cast_channel/cast_test_util.h
+++ b/components/cast_channel/cast_test_util.h
@@ -70,20 +70,40 @@
   MockCastSocketService();
   ~MockCastSocketService() override;
 
-  MOCK_METHOD4(OpenSocket,
+  int OpenSocket(const net::IPEndPoint& ip_endpoint,
+                 net::NetLog* net_log,
+                 CastSocket::OnOpenCallback open_cb,
+                 CastSocket::Observer* observer) override {
+    // Unit test should not call |open_cb| more than once. Just use
+    // base::AdaptCallbackForRepeating to pass |open_cb| to a mock method.
+    return OpenSocketInternal(
+        ip_endpoint, net_log,
+        base::AdaptCallbackForRepeating(std::move(open_cb)), observer);
+  }
+
+  MOCK_METHOD4(OpenSocketInternal,
                int(const net::IPEndPoint& ip_endpoint,
                    net::NetLog* net_log,
-                   const CastSocket::OnOpenCallback& open_cb,
+                   const base::Callback<void(int, ChannelError)>& open_cb,
                    CastSocket::Observer* observer));
   MOCK_CONST_METHOD1(GetSocket, CastSocket*(int channel_id));
 };
 
 class MockCastSocket : public CastSocket {
  public:
+  using MockOnOpenCallback =
+      base::Callback<void(int channel_id, ChannelError error_state)>;
+
   MockCastSocket();
   ~MockCastSocket() override;
 
-  MOCK_METHOD1(Connect, void(const OnOpenCallback& callback));
+  void Connect(CastSocket::OnOpenCallback callback) override {
+    // Unit test should not call |open_cb| more than once. Just use
+    // base::AdaptCallbackForRepeating to pass |open_cb| to a mock method.
+    ConnectInternal(base::AdaptCallbackForRepeating(std::move(callback)));
+  }
+
+  MOCK_METHOD1(ConnectInternal, void(const MockOnOpenCallback& callback));
   MOCK_METHOD1(Close, void(const net::CompletionCallback& callback));
   MOCK_CONST_METHOD0(ready_state, ReadyState());
   MOCK_METHOD1(AddObserver, void(Observer* observer));
diff --git a/components/content_settings/core/browser/content_settings_registry.cc b/components/content_settings/core/browser/content_settings_registry.cc
index cc19565..9413166 100644
--- a/components/content_settings/core/browser/content_settings_registry.cc
+++ b/components/content_settings/core/browser/content_settings_registry.cc
@@ -274,6 +274,14 @@
                WebsiteSettingsRegistry::PLATFORM_ANDROID,
            ContentSettingsInfo::INHERIT_IF_LESS_PERMISSIVE);
 
+  Register(CONTENT_SETTINGS_TYPE_SOUND, "sound", CONTENT_SETTING_ALLOW,
+           WebsiteSettingsInfo::UNSYNCABLE, WhitelistedSchemes(),
+           ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
+           WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE,
+           WebsiteSettingsRegistry::DESKTOP |
+               WebsiteSettingsRegistry::PLATFORM_ANDROID,
+           ContentSettingsInfo::INHERIT_IF_LESS_PERMISSIVE);
+
   Register(CONTENT_SETTINGS_TYPE_ADS, "subresource-filter",
            CONTENT_SETTING_BLOCK, WebsiteSettingsInfo::UNSYNCABLE,
            WhitelistedSchemes(),
diff --git a/components/content_settings/core/common/content_settings.cc b/components/content_settings/core/common/content_settings.cc
index e1dddb6..4b32cb9 100644
--- a/components/content_settings/core/common/content_settings.cc
+++ b/components/content_settings/core/common/content_settings.cc
@@ -28,7 +28,7 @@
 // content settings type name instead.
 //
 // The array size must be explicit for the static_asserts below.
-constexpr size_t kNumHistogramValues = 29;
+constexpr size_t kNumHistogramValues = 30;
 constexpr HistogramValue kHistogramValue[kNumHistogramValues] = {
     {CONTENT_SETTINGS_TYPE_COOKIES, 0},
     {CONTENT_SETTINGS_TYPE_IMAGES, 1},
@@ -59,6 +59,7 @@
     {CONTENT_SETTINGS_TYPE_ADS_DATA, 33},
     {CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, 34},
     {CONTENT_SETTINGS_TYPE_MEDIA_ENGAGEMENT, 35},
+    {CONTENT_SETTINGS_TYPE_SOUND, 36},
 };
 
 }  // namespace
diff --git a/components/content_settings/core/common/content_settings_types.h b/components/content_settings/core/common/content_settings_types.h
index 272ca9ac..e752e9e 100644
--- a/components/content_settings/core/common/content_settings_types.h
+++ b/components/content_settings/core/common/content_settings_types.h
@@ -71,6 +71,10 @@
   // specific origin.
   CONTENT_SETTINGS_TYPE_MEDIA_ENGAGEMENT,
 
+  // Website setting which stores whether or not the site can play audible
+  // sound. This will not block playback but instead the user will not hear it.
+  CONTENT_SETTINGS_TYPE_SOUND,
+
   CONTENT_SETTINGS_NUM_TYPES,
 };
 
diff --git a/components/crash/content/app/breakpad_linux.cc b/components/crash/content/app/breakpad_linux.cc
index 0207331..2199920 100644
--- a/components/crash/content/app/breakpad_linux.cc
+++ b/components/crash/content/app/breakpad_linux.cc
@@ -2099,4 +2099,8 @@
   return g_is_crash_reporter_enabled;
 }
 
+void SetFirstChanceExceptionHandler(bool (*handler)(int, void*, void*)) {
+  google_breakpad::SetFirstChanceExceptionHandler(handler);
+}
+
 }  // namespace breakpad
diff --git a/components/crash/content/app/breakpad_linux.h b/components/crash/content/app/breakpad_linux.h
index 0160f628..4a2a429 100644
--- a/components/crash/content/app/breakpad_linux.h
+++ b/components/crash/content/app/breakpad_linux.h
@@ -61,6 +61,10 @@
 
 // Generates a minidump on demand for this process, writing it to |dump_fd|.
 void GenerateMinidumpOnDemandForAndroid(int dump_fd);
+
+// Install a handler that gets a change to handle faults before Breakpad does
+// any processing. This is used by V8 for trap-based bounds checks.
+void SetFirstChanceExceptionHandler(bool (*handler)(int, void*, void*));
 }  // namespace breakpad
 
 #endif  // COMPONENTS_CRASH_CONTENT_APP_BREAKPAD_LINUX_H_
diff --git a/components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java b/components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java
index 9ab5f64..e60fa80d 100644
--- a/components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java
+++ b/components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java
@@ -269,7 +269,7 @@
     /**
      * Starts NetLog logging to a specified directory with a bounded size. The NetLog will contain
      * events emitted by all live CronetEngines. The NetLog is useful for debugging.
-     * The log can be viewed by stitching the files using net/log/stitch_net_log_files.py and
+     * The log can be viewed by stitching the files using net/tools/stitch_net_log_files.py and
      * using a Chrome browser navigated to chrome://net-internals/#import
      * @param dirPath the directory where the log files will be created. It must already exist.
      *            NetLog files must not already exist in the directory. If actively logging,
diff --git a/components/cronet/android/api_version.txt b/components/cronet/android/api_version.txt
index 1e8b314..7f8f011 100644
--- a/components/cronet/android/api_version.txt
+++ b/components/cronet/android/api_version.txt
@@ -1 +1 @@
-6
+7
diff --git a/components/cronet/android/cronet_bidirectional_stream_adapter.cc b/components/cronet/android/cronet_bidirectional_stream_adapter.cc
index 104cb43..74e7d84c 100644
--- a/components/cronet/android/cronet_bidirectional_stream_adapter.cc
+++ b/components/cronet/android/cronet_bidirectional_stream_adapter.cc
@@ -322,10 +322,11 @@
   DCHECK(context_->IsOnNetworkThread());
   stream_failed_ = true;
   JNIEnv* env = base::android::AttachCurrentThread();
-  // TODO(mgersh): Add support for NetErrorDetails (http://crbug.com/624942)
+  net::NetErrorDetails net_error_details;
+  bidi_stream_->PopulateNetErrorDetails(&net_error_details);
   cronet::Java_CronetBidirectionalStream_onError(
       env, owner_.obj(), NetErrorToUrlRequestError(error), error,
-      net::QUIC_NO_ERROR,
+      net_error_details.quic_connection_error,
       ConvertUTF8ToJavaString(env, net::ErrorToString(error)).obj(),
       bidi_stream_->GetTotalReceivedBytes());
 }
diff --git a/components/cronet/android/cronet_url_request_context_adapter.cc b/components/cronet/android/cronet_url_request_context_adapter.cc
index f7f8621a..3936a83 100644
--- a/components/cronet/android/cronet_url_request_context_adapter.cc
+++ b/components/cronet/android/cronet_url_request_context_adapter.cc
@@ -76,9 +76,6 @@
 
 namespace {
 
-// Always split NetLog events into 10 files.
-const int kNumNetLogEventFiles = 10;
-
 // This class wraps a NetLog that also contains network change events.
 class NetLogWithNetworkChangeEvents {
  public:
@@ -1052,12 +1049,16 @@
   if (net_log_file_observer_)
     return;
 
-  // Filepath for NetLog files must exist and be writable.
-  base::FilePath file_path(dir_path);
-  DCHECK(base::PathIsWritable(file_path));
+  // TODO(eroman): The cronet API passes a directory here. But it should now
+  // just pass a file path.
+  base::FilePath file_path =
+      base::FilePath(dir_path).AppendASCII("netlog.json");
+  if (!base::PathIsWritable(file_path)) {
+    LOG(ERROR) << "Path is not writable: " << file_path.value();
+  }
 
   net_log_file_observer_ = net::FileNetLogObserver::CreateBounded(
-      file_path, size, kNumNetLogEventFiles, /*constants=*/nullptr);
+      file_path, size, /*constants=*/nullptr);
 
   CreateNetLogEntriesForActiveObjects({context_.get()},
                                       net_log_file_observer_.get());
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java
index 28f6612..5ff68b4 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/BidirectionalStreamQuicTest.java
@@ -334,6 +334,11 @@
         NetworkException networkError = (NetworkException) callback.mError;
         assertTrue(NetError.ERR_QUIC_PROTOCOL_ERROR == networkError.getCronetInternalErrorCode()
                 || NetError.ERR_CONNECTION_REFUSED == networkError.getCronetInternalErrorCode());
+        if (NetError.ERR_CONNECTION_REFUSED == networkError.getCronetInternalErrorCode()) return;
+        assertTrue(callback.mError instanceof QuicException);
+        QuicException quicException = (QuicException) callback.mError;
+        // 16 is QUIC_PEER_GOING_AWAY
+        assertEquals(16, quicException.getQuicDetailedErrorCode());
     }
 
     @SmallTest
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/BrotliTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/BrotliTest.java
index e1504474..e96ab97 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/BrotliTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/BrotliTest.java
@@ -19,6 +19,7 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+        TestFilesInstaller.installIfNeeded(getContext());
         assertTrue(Http2TestServer.startHttp2TestServer(
                 getContext(), SERVER_CERT_PEM, SERVER_KEY_PKCS8_PEM));
     }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetTestBase.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetTestBase.java
index 8e004ed3..54d9156 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetTestBase.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetTestBase.java
@@ -77,11 +77,14 @@
         PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX);
         prepareTestStorage(getContext());
         mOldVmPolicy = StrictMode.getVmPolicy();
-        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
-                                       .detectLeakedClosableObjects()
-                                       .penaltyLog()
-                                       .penaltyDeath()
-                                       .build());
+        // Only enable StrictMode testing after leaks were fixed in crrev.com/475945
+        if (getMaximumAvailableApiLevel() >= 7) {
+            StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
+                                           .detectLeakedClosableObjects()
+                                           .penaltyLog()
+                                           .penaltyDeath()
+                                           .build());
+        }
     }
 
     @SuppressFBWarnings("DM_GC") // Used to trigger strictmode detecting leaked closeables
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 3bbefe7..14c546b 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
@@ -366,7 +366,7 @@
         File netLogDir = new File(directory, "NetLog");
         assertFalse(netLogDir.exists());
         assertTrue(netLogDir.mkdir());
-        File eventFile = new File(netLogDir, "event_file_0.json");
+        File logFile = new File(netLogDir, "netlog.json");
         ExperimentalCronetEngine cronetEngine =
                 new ExperimentalCronetEngine.Builder(context).build();
         // Start NetLog immediately after the request context is created to make
@@ -381,9 +381,9 @@
         urlRequestBuilder.build().start();
         callback.blockForDone();
         cronetEngine.stopNetLog();
-        assertTrue(eventFile.exists());
-        assertTrue(eventFile.length() != 0);
-        assertFalse(hasBytesInNetLog(eventFile));
+        assertTrue(logFile.exists());
+        assertTrue(logFile.length() != 0);
+        assertFalse(hasBytesInNetLog(logFile));
         FileUtils.recursivelyDeleteFile(netLogDir);
         assertFalse(netLogDir.exists());
     }
@@ -426,7 +426,7 @@
         File netLogDir = new File(directory, "NetLog");
         assertFalse(netLogDir.exists());
         assertTrue(netLogDir.mkdir());
-        File eventFile = new File(netLogDir, "event_file_0.json");
+        File logFile = new File(netLogDir, "netlog.json");
         ExperimentalCronetEngine cronetEngine =
                 new ExperimentalCronetEngine.Builder(context).build();
         cronetEngine.startNetLogToDisk(netLogDir.getPath(), false, MAX_FILE_SIZE);
@@ -439,8 +439,8 @@
         callback.blockForDone();
         // Shut down the engine without calling stopNetLog.
         cronetEngine.shutdown();
-        assertTrue(eventFile.exists());
-        assertTrue(eventFile.length() != 0);
+        assertTrue(logFile.exists());
+        assertTrue(logFile.length() != 0);
 
         FileUtils.recursivelyDeleteFile(netLogDir);
         assertFalse(netLogDir.exists());
@@ -499,8 +499,8 @@
         File netLogDir2 = new File(directory, "NetLog2");
         assertFalse(netLogDir2.exists());
         assertTrue(netLogDir2.mkdir());
-        File eventFile1 = new File(netLogDir1, "event_file_0.json");
-        File eventFile2 = new File(netLogDir2, "event_file_0.json");
+        File logFile1 = new File(netLogDir1, "netlog.json");
+        File logFile2 = new File(netLogDir2, "netlog.json");
 
         ExperimentalCronetEngine cronetEngine1 =
                 new ExperimentalCronetEngine.Builder(context).build();
@@ -524,17 +524,17 @@
         cronetEngine1.stopNetLog();
         cronetEngine2.stopNetLog();
 
-        assertTrue(eventFile1.exists());
-        assertTrue(eventFile2.exists());
-        assertTrue(eventFile1.length() != 0);
-        assertTrue(eventFile2.length() != 0);
+        assertTrue(logFile1.exists());
+        assertTrue(logFile2.exists());
+        assertTrue(logFile1.length() != 0);
+        assertTrue(logFile2.length() != 0);
 
         // Make sure both files contain the two requests made separately using
         // different engines.
-        assertTrue(containsStringInNetLog(eventFile1, mUrl404));
-        assertTrue(containsStringInNetLog(eventFile1, mUrl500));
-        assertTrue(containsStringInNetLog(eventFile2, mUrl404));
-        assertTrue(containsStringInNetLog(eventFile2, mUrl500));
+        assertTrue(containsStringInNetLog(logFile1, mUrl404));
+        assertTrue(containsStringInNetLog(logFile1, mUrl500));
+        assertTrue(containsStringInNetLog(logFile2, mUrl404));
+        assertTrue(containsStringInNetLog(logFile2, mUrl500));
 
         FileUtils.recursivelyDeleteFile(netLogDir1);
         assertFalse(netLogDir1.exists());
@@ -698,7 +698,7 @@
         File netLogDir = new File(directory, "NetLog");
         assertFalse(netLogDir.exists());
         assertTrue(netLogDir.mkdir());
-        File constantsFile = new File(netLogDir, "constants.json");
+        File logFile = new File(netLogDir, "netlog.json");
         try {
             testFramework.mCronetEngine.startNetLogToDisk(
                     netLogDir.getPath(), false, MAX_FILE_SIZE);
@@ -706,7 +706,7 @@
         } catch (Exception e) {
             assertEquals("Engine is shut down.", e.getMessage());
         }
-        assertFalse(constantsFile.exists());
+        assertFalse(logFile.exists());
         FileUtils.recursivelyDeleteFile(netLogDir);
         assertFalse(netLogDir.exists());
     }
@@ -744,7 +744,7 @@
         File netLogDir = new File(directory, "NetLog");
         assertFalse(netLogDir.exists());
         assertTrue(netLogDir.mkdir());
-        File eventFile = new File(netLogDir, "event_file_0.json");
+        File logFile = new File(netLogDir, "netlog.json");
         // Start NetLog multiple times. This should be equivalent to starting NetLog
         // once. Each subsequent start (without calling stopNetLog) should be a no-op.
         testFramework.mCronetEngine.startNetLogToDisk(netLogDir.getPath(), false, MAX_FILE_SIZE);
@@ -758,9 +758,9 @@
         urlRequestBuilder.build().start();
         callback.blockForDone();
         testFramework.mCronetEngine.stopNetLog();
-        assertTrue(eventFile.exists());
-        assertTrue(eventFile.length() != 0);
-        assertFalse(hasBytesInNetLog(eventFile));
+        assertTrue(logFile.exists());
+        assertTrue(logFile.length() != 0);
+        assertFalse(hasBytesInNetLog(logFile));
         FileUtils.recursivelyDeleteFile(netLogDir);
         assertFalse(netLogDir.exists());
     }
@@ -799,7 +799,7 @@
         File netLogDir = new File(directory, "NetLog");
         assertFalse(netLogDir.exists());
         assertTrue(netLogDir.mkdir());
-        File eventFile = new File(netLogDir, "event_file_0.json");
+        File logFile = new File(netLogDir, "netlog.json");
         testFramework.mCronetEngine.startNetLogToDisk(netLogDir.getPath(), false, MAX_FILE_SIZE);
         // Start a request.
         TestUrlRequestCallback callback = new TestUrlRequestCallback();
@@ -814,9 +814,9 @@
         testFramework.mCronetEngine.stopNetLog();
         testFramework.mCronetEngine.stopNetLog();
         testFramework.mCronetEngine.stopNetLog();
-        assertTrue(eventFile.exists());
-        assertTrue(eventFile.length() != 0);
-        assertFalse(hasBytesInNetLog(eventFile));
+        assertTrue(logFile.exists());
+        assertTrue(logFile.length() != 0);
+        assertFalse(hasBytesInNetLog(logFile));
         FileUtils.recursivelyDeleteFile(netLogDir);
         assertFalse(netLogDir.exists());
     }
@@ -854,7 +854,7 @@
         File netLogDir = new File(directory, "NetLog");
         assertFalse(netLogDir.exists());
         assertTrue(netLogDir.mkdir());
-        File eventFile = new File(netLogDir, "event_file_0.json");
+        File logFile = new File(netLogDir, "netlog.json");
         ExperimentalCronetEngine cronetEngine =
                 new ExperimentalCronetEngine.Builder(context).build();
         // Start NetLog with logAll as true.
@@ -867,9 +867,9 @@
         callback.blockForDone();
         cronetEngine.stopNetLog();
 
-        assertTrue(eventFile.exists());
-        assertTrue(eventFile.length() != 0);
-        assertTrue(hasBytesInNetLog(eventFile));
+        assertTrue(logFile.exists());
+        assertTrue(logFile.length() != 0);
+        assertTrue(hasBytesInNetLog(logFile));
         FileUtils.recursivelyDeleteFile(netLogDir);
         assertFalse(netLogDir.exists());
     }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetBufferedOutputStreamTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetBufferedOutputStreamTest.java
index 71488bf..4b23ca8 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetBufferedOutputStreamTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetBufferedOutputStreamTest.java
@@ -354,6 +354,7 @@
                             + " bytes",
                     e.getMessage());
         }
+        connection.disconnect();
     }
 
     /**
@@ -385,6 +386,7 @@
                             + " bytes",
                     e.getMessage());
         }
+        connection.disconnect();
     }
 
     /**
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetChunkedOutputStreamTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetChunkedOutputStreamTest.java
index a8fd53b13..d012f31 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetChunkedOutputStreamTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetChunkedOutputStreamTest.java
@@ -104,6 +104,7 @@
                         NetworkException.ERROR_CONNECTION_REFUSED, requestException.getErrorCode());
             }
         }
+        connection.disconnect();
         // Restarting server to run the test for a second time.
         assertTrue(NativeTestServer.startNativeTestServer(getContext()));
     }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetFixedModeOutputStreamTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetFixedModeOutputStreamTest.java
index 716bb7f6..02839fa 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetFixedModeOutputStreamTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetFixedModeOutputStreamTest.java
@@ -102,6 +102,7 @@
                         NetworkException.ERROR_CONNECTION_REFUSED, requestException.getErrorCode());
             }
         }
+        connection.disconnect();
         // Restarting server to run the test for a second time.
         assertTrue(NativeTestServer.startNativeTestServer(getContext()));
     }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java
index da751331..d48dfb7 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/urlconnection/CronetHttpURLConnectionTest.java
@@ -271,6 +271,7 @@
                     || e.getMessage().contains("net::ERR_CONNECTION_REFUSED")));
         }
         checkExceptionsAreThrown(secondConnection);
+        urlConnection.disconnect();
         // Starts the server to avoid crashing on shutdown in tearDown().
         assertTrue(NativeTestServer.startNativeTestServer(getContext()));
     }
diff --git a/components/cronet/android/test/src/org/chromium/net/Http2TestServer.java b/components/cronet/android/test/src/org/chromium/net/Http2TestServer.java
index 57ba70ff..941009b6 100644
--- a/components/cronet/android/test/src/org/chromium/net/Http2TestServer.java
+++ b/components/cronet/android/test/src/org/chromium/net/Http2TestServer.java
@@ -120,6 +120,10 @@
                     Protocol.ALPN, SelectorFailureBehavior.NO_ADVERTISE,
                     SelectedListenerFailureBehavior.ACCEPT, ApplicationProtocolNames.HTTP_2);
 
+            // Don't make netty use java.security.KeyStore.getInstance("JKS") as it doesn't
+            // exist.  Just avoid a KeyManagerFactory as it's unnecessary for our testing.
+            System.setProperty("io.netty.handler.ssl.openssl.useKeyManagerFactory", "false");
+
             mSslCtx = new OpenSslServerContext(certFile, keyFile, null, null,
                     Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE,
                     applicationProtocolConfig, 0, 0);
diff --git a/components/download/content/factory/download_service_factory.cc b/components/download/content/factory/download_service_factory.cc
index 25355f7..95fbf6a 100644
--- a/components/download/content/factory/download_service_factory.cc
+++ b/components/download/content/factory/download_service_factory.cc
@@ -42,7 +42,8 @@
   auto store = base::MakeUnique<DownloadStore>(entry_db_storage_dir,
                                                std::move(entry_db));
   auto model = base::MakeUnique<ModelImpl>(std::move(store));
-  auto device_status_listener = base::MakeUnique<DeviceStatusListener>();
+  auto device_status_listener =
+      base::MakeUnique<DeviceStatusListener>(config->network_change_delay);
   auto scheduler = base::MakeUnique<SchedulerImpl>(
       task_scheduler.get(), config.get(), client_set.get());
   auto file_monitor = base::MakeUnique<FileMonitorImpl>(
diff --git a/components/download/internal/config.cc b/components/download/internal/config.cc
index a25aa634..b7ede40 100644
--- a/components/download/internal/config.cc
+++ b/components/download/internal/config.cc
@@ -41,6 +41,11 @@
 // Default value for the end window time for OS to schedule background task.
 const uint32_t kDefaultWindowEndTimeSeconds = 3600 * 8; /* 8 hours. */
 
+// The default delay to notify the observer when network changes from
+// disconnected to connected.
+const base::TimeDelta kDefaultNetworkChangeDelay =
+    base::TimeDelta::FromSeconds(5);
+
 // Helper routine to get Finch experiment parameter. If no Finch seed was found,
 // use the |default_value|. The |name| should match an experiment
 // parameter in Finch server configuration.
@@ -74,6 +79,11 @@
       kWindowStartTimeConfig, kDefaultWindowStartTimeSeconds);
   config->window_end_time_seconds =
       GetFinchConfigUInt(kWindowEndTimeConfig, kDefaultWindowEndTimeSeconds);
+  config->network_change_delay =
+      base::TimeDelta::FromMilliseconds(base::saturated_cast<int>(
+          GetFinchConfigUInt(kNetworkChangeDelayConfig,
+                             kDefaultNetworkChangeDelay.InMilliseconds())));
+
   return config;
 }
 
@@ -87,6 +97,7 @@
       file_cleanup_window(base::TimeDelta::FromMinutes(
           base::saturated_cast<int>(kDefaultFileCleanupWindowMinutes))),
       window_start_time_seconds(kDefaultWindowStartTimeSeconds),
-      window_end_time_seconds(kDefaultWindowEndTimeSeconds) {}
+      window_end_time_seconds(kDefaultWindowEndTimeSeconds),
+      network_change_delay(kDefaultNetworkChangeDelay) {}
 
 }  // namespace download
diff --git a/components/download/internal/config.h b/components/download/internal/config.h
index 9abd50e..1b22a4f 100644
--- a/components/download/internal/config.h
+++ b/components/download/internal/config.h
@@ -36,6 +36,10 @@
 // Configuration name for window end time.
 constexpr char kWindowEndTimeConfig[] = "window_end_time_seconds";
 
+// Configuration name for the delay to notify network status change, measured in
+// milliseconds.
+constexpr char kNetworkChangeDelayConfig[] = "network_change_delay_ms";
+
 // Download service configuration.
 //
 // Loaded based on experiment parameters from the server. Use default values if
@@ -77,6 +81,9 @@
   // The OS will trigger the background task in this window.
   uint32_t window_end_time_seconds;
 
+  // The delay to notify network status changes.
+  base::TimeDelta network_change_delay;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Configuration);
 };
diff --git a/components/download/internal/controller.h b/components/download/internal/controller.h
index 6d6d30c1..a19a223f 100644
--- a/components/download/internal/controller.h
+++ b/components/download/internal/controller.h
@@ -16,7 +16,6 @@
 
 struct DownloadParams;
 struct SchedulingParams;
-struct StartupStatus;
 
 // The type of completion when the download entry transits to complete state.
 // TODO(xingliu): Implement timeout and unknown failure types.
@@ -41,6 +40,26 @@
 // together to manage the active downloads.
 class Controller {
  public:
+  enum class State {
+    // The Controller has been created but has not been initialized yet.  It
+    // cannot be used.
+    CREATED = 1,
+
+    // The Controller has been created and Initialize() has been called but has
+    // not yet finished.  It cannot be used.
+    INITIALIZING = 2,
+
+    // The Controller has been created and initialized.  It can be used.
+    READY = 3,
+
+    // The Controller failed to initialize and is in the process of recovering.
+    // It cannot be used.
+    RECOVERING = 4,
+
+    // The Controller was unable to recover and is unusable this session.
+    UNAVAILABLE = 5,
+  };
+
   Controller() = default;
   virtual ~Controller() = default;
 
@@ -48,7 +67,7 @@
   virtual void Initialize(const base::Closure& callback) = 0;
 
   // Returns the status of Controller.
-  virtual const StartupStatus* GetStartupStatus() = 0;
+  virtual State GetState() = 0;
 
   // Starts a download with |params|.  See DownloadParams::StartCallback and
   // DownloadParams::StartResponse for information on how a caller can determine
diff --git a/components/download/internal/controller_impl.cc b/components/download/internal/controller_impl.cc
index 5489bcb..692080ba 100644
--- a/components/download/internal/controller_impl.cc
+++ b/components/download/internal/controller_impl.cc
@@ -90,42 +90,43 @@
       scheduler_(std::move(scheduler)),
       task_scheduler_(std::move(task_scheduler)),
       file_monitor_(std::move(file_monitor)),
-      initializing_internals_(false),
+      controller_state_(State::CREATED),
       weak_ptr_factory_(this) {}
 
 ControllerImpl::~ControllerImpl() = default;
 
 void ControllerImpl::Initialize(const base::Closure& callback) {
-  DCHECK(!startup_status_.Complete());
+  DCHECK_EQ(controller_state_, State::CREATED);
 
   init_callback_ = callback;
-  initializing_internals_ = true;
+  controller_state_ = State::INITIALIZING;
+
   driver_->Initialize(this);
   model_->Initialize(this);
   file_monitor_->Initialize(base::Bind(&ControllerImpl::OnFileMonitorReady,
                                        weak_ptr_factory_.GetWeakPtr()));
 }
 
-const StartupStatus* ControllerImpl::GetStartupStatus() {
-  return &startup_status_;
+Controller::State ControllerImpl::GetState() {
+  return controller_state_;
 }
 
 void ControllerImpl::StartDownload(const DownloadParams& params) {
-  DCHECK(startup_status_.Complete());
-  if (!startup_status_.Ok()) {
+  DCHECK(controller_state_ == State::READY ||
+         controller_state_ == State::UNAVAILABLE);
+
+  // TODO(dtrainor): Validate all input parameters.
+  DCHECK_LE(base::Time::Now(), params.scheduling_params.cancel_time);
+
+  if (controller_state_ != State::READY) {
     HandleStartDownloadResponse(params.client, params.guid,
                                 DownloadParams::StartResult::INTERNAL_ERROR,
                                 params.callback);
     return;
   }
 
-  DCHECK_LE(base::Time::Now(), params.scheduling_params.cancel_time);
   KillTimedOutDownloads();
 
-  // TODO(dtrainor): Check if there are any downloads we can cancel.  We don't
-  // want to return a BACKOFF if we technically could time out a download to
-  // start this one.
-
   if (start_callbacks_.find(params.guid) != start_callbacks_.end() ||
       model_->Get(params.guid) != nullptr) {
     HandleStartDownloadResponse(params.client, params.guid,
@@ -158,8 +159,9 @@
 }
 
 void ControllerImpl::PauseDownload(const std::string& guid) {
-  DCHECK(startup_status_.Complete());
-  if (!startup_status_.Ok())
+  DCHECK(controller_state_ == State::READY ||
+         controller_state_ == State::UNAVAILABLE);
+  if (controller_state_ != State::READY)
     return;
 
   auto* entry = model_->Get(guid);
@@ -179,8 +181,9 @@
 }
 
 void ControllerImpl::ResumeDownload(const std::string& guid) {
-  DCHECK(startup_status_.Complete());
-  if (!startup_status_.Ok())
+  DCHECK(controller_state_ == State::READY ||
+         controller_state_ == State::UNAVAILABLE);
+  if (controller_state_ != State::READY)
     return;
 
   auto* entry = model_->Get(guid);
@@ -196,8 +199,9 @@
 }
 
 void ControllerImpl::CancelDownload(const std::string& guid) {
-  DCHECK(startup_status_.Complete());
-  if (!startup_status_.Ok())
+  DCHECK(controller_state_ == State::READY ||
+         controller_state_ == State::UNAVAILABLE);
+  if (controller_state_ != State::READY)
     return;
 
   auto* entry = model_->Get(guid);
@@ -217,8 +221,9 @@
 
 void ControllerImpl::ChangeDownloadCriteria(const std::string& guid,
                                             const SchedulingParams& params) {
-  DCHECK(startup_status_.Complete());
-  if (!startup_status_.Ok())
+  DCHECK(controller_state_ == State::READY ||
+         controller_state_ == State::UNAVAILABLE);
+  if (controller_state_ != State::READY)
     return;
 
   auto* entry = model_->Get(guid);
@@ -237,8 +242,9 @@
 }
 
 DownloadClient ControllerImpl::GetOwnerOfDownload(const std::string& guid) {
-  DCHECK(startup_status_.Complete());
-  if (!startup_status_.Ok())
+  DCHECK(controller_state_ == State::READY ||
+         controller_state_ == State::UNAVAILABLE);
+  if (controller_state_ != State::READY)
     return DownloadClient::INVALID;
 
   auto* entry = model_->Get(guid);
@@ -248,18 +254,26 @@
 void ControllerImpl::OnStartScheduledTask(
     DownloadTaskType task_type,
     const TaskFinishedCallback& callback) {
-  DCHECK(startup_status_.Complete());
   task_finished_callbacks_[task_type] = callback;
-  if (!startup_status_.Ok()) {
-    HandleTaskFinished(task_type, false,
-                       stats::ScheduledTaskStatus::ABORTED_ON_FAILED_INIT);
-    return;
-  }
 
-  if (task_type == DownloadTaskType::DOWNLOAD_TASK) {
-    ActivateMoreDownloads();
-  } else if (task_type == DownloadTaskType::CLEANUP_TASK) {
-    RemoveCleanupEligibleDownloads();
+  switch (controller_state_) {
+    case State::READY:
+      if (task_type == DownloadTaskType::DOWNLOAD_TASK) {
+        ActivateMoreDownloads();
+      } else if (task_type == DownloadTaskType::CLEANUP_TASK) {
+        RemoveCleanupEligibleDownloads();
+      }
+      break;
+    case State::UNAVAILABLE:
+      HandleTaskFinished(task_type, false,
+                         stats::ScheduledTaskStatus::ABORTED_ON_FAILED_INIT);
+      break;
+    case State::CREATED:       // Intentional fallthrough.
+    case State::INITIALIZING:  // Intentional fallthrough.
+    case State::RECOVERING:    // Intentional fallthrough.
+    default:
+      NOTREACHED();
+      break;
   }
 }
 
@@ -311,7 +325,7 @@
 void ControllerImpl::OnDriverHardRecoverComplete(bool success) {}
 
 void ControllerImpl::OnDownloadCreated(const DriverEntry& download) {
-  if (initializing_internals_)
+  if (controller_state_ != State::READY)
     return;
 
   Entry* entry = model_->Get(download.guid);
@@ -334,7 +348,7 @@
 
 void ControllerImpl::OnDownloadFailed(const DriverEntry& download,
                                       FailureType failure_type) {
-  if (initializing_internals_)
+  if (controller_state_ != State::READY)
     return;
 
   Entry* entry = model_->Get(download.guid);
@@ -354,7 +368,7 @@
 }
 
 void ControllerImpl::OnDownloadSucceeded(const DriverEntry& download) {
-  if (initializing_internals_)
+  if (controller_state_ != State::READY)
     return;
 
   Entry* entry = model_->Get(download.guid);
@@ -367,7 +381,7 @@
 }
 
 void ControllerImpl::OnDownloadUpdated(const DriverEntry& download) {
-  if (initializing_internals_)
+  if (controller_state_ != State::READY)
     return;
 
   Entry* entry = model_->Get(download.guid);
@@ -447,11 +461,16 @@
 }
 
 void ControllerImpl::OnDeviceStatusChanged(const DeviceStatus& device_status) {
+  if (controller_state_ != State::READY)
+    return;
+
   UpdateDriverStates();
   ActivateMoreDownloads();
 }
 
 void ControllerImpl::AttemptToFinalizeSetup() {
+  DCHECK_EQ(controller_state_, State::INITIALIZING);
+
   if (!startup_status_.Complete())
     return;
 
@@ -459,6 +478,7 @@
   if (!startup_status_.Ok()) {
     // TODO(dtrainor): Recover here.  Try to clean up any disk state and, if
     // possible, any DownloadDriver data and continue with initialization?
+    controller_state_ = State::UNAVAILABLE;
 
     // If we cannot recover, notify Clients that the service is unavailable.
     base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -478,7 +498,7 @@
 
   NotifyClientsOfStartup();
 
-  initializing_internals_ = false;
+  controller_state_ = State::READY;
 
   UpdateDriverStates();
 
@@ -490,6 +510,8 @@
 }
 
 void ControllerImpl::PollActiveDriverDownloads() {
+  DCHECK_EQ(controller_state_, State::INITIALIZING);
+
   std::set<std::string> guids = driver_->GetActiveDownloads();
 
   for (auto guid : guids) {
@@ -499,6 +521,8 @@
 }
 
 void ControllerImpl::CancelOrphanedRequests() {
+  DCHECK_EQ(controller_state_, State::INITIALIZING);
+
   auto entries = model_->PeekEntries();
 
   std::vector<std::string> guids_to_remove;
@@ -520,6 +544,8 @@
 }
 
 void ControllerImpl::CleanupUnknownFiles() {
+  DCHECK_EQ(controller_state_, State::INITIALIZING);
+
   auto entries = model_->PeekEntries();
   std::vector<DriverEntry> driver_entries;
   for (auto* entry : entries) {
@@ -532,6 +558,8 @@
 }
 
 void ControllerImpl::ResolveInitialRequestStates() {
+  DCHECK_EQ(controller_state_, State::INITIALIZING);
+
   auto entries = model_->PeekEntries();
   for (auto* entry : entries) {
     // Pull the initial Entry::State and DriverEntry::State.
@@ -656,7 +684,7 @@
 }
 
 void ControllerImpl::UpdateDriverState(Entry* entry) {
-  DCHECK(!initializing_internals_);
+  DCHECK_EQ(controller_state_, State::READY);
 
   if (entry->state != Entry::State::ACTIVE &&
       entry->state != Entry::State::PAUSED) {
@@ -856,7 +884,7 @@
 }
 
 void ControllerImpl::ActivateMoreDownloads() {
-  if (initializing_internals_)
+  if (controller_state_ != State::READY)
     return;
 
   // Check all the entries and the configuration to throttle number of
diff --git a/components/download/internal/controller_impl.h b/components/download/internal/controller_impl.h
index 16eac64..ac21583 100644
--- a/components/download/internal/controller_impl.h
+++ b/components/download/internal/controller_impl.h
@@ -56,7 +56,7 @@
 
   // Controller implementation.
   void Initialize(const base::Closure& callback) override;
-  const StartupStatus* GetStartupStatus() override;
+  State GetState() override;
   void StartDownload(const DownloadParams& params) override;
   void PauseDownload(const std::string& guid) override;
   void ResumeDownload(const std::string& guid) override;
@@ -200,12 +200,8 @@
   std::unique_ptr<FileMonitor> file_monitor_;
 
   // Internal state.
-  // Is set to true if this class is currently in the process of initializing
-  // it's internal state.  This will be false until |startup_status_| signals it
-  // is complete *and* all internal structures are set up.  This is to prevent
-  // outside signals from triggering state updates before we are ready.
-  bool initializing_internals_;
   base::Closure init_callback_;
+  State controller_state_;
   StartupStatus startup_status_;
   std::set<std::string> externally_active_downloads_;
   std::map<std::string, DownloadParams::StartCallback> start_callbacks_;
diff --git a/components/download/internal/controller_impl_unittest.cc b/components/download/internal/controller_impl_unittest.cc
index 65dc396..15e52b382 100644
--- a/components/download/internal/controller_impl_unittest.cc
+++ b/components/download/internal/controller_impl_unittest.cc
@@ -161,7 +161,8 @@
 
  protected:
   void OnInitCompleted() {
-    DCHECK(controller_->GetStartupStatus()->Complete());
+    EXPECT_TRUE(controller_->GetState() == Controller::State::READY ||
+                controller_->GetState() == Controller::State::UNAVAILABLE);
     init_callback_called_ = true;
   }
 
@@ -206,26 +207,24 @@
 }  // namespace
 
 TEST_F(DownloadServiceControllerImplTest, SuccessfulInitModelFirst) {
-  EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(0);
   base::HistogramTester histogram_tester;
 
+  EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(0);
+  EXPECT_EQ(controller_->GetState(), Controller::State::CREATED);
+
   InitializeController();
   EXPECT_TRUE(store_->init_called());
-  EXPECT_FALSE(controller_->GetStartupStatus()->Complete());
+  EXPECT_EQ(controller_->GetState(), Controller::State::INITIALIZING);
 
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>());
-  EXPECT_FALSE(controller_->GetStartupStatus()->Complete());
-  EXPECT_FALSE(controller_->GetStartupStatus()->driver_ok.has_value());
-  EXPECT_TRUE(controller_->GetStartupStatus()->model_ok.value());
+  EXPECT_EQ(controller_->GetState(), Controller::State::INITIALIZING);
 
   EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1);
   EXPECT_CALL(*scheduler_, Next(_, _)).Times(1);
   EXPECT_CALL(*scheduler_, Reschedule(_)).Times(1);
 
   driver_->MakeReady();
-  EXPECT_TRUE(controller_->GetStartupStatus()->Complete());
-  EXPECT_TRUE(controller_->GetStartupStatus()->driver_ok.value());
-  EXPECT_TRUE(controller_->GetStartupStatus()->Ok());
+  EXPECT_EQ(controller_->GetState(), Controller::State::READY);
 
   task_runner_->RunUntilIdle();
 
@@ -237,25 +236,22 @@
 
 TEST_F(DownloadServiceControllerImplTest, SuccessfulInitDriverFirst) {
   EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(0);
+  EXPECT_EQ(controller_->GetState(), Controller::State::CREATED);
 
   InitializeController();
   EXPECT_TRUE(store_->init_called());
-  EXPECT_FALSE(controller_->GetStartupStatus()->Complete());
+  EXPECT_EQ(controller_->GetState(), Controller::State::INITIALIZING);
 
   driver_->MakeReady();
-  EXPECT_FALSE(controller_->GetStartupStatus()->Complete());
-  EXPECT_FALSE(controller_->GetStartupStatus()->model_ok.has_value());
-  EXPECT_TRUE(controller_->GetStartupStatus()->driver_ok.value());
   EXPECT_FALSE(init_callback_called_);
+  EXPECT_EQ(controller_->GetState(), Controller::State::INITIALIZING);
 
   EXPECT_CALL(*client_, OnServiceInitialized(_)).Times(1);
   EXPECT_CALL(*scheduler_, Next(_, _)).Times(1);
   EXPECT_CALL(*scheduler_, Reschedule(_)).Times(1);
 
   store_->TriggerInit(true, base::MakeUnique<std::vector<Entry>>());
-  EXPECT_TRUE(controller_->GetStartupStatus()->Complete());
-  EXPECT_TRUE(controller_->GetStartupStatus()->model_ok.value());
-  EXPECT_TRUE(controller_->GetStartupStatus()->Ok());
+  EXPECT_EQ(controller_->GetState(), Controller::State::READY);
 
   task_runner_->RunUntilIdle();
   EXPECT_TRUE(init_callback_called_);
diff --git a/components/download/internal/download_service_impl.cc b/components/download/internal/download_service_impl.cc
index bf75aba5..ceff12d 100644
--- a/components/download/internal/download_service_impl.cc
+++ b/components/download/internal/download_service_impl.cc
@@ -58,13 +58,17 @@
 }
 
 DownloadService::ServiceStatus DownloadServiceImpl::GetStatus() {
-  if (!controller_->GetStartupStatus()->Complete())
-    return DownloadService::ServiceStatus::STARTING_UP;
-
-  if (!controller_->GetStartupStatus()->Ok())
-    return DownloadService::ServiceStatus::UNAVAILABLE;
-
-  return DownloadService::ServiceStatus::READY;
+  switch (controller_->GetState()) {
+    case Controller::State::CREATED:       // Intentional fallthrough.
+    case Controller::State::INITIALIZING:  // Intentional fallthrough.
+    case Controller::State::RECOVERING:
+      return DownloadService::ServiceStatus::STARTING_UP;
+    case Controller::State::READY:
+      return DownloadService::ServiceStatus::READY;
+    case Controller::State::UNAVAILABLE:  // Intentional fallthrough.
+    default:
+      return DownloadService::ServiceStatus::UNAVAILABLE;
+  }
 }
 
 void DownloadServiceImpl::StartDownload(const DownloadParams& download_params) {
diff --git a/components/download/internal/download_service_impl_unittest.cc b/components/download/internal/download_service_impl_unittest.cc
index efeaecd..74090dfb 100644
--- a/components/download/internal/download_service_impl_unittest.cc
+++ b/components/download/internal/download_service_impl_unittest.cc
@@ -54,18 +54,13 @@
 
 TEST_F(DownloadServiceImplTest, TestGetStatus) {
   StartupStatus startup_status;
-  EXPECT_CALL(*controller_, GetStartupStatus())
-      .WillRepeatedly(Return(&startup_status));
+  EXPECT_CALL(*controller_, GetState())
+      .WillOnce(Return(Controller::State::INITIALIZING))
+      .WillOnce(Return(Controller::State::READY))
+      .WillOnce(Return(Controller::State::UNAVAILABLE));
 
   EXPECT_EQ(DownloadService::ServiceStatus::STARTING_UP, service_->GetStatus());
-
-  startup_status.driver_ok = true;
-  startup_status.model_ok = true;
-  startup_status.file_monitor_ok = true;
   EXPECT_EQ(DownloadService::ServiceStatus::READY, service_->GetStatus());
-
-  startup_status.driver_ok = false;
-  startup_status.model_ok = true;
   EXPECT_EQ(DownloadService::ServiceStatus::UNAVAILABLE, service_->GetStatus());
 }
 
diff --git a/components/download/internal/scheduler/device_status_listener.cc b/components/download/internal/scheduler/device_status_listener.cc
index 15b03ace..ba277b0 100644
--- a/components/download/internal/scheduler/device_status_listener.cc
+++ b/components/download/internal/scheduler/device_status_listener.cc
@@ -37,8 +37,8 @@
 
 }  // namespace
 
-DeviceStatusListener::DeviceStatusListener()
-    : observer_(nullptr), listening_(false) {}
+DeviceStatusListener::DeviceStatusListener(const base::TimeDelta& delay)
+    : observer_(nullptr), listening_(false), delay_(delay) {}
 
 DeviceStatusListener::~DeviceStatusListener() {
   Stop();
@@ -82,9 +82,24 @@
 
 void DeviceStatusListener::OnConnectionTypeChanged(
     net::NetworkChangeNotifier::ConnectionType type) {
-  NetworkStatus new_status = ToNetworkStatus(type);
-  if (status_.network_status != new_status) {
-    status_.network_status = new_status;
+  NetworkStatus new_network_status = ToNetworkStatus(type);
+  if (status_.network_status == new_network_status)
+    return;
+
+  bool change_to_online =
+      (status_.network_status == NetworkStatus::DISCONNECTED) &&
+      (new_network_status != NetworkStatus::DISCONNECTED);
+
+  // It's unreliable to send requests immediately after the network becomes
+  // online. Notify network change to the observer after a delay.
+  if (change_to_online) {
+    timer_.Start(
+        FROM_HERE, delay_,
+        base::Bind(&DeviceStatusListener::NotifyNetworkChangeAfterDelay,
+                   base::Unretained(this), new_network_status));
+  } else {
+    status_.network_status = new_network_status;
+    timer_.Stop();
     NotifyStatusChange();
   }
 }
@@ -98,4 +113,10 @@
   observer_->OnDeviceStatusChanged(status_);
 }
 
+void DeviceStatusListener::NotifyNetworkChangeAfterDelay(
+    NetworkStatus network_status) {
+  status_.network_status = network_status;
+  NotifyStatusChange();
+}
+
 }  // namespace download
diff --git a/components/download/internal/scheduler/device_status_listener.h b/components/download/internal/scheduler/device_status_listener.h
index 4a94608..a14a28c6 100644
--- a/components/download/internal/scheduler/device_status_listener.h
+++ b/components/download/internal/scheduler/device_status_listener.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_DOWNLOAD_INTERNAL_SCHEDULER_DEVICE_STATUS_LISTENER_H_
 
 #include "base/power_monitor/power_observer.h"
+#include "base/timer/timer.h"
 #include "components/download/internal/scheduler/device_status.h"
 #include "net/base/network_change_notifier.h"
 
@@ -22,7 +23,7 @@
     virtual void OnDeviceStatusChanged(const DeviceStatus& device_status) = 0;
   };
 
-  DeviceStatusListener();
+  DeviceStatusListener(const base::TimeDelta& delay);
   ~DeviceStatusListener() override;
 
   // Returns the current device status for download scheduling.
@@ -44,16 +45,25 @@
   bool listening_;
 
  private:
-  // net::NetworkChangeNotifier implementation.
+  // net::NetworkChangeNotifier::ConnectionTypeObserver implementation.
   void OnConnectionTypeChanged(
       net::NetworkChangeNotifier::ConnectionType type) override;
 
   // base::PowerObserver implementation.
   void OnPowerStateChange(bool on_battery_power) override;
 
-  // Notifies |observers_| about device status change.
+  // Notifies the observer about device status change.
   void NotifyStatusChange();
 
+  // Called after a delay to notify the observer. See |delay_|.
+  void NotifyNetworkChangeAfterDelay(NetworkStatus network_status);
+
+  // Used to notify the observer after a delay when network becomes connected.
+  base::OneShotTimer timer_;
+
+  // The delay used by |timer_|.
+  base::TimeDelta delay_;
+
   DISALLOW_COPY_AND_ASSIGN(DeviceStatusListener);
 };
 
diff --git a/components/download/internal/scheduler/device_status_listener_unittest.cc b/components/download/internal/scheduler/device_status_listener_unittest.cc
index a1580ddb..45fea61 100644
--- a/components/download/internal/scheduler/device_status_listener_unittest.cc
+++ b/components/download/internal/scheduler/device_status_listener_unittest.cc
@@ -38,7 +38,6 @@
     conn_type_ = type;
     net::NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
         type);
-    base::RunLoop().RunUntilIdle();
   }
 
  private:
@@ -58,7 +57,8 @@
     power_monitor_ = base::MakeUnique<base::PowerMonitor>(
         base::MakeUnique<base::PowerMonitorTestSource>());
 
-    listener_ = base::MakeUnique<DeviceStatusListener>();
+    listener_ =
+        base::MakeUnique<DeviceStatusListener>(base::TimeDelta::FromSeconds(0));
   }
 
   void TearDown() override { listener_.reset(); }
@@ -102,6 +102,11 @@
   ChangeNetworkType(ConnectionType::CONNECTION_4G);
   ChangeNetworkType(ConnectionType::CONNECTION_3G);
   ChangeNetworkType(ConnectionType::CONNECTION_2G);
+
+  // Verifies the online signal is sent in a post task after a delay.
+  EXPECT_EQ(NetworkStatus::DISCONNECTED,
+            listener_->CurrentDeviceStatus().network_status);
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(NetworkStatus::METERED,
             listener_->CurrentDeviceStatus().network_status);
 
@@ -114,6 +119,10 @@
 
   ChangeNetworkType(ConnectionType::CONNECTION_WIFI);
   ChangeNetworkType(ConnectionType::CONNECTION_ETHERNET);
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(NetworkStatus::UNMETERED,
+            listener_->CurrentDeviceStatus().network_status);
 }
 
 // Ensures the observer is notified when battery condition changes.
diff --git a/components/download/internal/test/mock_controller.h b/components/download/internal/test/mock_controller.h
index 0c987d0e..e61bec80 100644
--- a/components/download/internal/test/mock_controller.h
+++ b/components/download/internal/test/mock_controller.h
@@ -21,7 +21,7 @@
 
   // Controller implementation.
   void Initialize(const base::Closure& callback) override;
-  MOCK_METHOD0(GetStartupStatus, const StartupStatus*());
+  MOCK_METHOD0(GetState, Controller::State());
   MOCK_METHOD1(StartDownload, void(const DownloadParams&));
   MOCK_METHOD1(PauseDownload, void(const std::string&));
   MOCK_METHOD1(ResumeDownload, void(const std::string&));
diff --git a/components/download/internal/test/test_device_status_listener.cc b/components/download/internal/test/test_device_status_listener.cc
index d7dc52b..7ca03dc2 100644
--- a/components/download/internal/test/test_device_status_listener.cc
+++ b/components/download/internal/test/test_device_status_listener.cc
@@ -7,7 +7,8 @@
 namespace download {
 namespace test {
 
-TestDeviceStatusListener::TestDeviceStatusListener() = default;
+TestDeviceStatusListener::TestDeviceStatusListener()
+    : DeviceStatusListener(base::TimeDelta::FromSeconds(0)) {}
 
 TestDeviceStatusListener::~TestDeviceStatusListener() {
   // Mark |listening_| to false to bypass the remove observer calls in the base
diff --git a/components/exo/BUILD.gn b/components/exo/BUILD.gn
index 8a712ba..57d8790 100644
--- a/components/exo/BUILD.gn
+++ b/components/exo/BUILD.gn
@@ -100,8 +100,8 @@
 
   deps = [
     ":exo",
+    "//ash:test_support_without_content",
     "//ash/public/cpp:ash_public_cpp",
-    "//ash/test:test_support_without_content",
     "//base",
     "//gpu",
     "//skia",
@@ -133,8 +133,8 @@
     ":exo",
     ":test_support",
     "//ash",
+    "//ash:test_support_without_content",
     "//ash/public/cpp:ash_public_cpp",
-    "//ash/test:test_support_without_content",
     "//base",
     "//base/test:test_support",
     "//cc",
@@ -179,8 +179,8 @@
 
   deps = [
     ":unit_tests",
+    "//ash:test_support_without_content",
     "//ash/public/cpp:ash_public_cpp",
-    "//ash/test:test_support_without_content",
     "//base",
     "//base/test:test_support",
     "//cc:test_support",
diff --git a/components/exo/pointer.cc b/components/exo/pointer.cc
index 0fb58512..71290a87 100644
--- a/components/exo/pointer.cc
+++ b/components/exo/pointer.cc
@@ -360,9 +360,9 @@
   host_window()->SetTransform(gfx::GetScaleTransform(gfx::Point(), scale));
 
   std::unique_ptr<cc::CopyOutputRequest> request =
-      cc::CopyOutputRequest::CreateBitmapRequest(
-          base::Bind(&Pointer::OnCursorCaptured,
-                     cursor_capture_weak_ptr_factory_.GetWeakPtr(), hotspot));
+      cc::CopyOutputRequest::CreateBitmapRequest(base::BindOnce(
+          &Pointer::OnCursorCaptured,
+          cursor_capture_weak_ptr_factory_.GetWeakPtr(), hotspot));
 
   request->set_source(cursor_capture_source_id_);
   host_window()->layer()->RequestCopyOfOutput(std::move(request));
diff --git a/components/exo/shell_surface_unittest.cc b/components/exo/shell_surface_unittest.cc
index 537699e..d772fea 100644
--- a/components/exo/shell_surface_unittest.cc
+++ b/components/exo/shell_surface_unittest.cc
@@ -10,11 +10,11 @@
 #include "ash/public/interfaces/window_pin_type.mojom.h"
 #include "ash/shell.h"
 #include "ash/shell_port.h"
-#include "ash/test/shell_test_api.h"
-#include "ash/test/workspace_controller_test_api.h"
+#include "ash/shell_test_api.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/wm_event.h"
 #include "ash/wm/workspace/workspace_window_resizer.h"
+#include "ash/wm/workspace_controller_test_api.h"
 #include "base/message_loop/message_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/exo/buffer.h"
diff --git a/components/invalidation/impl/ticl_invalidation_service.cc b/components/invalidation/impl/ticl_invalidation_service.cc
index 9d131122..aba8a6d 100644
--- a/components/invalidation/impl/ticl_invalidation_service.cc
+++ b/components/invalidation/impl/ticl_invalidation_service.cc
@@ -253,6 +253,11 @@
   }
 }
 
+void TiclInvalidationService::OnActiveAccountLogin() {
+  if (!IsStarted() && IsReadyToStart())
+    StartInvalidator(network_channel_type_);
+}
+
 void TiclInvalidationService::OnRefreshTokenAvailable(
     const std::string& account_id) {
   if (!IsStarted() && IsReadyToStart())
diff --git a/components/invalidation/impl/ticl_invalidation_service.h b/components/invalidation/impl/ticl_invalidation_service.h
index fa68170..63faaa90 100644
--- a/components/invalidation/impl/ticl_invalidation_service.h
+++ b/components/invalidation/impl/ticl_invalidation_service.h
@@ -98,6 +98,7 @@
   void OnRefreshTokenRevoked(const std::string& account_id) override;
 
   // IdentityProvider::Observer implementation.
+  void OnActiveAccountLogin() override;
   void OnActiveAccountLogout() override;
 
   // TiclSettingsProvider::Observer implementation.
diff --git a/components/nacl/OWNERS b/components/nacl/OWNERS
index 5f4bb016..4d29309 100644
--- a/components/nacl/OWNERS
+++ b/components/nacl/OWNERS
@@ -1,7 +1,5 @@
 bradnelson@chromium.org
 dschuff@chromium.org
 mseaborn@chromium.org
-sehr@chromium.org
-
 
 # COMPONENT: Platform>NaCl
diff --git a/components/net_log/net_export_file_writer.cc b/components/net_log/net_export_file_writer.cc
index 94d64e6..8c4faafd 100644
--- a/components/net_log/net_export_file_writer.cc
+++ b/components/net_log/net_export_file_writer.cc
@@ -101,6 +101,8 @@
 
 }  // namespace
 
+const size_t NetExportFileWriter::kNoLimit = net::FileNetLogObserver::kNoLimit;
+
 NetExportFileWriter::NetExportFileWriter(ChromeNetLog* chrome_net_log)
     : state_(STATE_UNINITIALIZED),
       log_exists_(false),
@@ -156,6 +158,7 @@
 void NetExportFileWriter::StartNetLog(
     const base::FilePath& log_path,
     net::NetLogCaptureMode capture_mode,
+    size_t max_file_size,
     const base::CommandLine::StringType& command_line_string,
     const std::string& channel_string,
     const URLRequestContextGetterList& context_getters) {
@@ -177,8 +180,8 @@
   std::unique_ptr<base::Value> constants(
       ChromeNetLog::GetConstants(command_line_string, channel_string));
 
-  file_net_log_observer_ =
-      net::FileNetLogObserver::CreateUnbounded(log_path_, std::move(constants));
+  file_net_log_observer_ = net::FileNetLogObserver::CreateBounded(
+      log_path_, max_file_size, std::move(constants));
 
   net_task_runner_->PostTaskAndReply(
       FROM_HERE,
diff --git a/components/net_log/net_export_file_writer.h b/components/net_log/net_export_file_writer.h
index 73074826..69e81ad 100644
--- a/components/net_log/net_export_file_writer.h
+++ b/components/net_log/net_export_file_writer.h
@@ -55,6 +55,9 @@
 // code on the |file_task_runner_| and |net_task_runner_|.
 class NetExportFileWriter {
  public:
+  // Special value meaning "can use an unlimited number of bytes".
+  static const size_t kNoLimit;
+
   // The observer interface to be implemented by code that wishes to be notified
   // of NetExportFileWriter's state changes.
   class StateObserver {
@@ -99,12 +102,16 @@
   // empty, the default log path is used. If NetExportFileWriter is already
   // logging, this is a no-op and |capture_mode| is ignored.
   //
+  // |max_file_size| places a bound on how large the log file can grow. To make
+  // it grow unboundedly pass kNoLimit.
+  //
   // |context_getters| is an optional list of URLRequestContextGetters used only
   // to add log entries for ongoing events when logging starts. They are not
   // used for retrieving polled data. All the contexts must be bound to the same
   // thread.
   void StartNetLog(const base::FilePath& log_path,
                    net::NetLogCaptureMode capture_mode,
+                   size_t max_file_size,
                    const base::CommandLine::StringType& command_line_string,
                    const std::string& channel_string,
                    const URLRequestContextGetterList& context_getters);
diff --git a/components/net_log/net_export_file_writer_unittest.cc b/components/net_log/net_export_file_writer_unittest.cc
index cf61b07..88a1842ca 100644
--- a/components/net_log/net_export_file_writer_unittest.cc
+++ b/components/net_log/net_export_file_writer_unittest.cc
@@ -34,6 +34,7 @@
 namespace {
 
 const char kChannelString[] = "SomeChannel";
+const size_t kMaxLogSizeBytes = 100 * 1024 * 1024;  // 100MiB
 
 // Keep this in sync with kLogRelativePath defined in net_export_file_writer.cc.
 base::FilePath::CharType kLogRelativePath[] =
@@ -329,7 +330,7 @@
       net::NetLogCaptureMode capture_mode,
       const std::string& expected_capture_mode_string,
       const URLRequestContextGetterList& context_getters) {
-    file_writer_.StartNetLog(custom_log_path, capture_mode,
+    file_writer_.StartNetLog(custom_log_path, capture_mode, kMaxLogSizeBytes,
                              base::CommandLine::StringType(), kChannelString,
                              context_getters);
     std::unique_ptr<base::DictionaryValue> state =
@@ -498,14 +499,14 @@
     // with various capture modes; they should all be ignored and result in no
     // state change.
     file_writer_.StartNetLog(base::FilePath(), capture_modes[i],
-                             base::CommandLine::StringType(), kChannelString,
-                             URLRequestContextGetterList());
+                             kMaxLogSizeBytes, base::CommandLine::StringType(),
+                             kChannelString, URLRequestContextGetterList());
     file_writer_.StartNetLog(base::FilePath(), capture_modes[(i + 1) % 3],
-                             base::CommandLine::StringType(), kChannelString,
-                             URLRequestContextGetterList());
+                             kMaxLogSizeBytes, base::CommandLine::StringType(),
+                             kChannelString, URLRequestContextGetterList());
     file_writer_.StartNetLog(base::FilePath(), capture_modes[(i + 2) % 3],
-                             base::CommandLine::StringType(), kChannelString,
-                             URLRequestContextGetterList());
+                             kMaxLogSizeBytes, base::CommandLine::StringType(),
+                             kChannelString, URLRequestContextGetterList());
 
     // StopNetLog(), should result in state change. The capture mode should
     // match that of the first StartNetLog() call (called by
@@ -745,8 +746,8 @@
   // before |file_writer_| finishes initialization, which means this
   // should be a no-op.
   file_writer_.StartNetLog(base::FilePath(), net::NetLogCaptureMode::Default(),
-                           base::CommandLine::StringType(), kChannelString,
-                           URLRequestContextGetterList());
+                           kMaxLogSizeBytes, base::CommandLine::StringType(),
+                           kChannelString, URLRequestContextGetterList());
 
   // Now run the main message loop. Make sure StartNetLog() was ignored by
   // checking that the next two states are "initializing" followed by
@@ -776,8 +777,8 @@
   // |file_writer_| finishes stopping, which means this should be a
   // no-op.
   file_writer_.StartNetLog(base::FilePath(), net::NetLogCaptureMode::Default(),
-                           base::CommandLine::StringType(), kChannelString,
-                           URLRequestContextGetterList());
+                           kMaxLogSizeBytes, base::CommandLine::StringType(),
+                           kChannelString, URLRequestContextGetterList());
 
   // Now run the main message loop. Make sure the last StartNetLog() was
   // ignored by checking that the next two states are "stopping-log" followed by
diff --git a/components/net_log/resources/net_export.css b/components/net_log/resources/net_export.css
index 322df33..03a68843 100644
--- a/components/net_log/resources/net_export.css
+++ b/components/net_log/resources/net_export.css
@@ -20,7 +20,7 @@
   font-weight: bold;
   margin: 10px auto;
   padding: 1em;
-  width: 14em;
+  width: 15em;
 }
 
 h2 {
diff --git a/components/net_log/resources/net_export.html b/components/net_log/resources/net_export.html
index 66c2d03..823892b 100644
--- a/components/net_log/resources/net_export.html
+++ b/components/net_log/resources/net_export.html
@@ -70,6 +70,13 @@
             Include raw bytes (will include cookies and credentials)
           </label>
         </div>
+        <div>
+          <label>
+            Maximum log size (megabytes):
+            <input id='log-max-filesize' value="100" size="4" />
+            (Blank means unlimited).
+          </label>
+        </div>
       </div>
     </div>
 
@@ -136,9 +143,12 @@
 
         <div id="toobig-read-more">
           <ul>
-            <li>Compressing the log file before attaching is a good idea.</li>
-            <li>If the log file is still too big, you can try capturing again,
-              but over a shorter period of time</li>
+            <li>The maximum log size can be specified when starting
+            logging.</li>
+            <li>Compressing the log file before attaching is a good
+              idea.</li>
+            <li>Capture logs over a shorter period of time; stop
+              logging once the issue has reproduced.</li>
             <li>Existing log files can be shrunk using
               <a
                 href="https://chromium.googlesource.com/chromium/src/+/master/net/tools/truncate_net_log.py"
diff --git a/components/net_log/resources/net_export.js b/components/net_log/resources/net_export.js
index 2d81fbc..9ecbdfe6 100644
--- a/components/net_log/resources/net_export.js
+++ b/components/net_log/resources/net_export.js
@@ -37,6 +37,7 @@
   var kIdPrivacyReadMoreDiv = 'privacy-read-more'
   var kIdTooBigReadMoreLink = 'toobig-read-more-link';
   var kIdTooBigReadMoreDiv = 'toobig-read-more'
+  var kIdLogMaxFileSizeInput = 'log-max-filesize'
 
   /**
    * @constructor
@@ -56,9 +57,21 @@
      * Starts saving NetLog data to a file.
      */
     onStartLogging_: function() {
+      // Determine the capture mode to use.
       var logMode =
           document.querySelector('input[name="log-mode"]:checked').value;
-      chrome.send('startNetLog', [logMode]);
+
+      // Determine the maximum file size, as the number of bytes (or -1 to mean
+      // no limit)
+      var maxLogFileSizeBytes = -1;
+      var fileSizeString = $(kIdLogMaxFileSizeInput).value;
+      var numMegabytes = parseFloat(fileSizeString);
+      if (!isNaN(numMegabytes)) {
+        // Convert to an integral number of bytes.
+        maxLogFileSizeBytes = Math.round(numMegabytes * 1024 * 1024);
+      }
+
+      chrome.send('startNetLog', [logMode, maxLogFileSizeBytes]);
     },
 
     /**
diff --git a/components/offline_pages/core/offline_page_model_impl.cc b/components/offline_pages/core/offline_page_model_impl.cc
index 4909a12c..f6d192be 100644
--- a/components/offline_pages/core/offline_page_model_impl.cc
+++ b/components/offline_pages/core/offline_page_model_impl.cc
@@ -323,7 +323,11 @@
 
 // protected
 OfflinePageModelImpl::OfflinePageModelImpl()
-    : OfflinePageModel(), is_loaded_(false), weak_ptr_factory_(this) {}
+    : OfflinePageModel(),
+      is_loaded_(false),
+      testing_clock_(nullptr),
+      skip_clearing_original_url_for_testing_(false),
+      weak_ptr_factory_(this) {}
 
 OfflinePageModelImpl::OfflinePageModelImpl(
     std::unique_ptr<OfflinePageMetadataStore> store,
@@ -335,6 +339,7 @@
       policy_controller_(new ClientPolicyController()),
       archive_manager_(new ArchiveManager(archives_dir, task_runner)),
       testing_clock_(nullptr),
+      skip_clearing_original_url_for_testing_(false),
       weak_ptr_factory_(this) {
   archive_manager_->EnsureArchivesDirCreated(
       base::Bind(&OfflinePageModelImpl::OnEnsureArchivesDirCreatedDone,
@@ -731,7 +736,15 @@
                                     save_page_params.client_id, file_path,
                                     file_size, start_time);
   offline_page_item.title = title;
-  offline_page_item.original_url = save_page_params.original_url;
+
+  // Don't record the original URL if it is identical to the final URL. This is
+  // because some websites might route the redirect finally back to itself upon
+  // the completion of certain action, i.e., authentication, in the middle.
+  if (skip_clearing_original_url_for_testing_ ||
+      save_page_params.original_url != offline_page_item.url) {
+    offline_page_item.original_url = save_page_params.original_url;
+  }
+
   offline_page_item.request_origin = save_page_params.request_origin;
   store_->AddOfflinePage(offline_page_item,
                          base::Bind(&OfflinePageModelImpl::OnAddOfflinePageDone,
diff --git a/components/offline_pages/core/offline_page_model_impl.h b/components/offline_pages/core/offline_page_model_impl.h
index 0b9ba3e..17492ce3 100644
--- a/components/offline_pages/core/offline_page_model_impl.h
+++ b/components/offline_pages/core/offline_page_model_impl.h
@@ -110,6 +110,10 @@
 
   OfflineEventLogger* GetLogger() override;
 
+  void set_skip_clearing_original_url_for_testing() {
+    skip_clearing_original_url_for_testing_ = true;
+  }
+
  protected:
   // Adding a protected constructor for testing-only purposes in
   // offline_page_storage_manager_unittest.cc
@@ -285,6 +289,9 @@
   // it once it is not longer needed.
   base::Clock* testing_clock_;
 
+  // Don't clear original URL if it is same as final URL. For testing only.
+  bool skip_clearing_original_url_for_testing_;
+
   base::WeakPtrFactory<OfflinePageModelImpl> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(OfflinePageModelImpl);
diff --git a/components/offline_pages/core/offline_page_model_impl_unittest.cc b/components/offline_pages/core/offline_page_model_impl_unittest.cc
index 235dbe5f..5c0c3c2b 100644
--- a/components/offline_pages/core/offline_page_model_impl_unittest.cc
+++ b/components/offline_pages/core/offline_page_model_impl_unittest.cc
@@ -567,6 +567,25 @@
   EXPECT_EQ("", offline_pages[0].request_origin);
 }
 
+TEST_F(OfflinePageModelImplTest, SavePageSuccessfulWithSameOriginalURL) {
+  std::unique_ptr<OfflinePageTestArchiver> archiver(BuildArchiver(
+      kTestUrl, OfflinePageArchiver::ArchiverResult::SUCCESSFULLY_CREATED));
+  // Pass the original URL same as the final URL.
+  SavePageWithArchiverAsync(kTestUrl, kTestClientId1, kTestUrl, "",
+                            std::move(archiver));
+  PumpLoop();
+
+  EXPECT_EQ(SavePageResult::SUCCESS, last_save_result());
+  ResetResults();
+
+  const std::vector<OfflinePageItem>& offline_pages = GetAllPages();
+
+  ASSERT_EQ(1UL, offline_pages.size());
+  EXPECT_EQ(kTestUrl, offline_pages[0].url);
+  // The original URL should be empty.
+  EXPECT_TRUE(offline_pages[0].original_url.is_empty());
+}
+
 TEST_F(OfflinePageModelImplTest, SavePageSuccessfulWithRequestOrigin) {
   EXPECT_FALSE(HasPages(kTestClientNamespace));
 
diff --git a/components/offline_pages/core/prefetch/README.md b/components/offline_pages/core/prefetch/README.md
index bd1baf0..1d6e9ca 100644
--- a/components/offline_pages/core/prefetch/README.md
+++ b/components/offline_pages/core/prefetch/README.md
@@ -20,6 +20,18 @@
 abstracted components (Downloads, persistent store, GCM, etc) to execute them.
 They implement TaskQueue's Task API so that they can be exclusively executed.
 
+## Prefetch store
+
+* The PrefetchStore depends publicly on SQL and acts as a gateway to the SQLite
+  database.
+* It defines specific method signatures used to create callbacks that are passed
+  to the store for the proper execution of SQL commands.
+* SQL access resources are granted to those callbacks only when needed and in an
+  appropriate environment (correct thread, etc).
+* Pipeline tasks define methods following those signatures that contain the SQL
+  commands they require to do their work.
+* Tasks receive a pointer to the store to be able to execute their SQL commands.
+
 ## Development guidelines
 
 * Implementations that are injected dependencies during service creation should
diff --git a/components/offline_pages/core/prefetch/add_unique_urls_task.cc b/components/offline_pages/core/prefetch/add_unique_urls_task.cc
index 9307342..732941c6 100644
--- a/components/offline_pages/core/prefetch/add_unique_urls_task.cc
+++ b/components/offline_pages/core/prefetch/add_unique_urls_task.cc
@@ -11,6 +11,7 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/logging.h"
 #include "base/time/time.h"
 #include "components/offline_pages/core/prefetch/prefetch_types.h"
 #include "components/offline_pages/core/prefetch/store/prefetch_store.h"
@@ -133,8 +134,11 @@
 }
 
 void AddUniqueUrlsTask::OnUrlsAdded(Result result) {
-  // TODO(carlosk): schedule NWake here if at least one new entry was added to
-  // the store.
+  if (result == Result::URLS_ADDED) {
+    // TODO(carlosk): schedule NWake here if at least one new entry was added to
+    // the store.
+    NOTIMPLEMENTED();
+  }
   TaskComplete();
 }
 
diff --git a/components/payments/android/web_app_manifest_section_table.cc b/components/payments/android/web_app_manifest_section_table.cc
index ad2529cc..f48db6f 100644
--- a/components/payments/android/web_app_manifest_section_table.cc
+++ b/components/payments/android/web_app_manifest_section_table.cc
@@ -114,9 +114,12 @@
 
   sql::Statement s1(db_->GetUniqueStatement(
       "DELETE FROM web_app_manifest_section WHERE id=? "));
-  s1.BindString(0, manifest[0]->id);
-  if (!s1.Run())
-    return false;
+  for (const auto& section : manifest) {
+    s1.BindString(0, section->id);
+    if (!s1.Run())
+      return false;
+    s1.Reset(true);
+  }
 
   sql::Statement s2(
       db_->GetUniqueStatement("INSERT INTO web_app_manifest_section "
@@ -125,7 +128,6 @@
   const time_t expire_date_in_seconds =
       base::Time::NowFromSystemTime().ToTimeT() + DATA_VALID_TIME_IN_SECONDS;
   for (const auto& section : manifest) {
-    DCHECK_EQ(manifest[0]->id, section->id);
     int index = 0;
     s2.BindInt64(index++, expire_date_in_seconds);
     s2.BindString(index++, section->id);
diff --git a/components/payments/android/web_app_manifest_section_table_unittest.cc b/components/payments/android/web_app_manifest_section_table_unittest.cc
index 97c82f2d..3e1859d 100644
--- a/components/payments/android/web_app_manifest_section_table_unittest.cc
+++ b/components/payments/android/web_app_manifest_section_table_unittest.cc
@@ -140,6 +140,61 @@
   ASSERT_TRUE(alicepay_manifest[0]->fingerprints[1] == fingerprint_four);
 }
 
+// A single manifest can have multiple package names, e.g., one for developer
+// and one for production version of the app. A package name is unique among all
+// the apps on Android, so this means we can define multiple apps in a single
+// manifest.
+TEST_F(WebAppManifestSectionTableTest, AddAndGetSingleManifestWithTwoIds) {
+  std::vector<uint8_t> fingerprint_dev = GenerateFingerprint(1);
+  std::vector<uint8_t> fingerprint_prod = GenerateFingerprint(32);
+
+  WebAppManifestSectionTable* web_app_manifest_section_table =
+      WebAppManifestSectionTable::FromWebDatabase(db_.get());
+
+  std::vector<mojom::WebAppManifestSectionPtr> manifest;
+  {
+    // Adds dev version to the manifest.
+    mojom::WebAppManifestSectionPtr manifest_dev_section =
+        mojom::WebAppManifestSection::New();
+    manifest_dev_section->id = "com.bobpay.dev";
+    manifest_dev_section->min_version = static_cast<int64_t>(2);
+    manifest_dev_section->fingerprints.push_back(fingerprint_dev);
+    manifest.emplace_back(std::move(manifest_dev_section));
+  }
+  {
+    // Adds prod version to the manifest.
+    mojom::WebAppManifestSectionPtr manifest_prod_section =
+        mojom::WebAppManifestSection::New();
+    manifest_prod_section->id = "com.bobpay.prod";
+    manifest_prod_section->min_version = static_cast<int64_t>(1);
+    manifest_prod_section->fingerprints.push_back(fingerprint_prod);
+    manifest.emplace_back(std::move(manifest_prod_section));
+  }
+  ASSERT_TRUE(web_app_manifest_section_table->AddWebAppManifest(manifest));
+
+  {
+    // Verify the dev manifest.
+    std::vector<mojom::WebAppManifestSectionPtr> actual_manifest =
+        web_app_manifest_section_table->GetWebAppManifest("com.bobpay.dev");
+    ASSERT_EQ(actual_manifest.size(), 1U);
+    EXPECT_EQ(actual_manifest[0]->id, "com.bobpay.dev");
+    EXPECT_EQ(actual_manifest[0]->min_version, 2);
+    ASSERT_EQ(actual_manifest[0]->fingerprints.size(), 1U);
+    EXPECT_TRUE(actual_manifest[0]->fingerprints[0] == fingerprint_dev);
+  }
+
+  {
+    // Verify the prod manifest.
+    std::vector<mojom::WebAppManifestSectionPtr> actual_manifest =
+        web_app_manifest_section_table->GetWebAppManifest("com.bobpay.prod");
+    ASSERT_EQ(actual_manifest.size(), 1U);
+    EXPECT_EQ(actual_manifest[0]->id, "com.bobpay.prod");
+    EXPECT_EQ(actual_manifest[0]->min_version, 1);
+    ASSERT_EQ(actual_manifest[0]->fingerprints.size(), 1U);
+    EXPECT_TRUE(actual_manifest[0]->fingerprints[0] == fingerprint_prod);
+  }
+}
+
 }  // namespace
 
 }  // namespace payments
diff --git a/components/payments/content/utility/payment_manifest_parser.cc b/components/payments/content/utility/payment_manifest_parser.cc
index 2bdf4b4..27bf6979 100644
--- a/components/payments/content/utility/payment_manifest_parser.cc
+++ b/components/payments/content/utility/payment_manifest_parser.cc
@@ -274,7 +274,7 @@
       base::DictionaryValue* fingerprint_dict = nullptr;
       std::string fingerprint_type;
       std::string fingerprint_value;
-      if (!fingerprints_list->GetDictionary(i, &fingerprint_dict) ||
+      if (!fingerprints_list->GetDictionary(j, &fingerprint_dict) ||
           !fingerprint_dict ||
           !fingerprint_dict->GetString("type", &fingerprint_type) ||
           fingerprint_type != "sha256_cert" ||
diff --git a/components/payments/content/utility/payment_manifest_parser_unittest.cc b/components/payments/content/utility/payment_manifest_parser_unittest.cc
index f1d9391e..d7893d7 100644
--- a/components/payments/content/utility/payment_manifest_parser_unittest.cc
+++ b/components/payments/content/utility/payment_manifest_parser_unittest.cc
@@ -611,5 +611,80 @@
         0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xC0, 0xC1}});
 }
 
+TEST(PaymentManifestParserTest, TwoDifferentSignaturesWellFormed) {
+  ExpectParsedWebAppManifest(
+      "{"
+      "  \"related_applications\": [{"
+      "    \"platform\": \"play\", "
+      "    \"id\": \"com.bobpay.app\", "
+      "    \"min_version\": \"1\", "
+      "    \"fingerprints\": [{"
+      "      \"type\": \"sha256_cert\", "
+      "      \"value\": \"00:01:02:03:04:05:06:07:08:09:A0:A1:A2:A3:A4:A5:A6:A7"
+      ":A8:A9:B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:C0:C1\""
+      "    }, {"
+      "      \"type\": \"sha256_cert\", "
+      "      \"value\": \"AA:01:02:03:04:05:06:07:08:09:A0:A1:A2:A3:A4:A5:A6:A7"
+      ":A8:A9:B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:C0:C1\""
+      "    }]"
+      "  }]"
+      "}",
+      "com.bobpay.app", 1,
+      {{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xA0,
+        0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xB0, 0xB1,
+        0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xC0, 0xC1},
+       {0xAA, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xA0,
+        0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xB0, 0xB1,
+        0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xC0, 0xC1}});
+}
+
+TEST(PaymentManifestParserTest, TwoRelatedApplicationsWellFormed) {
+  std::vector<mojom::WebAppManifestSectionPtr> actual_output =
+      PaymentManifestParser::ParseWebAppManifestIntoVector(
+          "{"
+          "  \"related_applications\": [{"
+          "    \"platform\": \"play\", "
+          "    \"id\": \"com.bobpay.app.dev\", "
+          "    \"min_version\": \"2\", "
+          "    \"fingerprints\": [{"
+          "      \"type\": \"sha256_cert\", "
+          "      \"value\": "
+          "\"00:01:02:03:04:05:06:07:08:09:A0:A1:A2:A3:A4:A5:A6:A7"
+          ":A8:A9:B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:C0:C1\""
+          "    }]"
+          "  }, {"
+          "    \"platform\": \"play\", "
+          "    \"id\": \"com.bobpay.app.prod\", "
+          "    \"min_version\": \"1\", "
+          "    \"fingerprints\": [{"
+          "      \"type\": \"sha256_cert\", "
+          "      \"value\": "
+          "\"AA:01:02:03:04:05:06:07:08:09:A0:A1:A2:A3:A4:A5:A6:A7"
+          ":A8:A9:B0:B1:B2:B3:B4:B5:B6:B7:B8:B9:C0:C1\""
+          "    }]"
+          "  }]"
+          "}");
+
+  ASSERT_EQ(2U, actual_output.size());
+
+  EXPECT_EQ("com.bobpay.app.dev", actual_output.front()->id);
+  EXPECT_EQ(2, actual_output.front()->min_version);
+  EXPECT_EQ(
+      std::vector<std::vector<uint8_t>>(
+          {{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xA0,
+            0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xB0, 0xB1,
+            0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xC0, 0xC1}}),
+      actual_output.front()->fingerprints);
+
+  EXPECT_EQ("com.bobpay.app.prod", actual_output.back()->id);
+  EXPECT_EQ(1, actual_output.back()->min_version);
+  EXPECT_EQ(
+      std::vector<std::vector<uint8_t>>(
+          {{0xAA, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xA0,
+            0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xB0, 0xB1,
+            0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xC0, 0xC1}}),
+      actual_output.back()->fingerprints);
+}
+
 }  // namespace
 }  // namespace payments
diff --git a/components/proximity_auth/BUILD.gn b/components/proximity_auth/BUILD.gn
index db7d253..66a7dc20 100644
--- a/components/proximity_auth/BUILD.gn
+++ b/components/proximity_auth/BUILD.gn
@@ -55,6 +55,7 @@
     "//base",
     "//components/cryptauth",
     "//components/cryptauth/ble",
+    "//components/pref_registry:pref_registry",
     "//components/prefs",
     "//components/proximity_auth/logging",
     "//components/proximity_auth/public/interfaces",
@@ -121,6 +122,7 @@
     "//components/prefs:test_support",
     "//components/proximity_auth/logging",
     "//components/proximity_auth/logging:unit_tests",
+    "//components/sync_preferences:test_support",
     "//device/bluetooth:mocks",
     "//testing/gmock",
     "//testing/gtest",
diff --git a/components/proximity_auth/DEPS b/components/proximity_auth/DEPS
index 3a0d524..8adcc9e3 100644
--- a/components/proximity_auth/DEPS
+++ b/components/proximity_auth/DEPS
@@ -1,7 +1,9 @@
 include_rules = [
   "+components/cryptauth",
   "+components/prefs",
+  "+components/pref_registry/pref_registry_syncable.h",
   "+components/signin/core/account_id/account_id.h",
+  "+components/sync_preferences/testing_pref_service_syncable.h",
   "+device/bluetooth",
   "+net",
 ]
diff --git a/components/proximity_auth/proximity_auth_pref_manager.cc b/components/proximity_auth/proximity_auth_pref_manager.cc
index c8c637c..39101cb 100644
--- a/components/proximity_auth/proximity_auth_pref_manager.cc
+++ b/components/proximity_auth/proximity_auth_pref_manager.cc
@@ -9,7 +9,7 @@
 
 #include "base/macros.h"
 #include "base/values.h"
-#include "components/prefs/pref_registry_simple.h"
+#include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/proximity_auth/logging/logging.h"
@@ -23,10 +23,14 @@
 ProximityAuthPrefManager::~ProximityAuthPrefManager() {}
 
 // static
-void ProximityAuthPrefManager::RegisterPrefs(PrefRegistrySimple* registry) {
+void ProximityAuthPrefManager::RegisterPrefs(
+    user_prefs::PrefRegistrySyncable* registry) {
   registry->RegisterInt64Pref(prefs::kProximityAuthLastPasswordEntryTimestampMs,
                               0L);
   registry->RegisterDictionaryPref(prefs::kProximityAuthRemoteBleDevices);
+  registry->RegisterIntegerPref(
+      prefs::kEasyUnlockProximityThreshold, 1,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
 }
 
 bool ProximityAuthPrefManager::HasDeviceWithAddress(
@@ -121,4 +125,15 @@
   return pref_service_->GetDictionary(prefs::kProximityAuthRemoteBleDevices);
 }
 
+void ProximityAuthPrefManager::SetProximityThreshold(ProximityThreshold value) {
+  pref_service_->SetInteger(prefs::kEasyUnlockProximityThreshold, value);
+}
+
+ProximityAuthPrefManager::ProximityThreshold
+ProximityAuthPrefManager::GetProximityThreshold() const {
+  int pref_value =
+      pref_service_->GetInteger(prefs::kEasyUnlockProximityThreshold);
+  return static_cast<ProximityThreshold>(pref_value);
+}
+
 }  // namespace proximity_auth
diff --git a/components/proximity_auth/proximity_auth_pref_manager.h b/components/proximity_auth/proximity_auth_pref_manager.h
index 9f741914..9d945e1 100644
--- a/components/proximity_auth/proximity_auth_pref_manager.h
+++ b/components/proximity_auth/proximity_auth_pref_manager.h
@@ -11,13 +11,16 @@
 
 #include "base/macros.h"
 
-class PrefRegistrySimple;
 class PrefService;
 
 namespace base {
 class DictionaryValue;
 }  // namespace base
 
+namespace user_prefs {
+class PrefRegistrySyncable;
+}  // namespace user_prefs
+
 namespace proximity_auth {
 
 // This class manages the local (persistent) settings used by Smart Lock. It
@@ -33,7 +36,7 @@
   virtual ~ProximityAuthPrefManager();
 
   // Registers the prefs used by this class to the given |pref_service|.
-  static void RegisterPrefs(PrefRegistrySimple* registry);
+  static void RegisterPrefs(user_prefs::PrefRegistrySyncable* registry);
 
   // Methods used to handle remote BLE devices stored in prefs
   // (kProximityAuthRemoteBleDevices).
@@ -65,6 +68,22 @@
   virtual void SetLastPasswordEntryTimestampMs(int64_t timestamp_ms);
   virtual int64_t GetLastPasswordEntryTimestampMs() const;
 
+  // These are arbitrary labels displayed in the settings page for the user
+  // to select. The actual mapping is done in the ProximityMonitorImpl.
+  enum ProximityThreshold {
+    kVeryClose = 0,
+    kClose = 1,
+    kFar = 2,
+    kVeryFar = 3
+  };
+
+  // Setter and getter for the proximity threshold. This preference is
+  // exposed to the user, allowing him / her to change how close the
+  // phone must for the unlock to be allowed.
+  // Note: These are arbitrary values,
+  virtual void SetProximityThreshold(ProximityThreshold value);
+  virtual ProximityThreshold GetProximityThreshold() const;
+
  private:
   const base::DictionaryValue* GetRemoteBleDevices() const;
 
diff --git a/components/proximity_auth/proximity_auth_pref_manager_unittest.cc b/components/proximity_auth/proximity_auth_pref_manager_unittest.cc
index 3ae2072..78856f7 100644
--- a/components/proximity_auth/proximity_auth_pref_manager_unittest.cc
+++ b/components/proximity_auth/proximity_auth_pref_manager_unittest.cc
@@ -10,8 +10,8 @@
 #include <vector>
 
 #include "base/macros.h"
-#include "components/prefs/testing_pref_service.h"
 #include "components/proximity_auth/proximity_auth_pref_names.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -27,6 +27,11 @@
 const int64_t kPasswordEntryTimestampMs1 = 123456789L;
 const int64_t kPasswordEntryTimestampMs2 = 987654321L;
 
+const ProximityAuthPrefManager::ProximityThreshold kProximityThreshold1 =
+    ProximityAuthPrefManager::ProximityThreshold::kFar;
+const ProximityAuthPrefManager::ProximityThreshold kProximityThreshold2 =
+    ProximityAuthPrefManager::ProximityThreshold::kVeryFar;
+
 }  //  namespace
 
 class ProximityAuthProximityAuthPrefManagerTest : public testing::Test {
@@ -47,14 +52,14 @@
     EXPECT_EQ(pref_manager.GetDeviceAddress(public_key), bluetooth_address);
   }
 
-  TestingPrefServiceSimple pref_service_;
+  sync_preferences::TestingPrefServiceSyncable pref_service_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ProximityAuthProximityAuthPrefManagerTest);
 };
 
 TEST_F(ProximityAuthProximityAuthPrefManagerTest, RegisterPrefs) {
-  TestingPrefServiceSimple pref_service;
+  sync_preferences::TestingPrefServiceSyncable pref_service;
   ProximityAuthPrefManager::RegisterPrefs(pref_service.registry());
   EXPECT_TRUE(
       pref_service.FindPreference(prefs::kProximityAuthRemoteBleDevices));
@@ -170,4 +175,13 @@
             pref_manager.GetLastPasswordEntryTimestampMs());
 }
 
+TEST_F(ProximityAuthProximityAuthPrefManagerTest, ProximityThreshold) {
+  ProximityAuthPrefManager pref_manager(&pref_service_);
+  EXPECT_EQ(1, pref_manager.GetProximityThreshold());
+  pref_manager.SetProximityThreshold(kProximityThreshold1);
+  EXPECT_EQ(kProximityThreshold1, pref_manager.GetProximityThreshold());
+  pref_manager.SetProximityThreshold(kProximityThreshold2);
+  EXPECT_EQ(kProximityThreshold2, pref_manager.GetProximityThreshold());
+}
+
 }  // namespace proximity_auth
diff --git a/components/proximity_auth/proximity_auth_pref_names.cc b/components/proximity_auth/proximity_auth_pref_names.cc
index 3e0267e..9ef2349 100644
--- a/components/proximity_auth/proximity_auth_pref_names.cc
+++ b/components/proximity_auth/proximity_auth_pref_names.cc
@@ -16,5 +16,9 @@
 const char kProximityAuthRemoteBleDevices[] =
     "proximity_auth.remote_ble_devices";
 
+// How close the remote and the local device should be in order to use Easy
+// Unlock.
+const char kEasyUnlockProximityThreshold[] = "easy_unlock.proximity_threshold";
+
 }  // namespace prefs
 }  // namespace proximity_auth
diff --git a/components/proximity_auth/proximity_auth_pref_names.h b/components/proximity_auth/proximity_auth_pref_names.h
index 02ef2f3..de4198e 100644
--- a/components/proximity_auth/proximity_auth_pref_names.h
+++ b/components/proximity_auth/proximity_auth_pref_names.h
@@ -8,6 +8,7 @@
 namespace proximity_auth {
 namespace prefs {
 
+extern const char kEasyUnlockProximityThreshold[];
 extern const char kProximityAuthLastPasswordEntryTimestampMs[];
 extern const char kProximityAuthRemoteBleDevices[];
 
diff --git a/components/proximity_auth/proximity_auth_system.cc b/components/proximity_auth/proximity_auth_system.cc
index 86af9753..f425e73 100644
--- a/components/proximity_auth/proximity_auth_system.cc
+++ b/components/proximity_auth/proximity_auth_system.cc
@@ -29,11 +29,12 @@
     ProximityAuthClient* proximity_auth_client)
     : screenlock_type_(screenlock_type),
       proximity_auth_client_(proximity_auth_client),
-      unlock_manager_(
-          new UnlockManagerImpl(screenlock_type, proximity_auth_client)),
       clock_(new base::DefaultClock()),
       pref_manager_(new ProximityAuthPrefManager(
           proximity_auth_client->GetPrefService())),
+      unlock_manager_(new UnlockManagerImpl(screenlock_type,
+                                            proximity_auth_client_,
+                                            pref_manager_.get())),
       suspended_(false),
       started_(false),
       weak_ptr_factory_(this) {}
@@ -46,9 +47,9 @@
     std::unique_ptr<ProximityAuthPrefManager> pref_manager)
     : screenlock_type_(screenlock_type),
       proximity_auth_client_(proximity_auth_client),
-      unlock_manager_(std::move(unlock_manager)),
       clock_(std::move(clock)),
       pref_manager_(std::move(pref_manager)),
+      unlock_manager_(std::move(unlock_manager)),
       suspended_(false),
       started_(false),
       weak_ptr_factory_(this) {}
diff --git a/components/proximity_auth/proximity_auth_system.h b/components/proximity_auth/proximity_auth_system.h
index 980f7fc..5bab44f1 100644
--- a/components/proximity_auth/proximity_auth_system.h
+++ b/components/proximity_auth/proximity_auth_system.h
@@ -113,15 +113,15 @@
   // the RemoteDevice of the currently focused user.
   std::unique_ptr<RemoteDeviceLifeCycle> remote_device_life_cycle_;
 
-  // Handles the interaction with the lock screen UI.
-  std::unique_ptr<UnlockManager> unlock_manager_;
-
   // Used to get the current timestamp.
   std::unique_ptr<base::Clock> clock_;
 
   // Fetches EasyUnlock preferences.
   std::unique_ptr<ProximityAuthPrefManager> pref_manager_;
 
+  // Handles the interaction with the lock screen UI.
+  std::unique_ptr<UnlockManager> unlock_manager_;
+
   // True if the system is suspended.
   bool suspended_;
 
diff --git a/components/proximity_auth/proximity_monitor_impl.cc b/components/proximity_auth/proximity_monitor_impl.cc
index 202be9de..c592acc2 100644
--- a/components/proximity_auth/proximity_monitor_impl.cc
+++ b/components/proximity_auth/proximity_monitor_impl.cc
@@ -14,6 +14,7 @@
 #include "base/time/time.h"
 #include "components/proximity_auth/logging/logging.h"
 #include "components/proximity_auth/metrics.h"
+#include "components/proximity_auth/proximity_auth_pref_manager.h"
 #include "components/proximity_auth/proximity_monitor_observer.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
@@ -25,22 +26,22 @@
 // The time to wait, in milliseconds, between proximity polling iterations.
 const int kPollingTimeoutMs = 250;
 
-// The RSSI threshold below which we consider the remote device to not be in
-// proximity.
-// Note: Because this threshold is unconfigurable right now, it is set quite
-// conservatively in order to avoid blocking users.
-const int kRssiThreshold = -70;
-
 // The weight of the most recent RSSI sample.
 const double kRssiSampleWeight = 0.3;
 
+// The default RSSI threshold.
+const int kDefaultRssiThreshold = -70;
+
 ProximityMonitorImpl::ProximityMonitorImpl(
     cryptauth::Connection* connection,
-    std::unique_ptr<base::TickClock> clock)
+    std::unique_ptr<base::TickClock> clock,
+    ProximityAuthPrefManager* pref_manager)
     : connection_(connection),
       remote_device_is_in_proximity_(false),
       is_active_(false),
+      rssi_threshold_(kDefaultRssiThreshold),
       clock_(std::move(clock)),
+      pref_manager_(pref_manager),
       polling_weak_ptr_factory_(this),
       weak_ptr_factory_(this) {
   if (device::BluetoothAdapterFactory::IsBluetoothSupported()) {
@@ -58,6 +59,7 @@
 
 void ProximityMonitorImpl::Start() {
   is_active_ = true;
+  GetRssiThresholdFromPrefs();
   UpdatePollingState();
 }
 
@@ -192,7 +194,7 @@
 
 void ProximityMonitorImpl::CheckForProximityStateChange() {
   bool is_now_in_proximity =
-      rssi_rolling_average_ && *rssi_rolling_average_ > kRssiThreshold;
+      rssi_rolling_average_ && *rssi_rolling_average_ > rssi_threshold_;
 
   if (rssi_rolling_average_)
     PA_LOG(INFO) << "  Rolling RSSI: " << *rssi_rolling_average_;
@@ -206,4 +208,24 @@
   }
 }
 
+void ProximityMonitorImpl::GetRssiThresholdFromPrefs() {
+  ProximityAuthPrefManager::ProximityThreshold threshold =
+      pref_manager_->GetProximityThreshold();
+  switch (threshold) {
+    case ProximityAuthPrefManager::ProximityThreshold::kVeryClose:
+      rssi_threshold_ = -45;
+      return;
+    case ProximityAuthPrefManager::ProximityThreshold::kClose:
+      rssi_threshold_ = -60;
+      return;
+    case ProximityAuthPrefManager::ProximityThreshold::kFar:
+      rssi_threshold_ = -70;
+      return;
+    case ProximityAuthPrefManager::ProximityThreshold::kVeryFar:
+      rssi_threshold_ = -85;
+      return;
+  }
+  NOTREACHED();
+}
+
 }  // namespace proximity_auth
diff --git a/components/proximity_auth/proximity_monitor_impl.h b/components/proximity_auth/proximity_monitor_impl.h
index 1aebd2e..e882dc9 100644
--- a/components/proximity_auth/proximity_monitor_impl.h
+++ b/components/proximity_auth/proximity_monitor_impl.h
@@ -26,6 +26,7 @@
 
 namespace proximity_auth {
 
+class ProximityAuthPrefManager;
 class ProximityMonitorObserver;
 
 // The concrete implemenation of the proximity monitor interface.
@@ -33,7 +34,8 @@
  public:
   // The |connection| is not owned, and must outlive |this| instance.
   ProximityMonitorImpl(cryptauth::Connection* connection,
-                       std::unique_ptr<base::TickClock> clock);
+                       std::unique_ptr<base::TickClock> clock,
+                       ProximityAuthPrefManager* pref_manager);
   ~ProximityMonitorImpl() override;
 
   // ProximityMonitor:
@@ -82,6 +84,10 @@
   // samples. Notifies |observers_| on a change.
   void CheckForProximityStateChange();
 
+  // Gets the user-selected proximity threshold and converts it to a
+  // RSSI value.
+  void GetRssiThresholdFromPrefs();
+
   // The current connection being monitored. Not owned and must outlive this
   // instance.
   cryptauth::Connection* connection_;
@@ -100,6 +106,9 @@
   // for proximity to the remote device.
   bool is_active_;
 
+  // When the RSSI is below this value the phone the unlock is not allowed.
+  int rssi_threshold_;
+
   // The exponentailly weighted rolling average of the RSSI, used to smooth the
   // RSSI readings. Null if the monitor is inactive, has not recently observed
   // an RSSI reading, or the most recent connection info included an invalid
@@ -109,6 +118,10 @@
   // Used to access non-decreasing time measurements.
   std::unique_ptr<base::TickClock> clock_;
 
+  // Contains perferences that outlive the lifetime of this object and across
+  // process restarts. Not owned and must outlive this instance.
+  ProximityAuthPrefManager* pref_manager_;
+
   // Used to vend weak pointers for polling. Using a separate factory for these
   // weak pointers allows the weak pointers to be invalidated when polling
   // stops, which effectively cancels the scheduled tasks.
diff --git a/components/proximity_auth/proximity_monitor_impl_unittest.cc b/components/proximity_auth/proximity_monitor_impl_unittest.cc
index 24fac5c..cc7844c 100644
--- a/components/proximity_auth/proximity_monitor_impl_unittest.cc
+++ b/components/proximity_auth/proximity_monitor_impl_unittest.cc
@@ -17,7 +17,9 @@
 #include "base/time/time.h"
 #include "components/cryptauth/fake_connection.h"
 #include "components/cryptauth/remote_device.h"
+#include "components/prefs/testing_pref_service.h"
 #include "components/proximity_auth/logging/logging.h"
+#include "components/proximity_auth/proximity_auth_pref_manager.h"
 #include "components/proximity_auth/proximity_monitor_observer.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
@@ -38,6 +40,11 @@
 const char kRemoteDeviceName[] = "LGE Nexus 5";
 const char kBluetoothAddress[] = "AA:BB:CC:DD:EE:FF";
 const char kPersistentSymmetricKey[] = "PSK";
+
+// The proximity threshold corresponds to a RSSI of -70.
+const ProximityAuthPrefManager::ProximityThreshold
+    kProximityThresholdPrefValue =
+        ProximityAuthPrefManager::ProximityThreshold::kFar;
 const int kRssiThreshold = -70;
 
 class MockProximityMonitorObserver : public ProximityMonitorObserver {
@@ -51,6 +58,18 @@
   DISALLOW_COPY_AND_ASSIGN(MockProximityMonitorObserver);
 };
 
+class MockProximityAuthPrefManager : public ProximityAuthPrefManager {
+ public:
+  MockProximityAuthPrefManager() : ProximityAuthPrefManager(nullptr) {}
+  ~MockProximityAuthPrefManager() override {}
+
+  MOCK_CONST_METHOD0(GetProximityThreshold,
+                     ProximityAuthPrefManager::ProximityThreshold(void));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockProximityAuthPrefManager);
+};
+
 // Creates a mock Bluetooth adapter and sets it as the global adapter for
 // testing.
 scoped_refptr<device::MockBluetoothAdapter>
@@ -81,7 +100,8 @@
                        kPersistentSymmetricKey,
                        std::string()),
         connection_(remote_device_),
-        monitor_(&connection_, base::WrapUnique(clock_)),
+        pref_manager_(new NiceMock<MockProximityAuthPrefManager>()),
+        monitor_(&connection_, base::WrapUnique(clock_), pref_manager_.get()),
         task_runner_(new base::TestSimpleTaskRunner()),
         thread_task_runner_handle_(task_runner_) {
     ON_CALL(*bluetooth_adapter_, GetDevice(kBluetoothAddress))
@@ -89,6 +109,8 @@
     ON_CALL(remote_bluetooth_device_, GetConnectionInfo(_))
         .WillByDefault(SaveArg<0>(&connection_info_callback_));
     monitor_.AddObserver(&observer_);
+    ON_CALL(*pref_manager_, GetProximityThreshold())
+        .WillByDefault(Return(kProximityThresholdPrefValue));
   }
 
   ~ProximityAuthProximityMonitorImplTest() override {}
@@ -118,6 +140,9 @@
   cryptauth::RemoteDevice remote_device_;
   cryptauth::FakeConnection connection_;
 
+  // ProximityAuthPrefManager mock.
+  std::unique_ptr<NiceMock<MockProximityAuthPrefManager>> pref_manager_;
+
   // The proximity monitor under test.
   ProximityMonitorImpl monitor_;
 
@@ -342,7 +367,8 @@
   cryptauth::FakeConnection connection(unnamed_remote_device);
 
   std::unique_ptr<base::TickClock> clock(new base::SimpleTestTickClock());
-  ProximityMonitorImpl monitor(&connection, std::move(clock));
+  ProximityMonitorImpl monitor(&connection, std::move(clock),
+                               pref_manager_.get());
   monitor.AddObserver(&observer_);
   monitor.Start();
   ProvideConnectionInfo({127, 127, 127});
diff --git a/components/proximity_auth/unlock_manager_impl.cc b/components/proximity_auth/unlock_manager_impl.cc
index c2af9d1c..64bb272 100644
--- a/components/proximity_auth/unlock_manager_impl.cc
+++ b/components/proximity_auth/unlock_manager_impl.cc
@@ -18,6 +18,7 @@
 #include "components/proximity_auth/messenger.h"
 #include "components/proximity_auth/metrics.h"
 #include "components/proximity_auth/proximity_auth_client.h"
+#include "components/proximity_auth/proximity_auth_pref_manager.h"
 #include "components/proximity_auth/proximity_monitor_impl.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 
@@ -80,12 +81,16 @@
 
 }  // namespace
 
+class ProximityAuthPrefManager;
+
 UnlockManagerImpl::UnlockManagerImpl(
     ProximityAuthSystem::ScreenlockType screenlock_type,
-    ProximityAuthClient* proximity_auth_client)
+    ProximityAuthClient* proximity_auth_client,
+    ProximityAuthPrefManager* pref_manager)
     : screenlock_type_(screenlock_type),
       life_cycle_(nullptr),
       proximity_auth_client_(proximity_auth_client),
+      pref_manager_(pref_manager),
       is_locked_(false),
       is_attempting_auth_(false),
       is_waking_up_(false),
@@ -158,7 +163,8 @@
   if (state == RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED) {
     DCHECK(life_cycle_->GetConnection());
     DCHECK(GetMessenger());
-    proximity_monitor_ = CreateProximityMonitor(life_cycle_->GetConnection());
+    proximity_monitor_ =
+        CreateProximityMonitor(life_cycle_->GetConnection(), pref_manager_);
     GetMessenger()->AddObserver(this);
   }
 
@@ -323,9 +329,10 @@
 }
 
 std::unique_ptr<ProximityMonitor> UnlockManagerImpl::CreateProximityMonitor(
-    cryptauth::Connection* connection) {
+    cryptauth::Connection* connection,
+    ProximityAuthPrefManager* pref_manager) {
   return base::MakeUnique<ProximityMonitorImpl>(
-      connection, base::WrapUnique(new base::DefaultTickClock()));
+      connection, base::WrapUnique(new base::DefaultTickClock()), pref_manager);
 }
 
 void UnlockManagerImpl::SendSignInChallenge() {
diff --git a/components/proximity_auth/unlock_manager_impl.h b/components/proximity_auth/unlock_manager_impl.h
index c880844..e37e708 100644
--- a/components/proximity_auth/unlock_manager_impl.h
+++ b/components/proximity_auth/unlock_manager_impl.h
@@ -27,6 +27,7 @@
 
 class Messenger;
 class ProximityAuthClient;
+class ProximityAuthPrefManager;
 class ProximityMonitor;
 
 // The unlock manager is responsible for controlling the lock screen UI based on
@@ -43,7 +44,8 @@
   // The |proximity_auth_client| is not owned and should outlive the constructed
   // unlock manager.
   UnlockManagerImpl(ProximityAuthSystem::ScreenlockType screenlock_type,
-                    ProximityAuthClient* proximity_auth_client);
+                    ProximityAuthClient* proximity_auth_client,
+                    ProximityAuthPrefManager* pref_manager);
   ~UnlockManagerImpl() override;
 
   // UnlockManager:
@@ -56,7 +58,8 @@
   // Creates a ProximityMonitor instance for the given |connection|.
   // Exposed for testing.
   virtual std::unique_ptr<ProximityMonitor> CreateProximityMonitor(
-      cryptauth::Connection* connection);
+      cryptauth::Connection* connection,
+      ProximityAuthPrefManager* pref_manager);
 
  private:
   // The possible lock screen states for the remote device.
@@ -155,6 +158,9 @@
   // Used to call into the embedder. Expected to outlive |this| instance.
   ProximityAuthClient* proximity_auth_client_;
 
+  // Used to access the common prefs. Expected to outlive |this| instance.
+  ProximityAuthPrefManager* pref_manager_;
+
   // Whether the screen is currently locked.
   bool is_locked_;
 
diff --git a/components/proximity_auth/unlock_manager_impl_unittest.cc b/components/proximity_auth/unlock_manager_impl_unittest.cc
index e9131f5..2a0f428 100644
--- a/components/proximity_auth/unlock_manager_impl_unittest.cc
+++ b/components/proximity_auth/unlock_manager_impl_unittest.cc
@@ -119,7 +119,7 @@
  public:
   TestUnlockManager(ProximityAuthSystem::ScreenlockType screenlock_type,
                     ProximityAuthClient* proximity_auth_client)
-      : UnlockManagerImpl(screenlock_type, proximity_auth_client),
+      : UnlockManagerImpl(screenlock_type, proximity_auth_client, nullptr),
         proximity_monitor_(nullptr) {}
   ~TestUnlockManager() override {}
 
@@ -137,7 +137,8 @@
 
  private:
   std::unique_ptr<ProximityMonitor> CreateProximityMonitor(
-      cryptauth::Connection* connection) override {
+      cryptauth::Connection* connection,
+      ProximityAuthPrefManager* pref_manager) override {
     EXPECT_EQ(cryptauth::kTestRemoteDevicePublicKey,
               connection->remote_device().public_key);
     std::unique_ptr<MockProximityMonitor> proximity_monitor(
diff --git a/components/safe_browsing/DEPS b/components/safe_browsing/DEPS
index ccceca9..aa87f2c 100644
--- a/components/safe_browsing/DEPS
+++ b/components/safe_browsing/DEPS
@@ -6,6 +6,7 @@
   "+content/public/browser",
   "+content/public/common",
   "+google_apis",
+  "+mojo/public/cpp",
   "+net/base",
   "+net/log",
   "+net/traffic_annotation",
diff --git a/components/safe_browsing/base_resource_throttle.h b/components/safe_browsing/base_resource_throttle.h
index 249be76..38de36f5 100644
--- a/components/safe_browsing/base_resource_throttle.h
+++ b/components/safe_browsing/base_resource_throttle.h
@@ -107,6 +107,11 @@
       scoped_refptr<BaseUIManager> ui_manager,
       const security_interstitials::UnsafeResource& resource);
 
+  // Starts running |url| through the safe browsing check. Returns true if the
+  // URL is safe to visit. Otherwise returns false and will call
+  // OnBrowseUrlResult() when the check has completed.
+  virtual bool CheckUrl(const GURL& url);
+
   scoped_refptr<BaseUIManager> ui_manager();
 
  private:
@@ -136,11 +141,6 @@
 
   scoped_refptr<BaseUIManager> ui_manager_;
 
-  // Starts running |url| through the safe browsing check. Returns true if the
-  // URL is safe to visit. Otherwise returns false and will call
-  // OnBrowseUrlResult() when the check has completed.
-  bool CheckUrl(const GURL& url);
-
   // Callback for when the safe browsing check (which was initiated by
   // StartCheckingUrl()) has taken longer than kCheckUrlTimeoutMs.
   void OnCheckUrlTimeout();
diff --git a/components/safe_browsing/browser/BUILD.gn b/components/safe_browsing/browser/BUILD.gn
index 8d7b1880..1ad4965 100644
--- a/components/safe_browsing/browser/BUILD.gn
+++ b/components/safe_browsing/browser/BUILD.gn
@@ -6,6 +6,12 @@
 
 source_set("browser") {
   sources = [
+    "browser_url_loader_throttle.cc",
+    "browser_url_loader_throttle.h",
+    "mojo_safe_browsing_impl.cc",
+    "mojo_safe_browsing_impl.h",
+    "safe_browsing_url_checker_impl.cc",
+    "safe_browsing_url_checker_impl.h",
     "safe_browsing_url_request_context_getter.cc",
     "safe_browsing_url_request_context_getter.h",
     "threat_details.cc",
@@ -14,6 +20,7 @@
     "threat_details_cache.h",
     "threat_details_history.cc",
     "threat_details_history.h",
+    "url_checker_delegate.h",
   ]
 
   deps = [
@@ -22,6 +29,7 @@
     "//components/safe_browsing:csd_proto",
     "//components/safe_browsing:safe_browsing",
     "//components/safe_browsing/common:common",
+    "//components/safe_browsing_db:database_manager",
     "//components/security_interstitials/content:security_interstitial_page",
     "//content/public/browser:browser",
     "//net:extras",
diff --git a/components/safe_browsing/browser/DEPS b/components/safe_browsing/browser/DEPS
index 37c9112..d98a2a4d 100644
--- a/components/safe_browsing/browser/DEPS
+++ b/components/safe_browsing/browser/DEPS
@@ -2,9 +2,10 @@
   "+components/history/core/browser",
   "+components/safe_browsing/csd.pb.h",
   "+content/public/browser",
+  "+ipc/ipc_message.h",
   "+net/cookies",
   "+net/extras",
   "+net/http",
   "+net/ssl",
   "+net/traffic_annotation",
-]
\ No newline at end of file
+]
diff --git a/chrome/browser/safe_browsing/browser_url_loader_throttle.cc b/components/safe_browsing/browser/browser_url_loader_throttle.cc
similarity index 68%
rename from chrome/browser/safe_browsing/browser_url_loader_throttle.cc
rename to components/safe_browsing/browser/browser_url_loader_throttle.cc
index a8563ae4..f841da38 100644
--- a/chrome/browser/safe_browsing/browser_url_loader_throttle.cc
+++ b/components/safe_browsing/browser/browser_url_loader_throttle.cc
@@ -2,22 +2,33 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/safe_browsing/browser_url_loader_throttle.h"
+#include "components/safe_browsing/browser/browser_url_loader_throttle.h"
 
 #include "base/logging.h"
-#include "chrome/browser/safe_browsing/safe_browsing_url_checker_impl.h"
-#include "chrome/browser/safe_browsing/ui_manager.h"
-#include "components/safe_browsing_db/database_manager.h"
+#include "components/safe_browsing/browser/safe_browsing_url_checker_impl.h"
+#include "components/safe_browsing/browser/url_checker_delegate.h"
 #include "net/url_request/redirect_info.h"
 
 namespace safe_browsing {
 
+// static
+std::unique_ptr<BrowserURLLoaderThrottle> BrowserURLLoaderThrottle::MaybeCreate(
+    scoped_refptr<UrlCheckerDelegate> url_checker_delegate,
+    const base::Callback<content::WebContents*()>& web_contents_getter) {
+  if (!url_checker_delegate ||
+      !url_checker_delegate->GetDatabaseManager()->IsSupported()) {
+    return nullptr;
+  }
+
+  return base::WrapUnique<BrowserURLLoaderThrottle>(
+      new BrowserURLLoaderThrottle(std::move(url_checker_delegate),
+                                   web_contents_getter));
+}
+
 BrowserURLLoaderThrottle::BrowserURLLoaderThrottle(
-    scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
-    scoped_refptr<SafeBrowsingUIManager> ui_manager,
+    scoped_refptr<UrlCheckerDelegate> url_checker_delegate,
     const base::Callback<content::WebContents*()>& web_contents_getter)
-    : database_manager_(database_manager),
-      ui_manager_(ui_manager),
+    : url_checker_delegate_(std::move(url_checker_delegate)),
       web_contents_getter_(web_contents_getter) {}
 
 BrowserURLLoaderThrottle::~BrowserURLLoaderThrottle() = default;
@@ -33,8 +44,8 @@
 
   pending_checks_++;
   url_checker_ = base::MakeUnique<SafeBrowsingUrlCheckerImpl>(
-      load_flags, resource_type, std::move(database_manager_),
-      std::move(ui_manager_), web_contents_getter_);
+      load_flags, resource_type, std::move(url_checker_delegate_),
+      web_contents_getter_);
   url_checker_->CheckUrl(
       url, base::BindOnce(&BrowserURLLoaderThrottle::OnCheckUrlResult,
                           base::Unretained(this)));
diff --git a/chrome/browser/safe_browsing/browser_url_loader_throttle.h b/components/safe_browsing/browser/browser_url_loader_throttle.h
similarity index 73%
rename from chrome/browser/safe_browsing/browser_url_loader_throttle.h
rename to components/safe_browsing/browser/browser_url_loader_throttle.h
index 1eca9d49..f57ce49 100644
--- a/chrome/browser/safe_browsing/browser_url_loader_throttle.h
+++ b/components/safe_browsing/browser/browser_url_loader_throttle.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 CHROME_BROWSER_SAFE_BROWSING_BROWSER_URL_LOADER_THROTTLE_H_
-#define CHROME_BROWSER_SAFE_BROWSING_BROWSER_URL_LOADER_THROTTLE_H_
+#ifndef COMPONENTS_SAFE_BROWSING_BROWSER_BROWSER_URL_LOADER_THROTTLE_H_
+#define COMPONENTS_SAFE_BROWSING_BROWSER_BROWSER_URL_LOADER_THROTTLE_H_
 
 #include <memory>
 
@@ -18,8 +18,7 @@
 
 namespace safe_browsing {
 
-class SafeBrowsingDatabaseManager;
-class SafeBrowsingUIManager;
+class UrlCheckerDelegate;
 class SafeBrowsingUrlCheckerImpl;
 
 // BrowserURLLoaderThrottle is used in the browser process to query
@@ -29,12 +28,10 @@
 // Used when --enable-network-service is in effect.
 class BrowserURLLoaderThrottle : public content::URLLoaderThrottle {
  public:
-  // |web_contents_getter| is used for displaying SafeBrowsing UI when
-  // necessary.
-  BrowserURLLoaderThrottle(
-      scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
-      scoped_refptr<SafeBrowsingUIManager> ui_manager,
+  static std::unique_ptr<BrowserURLLoaderThrottle> MaybeCreate(
+      scoped_refptr<UrlCheckerDelegate> url_checker_delegate,
       const base::Callback<content::WebContents*()>& web_contents_getter);
+
   ~BrowserURLLoaderThrottle() override;
 
   // content::URLLoaderThrottle implementation.
@@ -47,11 +44,16 @@
   void WillProcessResponse(bool* defer) override;
 
  private:
+  // |web_contents_getter| is used for displaying SafeBrowsing UI when
+  // necessary.
+  BrowserURLLoaderThrottle(
+      scoped_refptr<UrlCheckerDelegate> url_checker_delegate,
+      const base::Callback<content::WebContents*()>& web_contents_getter);
+
   void OnCheckUrlResult(bool safe);
 
-  // The following two members stay valid until |url_checker_| is created.
-  scoped_refptr<SafeBrowsingDatabaseManager> database_manager_;
-  scoped_refptr<SafeBrowsingUIManager> ui_manager_;
+  // The following member stays valid until |url_checker_| is created.
+  scoped_refptr<UrlCheckerDelegate> url_checker_delegate_;
 
   base::Callback<content::WebContents*()> web_contents_getter_;
 
@@ -65,4 +67,4 @@
 
 }  // namespace safe_browsing
 
-#endif  // CHROME_BROWSER_SAFE_BROWSING_BROWSER_URL_LOADER_THROTTLE_H_
+#endif  // COMPONENTS_SAFE_BROWSING_BROWSER_BROWSER_URL_LOADER_THROTTLE_H_
diff --git a/chrome/browser/safe_browsing/mojo_safe_browsing_impl.cc b/components/safe_browsing/browser/mojo_safe_browsing_impl.cc
similarity index 72%
rename from chrome/browser/safe_browsing/mojo_safe_browsing_impl.cc
rename to components/safe_browsing/browser/mojo_safe_browsing_impl.cc
index 3a59a17..5006795 100644
--- a/chrome/browser/safe_browsing/mojo_safe_browsing_impl.cc
+++ b/components/safe_browsing/browser/mojo_safe_browsing_impl.cc
@@ -2,15 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/safe_browsing/mojo_safe_browsing_impl.h"
+#include "components/safe_browsing/browser/mojo_safe_browsing_impl.h"
 
 #include <vector>
 
 #include "base/memory/ptr_util.h"
-#include "chrome/browser/safe_browsing/safe_browsing_url_checker_impl.h"
-#include "chrome/browser/safe_browsing/ui_manager.h"
-#include "components/safe_browsing_db/database_manager.h"
-#include "components/safe_browsing_db/v4_protocol_manager_util.h"
+#include "components/safe_browsing/browser/safe_browsing_url_checker_impl.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
@@ -54,28 +51,29 @@
 }  // namespace
 
 MojoSafeBrowsingImpl::MojoSafeBrowsingImpl(
-    scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
-    scoped_refptr<SafeBrowsingUIManager> ui_manager,
+    scoped_refptr<UrlCheckerDelegate> delegate,
     int render_process_id)
-    : database_manager_(std::move(database_manager)),
-      ui_manager_(std::move(ui_manager)),
-      render_process_id_(render_process_id) {}
+    : delegate_(std::move(delegate)), render_process_id_(render_process_id) {}
 
 MojoSafeBrowsingImpl::~MojoSafeBrowsingImpl() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
 }
 
 // static
-void MojoSafeBrowsingImpl::Create(
-    scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
-    scoped_refptr<SafeBrowsingUIManager> ui_manager,
+void MojoSafeBrowsingImpl::MaybeCreate(
     int render_process_id,
+    const base::Callback<UrlCheckerDelegate*()>& delegate_getter,
     const service_manager::BindSourceInfo& source_info,
     mojom::SafeBrowsingRequest request) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-  mojo::MakeStrongBinding(base::MakeUnique<MojoSafeBrowsingImpl>(
-                              std::move(database_manager),
-                              std::move(ui_manager), render_process_id),
+
+  scoped_refptr<UrlCheckerDelegate> delegate = delegate_getter.Run();
+
+  if (!delegate || !delegate->GetDatabaseManager()->IsSupported())
+    return;
+
+  mojo::MakeStrongBinding(base::WrapUnique(new MojoSafeBrowsingImpl(
+                              std::move(delegate), render_process_id)),
                           std::move(request));
 }
 
@@ -88,8 +86,7 @@
     CreateCheckerAndCheckCallback callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   auto checker_impl = base::MakeUnique<SafeBrowsingUrlCheckerImpl>(
-      static_cast<int>(load_flags), resource_type, database_manager_,
-      ui_manager_,
+      static_cast<int>(load_flags), resource_type, delegate_,
       base::Bind(&GetWebContentsFromID, render_process_id_,
                  static_cast<int>(render_frame_id)));
 
diff --git a/chrome/browser/safe_browsing/mojo_safe_browsing_impl.h b/components/safe_browsing/browser/mojo_safe_browsing_impl.h
similarity index 63%
rename from chrome/browser/safe_browsing/mojo_safe_browsing_impl.h
rename to components/safe_browsing/browser/mojo_safe_browsing_impl.h
index 606c950..057d247 100644
--- a/chrome/browser/safe_browsing/mojo_safe_browsing_impl.h
+++ b/components/safe_browsing/browser/mojo_safe_browsing_impl.h
@@ -2,14 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_SAFE_BROWSING_MOJO_SAFE_BROWSING_IMPL_H_
-#define CHROME_BROWSER_SAFE_BROWSING_MOJO_SAFE_BROWSING_IMPL_H_
+#ifndef COMPONENTS_SAFE_BROWSING_BROWSER_MOJO_SAFE_BROWSING_IMPL_H_
+#define COMPONENTS_SAFE_BROWSING_BROWSER_MOJO_SAFE_BROWSING_IMPL_H_
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "chrome/browser/safe_browsing/ui_manager.h"
+#include "components/safe_browsing/browser/url_checker_delegate.h"
 #include "components/safe_browsing/common/safe_browsing.mojom.h"
-#include "components/safe_browsing_db/database_manager.h"
 #include "ipc/ipc_message.h"
 
 namespace service_manager {
@@ -22,20 +21,18 @@
 // SafeBrowsing URL checks.
 class MojoSafeBrowsingImpl : public mojom::SafeBrowsing {
  public:
-  MojoSafeBrowsingImpl(
-      scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
-      scoped_refptr<SafeBrowsingUIManager> ui_manager,
-      int render_process_id);
   ~MojoSafeBrowsingImpl() override;
 
-  static void Create(
-      scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
-      scoped_refptr<SafeBrowsingUIManager> ui_manager,
+  static void MaybeCreate(
       int render_process_id,
+      const base::Callback<UrlCheckerDelegate*()>& delegate_getter,
       const service_manager::BindSourceInfo& source_info,
       mojom::SafeBrowsingRequest request);
 
  private:
+  MojoSafeBrowsingImpl(scoped_refptr<UrlCheckerDelegate> delegate,
+                       int render_process_id);
+
   // mojom::SafeBrowsing implementation.
   void CreateCheckerAndCheck(int32_t render_frame_id,
                              mojom::SafeBrowsingUrlCheckerRequest request,
@@ -44,8 +41,7 @@
                              content::ResourceType resource_type,
                              CreateCheckerAndCheckCallback callback) override;
 
-  scoped_refptr<SafeBrowsingDatabaseManager> database_manager_;
-  scoped_refptr<SafeBrowsingUIManager> ui_manager_;
+  scoped_refptr<UrlCheckerDelegate> delegate_;
   int render_process_id_ = MSG_ROUTING_NONE;
 
   DISALLOW_COPY_AND_ASSIGN(MojoSafeBrowsingImpl);
@@ -53,4 +49,4 @@
 
 }  // namespace safe_browsing
 
-#endif  // CHROME_BROWSER_SAFE_BROWSING_MOJO_SAFE_BROWSING_IMPL_H_
+#endif  // COMPONENTS_SAFE_BROWSING_BROWSER_MOJO_SAFE_BROWSING_IMPL_H_
diff --git a/chrome/browser/safe_browsing/safe_browsing_url_checker_impl.cc b/components/safe_browsing/browser/safe_browsing_url_checker_impl.cc
similarity index 71%
rename from chrome/browser/safe_browsing/safe_browsing_url_checker_impl.cc
rename to components/safe_browsing/browser/safe_browsing_url_checker_impl.cc
index 025639f..174e75e 100644
--- a/chrome/browser/safe_browsing/safe_browsing_url_checker_impl.cc
+++ b/components/safe_browsing/browser/safe_browsing_url_checker_impl.cc
@@ -2,11 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/safe_browsing/safe_browsing_url_checker_impl.h"
+#include "components/safe_browsing/browser/safe_browsing_url_checker_impl.h"
 
-#include "chrome/browser/prerender/prerender_contents.h"
-#include "chrome/browser/safe_browsing/ui_manager.h"
-#include "components/safe_browsing_db/v4_protocol_manager_util.h"
+#include "components/safe_browsing/browser/url_checker_delegate.h"
+#include "components/security_interstitials/content/unsafe_resource.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents.h"
 #include "net/base/load_flags.h"
@@ -25,14 +24,13 @@
 SafeBrowsingUrlCheckerImpl::SafeBrowsingUrlCheckerImpl(
     int load_flags,
     content::ResourceType resource_type,
-    scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
-    scoped_refptr<SafeBrowsingUIManager> ui_manager,
+    scoped_refptr<UrlCheckerDelegate> url_checker_delegate,
     const base::Callback<content::WebContents*()>& web_contents_getter)
     : load_flags_(load_flags),
       resource_type_(resource_type),
       web_contents_getter_(web_contents_getter),
-      database_manager_(std::move(database_manager)),
-      ui_manager_(std::move(ui_manager)),
+      url_checker_delegate_(std::move(url_checker_delegate)),
+      database_manager_(url_checker_delegate_->GetDatabaseManager()),
       weak_factory_(this) {}
 
 SafeBrowsingUrlCheckerImpl::~SafeBrowsingUrlCheckerImpl() {
@@ -71,8 +69,10 @@
   }
 
   if (load_flags_ & net::LOAD_PREFETCH) {
-    // TODO(yzshen): Destroy prerender contents if necessary.
-
+    // Destroy the prefetch with FINAL_STATUS_SAFEBROSWING.
+    if (resource_type_ == content::RESOURCE_TYPE_MAIN_FRAME)
+      url_checker_delegate_->MaybeDestroyPrerenderContents(
+          web_contents_getter_);
     BlockAndProcessUrls();
     return;
   }
@@ -95,35 +95,7 @@
   resource.threat_source = database_manager_->GetThreatSource();
 
   state_ = STATE_DISPLAYING_BLOCKING_PAGE;
-
-  content::BrowserThread::PostTask(
-      content::BrowserThread::UI, FROM_HERE,
-      base::BindOnce(&SafeBrowsingUrlCheckerImpl::StartDisplayingBlockingPage,
-                     weak_factory_.GetWeakPtr(), ui_manager_, resource));
-}
-
-// static
-void SafeBrowsingUrlCheckerImpl::StartDisplayingBlockingPage(
-    const base::WeakPtr<SafeBrowsingUrlCheckerImpl>& checker,
-    scoped_refptr<BaseUIManager> ui_manager,
-    const security_interstitials::UnsafeResource& resource) {
-  content::WebContents* web_contents = resource.web_contents_getter.Run();
-  if (web_contents) {
-    prerender::PrerenderContents* prerender_contents =
-        prerender::PrerenderContents::FromWebContents(web_contents);
-    if (prerender_contents) {
-      prerender_contents->Destroy(prerender::FINAL_STATUS_SAFE_BROWSING);
-    } else {
-      ui_manager->DisplayBlockingPage(resource);
-      return;
-    }
-  }
-
-  // Tab is gone or it's being prerendered.
-  content::BrowserThread::PostTask(
-      content::BrowserThread::IO, FROM_HERE,
-      base::BindOnce(&SafeBrowsingUrlCheckerImpl::BlockAndProcessUrls,
-                     checker));
+  url_checker_delegate_->StartDisplayingBlockingPageHelper(resource);
 }
 
 void SafeBrowsingUrlCheckerImpl::OnCheckUrlTimeout() {
@@ -146,14 +118,9 @@
     // TODO(yzshen): Consider moving CanCheckResourceType() to the renderer
     // side. That would save some IPCs. It requires a method on the
     // SafeBrowsing mojo interface to query all supported resource types.
-    // TODO(ricea):  SB_THREAT_TYPE_URL_UNWANTED should not be included for
-    // Android WebView.
     if (!database_manager_->CanCheckResourceType(resource_type_) ||
         database_manager_->CheckBrowseUrl(
-            urls_[next_index_],
-            CreateSBThreatTypeSet({SB_THREAT_TYPE_URL_PHISHING,
-                                   SB_THREAT_TYPE_URL_MALWARE,
-                                   SB_THREAT_TYPE_URL_UNWANTED}),
+            urls_[next_index_], url_checker_delegate_->GetThreatTypes(),
             this)) {
       std::move(callbacks_[next_index_]).Run(true);
       next_index_++;
diff --git a/chrome/browser/safe_browsing/safe_browsing_url_checker_impl.h b/components/safe_browsing/browser/safe_browsing_url_checker_impl.h
similarity index 78%
rename from chrome/browser/safe_browsing/safe_browsing_url_checker_impl.h
rename to components/safe_browsing/browser/safe_browsing_url_checker_impl.h
index 4815e99..b037d8d 100644
--- a/chrome/browser/safe_browsing/safe_browsing_url_checker_impl.h
+++ b/components/safe_browsing/browser/safe_browsing_url_checker_impl.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 CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_URL_CHECKER_IMPL_H_
-#define CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_URL_CHECKER_IMPL_H_
+#ifndef COMPONENTS_SAFE_BROWSING_BROWSER_SAFE_BROWSING_URL_CHECKER_IMPL_H_
+#define COMPONENTS_SAFE_BROWSING_BROWSER_SAFE_BROWSING_URL_CHECKER_IMPL_H_
 
 #include <vector>
 
@@ -20,14 +20,9 @@
 class WebContents;
 }
 
-namespace security_interstitials {
-struct UnsafeResource;
-}
-
 namespace safe_browsing {
 
-class SafeBrowsingUIManager;
-class BaseUIManager;
+class UrlCheckerDelegate;
 
 // A SafeBrowsingUrlCheckerImpl instance is used to perform SafeBrowsing check
 // for a URL and its redirect URLs. It implements Mojo interface so that it can
@@ -36,9 +31,6 @@
 // directly instead of through Mojo.
 // Used when --enable-network-service is in effect.
 //
-// TODO(yzshen): Handle the case where SafeBrowsing is not enabled, or
-// !database_manager()->IsSupported().
-// TODO(yzshen): Make sure it also works on Andorid.
 // TODO(yzshen): Do all the logging like what BaseResourceThrottle does.
 class SafeBrowsingUrlCheckerImpl : public mojom::SafeBrowsingUrlChecker,
                                    public SafeBrowsingDatabaseManager::Client {
@@ -46,8 +38,7 @@
   SafeBrowsingUrlCheckerImpl(
       int load_flags,
       content::ResourceType resource_type,
-      scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
-      scoped_refptr<SafeBrowsingUIManager> ui_manager,
+      scoped_refptr<UrlCheckerDelegate> url_checker_delegate,
       const base::Callback<content::WebContents*()>& web_contents_getter);
 
   ~SafeBrowsingUrlCheckerImpl() override;
@@ -61,11 +52,6 @@
                               SBThreatType threat_type,
                               const ThreatMetadata& metadata) override;
 
-  static void StartDisplayingBlockingPage(
-      const base::WeakPtr<SafeBrowsingUrlCheckerImpl>& checker,
-      scoped_refptr<BaseUIManager> ui_manager,
-      const security_interstitials::UnsafeResource& resource);
-
   void OnCheckUrlTimeout();
 
   void ProcessUrls();
@@ -88,8 +74,8 @@
   const int load_flags_;
   const content::ResourceType resource_type_;
   base::Callback<content::WebContents*()> web_contents_getter_;
+  scoped_refptr<UrlCheckerDelegate> url_checker_delegate_;
   scoped_refptr<SafeBrowsingDatabaseManager> database_manager_;
-  scoped_refptr<BaseUIManager> ui_manager_;
 
   // The redirect chain for this resource, including the original URL and
   // subsequent redirect URLs.
@@ -113,4 +99,4 @@
 
 }  // namespace safe_browsing
 
-#endif  // CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_URL_CHECKER_IMPL_H_
+#endif  // COMPONENTS_SAFE_BROWSING_BROWSER_SAFE_BROWSING_URL_CHECKER_IMPL_H_
diff --git a/components/safe_browsing/browser/url_checker_delegate.h b/components/safe_browsing/browser/url_checker_delegate.h
new file mode 100644
index 0000000..02f442e
--- /dev/null
+++ b/components/safe_browsing/browser/url_checker_delegate.h
@@ -0,0 +1,52 @@
+// Copyright 2017 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_SAFE_BROWSING_BROWSER_URL_CHECKER_DELEGATE_H_
+#define COMPONENTS_SAFE_BROWSING_BROWSER_URL_CHECKER_DELEGATE_H_
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "components/safe_browsing_db/v4_protocol_manager_util.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace security_interstitials {
+struct UnsafeResource;
+}
+
+namespace safe_browsing {
+
+class BaseUIManager;
+class SafeBrowsingDatabaseManager;
+
+// Delegate interface for SafeBrowsingUrlCheckerImpl. SafeBrowsingUrlCheckerImpl
+// is embedder-independent. It delegates to this interface those operations that
+// different embedders (Chrome and Android WebView) handle differently.
+//
+// All methods should only be called from the IO thread.
+class UrlCheckerDelegate
+    : public base::RefCountedThreadSafe<UrlCheckerDelegate> {
+ public:
+  // Destroys prerender contents if necessary.
+  virtual void MaybeDestroyPrerenderContents(
+      const base::Callback<content::WebContents*()>& web_contents_getter) = 0;
+
+  // Starts displaying the SafeBrowsing interstitial page.
+  virtual void StartDisplayingBlockingPageHelper(
+      const security_interstitials::UnsafeResource& resource) = 0;
+
+  virtual const SBThreatTypeSet& GetThreatTypes() = 0;
+  virtual SafeBrowsingDatabaseManager* GetDatabaseManager() = 0;
+  virtual BaseUIManager* GetUIManager() = 0;
+
+ protected:
+  friend class base::RefCountedThreadSafe<UrlCheckerDelegate>;
+  virtual ~UrlCheckerDelegate() {}
+};
+
+}  // namespace safe_browsing
+
+#endif  // COMPONENTS_SAFE_BROWSING_BROWSER_URL_CHECKER_DELEGATE_H_
diff --git a/components/safe_browsing/common/BUILD.gn b/components/safe_browsing/common/BUILD.gn
index 61bc49b..6de5638 100644
--- a/components/safe_browsing/common/BUILD.gn
+++ b/components/safe_browsing/common/BUILD.gn
@@ -24,6 +24,10 @@
     "//ipc",
     "//url/ipc:url_ipc",
   ]
+
+  public_deps = [
+    ":interfaces",
+  ]
 }
 
 static_library("safe_browsing_prefs") {
diff --git a/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.cc b/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.cc
index d8ae42f..2db31a5e 100644
--- a/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.cc
+++ b/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.cc
@@ -120,7 +120,7 @@
         delay, base::TimeDelta::FromMicroseconds(1),
         base::TimeDelta::FromSeconds(10), 50);
   }
-  navigation_handle()->Resume();
+  Resume();
 }
 
 AsyncDocumentSubresourceFilter*
diff --git a/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.cc b/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.cc
index ad6b79b..21a5f71a 100644
--- a/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.cc
+++ b/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.cc
@@ -110,12 +110,12 @@
     const bool block_and_collapse_is_supported =
         content::IsBrowserSideNavigationEnabled() ||
         stage == ThrottlingStage::WillStartRequest;
-    navigation_handle()->CancelDeferredNavigation(
+    CancelDeferredNavigation(
         block_and_collapse_is_supported
             ? content::NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE
             : content::NavigationThrottle::CANCEL);
   } else {
-    navigation_handle()->Resume();
+    Resume();
   }
 }
 
diff --git a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc
index 657ab8d..5c578c41 100644
--- a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc
+++ b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc
@@ -133,7 +133,7 @@
   stored_result = result;
   if (!defer_time_.is_null() && request_id == check_results_.size() - 1) {
     NotifyResult();
-    navigation_handle()->Resume();
+    Resume();
   }
 }
 
diff --git a/components/subresource_filter/content/renderer/subresource_filter_agent.cc b/components/subresource_filter/content/renderer/subresource_filter_agent.cc
index c3685ee..8c66b5b 100644
--- a/components/subresource_filter/content/renderer/subresource_filter_agent.cc
+++ b/components/subresource_filter/content/renderer/subresource_filter_agent.cc
@@ -21,12 +21,14 @@
 #include "components/subresource_filter/core/common/scoped_timers.h"
 #include "components/subresource_filter/core/common/time_measurements.h"
 #include "content/public/common/content_features.h"
+#include "content/public/common/url_constants.h"
 #include "content/public/renderer/render_frame.h"
 #include "ipc/ipc_message.h"
 #include "third_party/WebKit/public/platform/WebWorkerFetchContext.h"
 #include "third_party/WebKit/public/web/WebDataSource.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
+#include "url/url_constants.h"
 
 namespace subresource_filter {
 
@@ -34,6 +36,7 @@
     content::RenderFrame* render_frame,
     UnverifiedRulesetDealer* ruleset_dealer)
     : content::RenderFrameObserver(render_frame),
+      content::RenderFrameObserverTracker<SubresourceFilterAgent>(render_frame),
       ruleset_dealer_(ruleset_dealer) {
   DCHECK(ruleset_dealer);
 }
@@ -62,6 +65,20 @@
       render_frame()->GetRoutingID(), statistics));
 }
 
+// static
+ActivationState SubresourceFilterAgent::GetParentActivationState(
+    content::RenderFrame* render_frame) {
+  blink::WebFrame* parent =
+      render_frame ? render_frame->GetWebFrame()->Parent() : nullptr;
+  if (parent && parent->IsWebLocalFrame()) {
+    auto* agent = SubresourceFilterAgent::Get(
+        content::RenderFrame::FromWebFrame(parent->ToWebLocalFrame()));
+    if (agent && agent->filter_for_last_committed_load_)
+      return agent->filter_for_last_committed_load_->activation_state();
+  }
+  return ActivationState(ActivationLevel::DISABLED);
+}
+
 void SubresourceFilterAgent::OnActivateForNextCommittedLoad(
     ActivationState activation_state) {
   activation_state_for_next_commit_ = activation_state;
@@ -145,7 +162,15 @@
   // TODO(csharrison): Use WebURL and WebSecurityOrigin for efficiency here,
   // which require changes to the unit tests.
   const GURL& url = GetDocumentURL();
-  if (url.SchemeIsHTTPOrHTTPS() || url.SchemeIsFile()) {
+
+  bool use_parent_activation = ShouldUseParentActivation(url);
+  if (use_parent_activation) {
+    activation_state_for_next_commit_ =
+        GetParentActivationState(render_frame());
+  }
+
+  if (url.SchemeIsHTTPOrHTTPS() || url.SchemeIsFile() ||
+      use_parent_activation) {
     RecordHistogramsOnLoadCommitted();
     if (activation_state_for_next_commit_.activation_level !=
             ActivationLevel::DISABLED &&
@@ -214,4 +239,14 @@
                          AsWeakPtr())));
 }
 
+bool SubresourceFilterAgent::ShouldUseParentActivation(const GURL& url) const {
+  // TODO(csharrison): It is not always true that a data URL can use its
+  // parent's activation in OOPIF mode, where the resulting data frame will
+  // be same-process to its initiator. See crbug.com/739777 for more
+  // information.
+  return render_frame() && !render_frame()->IsMainFrame() &&
+         (url.SchemeIs(url::kDataScheme) || url == url::kAboutBlankURL ||
+          url == content::kAboutSrcDocURL);
+}
+
 }  // namespace subresource_filter
diff --git a/components/subresource_filter/content/renderer/subresource_filter_agent.h b/components/subresource_filter/content/renderer/subresource_filter_agent.h
index a990a1c..3b886c3 100644
--- a/components/subresource_filter/content/renderer/subresource_filter_agent.h
+++ b/components/subresource_filter/content/renderer/subresource_filter_agent.h
@@ -11,6 +11,7 @@
 #include "base/memory/weak_ptr.h"
 #include "components/subresource_filter/core/common/activation_state.h"
 #include "content/public/renderer/render_frame_observer.h"
+#include "content/public/renderer/render_frame_observer_tracker.h"
 #include "url/gurl.h"
 
 namespace blink {
@@ -29,6 +30,7 @@
 // to do so by the driver.
 class SubresourceFilterAgent
     : public content::RenderFrameObserver,
+      public content::RenderFrameObserverTracker<SubresourceFilterAgent>,
       public base::SupportsWeakPtr<SubresourceFilterAgent> {
  public:
   // The |ruleset_dealer| must not be null and must outlive this instance. The
@@ -57,6 +59,11 @@
       const DocumentLoadStatistics& statistics);
 
  private:
+  // Assumes that the parent will be in a local frame relative to this one, upon
+  // construction.
+  static ActivationState GetParentActivationState(
+      content::RenderFrame* render_frame);
+
   void OnActivateForNextCommittedLoad(ActivationState activation_state);
   void RecordHistogramsOnLoadCommitted();
   void RecordHistogramsOnLoadFinished();
@@ -71,6 +78,11 @@
   bool OnMessageReceived(const IPC::Message& message) override;
   void WillCreateWorkerFetchContext(blink::WebWorkerFetchContext*) override;
 
+  // Subframe navigations matching these URLs/schemes will not trigger
+  // ReadyToCommitNavigation in the browser process, so they must be treated
+  // specially to maintain activation.
+  bool ShouldUseParentActivation(const GURL& url) const;
+
   // Owned by the ChromeContentRendererClient and outlives us.
   UnverifiedRulesetDealer* ruleset_dealer_;
 
diff --git a/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc b/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
index eb8a67b..ab9962885 100644
--- a/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
+++ b/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
@@ -249,6 +249,10 @@
   histogram_tester.ExpectTotalCount(kEvaluationTotalCPUDuration, 0);
 }
 
+// Never inject a filter for main frame about:blank loads, even though we do for
+// subframe loads. Those are tested via browser tests.
+// TODO(csharrison): Refactor these unit tests so it is easier to test with
+// real backing RenderFrames.
 TEST_F(SubresourceFilterAgentTest, EmptyDocumentLoad_NoFilterIsInjected) {
   base::HistogramTester histogram_tester;
   ExpectNoSubresourceFilterGetsInjected();
diff --git a/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.cc b/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.cc
index 0d1e297..f44fbce6 100644
--- a/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.cc
+++ b/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.cc
@@ -107,7 +107,8 @@
     ActivationState activation_state,
     scoped_refptr<const MemoryMappedRuleset> ruleset,
     base::OnceClosure first_disallowed_load_callback)
-    : filter_(std::move(document_origin), activation_state, std::move(ruleset)),
+    : activation_state_(activation_state),
+      filter_(std::move(document_origin), activation_state, std::move(ruleset)),
       first_disallowed_load_callback_(
           std::move(first_disallowed_load_callback)) {}
 
@@ -130,7 +131,7 @@
 }
 
 bool WebDocumentSubresourceFilterImpl::ShouldLogToConsole() {
-  return filter_.activation_state().enable_logging;
+  return activation_state().enable_logging;
 }
 
 WebLoadPolicy WebDocumentSubresourceFilterImpl::getLoadPolicyImpl(
diff --git a/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.h b/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.h
index 606509b..826a07e 100644
--- a/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.h
+++ b/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.h
@@ -68,11 +68,16 @@
   void ReportDisallowedLoad() override;
   bool ShouldLogToConsole() override;
 
+  const ActivationState& activation_state() const {
+    return filter_.activation_state();
+  }
+
  private:
   LoadPolicy getLoadPolicyImpl(
       const blink::WebURL& url,
       url_pattern_index::proto::ElementType element_type);
 
+  ActivationState activation_state_;
   DocumentSubresourceFilter filter_;
   base::OnceClosure first_disallowed_load_callback_;
 
diff --git a/components/subresource_filter/core/common/document_subresource_filter.h b/components/subresource_filter/core/common/document_subresource_filter.h
index 02550c6..66496e3 100644
--- a/components/subresource_filter/core/common/document_subresource_filter.h
+++ b/components/subresource_filter/core/common/document_subresource_filter.h
@@ -44,7 +44,7 @@
 
   ~DocumentSubresourceFilter();
 
-  ActivationState activation_state() const { return activation_state_; }
+  const ActivationState& activation_state() const { return activation_state_; }
   const DocumentLoadStatistics& statistics() const { return statistics_; }
 
   // WARNING: This is only to allow DocumentSubresourceFilter's wrappers to
diff --git a/chrome/test/data/payments/.eslintrc.js b/components/test/data/payments/.eslintrc.js
similarity index 65%
rename from chrome/test/data/payments/.eslintrc.js
rename to components/test/data/payments/.eslintrc.js
index ae5ba4a..d9efa98 100644
--- a/chrome/test/data/payments/.eslintrc.js
+++ b/components/test/data/payments/.eslintrc.js
@@ -11,14 +11,17 @@
     'no-restricted-properties': 0,
     'no-irregular-whitespace': 2,
     'no-unexpected-multiline': 2,
-    'valid-jsdoc': [2, {
-      requireParamDescription: true,
-      requireReturnDescription: true,
-      requireReturn: false,
-      prefer: {
-        returns: 'return',
+    'valid-jsdoc': [
+      2,
+      {
+        requireParamDescription: true,
+        requireReturnDescription: true,
+        requireReturn: false,
+        prefer: {
+          returns: 'return',
+        },
       },
-    }],
+    ],
     'curly': [2, 'multi-line'],
     'guard-for-in': 2,
     'no-caller': 2,
@@ -30,14 +33,20 @@
     'no-new-wrappers': 2,
     'no-throw-literal': 2,
     'no-with': 2,
-    'no-unused-vars': [2, {
-      args: 'none',
-    }],
+    'no-unused-vars': [
+      2,
+      {
+        args: 'none',
+      },
+    ],
     'array-bracket-spacing': [2, 'never'],
     'brace-style': 2,
-    'camelcase': [2, {
-      properties: 'never',
-    }],
+    'camelcase': [
+      2,
+      {
+        properties: 'never',
+      },
+    ],
     'comma-dangle': [2, 'always-multiline'],
     'comma-spacing': 2,
     'comma-style': 2,
@@ -47,37 +56,45 @@
     'key-spacing': 2,
     'keyword-spacing': 2,
     'linebreak-style': 2,
-    'max-len': [2, {
-      code: 80,
-      tabWidth: 2,
-      ignoreUrls: true,
-    }],
+    'max-len': [
+      2,
+      {
+        code: 80,
+        tabWidth: 2,
+        ignoreUrls: true,
+      },
+    ],
     'new-cap': 2,
     'no-array-constructor': 2,
     'no-mixed-spaces-and-tabs': 2,
-    'no-multiple-empty-lines': [2, {
-      max: 2,
-    }],
+    'no-multiple-empty-lines': [
+      2,
+      {
+        max: 2,
+      },
+    ],
     'no-new-object': 2,
     'no-trailing-spaces': 2,
     'object-curly-spacing': 2,
-    'one-var': [2, {
-      var: 'never',
-      let: 'never',
-      const: 'never',
-    }],
     'padded-blocks': [2, 'never'],
     'quote-props': [2, 'consistent'],
-    'quotes': [2, 'single', {
-      allowTemplateLiterals: true,
-    }],
-    'require-jsdoc': [2, {
-      require: {
-        FunctionDeclaration: true,
-        MethodDefinition: true,
-        ClassDeclaration: true,
+    'quotes': [
+      2,
+      'single',
+      {
+        allowTemplateLiterals: true,
       },
-    }],
+    ],
+    'require-jsdoc': [
+      2,
+      {
+        require: {
+          FunctionDeclaration: true,
+          MethodDefinition: true,
+          ClassDeclaration: true,
+        },
+      },
+    ],
     'semi-spacing': 2,
     'semi': 2,
     'space-before-blocks': 2,
@@ -88,7 +105,6 @@
     'generator-star-spacing': [2, 'after'],
     'no-new-symbol': 2,
     'no-this-before-super': 2,
-    'no-var': 2,
     'prefer-rest-params': 2,
     'prefer-spread': 2,
     'rest-spread-spacing': 2,
diff --git a/chrome/test/data/payments/PRESUBMIT.py b/components/test/data/payments/PRESUBMIT.py
similarity index 100%
rename from chrome/test/data/payments/PRESUBMIT.py
rename to components/test/data/payments/PRESUBMIT.py
diff --git a/chrome/test/data/payments/abort.js b/components/test/data/payments/abort.js
similarity index 81%
rename from chrome/test/data/payments/abort.js
rename to components/test/data/payments/abort.js
index 26c8b5c1..4d5ba82 100644
--- a/chrome/test/data/payments/abort.js
+++ b/components/test/data/payments/abort.js
@@ -27,11 +27,13 @@
  */
 function abort() {  // eslint-disable-line no-unused-vars
   try {
-    request.abort().then(() => {
-      print('Aborted');
-    }).catch(() => {
-      print('Cannot abort');
-    });
+    request.abort()
+        .then(function() {
+          print('Aborted');
+        })
+        .catch(function() {
+          print('Cannot abort');
+        });
   } catch (error) {
     print(error.message);
   }
diff --git a/chrome/test/data/payments/alicepay_bobpay_charliepay_and_cards.js b/components/test/data/payments/alicepay_bobpay_charliepay_and_cards.js
similarity index 70%
rename from chrome/test/data/payments/alicepay_bobpay_charliepay_and_cards.js
rename to components/test/data/payments/alicepay_bobpay_charliepay_and_cards.js
index db3f719b..558cdf5 100644
--- a/chrome/test/data/payments/alicepay_bobpay_charliepay_and_cards.js
+++ b/components/test/data/payments/alicepay_bobpay_charliepay_and_cards.js
@@ -13,15 +13,23 @@
 function buy() {  // eslint-disable-line no-unused-vars
   try {
     new PaymentRequest(
-        [{supportedMethods: ['https://alicepay.com', 'https://bobpay.com',
-            'https://charliepay.com', 'visa', 'mastercard']}],
+        [{
+          supportedMethods: [
+            'https://alicepay.com',
+            'https://bobpay.com',
+            'https://charliepay.com',
+            'visa',
+            'mastercard',
+          ],
+        }],
         {total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}})
         .show()
         .then(function(resp) {
           resp.complete('success')
               .then(function() {
-                print(resp.methodName + '<br>' +
-                      JSON.stringify(resp.details, undefined, 2));
+                print(
+                    resp.methodName + '<br>' +
+                    JSON.stringify(resp.details, undefined, 2));
               })
               .catch(function(error) {
                 print(error.message);
diff --git a/chrome/test/data/payments/app.json b/components/test/data/payments/app.json
similarity index 100%
rename from chrome/test/data/payments/app.json
rename to components/test/data/payments/app.json
diff --git a/components/test/data/payments/blob_url.js b/components/test/data/payments/blob_url.js
new file mode 100644
index 0000000..cc4c423
--- /dev/null
+++ b/components/test/data/payments/blob_url.js
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2017 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.
+ */
+
+/** Requests payment via a blob URL. */
+function buy() {  // eslint-disable-line no-unused-vars
+  var spoof = function() {
+    var payload =
+        'PGh0bWw+PGhlYWQ+PG1ldGEgbmFtZT0idmlld3BvcnQiIGNvbnRlbnQ9IndpZHRoPWRldmljZS13aWR0aCwgaW5pdGlhbC1zY2FsZT0yLCBtYXhpbXVtLXNjYWxlPTIiPjwvaGVhZD48Ym9keT48ZGl2IGlkPSJyZXN1bHQiPjwvZGl2PjxzY3JpcHQ+dHJ5IHsgIG5ldyBQYXltZW50UmVxdWVzdChbe3N1cHBvcnRlZE1ldGhvZHM6IFsiYmFzaWMtY2FyZCJdfV0sICAgIHt0b3RhbDoge2xhYmVsOiAiVCIsIGFtb3VudDoge2N1cnJlbmN5OiAiVVNEIiwgdmFsdWU6ICIxLjAwIn19fSkgIC5zaG93KCkgIC50aGVuKGZ1bmN0aW9uKGluc3RydW1lbnRSZXNwb25zZSkgeyAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgicmVzdWx0IikuaW5uZXJIVE1MID0gIlJlc29sdmVkIjsgIH0pLmNhdGNoKGZ1bmN0aW9uKGUpIHsgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoInJlc3VsdCIpLmlubmVySFRNTCA9ICJSZWplY3RlZDogIiArIGU7ICB9KTt9IGNhdGNoKGUpIHsgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCJyZXN1bHQiKS5pbm5lckhUTUwgPSAiRXhjZXB0aW9uOiAiICsgZTt9PC9zY3JpcHQ+PC9ib2R5PjwvaHRtbD4=';  // eslint-disable-line max-len
+    document.write(atob(payload));
+  };
+  window.location.href =
+      URL.createObjectURL(new Blob(['<script>(', spoof, ')();</script>'], {
+        type: 'text/html',
+      }));
+}
diff --git a/chrome/test/data/payments/bobpay.js b/components/test/data/payments/bobpay.js
similarity index 87%
rename from chrome/test/data/payments/bobpay.js
rename to components/test/data/payments/bobpay.js
index 9e4848c6..ac32393c 100644
--- a/chrome/test/data/payments/bobpay.js
+++ b/components/test/data/payments/bobpay.js
@@ -19,8 +19,9 @@
         .then(function(resp) {
           resp.complete('success')
               .then(function() {
-                print(resp.methodName + '<br>' +
-                      JSON.stringify(resp.details, undefined, 2));
+                print(
+                    resp.methodName + '<br>' +
+                    JSON.stringify(resp.details, undefined, 2));
               })
               .catch(function(error) {
                 print('complete() rejected<br>' + error);
diff --git a/chrome/test/data/payments/bobpay_and_basic_card_with_basic_card_modifiers.js b/components/test/data/payments/bobpay_and_basic_card_with_basic_card_modifiers.js
similarity index 98%
rename from chrome/test/data/payments/bobpay_and_basic_card_with_basic_card_modifiers.js
rename to components/test/data/payments/bobpay_and_basic_card_with_basic_card_modifiers.js
index de2ee33..42aaae6 100644
--- a/chrome/test/data/payments/bobpay_and_basic_card_with_basic_card_modifiers.js
+++ b/components/test/data/payments/bobpay_and_basic_card_with_basic_card_modifiers.js
@@ -13,8 +13,7 @@
 function buy() {  // eslint-disable-line no-unused-vars
   try {
     new PaymentRequest(
-        [{supportedMethods: ['https://bobpay.com', 'basic-card']}],
-        {
+        [{supportedMethods: ['https://bobpay.com', 'basic-card']}], {
           total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}},
           modifiers: [{
             supportedMethods: ['basic-card'],
@@ -56,8 +55,7 @@
 function creditSupportedType() {  // eslint-disable-line no-unused-vars
   try {
     new PaymentRequest(
-        [{supportedMethods: ['https://bobpay.com', 'basic-card']}],
-        {
+        [{supportedMethods: ['https://bobpay.com', 'basic-card']}], {
           total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}},
           modifiers: [{
             supportedMethods: ['basic-card'],
@@ -102,8 +100,7 @@
 function debitSupportedType() {  // eslint-disable-line no-unused-vars
   try {
     new PaymentRequest(
-        [{supportedMethods: ['https://bobpay.com', 'basic-card']}],
-        {
+        [{supportedMethods: ['https://bobpay.com', 'basic-card']}], {
           total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}},
           modifiers: [{
             supportedMethods: ['basic-card'],
@@ -148,8 +145,7 @@
 function visaSupportedNetwork() {  // eslint-disable-line no-unused-vars
   try {
     new PaymentRequest(
-        [{supportedMethods: ['https://bobpay.com', 'basic-card']}],
-        {
+        [{supportedMethods: ['https://bobpay.com', 'basic-card']}], {
           total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}},
           modifiers: [{
             supportedMethods: ['basic-card'],
@@ -196,8 +192,7 @@
 function mastercardSupportedNetwork() {  // eslint-disable-line no-unused-vars
   try {
     new PaymentRequest(
-        [{supportedMethods: ['https://bobpay.com', 'basic-card']}],
-        {
+        [{supportedMethods: ['https://bobpay.com', 'basic-card']}], {
           total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}},
           modifiers: [{
             supportedMethods: ['basic-card'],
diff --git a/chrome/test/data/payments/bobpay_and_basic_card_with_modifiers.js b/components/test/data/payments/bobpay_and_basic_card_with_modifiers.js
similarity index 86%
rename from chrome/test/data/payments/bobpay_and_basic_card_with_modifiers.js
rename to components/test/data/payments/bobpay_and_basic_card_with_modifiers.js
index 0a3c73229..1c89cf5e 100644
--- a/chrome/test/data/payments/bobpay_and_basic_card_with_modifiers.js
+++ b/components/test/data/payments/bobpay_and_basic_card_with_modifiers.js
@@ -13,20 +13,16 @@
 function buy() {  // eslint-disable-line no-unused-vars
   try {
     new PaymentRequest(
-        [{supportedMethods: ['https://bobpay.com', 'basic-card']}],
-        {
+        [{supportedMethods: ['https://bobpay.com', 'basic-card']}], {
           total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}},
           modifiers: [{
             supportedMethods: ['https://bobpay.com'],
-            total: {
-              label: 'Total',
-              amount: {currency: 'USD', value: '4.00'}
-            },
+            total: {label: 'Total', amount: {currency: 'USD', value: '4.00'}},
             additionalDisplayItems: [{
               label: 'BobPay discount',
-              amount: {currency: 'USD', value: '-1.00'}
+              amount: {currency: 'USD', value: '-1.00'},
             }],
-            data: {discountProgramParticipantId: '86328764873265'}
+            data: {discountProgramParticipantId: '86328764873265'},
           }],
         })
         .show()
diff --git a/chrome/test/data/payments/bobpay_and_cards.js b/components/test/data/payments/bobpay_and_cards.js
similarity index 86%
rename from chrome/test/data/payments/bobpay_and_cards.js
rename to components/test/data/payments/bobpay_and_cards.js
index 7cd3a2e9..8d44a31e 100644
--- a/chrome/test/data/payments/bobpay_and_cards.js
+++ b/components/test/data/payments/bobpay_and_cards.js
@@ -19,8 +19,9 @@
         .then(function(resp) {
           resp.complete('success')
               .then(function() {
-                print(resp.methodName + '<br>' +
-                      JSON.stringify(resp.details, undefined, 2));
+                print(
+                    resp.methodName + '<br>' +
+                    JSON.stringify(resp.details, undefined, 2));
               })
               .catch(function(error) {
                 print(error.message);
diff --git a/chrome/test/data/payments/bobpay_ui_skip.js b/components/test/data/payments/bobpay_ui_skip.js
similarity index 89%
rename from chrome/test/data/payments/bobpay_ui_skip.js
rename to components/test/data/payments/bobpay_ui_skip.js
index 62b4680..8bce925 100644
--- a/chrome/test/data/payments/bobpay_ui_skip.js
+++ b/components/test/data/payments/bobpay_ui_skip.js
@@ -23,8 +23,9 @@
         .then(function(resp) {
           resp.complete('success')
               .then(function() {
-                print(resp.methodName + '<br>' +
-                      JSON.stringify(resp.details, undefined, 2));
+                print(
+                    resp.methodName + '<br>' +
+                    JSON.stringify(resp.details, undefined, 2));
               })
               .catch(function(error) {
                 print('complete() rejected<br>' + error);
diff --git a/components/test/data/payments/bobpay_ui_skip_preload.js b/components/test/data/payments/bobpay_ui_skip_preload.js
new file mode 100644
index 0000000..c22b65f
--- /dev/null
+++ b/components/test/data/payments/bobpay_ui_skip_preload.js
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2017 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.
+ */
+
+/**
+ * Builds PaymentRequest for Bob Pay, but does not show any UI yet.
+ *
+ * @return {PaymentRequest} The PaymentRequest object.
+ */
+function initPaymentRequest() {
+  var supportedInstruments = [{
+    supportedMethods: ['https://bobpay.com'],
+  }];
+
+  var details = {
+    total: {
+      label: 'Donation',
+      amount: {
+        currency: 'USD',
+        value: '55.00',
+      },
+    },
+    displayItems: [
+      {
+        label: 'Original donation amount',
+        amount: {
+          currency: 'USD',
+          value: '65.00',
+        },
+      },
+      {
+        label: 'Friends and family discount',
+        amount: {
+          currency: 'USD',
+          value: '-10.00',
+        },
+      },
+    ],
+  };
+
+  return new PaymentRequest(supportedInstruments, details);
+}
+
+/**
+ * Launches the PaymentRequest UI with Bob Pay as the only payment method.
+ * Preloads the second instance of PaymentRequest while the first instance is
+ * showing.
+ */
+function buy() {  // eslint-disable-line no-unused-vars
+  var request = initPaymentRequest();
+  request.show()
+      .then(function(instrumentResponse) {
+        window.setTimeout(function() {
+          instrumentResponse.complete('success')
+              .then(function() {
+                print(JSON.stringify(instrumentResponse, undefined, 2));
+              })
+              .catch(function(err) {
+                print(err);
+              });
+        }, 500);
+      })
+      .catch(function(err) {
+        print(err);
+      });
+  request = initPaymentRequest();
+}
diff --git a/chrome/test/data/payments/can_make_payment_metrics.js b/components/test/data/payments/can_make_payment_metrics.js
similarity index 72%
rename from chrome/test/data/payments/can_make_payment_metrics.js
rename to components/test/data/payments/can_make_payment_metrics.js
index 2da01920..693dd5d 100644
--- a/chrome/test/data/payments/can_make_payment_metrics.js
+++ b/components/test/data/payments/can_make_payment_metrics.js
@@ -23,9 +23,13 @@
               .then(function() {
                 print(JSON.stringify(resp, undefined, 2));
               })
-              .catch(function(error) { print(error); });
+              .catch(function(error) {
+                print(error);
+              });
         })
-        .catch(function(error) { print(error); });
+        .catch(function(error) {
+          print(error);
+        });
   } catch (error) {
     print(error.message);
   }
@@ -40,17 +44,25 @@
         [{supportedMethods: ['https://bobpay.com', 'visa']}],
         {total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}});
     request.canMakePayment()
-        .then(function(result) { print(result); })
-        .catch(function(error) { print(error); });
+        .then(function(result) {
+          print(result);
+        })
+        .catch(function(error) {
+          print(error);
+        });
     request.show()
         .then(function(resp) {
           resp.complete('success')
               .then(function() {
                 print(JSON.stringify(resp, undefined, 2));
               })
-              .catch(function(error) { print(error); });
+              .catch(function(error) {
+                print(error);
+              });
         })
-        .catch(function(error) { print(error); });
+        .catch(function(error) {
+          print(error);
+        });
   } catch (error) {
     print(error.message);
   }
@@ -65,8 +77,12 @@
         [{supportedMethods: ['https://bobpay.com', 'visa']}],
         {total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}});
     request.canMakePayment()
-        .then(function(result) { print(result); })
-        .catch(function(error) { print(error); });
+        .then(function(result) {
+          print(result);
+        })
+        .catch(function(error) {
+          print(error);
+        });
   } catch (error) {
     print(error.message);
   }
@@ -77,11 +93,13 @@
  */
 function abort() {  // eslint-disable-line no-unused-vars
   try {
-    request.abort().then(() => {
-      print('Aborted');
-    }).catch(() => {
-      print('Cannot abort');
-    });
+    request.abort()
+        .then(function() {
+          print('Aborted');
+        })
+        .catch(function() {
+          print('Cannot abort');
+        });
   } catch (error) {
     print(error.message);
   }
diff --git a/chrome/test/data/payments/can_make_payment_query.js b/components/test/data/payments/can_make_payment_query.js
similarity index 100%
rename from chrome/test/data/payments/can_make_payment_query.js
rename to components/test/data/payments/can_make_payment_query.js
diff --git a/chrome/test/data/payments/can_make_payment_query_bobpay.js b/components/test/data/payments/can_make_payment_query_bobpay.js
similarity index 73%
rename from chrome/test/data/payments/can_make_payment_query_bobpay.js
rename to components/test/data/payments/can_make_payment_query_bobpay.js
index 25eae15..97e535b 100644
--- a/chrome/test/data/payments/can_make_payment_query_bobpay.js
+++ b/components/test/data/payments/can_make_payment_query_bobpay.js
@@ -13,6 +13,7 @@
 /**
  * Sets the |first| variable and prints both |first| and |second| only if both
  * were set.
+ * @param {object} result The object to print.
  */
 function printFirst(result) {
   first = result.toString();
@@ -24,6 +25,7 @@
 /**
  * Sets the |second| variable and prints both |first| and |second| only if both
  * were set.
+ * @param {object} result The object to print.
  */
 function printSecond(result) {
   second = result.toString();
@@ -44,8 +46,12 @@
         [{supportedMethods: ['https://bobpay.com']}],
         {total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}})
         .canMakePayment()
-        .then(function(result) { printFirst(result); })
-        .catch(function(error) { printFirst(error); });
+        .then(function(result) {
+          printFirst(result);
+        })
+        .catch(function(error) {
+          printFirst(error);
+        });
   } catch (error) {
     printFirst(error);
   }
@@ -55,8 +61,12 @@
         [{supportedMethods: ['https://bobpay.com']}],
         {total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}})
         .canMakePayment()
-        .then(function(result) { printSecond(result); })
-        .catch(function(error) { printSecond(error); });
+        .then(function(result) {
+          printSecond(result);
+        })
+        .catch(function(error) {
+          printSecond(error);
+        });
   } catch (error) {
     printSecond(error);
   }
@@ -74,8 +84,12 @@
         [{supportedMethods: ['https://bobpay.com']}],
         {total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}})
         .canMakePayment()
-        .then(function(result) { printFirst(result); })
-        .catch(function(error) { printFirst(error); });
+        .then(function(result) {
+          printFirst(result);
+        })
+        .catch(function(error) {
+          printFirst(error);
+        });
   } catch (error) {
     printFirst(error);
   }
@@ -85,8 +99,12 @@
         [{supportedMethods: ['https://alicepay.com']}],
         {total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}})
         .canMakePayment()
-        .then(function(result) { printSecond(result); })
-        .catch(function(error) { printSecond(error); });
+        .then(function(result) {
+          printSecond(result);
+        })
+        .catch(function(error) {
+          printSecond(error);
+        });
   } catch (error) {
     printSecond(error);
   }
diff --git a/chrome/test/data/payments/can_make_payment_query_cc.js b/components/test/data/payments/can_make_payment_query_cc.js
similarity index 93%
rename from chrome/test/data/payments/can_make_payment_query_cc.js
rename to components/test/data/payments/can_make_payment_query_cc.js
index a60e9dd..07f12407 100644
--- a/chrome/test/data/payments/can_make_payment_query_cc.js
+++ b/components/test/data/payments/can_make_payment_query_cc.js
@@ -9,7 +9,7 @@
  */
 function buy() {  // eslint-disable-line no-unused-vars
   try {
-    const request = new PaymentRequest(
+    var request = new PaymentRequest(
         [{supportedMethods: ['visa']}],
         {total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}});
     request.canMakePayment()
@@ -29,7 +29,7 @@
  */
 function other_buy() {  // eslint-disable-line no-unused-vars, camelcase
   try {
-    const request = new PaymentRequest(
+    var request = new PaymentRequest(
         [{supportedMethods: ['mastercard']}],
         {total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}});
     request.canMakePayment()
diff --git a/chrome/test/data/payments/contact_details.js b/components/test/data/payments/contact_details.js
similarity index 89%
rename from chrome/test/data/payments/contact_details.js
rename to components/test/data/payments/contact_details.js
index 67eca44..cdf924a 100644
--- a/chrome/test/data/payments/contact_details.js
+++ b/components/test/data/payments/contact_details.js
@@ -13,9 +13,11 @@
   try {
     new PaymentRequest(
         [{supportedMethods: ['https://bobpay.com', 'amex', 'visa']}],
-        {total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}},
-        {requestPayerName: true, requestPayerEmail: true,
-         requestPayerPhone: true})
+        {total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}}, {
+          requestPayerName: true,
+          requestPayerEmail: true,
+          requestPayerPhone: true,
+        })
         .show()
         .then(function(resp) {
           resp.complete('success')
diff --git a/chrome/test/data/payments/free_shipping.js b/components/test/data/payments/contact_details_and_free_shipping.js
similarity index 75%
copy from chrome/test/data/payments/free_shipping.js
copy to components/test/data/payments/contact_details_and_free_shipping.js
index 8ef4c61..2289cc99 100644
--- a/chrome/test/data/payments/free_shipping.js
+++ b/components/test/data/payments/contact_details_and_free_shipping.js
@@ -5,10 +5,10 @@
  */
 
 /* global PaymentRequest:false */
-/* global print:false */
 
 /**
- * Launches the PaymentRequest UI that offers free shipping worldwide.
+ * Launches the PaymentRequest UI that requests an email address and a phone
+ * number and offers free shipping worldwide.
  */
 function buy() {  // eslint-disable-line no-unused-vars
   try {
@@ -18,20 +18,24 @@
         id: 'freeShippingOption',
         label: 'Free global shipping',
         amount: {currency: 'USD', value: '0'},
-        selected: true
-      }]
+        selected: true,
+      }],
     };
     var request = new PaymentRequest(
-        [{supportedMethods: ['visa', 'unionpay', 'mir', 'mastercard',
-            'jcb', 'discover', 'diners', 'amex']}],
-        details,
-        {requestShipping: true});
+        [{supportedMethods: ['visa', 'https://bobpay.com']}], details, {
+          requestPayerName: true,
+          requestPayerEmail: true,
+          requestPayerPhone: true,
+          requestShipping: true,
+        });
+
     request.addEventListener('shippingaddresschange', function(e) {
       e.updateWith(new Promise(function(resolve) {
         // No changes in price based on shipping address change.
         resolve(details);
       }));
     });
+
     request.show()
         .then(function(resp) {
           resp.complete('success')
diff --git a/components/test/data/payments/debit.js b/components/test/data/payments/debit.js
new file mode 100644
index 0000000..38bd734b
--- /dev/null
+++ b/components/test/data/payments/debit.js
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2017 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.
+ */
+
+/**
+ * Builds a payment request for a debit card.
+ * @return {!PaymentRequest} A payment request for a debit card.
+ * @private
+ */
+function buildPaymentRequest() {
+  return new PaymentRequest(
+      [{
+        supportedMethods: ['basic-card'],
+        data: {
+          supportedTypes: ['debit'],
+        },
+      }],
+      {
+        total: {
+          label: 'Total',
+          amount: {
+            currency: 'USD',
+            value: '1.00',
+          },
+        },
+      });
+}
+
+/** Requests payment via a debit card. */
+function buy() {  // eslint-disable-line no-unused-vars
+  try {
+    buildPaymentRequest()
+        .show()
+        .then(function(response) {
+          response.complete()
+              .then(function() {
+                print(JSON.stringify(response, undefined, 2));
+              })
+              .catch(function(error) {
+                print(error);
+              });
+        })
+        .catch(function(error) {
+          print(error);
+        });
+  } catch (error) {
+    print(error);
+  }
+}
+
+/** Checks whether payment via a debit card is possible. */
+function canMakePayment() {  // eslint-disable-line no-unused-vars
+  try {
+    buildPaymentRequest()
+        .canMakePayment()
+        .then(function(result) {
+          print(result);
+        })
+        .catch(function(error) {
+          print(error);
+        });
+  } catch (error) {
+    print(error);
+  }
+}
diff --git a/chrome/test/data/payments/dynamic_shipping.js b/components/test/data/payments/dynamic_shipping.js
similarity index 93%
rename from chrome/test/data/payments/dynamic_shipping.js
rename to components/test/data/payments/dynamic_shipping.js
index bf06acb..d21fe6a 100644
--- a/chrome/test/data/payments/dynamic_shipping.js
+++ b/components/test/data/payments/dynamic_shipping.js
@@ -18,13 +18,10 @@
         {
           label: 'Pending shipping price',
           amount: {currency: 'USD', value: '0.00'},
-          pending: true
+          pending: true,
         },
-        {
-          label: 'Subtotal',
-          amount: {currency: 'USD', value: '5.00'}
-        }
-      ]
+        {label: 'Subtotal', amount: {currency: 'USD', value: '5.00'}},
+      ],
     };
 
     var request = new PaymentRequest(
@@ -67,7 +64,7 @@
       id: '',
       label: '',
       amount: {currency: 'USD', value: '0.00'},
-      selected: true
+      selected: true,
     };
     if (addr.region === 'CA') {
       shippingOption.id = 'californiaShippingOption';
diff --git a/chrome/test/data/payments/email.js b/components/test/data/payments/email.js
similarity index 99%
rename from chrome/test/data/payments/email.js
rename to components/test/data/payments/email.js
index 916c927..7ebe194a 100644
--- a/chrome/test/data/payments/email.js
+++ b/components/test/data/payments/email.js
@@ -6,7 +6,7 @@
 
 /* global PaymentRequest:false */
 
-/*
+/**
  * Launches the PaymentRequest UI that requests email address.
  */
 function buy() {  // eslint-disable-line no-unused-vars
diff --git a/chrome/test/data/payments/free_shipping.js b/components/test/data/payments/email_and_free_shipping.js
similarity index 69%
copy from chrome/test/data/payments/free_shipping.js
copy to components/test/data/payments/email_and_free_shipping.js
index 8ef4c61..4c117dd 100644
--- a/chrome/test/data/payments/free_shipping.js
+++ b/components/test/data/payments/email_and_free_shipping.js
@@ -5,10 +5,10 @@
  */
 
 /* global PaymentRequest:false */
-/* global print:false */
 
 /**
- * Launches the PaymentRequest UI that offers free shipping worldwide.
+ * Launches the PaymentRequest UI that requests an email address and offers free
+ * shipping worldwide.
  */
 function buy() {  // eslint-disable-line no-unused-vars
   try {
@@ -18,19 +18,14 @@
         id: 'freeShippingOption',
         label: 'Free global shipping',
         amount: {currency: 'USD', value: '0'},
-        selected: true
-      }]
+        selected: true,
+      }],
     };
     var request = new PaymentRequest(
-        [{supportedMethods: ['visa', 'unionpay', 'mir', 'mastercard',
-            'jcb', 'discover', 'diners', 'amex']}],
-        details,
-        {requestShipping: true});
+        [{supportedMethods: ['visa']}], details,
+        {requestPayerEmail: true, requestShipping: true});
     request.addEventListener('shippingaddresschange', function(e) {
-      e.updateWith(new Promise(function(resolve) {
-        // No changes in price based on shipping address change.
-        resolve(details);
-      }));
+      e.updateWith(details);
     });
     request.show()
         .then(function(resp) {
diff --git a/chrome/test/data/payments/email_and_phone.js b/components/test/data/payments/email_and_phone.js
similarity index 99%
rename from chrome/test/data/payments/email_and_phone.js
rename to components/test/data/payments/email_and_phone.js
index bdf9ac5..836615f 100644
--- a/chrome/test/data/payments/email_and_phone.js
+++ b/components/test/data/payments/email_and_phone.js
@@ -6,7 +6,7 @@
 
 /* global PaymentRequest:false */
 
-/*
+/**
  * Launches the PaymentRequest UI that requests email address and phone number.
  */
 function buy() {  // eslint-disable-line no-unused-vars
diff --git a/chrome/test/data/payments/extra_shipping_options.js b/components/test/data/payments/extra_shipping_options.js
similarity index 91%
rename from chrome/test/data/payments/extra_shipping_options.js
rename to components/test/data/payments/extra_shipping_options.js
index a3f6f01c..b801880 100644
--- a/chrome/test/data/payments/extra_shipping_options.js
+++ b/components/test/data/payments/extra_shipping_options.js
@@ -19,15 +19,16 @@
         id: 'freeShippingOption',
         label: 'Free global shipping',
         amount: {currency: 'USD', value: '0'},
-        selected: true
-      }]
+        selected: true,
+      }],
     };
     var request = new PaymentRequest([{supportedMethods: ['visa']}], details);
     request.show()
         .then(function(resp) {
           resp.complete('success')
               .then(function() {
-                print(resp.methodName + '<br>' +
+                print(
+                    resp.methodName + '<br>' +
                     JSON.stringify(resp.details, undefined, 2));
               })
               .catch(function(error) {
diff --git a/chrome/test/data/payments/fail_complete.js b/components/test/data/payments/fail_complete.js
similarity index 100%
rename from chrome/test/data/payments/fail_complete.js
rename to components/test/data/payments/fail_complete.js
diff --git a/chrome/test/data/payments/free_shipping.js b/components/test/data/payments/free_shipping.js
similarity index 80%
rename from chrome/test/data/payments/free_shipping.js
rename to components/test/data/payments/free_shipping.js
index 8ef4c61..bf6029f 100644
--- a/chrome/test/data/payments/free_shipping.js
+++ b/components/test/data/payments/free_shipping.js
@@ -18,14 +18,23 @@
         id: 'freeShippingOption',
         label: 'Free global shipping',
         amount: {currency: 'USD', value: '0'},
-        selected: true
-      }]
+        selected: true,
+      }],
     };
     var request = new PaymentRequest(
-        [{supportedMethods: ['visa', 'unionpay', 'mir', 'mastercard',
-            'jcb', 'discover', 'diners', 'amex']}],
-        details,
-        {requestShipping: true});
+        [{
+          supportedMethods: [
+            'visa',
+            'unionpay',
+            'mir',
+            'mastercard',
+            'jcb',
+            'discover',
+            'diners',
+            'amex',
+          ],
+        }],
+        details, {requestShipping: true});
     request.addEventListener('shippingaddresschange', function(e) {
       e.updateWith(new Promise(function(resolve) {
         // No changes in price based on shipping address change.
diff --git a/chrome/test/data/payments/initiated.js b/components/test/data/payments/initiated.js
similarity index 74%
rename from chrome/test/data/payments/initiated.js
rename to components/test/data/payments/initiated.js
index b72c168..569e74a 100644
--- a/chrome/test/data/payments/initiated.js
+++ b/components/test/data/payments/initiated.js
@@ -11,9 +11,9 @@
  * The Payment Request for this page.
  * @const
  */
-let REQUEST = new PaymentRequest(
-        [{supportedMethods: ['https://bobpay.com', 'visa']}],
-        {total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}});
+var REQUEST = new PaymentRequest(
+    [{supportedMethods: ['https://bobpay.com', 'visa']}],
+    {total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}});
 
 /**
  * Show the Payment Request UI.
@@ -43,11 +43,13 @@
  */
 function abort() {  // eslint-disable-line no-unused-vars
   try {
-    REQUEST.abort().then(() => {
-      print('Aborted');
-    }).catch(() => {
-      print('Cannot abort');
-    });
+    REQUEST.abort()
+        .then(function() {
+          print('Aborted');
+        })
+        .catch(function() {
+          print('Cannot abort');
+        });
   } catch (error) {
     print(error.message);
   }
diff --git a/chrome/test/data/payments/initiated_test.html b/components/test/data/payments/initiated_test.html
similarity index 100%
rename from chrome/test/data/payments/initiated_test.html
rename to components/test/data/payments/initiated_test.html
diff --git a/components/test/data/payments/long_id.js b/components/test/data/payments/long_id.js
new file mode 100644
index 0000000..08bbe515
--- /dev/null
+++ b/components/test/data/payments/long_id.js
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2017 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.
+ */
+
+/** Invokes PaymentRequest with a very long request identifier. */
+function buy() {  // eslint-disable-line no-unused-vars
+  var foo = Object.freeze({supportedMethods: ['basic-card']});
+  var defaultMethods = Object.freeze([foo]);
+  var defaultDetails = Object.freeze({
+    total: {
+      label: 'Label',
+      amount: {
+        currency: 'USD',
+        value: '1.00',
+      },
+    },
+  });
+  var newDetails = Object.assign({}, defaultDetails, {
+    id: ''.padStart(100000000, '\n very long id \t \n '),
+  });
+  try {
+    // eslint-disable-next-line no-unused-vars
+    var request = new PaymentRequest(defaultMethods, newDetails);
+  } catch (error) {
+    print(error);
+  }
+}
diff --git a/components/test/data/payments/metrics.js b/components/test/data/payments/metrics.js
new file mode 100644
index 0000000..fc8241b
--- /dev/null
+++ b/components/test/data/payments/metrics.js
@@ -0,0 +1,265 @@
+/*
+ * 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.
+ */
+
+/* global PaymentRequest:false */
+
+var request;
+
+/**
+ * Launches the PaymentRequest UI that accepts credit cards.
+ */
+function ccBuy() {  // eslint-disable-line no-unused-vars
+  try {
+    var details = {
+      total: {
+        label: 'Total',
+        amount: {
+          currency: 'USD',
+          value: '5.00',
+        },
+      },
+      shippingOptions: [{
+        id: 'freeShippingOption',
+        label: 'Free global shipping',
+        amount: {
+          currency: 'USD',
+          value: '0',
+        },
+        selected: true,
+      }],
+    };
+    request = new PaymentRequest(
+        [{
+          supportedMethods: ['visa'],
+        }],
+        {
+          total: {
+            label: 'Total',
+            amount: {
+              currency: 'USD',
+              value: '5.00',
+            },
+          },
+          shippingOptions: [{
+            id: 'freeShippingOption',
+            label: 'Free global shipping',
+            amount: {
+              currency: 'USD',
+              value: '0',
+            },
+            selected: true,
+          }],
+        },
+        {
+          requestShipping: true,
+        });
+    request.show()
+        .then(function(resp) {
+          return resp.complete('success');
+        })
+        .then(function() {
+          print(JSON.stringify(resp, undefined, 2));
+        })
+        .catch(function(error) {
+          print(error);
+        });
+    request.addEventListener('shippingaddresschange', function(e) {
+      e.updateWith(new Promise(function(resolve) {
+        // No changes in price based on shipping address change.
+        resolve(details);
+      }));
+    });
+  } catch (error) {
+    print(error.message);
+  }
+}
+
+/**
+ * Launches the PaymentRequest UI which accepts only Android Pay.
+ */
+function androidPayBuy() {  // eslint-disable-line no-unused-vars
+  try {
+    request = new PaymentRequest(
+        [{
+          supportedMethods: ['https://android.com/pay'],
+        }],
+        {
+          total: {
+            label: 'Total',
+            amount: {
+              currency: 'USD',
+              value: '5.00',
+            },
+          },
+          shippingOptions: [{
+            id: 'freeShippingOption',
+            label: 'Free global shipping',
+            amount: {
+              currency: 'USD',
+              value: '0',
+            },
+            selected: true,
+          }],
+        },
+        {
+          requestShipping: true,
+        });
+    request.show()
+        .then(function(resp) {
+          return resp.complete('success');
+        })
+        .then(function() {
+          print(JSON.stringify(resp, undefined, 2));
+        })
+        .catch(function(error) {
+          print(error);
+        });
+  } catch (error) {
+    print(error.message);
+  }
+}
+
+/**
+ * Launches the PaymentRequest UI which accepts only Android Pay and does not
+ * require any other information.
+ */
+function androidPaySkipUiBuy() {  // eslint-disable-line no-unused-vars
+  try {
+    request = new PaymentRequest(
+        [{
+          supportedMethods: ['https://android.com/pay'],
+        }],
+        {
+          total: {
+            label: 'Total',
+            amount: {
+              currency: 'USD',
+              value: '5.00',
+            },
+          },
+        });
+    request.show()
+        .then(function(resp) {
+          return resp.complete('success');
+        })
+        .then(function() {
+          print(JSON.stringify(resp, undefined, 2));
+        })
+        .catch(function(error) {
+          print(error);
+        });
+  } catch (error) {
+    print(error.message);
+  }
+}
+
+/**
+ * Launches the PaymentRequest UI which accepts only an unsupported payment
+ * method.
+ */
+function noSupported() {  // eslint-disable-line no-unused-vars
+  try {
+    request = new PaymentRequest(
+        [{
+          supportedMethods: ['https://randompay.com'],
+        }],
+        {
+          total: {
+            label: 'Total',
+            amount: {
+              currency: 'USD',
+              value: '5.00',
+            },
+          },
+          shippingOptions: [{
+            id: 'freeShippingOption',
+            label: 'Free global shipping',
+            amount: {
+              currency: 'USD',
+              value: '0',
+            },
+            selected: true,
+          }],
+        },
+        {
+          requestShipping: true,
+        });
+    request.show()
+        .then(function(resp) {
+          return resp.complete('success');
+        })
+        .then(function() {
+          print(JSON.stringify(resp, undefined, 2));
+        })
+        .catch(function(error) {
+          print(error);
+        });
+  } catch (error) {
+    print(error.message);
+  }
+}
+
+/**
+ * Launches the PaymentRequest UI which accepts credit cards and Bob Pay.
+ */
+function cardsAndBobPayBuy() {  // eslint-disable-line no-unused-vars
+  try {
+    request = new PaymentRequest(
+        [{
+          supportedMethods: ['visa', 'https://bobpay.com'],
+        }],
+        {
+          total: {
+            label: 'Total',
+            amount: {
+              currency: 'USD',
+              value: '5.00',
+            },
+          },
+          shippingOptions: [{
+            id: 'freeShippingOption',
+            label: 'Free global shipping',
+            amount: {
+              currency: 'USD',
+              value: '0',
+            },
+            selected: true,
+          }],
+        },
+        {
+          requestShipping: true,
+        });
+    request.show()
+        .then(function(resp) {
+          return resp.complete('success');
+        })
+        .then(function() {
+          print(JSON.stringify(resp, undefined, 2));
+        })
+        .catch(function(error) {
+          print(error);
+        });
+  } catch (error) {
+    print(error.message);
+  }
+}
+
+/**
+ * Aborts the current PaymentRequest.
+ */
+function abort() {  // eslint-disable-line no-unused-vars
+  try {
+    request.abort()
+        .then(function() {
+          print('Aborted');
+        })
+        .catch(function() {
+          print('Cannot abort');
+        });
+  } catch (error) {
+    print(error.message);
+  }
+}
diff --git a/chrome/test/data/payments/modifier.js b/components/test/data/payments/modifier.js
similarity index 61%
rename from chrome/test/data/payments/modifier.js
rename to components/test/data/payments/modifier.js
index 4fff18b..49e1285 100644
--- a/chrome/test/data/payments/modifier.js
+++ b/components/test/data/payments/modifier.js
@@ -8,12 +8,13 @@
  * Invokes the PaymentRequest with a modifier that contains the bare mininum of
  * required fields.
  */
-function buy() { // eslint-disable-line no-unused-vars
+function buy() {  // eslint-disable-line no-unused-vars
   try {
     new PaymentRequest(
         [{
           supportedMethods: ['foo'],
-        }], {
+        }],
+        {
           total: {
             label: 'Total',
             amount: {
@@ -25,19 +26,19 @@
             supportedMethods: ['foo'],
           }],
         })
-      .show()
-      .then(function(response) {
-        response.complete()
-          .then(function() {
-            print(complete);
-          })
-          .catch(function(error) {
-            print(error);
-          });
-      })
-      .catch(function(error) {
-        print(error);
-      });
+        .show()
+        .then(function(response) {
+          response.complete()
+              .then(function() {
+                print(complete);
+              })
+              .catch(function(error) {
+                print(error);
+              });
+        })
+        .catch(function(error) {
+          print(error);
+        });
   } catch (error) {
     print(error.message);
   }
diff --git a/chrome/test/data/payments/multiple_show.js b/components/test/data/payments/multiple_show.js
similarity index 78%
rename from chrome/test/data/payments/multiple_show.js
rename to components/test/data/payments/multiple_show.js
index fa4c82b..57b9dd5 100644
--- a/chrome/test/data/payments/multiple_show.js
+++ b/components/test/data/payments/multiple_show.js
@@ -23,9 +23,13 @@
               .then(function() {
                 print(JSON.stringify(resp, undefined, 2));
               })
-              .catch(function(error) { print(error); });
+              .catch(function(error) {
+                print(error);
+              });
         })
-        .catch(function(error) { print(error); });
+        .catch(function(error) {
+          print(error);
+        });
   } catch (error) {
     print(error.message);
   }
@@ -42,9 +46,13 @@
               .then(function() {
                 print(JSON.stringify(resp, undefined, 2));
               })
-              .catch(function(error) { print(error); });
+              .catch(function(error) {
+                print(error);
+              });
         })
-        .catch(function(error) { print(error); });
+        .catch(function(error) {
+          print(error);
+        });
   } catch (error) {
     print(error.message);
   }
@@ -64,9 +72,13 @@
               .then(function() {
                 print(JSON.stringify(resp, undefined, 2));
               })
-              .catch(function(error) { print(error); });
+              .catch(function(error) {
+                print(error);
+              });
         })
-        .catch(function(error) { print(error); });
+        .catch(function(error) {
+          print(error);
+        });
   } catch (error) {
     print(error.message);
   }
diff --git a/chrome/test/data/payments/name.js b/components/test/data/payments/name.js
similarity index 99%
rename from chrome/test/data/payments/name.js
rename to components/test/data/payments/name.js
index 0e3265b..6694201 100644
--- a/chrome/test/data/payments/name.js
+++ b/components/test/data/payments/name.js
@@ -6,7 +6,7 @@
 
 /* global PaymentRequest:false */
 
-/*
+/**
  * Launches the PaymentRequest UI that requests payer name.
  */
 function buy() {  // eslint-disable-line no-unused-vars
diff --git a/chrome/test/data/payments/name_and_free_shipping.js b/components/test/data/payments/name_and_free_shipping.js
similarity index 96%
rename from chrome/test/data/payments/name_and_free_shipping.js
rename to components/test/data/payments/name_and_free_shipping.js
index 37deffd..db49cbc 100644
--- a/chrome/test/data/payments/name_and_free_shipping.js
+++ b/components/test/data/payments/name_and_free_shipping.js
@@ -19,8 +19,8 @@
             id: 'freeShippingOption',
             label: 'Free global shipping',
             amount: {currency: 'USD', value: '0'},
-            selected: true
-          }]
+            selected: true,
+          }],
         },
         {requestPayerName: true, requestShipping: true});
     request.show()
diff --git a/chrome/test/data/payments/no_shipping.js b/components/test/data/payments/no_shipping.js
similarity index 96%
rename from chrome/test/data/payments/no_shipping.js
rename to components/test/data/payments/no_shipping.js
index 27981b45..a87473b 100644
--- a/chrome/test/data/payments/no_shipping.js
+++ b/components/test/data/payments/no_shipping.js
@@ -17,10 +17,10 @@
         {
           label: 'Subtotal',
           amount: {currency: 'USD', value: '4.50'},
-          pending: true
+          pending: true,
         },
-        {label: 'Taxes', amount: {currency: 'USD', value: '0.50'}}
-      ]
+        {label: 'Taxes', amount: {currency: 'USD', value: '0.50'}},
+      ],
     })
         .show()
         .then(function(resp) {
diff --git a/chrome/test/data/payments/payment-manifest.json b/components/test/data/payments/payment-manifest.json
similarity index 100%
rename from chrome/test/data/payments/payment-manifest.json
rename to components/test/data/payments/payment-manifest.json
diff --git a/chrome/test/data/payments/payment_method_identifier.js b/components/test/data/payments/payment_method_identifier.js
similarity index 62%
rename from chrome/test/data/payments/payment_method_identifier.js
rename to components/test/data/payments/payment_method_identifier.js
index c921aa9..6b04d0e 100644
--- a/chrome/test/data/payments/payment_method_identifier.js
+++ b/components/test/data/payments/payment_method_identifier.js
@@ -11,23 +11,22 @@
  */
 function canMakePaymentHelper(methodData) {
   try {
-    new PaymentRequest(
-        methodData, {
-          total: {
-            label: 'Total',
-            amount: {
-              currency: 'USD',
-              value: '5.00',
-            },
-          },
+    new PaymentRequest(methodData, {
+      total: {
+        label: 'Total',
+        amount: {
+          currency: 'USD',
+          value: '5.00',
+        },
+      },
+    })
+        .canMakePayment()
+        .then(function(result) {
+          print(result);
         })
-      .canMakePayment()
-      .then(function(result) {
-        print(result);
-      })
-      .catch(function(error) {
-        print(error);
-      });
+        .catch(function(error) {
+          print(error);
+        });
   } catch (error) {
     print(error);
   }
@@ -37,7 +36,7 @@
  * Merchant checks for ability to pay using "basic-card" regardless of issuer
  * network.
  */
-function checkBasicCard() { // eslint-disable-line no-unused-vars
+function checkBasicCard() {  // eslint-disable-line no-unused-vars
   canMakePaymentHelper([{
     supportedMethods: ['basic-card'],
   }]);
@@ -46,7 +45,7 @@
 /**
  * Merchant checks for ability to pay using debit cards.
  */
-function checkBasicDebit() { // eslint-disable-line no-unused-vars
+function checkBasicDebit() {  // eslint-disable-line no-unused-vars
   canMakePaymentHelper([{
     supportedMethods: ['basic-card'],
     data: {
@@ -59,7 +58,7 @@
  * Merchant checks for ability to pay using "basic-card" with "mastercard" as
  * the supported network.
  */
-function checkBasicMasterCard() { // eslint-disable-line no-unused-vars
+function checkBasicMasterCard() {  // eslint-disable-line no-unused-vars
   canMakePaymentHelper([{
     supportedMethods: ['basic-card'],
     data: {
@@ -72,7 +71,7 @@
  * Merchant checks for ability to pay using "basic-card" with "visa" as the
  * supported network.
  */
-function checkBasicVisa() { // eslint-disable-line no-unused-vars
+function checkBasicVisa() {  // eslint-disable-line no-unused-vars
   canMakePaymentHelper([{
     supportedMethods: ['basic-card'],
     data: {
@@ -84,7 +83,7 @@
 /**
  * Merchant checks for ability to pay using "mastercard".
  */
-function checkMasterCard() { // eslint-disable-line no-unused-vars
+function checkMasterCard() {  // eslint-disable-line no-unused-vars
   canMakePaymentHelper([{
     supportedMethods: ['mastercard'],
   }]);
@@ -93,7 +92,7 @@
 /**
  * Merchant checks for ability to pay using "visa".
  */
-function checkVisa() { // eslint-disable-line no-unused-vars
+function checkVisa() {  // eslint-disable-line no-unused-vars
   canMakePaymentHelper([{
     supportedMethods: ['visa'],
   }]);
@@ -107,27 +106,27 @@
 function buyHelper(methodData) {
   try {
     new PaymentRequest(methodData, {
-        total: {
-          label: 'Total',
-          amount: {
-            currency: 'USD',
-            value: '5.00',
-          },
+      total: {
+        label: 'Total',
+        amount: {
+          currency: 'USD',
+          value: '5.00',
         },
-      })
-      .show()
-      .then(function(response) {
-        response.complete('success')
-          .then(function() {
-            print(JSON.stringify(response, undefined, 2));
-          })
-          .catch(function(error) {
-            print(error);
-          });
-      })
-      .catch(function(error) {
-        print(error);
-      });
+      },
+    })
+        .show()
+        .then(function(response) {
+          response.complete('success')
+              .then(function() {
+                print(JSON.stringify(response, undefined, 2));
+              })
+              .catch(function(error) {
+                print(error);
+              });
+        })
+        .catch(function(error) {
+          print(error);
+        });
   } catch (error) {
     print(error);
   }
@@ -137,21 +136,24 @@
  * Merchant requests payment via either "mastercard" or "basic-card" with "visa"
  * as the supported network.
  */
-function buy() { // eslint-disable-line no-unused-vars
-  buyHelper([{
-    supportedMethods: ['mastercard'],
-  }, {
-    supportedMethods: ['basic-card'],
-    data: {
-      supportedNetworks: ['visa'],
+function buy() {  // eslint-disable-line no-unused-vars
+  buyHelper([
+    {
+      supportedMethods: ['mastercard'],
     },
-  }]);
+    {
+      supportedMethods: ['basic-card'],
+      data: {
+        supportedNetworks: ['visa'],
+      },
+    },
+  ]);
 }
 
 /**
  * Merchant requests payment via "basic-card" with any issuer network.
  */
-function buyBasicCard() { // eslint-disable-line no-unused-vars
+function buyBasicCard() {  // eslint-disable-line no-unused-vars
   buyHelper([{
     supportedMethods: ['basic-card'],
     data: {
@@ -164,7 +166,7 @@
  * Merchant requests payment via "basic-card" with "debit" as the supported card
  * type.
  */
-function buyBasicDebit() { // eslint-disable-line no-unused-vars
+function buyBasicDebit() {  // eslint-disable-line no-unused-vars
   buyHelper([{
     supportedMethods: ['basic-card'],
     data: {
@@ -177,7 +179,7 @@
  * Merchant requests payment via "basic-card" with "debit" as the supported card
  * type.
  */
-function buyBasicDebit() { // eslint-disable-line no-unused-vars
+function buyBasicDebit() {  // eslint-disable-line no-unused-vars
   buyHelper([{
     supportedMethods: ['basic-card'],
     data: {
@@ -190,7 +192,7 @@
  * Merchant requests payment via "basic-card" payment method with "mastercard"
  * as the only supported network.
  */
-function buyBasicMasterCard() { // eslint-disable-line no-unused-vars
+function buyBasicMasterCard() {  // eslint-disable-line no-unused-vars
   buyHelper([{
     supportedMethods: ['basic-card'],
     data: {
diff --git a/chrome/test/data/payments/payment_request_abort_test.html b/components/test/data/payments/payment_request_abort_test.html
similarity index 89%
rename from chrome/test/data/payments/payment_request_abort_test.html
rename to components/test/data/payments/payment_request_abort_test.html
index cd63ef76..e81a8c4 100644
--- a/chrome/test/data/payments/payment_request_abort_test.html
+++ b/components/test/data/payments/payment_request_abort_test.html
@@ -11,7 +11,7 @@
 <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
 </head>
 <body>
-<button onclick="buy()" id="buy">Buy</button><br>
+<div><button onclick="buy()" id="buy">Buy</button></div>
 <button onclick="abort()" id="abort">Abort</button>
 <pre id="result"></pre>
 <script src="util.js"></script>
diff --git a/chrome/test/data/payments/payment_request_alicepay_bobpay_charliepay_and_cards_test.html b/components/test/data/payments/payment_request_alicepay_bobpay_charliepay_and_cards_test.html
similarity index 86%
rename from chrome/test/data/payments/payment_request_alicepay_bobpay_charliepay_and_cards_test.html
rename to components/test/data/payments/payment_request_alicepay_bobpay_charliepay_and_cards_test.html
index 34effdc..d5ad667 100644
--- a/chrome/test/data/payments/payment_request_alicepay_bobpay_charliepay_and_cards_test.html
+++ b/components/test/data/payments/payment_request_alicepay_bobpay_charliepay_and_cards_test.html
@@ -12,7 +12,9 @@
 <link rel="stylesheet" type="text/css" href="style.css">
 </head>
 <body>
-<button onclick="buy()" id="buy">Multiple apps and Cards Test</button><br>
+<div>
+  <button onclick="buy()" id="buy">Multiple apps and Cards Test</button>
+</div>
 <pre id="result"></pre>
 <script src="util.js"></script>
 <script src="alicepay_bobpay_charliepay_and_cards.js"></script>
diff --git a/chrome/test/data/payments/payment_request_blob_url_test.html b/components/test/data/payments/payment_request_blob_url_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_blob_url_test.html
rename to components/test/data/payments/payment_request_blob_url_test.html
diff --git a/chrome/test/data/payments/payment_request_bobpay_and_basic_card_with_basic_card_modifiers_test.html b/components/test/data/payments/payment_request_bobpay_and_basic_card_with_basic_card_modifiers_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_bobpay_and_basic_card_with_basic_card_modifiers_test.html
rename to components/test/data/payments/payment_request_bobpay_and_basic_card_with_basic_card_modifiers_test.html
diff --git a/chrome/test/data/payments/payment_request_bobpay_and_basic_card_with_modifiers_test.html b/components/test/data/payments/payment_request_bobpay_and_basic_card_with_modifiers_test.html
similarity index 83%
rename from chrome/test/data/payments/payment_request_bobpay_and_basic_card_with_modifiers_test.html
rename to components/test/data/payments/payment_request_bobpay_and_basic_card_with_modifiers_test.html
index b74b29d..7fe8523 100644
--- a/chrome/test/data/payments/payment_request_bobpay_and_basic_card_with_modifiers_test.html
+++ b/components/test/data/payments/payment_request_bobpay_and_basic_card_with_modifiers_test.html
@@ -12,7 +12,11 @@
 <link rel="stylesheet" type="text/css" href="style.css">
 </head>
 <body>
-<button onclick="buy()" id="buy">Bob Pay and Basic-Card with modifiers Test</button><br>
+<div>
+  <button onclick="buy()" id="buy">
+    Bob Pay and Basic-Card with modifiers Test
+  </button>
+</div>
 <pre id="result"></pre>
 <script src="util.js"></script>
 <script src="bobpay_and_basic_card_with_modifiers.js"></script>
diff --git a/chrome/test/data/payments/payment_request_bobpay_and_cards_test.html b/components/test/data/payments/payment_request_bobpay_and_cards_test.html
similarity index 87%
rename from chrome/test/data/payments/payment_request_bobpay_and_cards_test.html
rename to components/test/data/payments/payment_request_bobpay_and_cards_test.html
index 9447253..93bde4c2 100644
--- a/chrome/test/data/payments/payment_request_bobpay_and_cards_test.html
+++ b/components/test/data/payments/payment_request_bobpay_and_cards_test.html
@@ -12,7 +12,7 @@
 <link rel="stylesheet" type="text/css" href="style.css">
 </head>
 <body>
-<button onclick="buy()" id="buy">Bob Pay and Cards Test</button><br>
+<div><button onclick="buy()" id="buy">Bob Pay and Cards Test</button></div>
 <pre id="result"></pre>
 <script src="util.js"></script>
 <script src="bobpay_and_cards.js"></script>
diff --git a/chrome/test/data/payments/payment_request_bobpay_test.html b/components/test/data/payments/payment_request_bobpay_test.html
similarity index 88%
rename from chrome/test/data/payments/payment_request_bobpay_test.html
rename to components/test/data/payments/payment_request_bobpay_test.html
index 83ea961..d2643cdc 100644
--- a/chrome/test/data/payments/payment_request_bobpay_test.html
+++ b/components/test/data/payments/payment_request_bobpay_test.html
@@ -12,7 +12,7 @@
 <link rel="stylesheet" type="text/css" href="style.css">
 </head>
 <body>
-<button onclick="buy()" id="buy">Bob Pay Test</button><br>
+<div><button onclick="buy()" id="buy">Bob Pay Test</button></div>
 <pre id="result"></pre>
 <script src="util.js"></script>
 <script src="bobpay.js"></script>
diff --git a/chrome/test/data/payments/payment_request_bobpay_ui_skip_preload_test.html b/components/test/data/payments/payment_request_bobpay_ui_skip_preload_test.html
similarity index 87%
rename from chrome/test/data/payments/payment_request_bobpay_ui_skip_preload_test.html
rename to components/test/data/payments/payment_request_bobpay_ui_skip_preload_test.html
index 6af1b47..2cd1f28b 100644
--- a/chrome/test/data/payments/payment_request_bobpay_ui_skip_preload_test.html
+++ b/components/test/data/payments/payment_request_bobpay_ui_skip_preload_test.html
@@ -12,7 +12,7 @@
 <link rel="stylesheet" type="text/css" href="style.css">
 </head>
 <body>
-<button onclick="buy()" id="buy">UI skip, preload test</button><br>
+<div><button onclick="buy()" id="buy">UI skip, preload test</button></div>
 <pre id="result"></pre>
 <script src="util.js"></script>
 <script src="bobpay_ui_skip_preload.js"></script>
diff --git a/chrome/test/data/payments/payment_request_bobpay_ui_skip_test.html b/components/test/data/payments/payment_request_bobpay_ui_skip_test.html
similarity index 88%
rename from chrome/test/data/payments/payment_request_bobpay_ui_skip_test.html
rename to components/test/data/payments/payment_request_bobpay_ui_skip_test.html
index 5d179cf7..9dfed6d 100644
--- a/chrome/test/data/payments/payment_request_bobpay_ui_skip_test.html
+++ b/components/test/data/payments/payment_request_bobpay_ui_skip_test.html
@@ -12,7 +12,7 @@
 <link rel="stylesheet" type="text/css" href="style.css">
 </head>
 <body>
-<button onclick="buy()" id="buy">Bob Pay Test</button><br>
+<div><button onclick="buy()" id="buy">Bob Pay Test</button></div>
 <pre id="result"></pre>
 <script src="util.js"></script>
 <script src="bobpay_ui_skip.js"></script>
diff --git a/chrome/test/data/payments/payment_request_can_make_payment_metrics_test.html b/components/test/data/payments/payment_request_can_make_payment_metrics_test.html
similarity index 62%
rename from chrome/test/data/payments/payment_request_can_make_payment_metrics_test.html
rename to components/test/data/payments/payment_request_can_make_payment_metrics_test.html
index f62b92f..481c74f 100644
--- a/chrome/test/data/payments/payment_request_can_make_payment_metrics_test.html
+++ b/components/test/data/payments/payment_request_can_make_payment_metrics_test.html
@@ -12,10 +12,14 @@
 <link rel="stylesheet" type="text/css" href="style.css">
 </head>
 <body>
-<button onclick="noQueryShow()" id="noQueryShow">No Query Show Test</button><br>
-<button onclick="queryShow()" id="queryShow">Query Show Test</button><br>
-<button onclick="queryNoShow()" id="queryNoShow">Query No Show Test</button><br>
-<button onclick="abort()" id="abort">Abort</button><br>
+<div>
+  <button onclick="noQueryShow()" id="noQueryShow">No Query Show Test</button>
+</div>
+<div><button onclick="queryShow()" id="queryShow">Query Show Test</button></div>
+<div>
+  <button onclick="queryNoShow()" id="queryNoShow">Query No Show Test</button>
+</div>
+<div><button onclick="abort()" id="abort">Abort</button></div>
 <pre id="result"></pre>
 <script src="util.js"></script>
 <script src="can_make_payment_metrics.js"></script>
diff --git a/chrome/test/data/payments/payment_request_can_make_payment_query_bobpay_test.html b/components/test/data/payments/payment_request_can_make_payment_query_bobpay_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_can_make_payment_query_bobpay_test.html
rename to components/test/data/payments/payment_request_can_make_payment_query_bobpay_test.html
diff --git a/chrome/test/data/payments/payment_request_can_make_payment_query_cc_test.html b/components/test/data/payments/payment_request_can_make_payment_query_cc_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_can_make_payment_query_cc_test.html
rename to components/test/data/payments/payment_request_can_make_payment_query_cc_test.html
diff --git a/chrome/test/data/payments/payment_request_can_make_payment_query_test.html b/components/test/data/payments/payment_request_can_make_payment_query_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_can_make_payment_query_test.html
rename to components/test/data/payments/payment_request_can_make_payment_query_test.html
diff --git a/chrome/test/data/payments/payment_request_contact_details_and_free_shipping_test.html b/components/test/data/payments/payment_request_contact_details_and_free_shipping_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_contact_details_and_free_shipping_test.html
rename to components/test/data/payments/payment_request_contact_details_and_free_shipping_test.html
diff --git a/chrome/test/data/payments/payment_request_contact_details_test.html b/components/test/data/payments/payment_request_contact_details_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_contact_details_test.html
rename to components/test/data/payments/payment_request_contact_details_test.html
diff --git a/chrome/test/data/payments/payment_request_debit_test.html b/components/test/data/payments/payment_request_debit_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_debit_test.html
rename to components/test/data/payments/payment_request_debit_test.html
diff --git a/chrome/test/data/payments/payment_request_dynamic_shipping_test.html b/components/test/data/payments/payment_request_dynamic_shipping_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_dynamic_shipping_test.html
rename to components/test/data/payments/payment_request_dynamic_shipping_test.html
diff --git a/chrome/test/data/payments/payment_request_email_and_free_shipping_test.html b/components/test/data/payments/payment_request_email_and_free_shipping_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_email_and_free_shipping_test.html
rename to components/test/data/payments/payment_request_email_and_free_shipping_test.html
diff --git a/chrome/test/data/payments/payment_request_email_and_phone_test.html b/components/test/data/payments/payment_request_email_and_phone_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_email_and_phone_test.html
rename to components/test/data/payments/payment_request_email_and_phone_test.html
diff --git a/chrome/test/data/payments/payment_request_email_test.html b/components/test/data/payments/payment_request_email_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_email_test.html
rename to components/test/data/payments/payment_request_email_test.html
diff --git a/chrome/test/data/payments/payment_request_extra_shipping_options_test.html b/components/test/data/payments/payment_request_extra_shipping_options_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_extra_shipping_options_test.html
rename to components/test/data/payments/payment_request_extra_shipping_options_test.html
diff --git a/chrome/test/data/payments/payment_request_fail_complete_test.html b/components/test/data/payments/payment_request_fail_complete_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_fail_complete_test.html
rename to components/test/data/payments/payment_request_fail_complete_test.html
diff --git a/chrome/test/data/payments/payment_request_free_shipping_test.html b/components/test/data/payments/payment_request_free_shipping_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_free_shipping_test.html
rename to components/test/data/payments/payment_request_free_shipping_test.html
diff --git a/chrome/test/data/payments/payment_request_id.js b/components/test/data/payments/payment_request_id.js
similarity index 81%
rename from chrome/test/data/payments/payment_request_id.js
rename to components/test/data/payments/payment_request_id.js
index abfda37a..58471ab3a 100644
--- a/chrome/test/data/payments/payment_request_id.js
+++ b/components/test/data/payments/payment_request_id.js
@@ -10,10 +10,10 @@
  */
 function buy() {  // eslint-disable-line no-unused-vars
   try {
-    new PaymentRequest(
-        [{supportedMethods: ['visa']}],
-        {id: 'my_payment_id',
-         total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}})
+    new PaymentRequest([{supportedMethods: ['visa']}], {
+      id: 'my_payment_id',
+      total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}},
+    })
         .show()
         .then(function(resp) {
           resp.complete('success')
diff --git a/chrome/test/data/payments/payment_request_id_test.html b/components/test/data/payments/payment_request_id_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_id_test.html
rename to components/test/data/payments/payment_request_id_test.html
diff --git a/chrome/test/data/payments/payment_request_iframe.html b/components/test/data/payments/payment_request_iframe.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_iframe.html
rename to components/test/data/payments/payment_request_iframe.html
diff --git a/chrome/test/data/payments/payment_request_long_id_test.html b/components/test/data/payments/payment_request_long_id_test.html
similarity index 88%
rename from chrome/test/data/payments/payment_request_long_id_test.html
rename to components/test/data/payments/payment_request_long_id_test.html
index 7417b0bb..b1e1d028 100644
--- a/chrome/test/data/payments/payment_request_long_id_test.html
+++ b/components/test/data/payments/payment_request_long_id_test.html
@@ -14,7 +14,7 @@
 </head>
 
 <body>
-  <button onclick="buy()" id="buy">Long ID Test</button><br>
+  <div><button onclick="buy()" id="buy">Long ID Test</button></div>
   <pre id="result"></pre>
   <script src="util.js"></script>
   <script src="long_id.js"></script>
diff --git a/chrome/test/data/payments/payment_request_main.html b/components/test/data/payments/payment_request_main.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_main.html
rename to components/test/data/payments/payment_request_main.html
diff --git a/chrome/test/data/payments/payment_request_metrics_test.html b/components/test/data/payments/payment_request_metrics_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_metrics_test.html
rename to components/test/data/payments/payment_request_metrics_test.html
diff --git a/chrome/test/data/payments/payment_request_modifier_test.html b/components/test/data/payments/payment_request_modifier_test.html
similarity index 86%
rename from chrome/test/data/payments/payment_request_modifier_test.html
rename to components/test/data/payments/payment_request_modifier_test.html
index 9ae88ba..6e515b0 100644
--- a/chrome/test/data/payments/payment_request_modifier_test.html
+++ b/components/test/data/payments/payment_request_modifier_test.html
@@ -11,7 +11,7 @@
 <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
 </head>
 <body>
-<button onclick="buy()" id="buy">Modifier Test</button><br>
+<div><button onclick="buy()" id="buy">Modifier Test</button></div>
 <pre id="result"></pre>
 <script src="util.js"></script>
 <script src="modifier.js"></script>
diff --git a/chrome/test/data/payments/payment_request_multiple_requests.html b/components/test/data/payments/payment_request_multiple_requests.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_multiple_requests.html
rename to components/test/data/payments/payment_request_multiple_requests.html
diff --git a/chrome/test/data/payments/payment_request_multiple_show_test.html b/components/test/data/payments/payment_request_multiple_show_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_multiple_show_test.html
rename to components/test/data/payments/payment_request_multiple_show_test.html
diff --git a/chrome/test/data/payments/payment_request_name_and_free_shipping_test.html b/components/test/data/payments/payment_request_name_and_free_shipping_test.html
similarity index 86%
rename from chrome/test/data/payments/payment_request_name_and_free_shipping_test.html
rename to components/test/data/payments/payment_request_name_and_free_shipping_test.html
index 70b9841c..72bba4d 100644
--- a/chrome/test/data/payments/payment_request_name_and_free_shipping_test.html
+++ b/components/test/data/payments/payment_request_name_and_free_shipping_test.html
@@ -12,7 +12,7 @@
 <link rel="stylesheet" type="text/css" href="style.css">
 </head>
 <body>
-<button onclick="buy()" id="buy">Name and Free Shipping Test</button><br>
+<div><button onclick="buy()" id="buy">Name and Free Shipping Test</button></div>
 <pre id="result"></pre>
 <script src="util.js"></script>
 <script src="name_and_free_shipping.js"></script>
diff --git a/chrome/test/data/payments/payment_request_name_test.html b/components/test/data/payments/payment_request_name_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_name_test.html
rename to components/test/data/payments/payment_request_name_test.html
diff --git a/chrome/test/data/payments/payment_request_no_shipping_test.html b/components/test/data/payments/payment_request_no_shipping_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_no_shipping_test.html
rename to components/test/data/payments/payment_request_no_shipping_test.html
diff --git a/chrome/test/data/payments/payment_request_payment_method_identifier_test.html b/components/test/data/payments/payment_request_payment_method_identifier_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_payment_method_identifier_test.html
rename to components/test/data/payments/payment_request_payment_method_identifier_test.html
diff --git a/chrome/test/data/payments/payment_request_phone_and_free_shipping_test.html b/components/test/data/payments/payment_request_phone_and_free_shipping_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_phone_and_free_shipping_test.html
rename to components/test/data/payments/payment_request_phone_and_free_shipping_test.html
diff --git a/chrome/test/data/payments/payment_request_phone_test.html b/components/test/data/payments/payment_request_phone_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_phone_test.html
rename to components/test/data/payments/payment_request_phone_test.html
diff --git a/chrome/test/data/payments/payment_request_shipping_address_change_test.html b/components/test/data/payments/payment_request_shipping_address_change_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_shipping_address_change_test.html
rename to components/test/data/payments/payment_request_shipping_address_change_test.html
diff --git a/chrome/test/data/payments/payment_request_show_twice_test.html b/components/test/data/payments/payment_request_show_twice_test.html
similarity index 100%
rename from chrome/test/data/payments/payment_request_show_twice_test.html
rename to components/test/data/payments/payment_request_show_twice_test.html
diff --git a/chrome/test/data/payments/phone.js b/components/test/data/payments/phone.js
similarity index 100%
rename from chrome/test/data/payments/phone.js
rename to components/test/data/payments/phone.js
diff --git a/chrome/test/data/payments/phone_and_free_shipping.js b/components/test/data/payments/phone_and_free_shipping.js
similarity index 96%
rename from chrome/test/data/payments/phone_and_free_shipping.js
rename to components/test/data/payments/phone_and_free_shipping.js
index ed49d3a..8ef8156 100644
--- a/chrome/test/data/payments/phone_and_free_shipping.js
+++ b/components/test/data/payments/phone_and_free_shipping.js
@@ -19,8 +19,8 @@
             id: 'freeShippingOption',
             label: 'Free global shipping',
             amount: {currency: 'USD', value: '0'},
-            selected: true
-          }]
+            selected: true,
+          }],
         },
         {requestPayerPhone: true, requestShipping: true});
     request.show()
diff --git a/chrome/test/data/payments/shipping_address_change.js b/components/test/data/payments/shipping_address_change.js
similarity index 86%
rename from chrome/test/data/payments/shipping_address_change.js
rename to components/test/data/payments/shipping_address_change.js
index 8bff1ff..67defe90 100644
--- a/chrome/test/data/payments/shipping_address_change.js
+++ b/components/test/data/payments/shipping_address_change.js
@@ -16,20 +16,15 @@
         {
           label: 'Pending shipping price',
           amount: {currency: 'USD', value: '0.00'},
-          pending: true
+          pending: true,
         },
-        {
-          label: 'Subtotal',
-          amount: {currency: 'USD', value: '5.00'}
-        }
-      ]
+        {label: 'Subtotal', amount: {currency: 'USD', value: '5.00'}},
+      ],
     };
 
     var request = new PaymentRequest(
         [{supportedMethods: ['visa']}], details, {requestShipping: true});
 
-    var shippingAddressChange;
-
     request.addEventListener('shippingaddresschange', function(evt) {
       evt.updateWith(new Promise(function(resolve) {
         print(JSON.stringify(request.shippingAddress, undefined, 2));
diff --git a/chrome/test/data/payments/show_twice.js b/components/test/data/payments/show_twice.js
similarity index 88%
rename from chrome/test/data/payments/show_twice.js
rename to components/test/data/payments/show_twice.js
index 1de167ba..ed5bc22 100644
--- a/chrome/test/data/payments/show_twice.js
+++ b/components/test/data/payments/show_twice.js
@@ -8,10 +8,10 @@
  * Launches the PaymentRequest UI twice.
  */
 function buy() {  // eslint-disable-line no-unused-vars
-  const payment1 = new PaymentRequest(
+  var payment1 = new PaymentRequest(
       [{supportedMethods: ['visa']}],
       {total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}});
-  const payment2 = new PaymentRequest(
+  var payment2 = new PaymentRequest(
       [{supportedMethods: ['visa']}],
       {total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}});
   payment1.show();
diff --git a/chrome/test/data/payments/style.css b/components/test/data/payments/style.css
similarity index 99%
rename from chrome/test/data/payments/style.css
rename to components/test/data/payments/style.css
index 1390298..efe83cb1 100644
--- a/chrome/test/data/payments/style.css
+++ b/components/test/data/payments/style.css
@@ -5,9 +5,9 @@
  */
 
 button {
-  width: 100%;
-  height: 5em;
   font-size: 3em;
+  height: 5em;
+  width: 100%;
 }
 
 pre {
diff --git a/chrome/test/data/payments/util.js b/components/test/data/payments/util.js
similarity index 83%
rename from chrome/test/data/payments/util.js
rename to components/test/data/payments/util.js
index d7fe08c7..4284c7c 100644
--- a/chrome/test/data/payments/util.js
+++ b/components/test/data/payments/util.js
@@ -8,6 +8,6 @@
  * Prints the message.
  * @param {String} msg - The message to print.
  */
-function print(msg) { // eslint-disable-line no-unused-vars
+function print(msg) {  // eslint-disable-line no-unused-vars
   document.getElementById('result').innerHTML = msg;
 }
diff --git a/chrome/test/data/payments/webpay b/components/test/data/payments/webpay
similarity index 100%
rename from chrome/test/data/payments/webpay
rename to components/test/data/payments/webpay
diff --git a/chrome/test/data/payments/webpay.mock-http-headers b/components/test/data/payments/webpay.mock-http-headers
similarity index 100%
rename from chrome/test/data/payments/webpay.mock-http-headers
rename to components/test/data/payments/webpay.mock-http-headers
diff --git a/components/viz/service/display/display_unittest.cc b/components/viz/service/display/display_unittest.cc
index b980608..26aefd6 100644
--- a/components/viz/service/display/display_unittest.cc
+++ b/components/viz/service/display/display_unittest.cc
@@ -331,7 +331,7 @@
     pass->damage_rect = gfx::Rect(10, 10, 0, 0);
     bool copy_called = false;
     pass->copy_requests.push_back(cc::CopyOutputRequest::CreateRequest(
-        base::Bind(&CopyCallback, &copy_called)));
+        base::BindOnce(&CopyCallback, &copy_called)));
     pass->id = 1u;
 
     pass_list.push_back(std::move(pass));
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc b/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
index 71475e5..db4f9d6c 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
@@ -732,7 +732,7 @@
 
   bool called1 = false;
   auto request = cc::CopyOutputRequest::CreateRequest(
-      base::Bind(&CopyRequestTestCallback, &called1));
+      base::BindOnce(&CopyRequestTestCallback, &called1));
   request->set_source(kArbitrarySourceId1);
 
   support_->RequestCopyOfSurface(std::move(request));
@@ -740,7 +740,7 @@
 
   bool called2 = false;
   request = cc::CopyOutputRequest::CreateRequest(
-      base::Bind(&CopyRequestTestCallback, &called2));
+      base::BindOnce(&CopyRequestTestCallback, &called2));
   request->set_source(kArbitrarySourceId2);
 
   support_->RequestCopyOfSurface(std::move(request));
@@ -750,7 +750,7 @@
 
   bool called3 = false;
   request = cc::CopyOutputRequest::CreateRequest(
-      base::Bind(&CopyRequestTestCallback, &called3));
+      base::BindOnce(&CopyRequestTestCallback, &called3));
   request->set_source(kArbitrarySourceId1);
 
   support_->RequestCopyOfSurface(std::move(request));
diff --git a/content/browser/DEPS b/content/browser/DEPS
index 4d234c09..ed95369 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -81,6 +81,7 @@
   "+third_party/WebKit/public/platform/WebReferrerPolicy.h",
   "+third_party/WebKit/public/platform/WebScreenInfo.h",
   "+third_party/WebKit/public/platform/WebSecurityStyle.h",
+  "+third_party/WebKit/public/platform/WebSuddenTerminationDisablerType.h",
   "+third_party/WebKit/public/platform/WebTouchEvent.h",
   "+third_party/WebKit/public/platform/WebTextInputType.h",
   "+third_party/WebKit/public/platform/mac/WebScrollbarTheme.h",
diff --git a/content/browser/appcache/appcache_job.cc b/content/browser/appcache/appcache_job.cc
index 635e9a8..3ef6fb86 100644
--- a/content/browser/appcache/appcache_job.cc
+++ b/content/browser/appcache/appcache_job.cc
@@ -25,8 +25,8 @@
     const OnPrepareToRestartCallback& restart_callback) {
   std::unique_ptr<AppCacheJob> job;
   if (base::FeatureList::IsEnabled(features::kNetworkService)) {
-    job.reset(
-        new AppCacheURLLoaderJob(*(request->GetResourceRequest()), storage));
+    job.reset(new AppCacheURLLoaderJob(*(request->GetResourceRequest()),
+                                       request->AsURLLoaderRequest(), storage));
   } else {
     job.reset(new AppCacheURLRequestJob(request->GetURLRequest(),
                                         network_delegate, storage, host,
diff --git a/content/browser/appcache/appcache_request.cc b/content/browser/appcache/appcache_request.cc
index 6fc31ec..d5ddc87 100644
--- a/content/browser/appcache/appcache_request.cc
+++ b/content/browser/appcache/appcache_request.cc
@@ -27,4 +27,12 @@
   return nullptr;
 }
 
+AppCacheURLRequest* AppCacheRequest::AsURLRequest() {
+  return nullptr;
+}
+
+AppCacheURLLoaderRequest* AppCacheRequest::AsURLLoaderRequest() {
+  return nullptr;
+}
+
 }  // namespace content
diff --git a/content/browser/appcache/appcache_request.h b/content/browser/appcache/appcache_request.h
index 4e14d65..63dc5ec 100644
--- a/content/browser/appcache/appcache_request.h
+++ b/content/browser/appcache/appcache_request.h
@@ -16,6 +16,8 @@
 }
 
 namespace content {
+class AppCacheURLLoaderRequest;
+class AppCacheURLRequest;
 struct ResourceRequest;
 
 // Interface for an AppCache request. Subclasses implement this interface to
@@ -58,6 +60,14 @@
   static bool IsSchemeAndMethodSupportedForAppCache(
       const AppCacheRequest* request);
 
+  // Returns the underlying AppCacheURLRequest if any. This only applies to
+  // AppCache requests loaded via the URLRequest mechanism
+  virtual AppCacheURLRequest* AsURLRequest();
+
+  // Returns the underlying AppCacheURLLoaderRequest if any. This only applies
+  // to AppCache requests loaded via the URLLoader mechanism.
+  virtual AppCacheURLLoaderRequest* AsURLLoaderRequest();
+
  protected:
   friend class AppCacheRequestHandler;
   // Enables the AppCacheJob to call GetURLRequest() and GetResourceRequest().
diff --git a/content/browser/appcache/appcache_request_handler.cc b/content/browser/appcache/appcache_request_handler.cc
index 652eff24..8db5e59 100644
--- a/content/browser/appcache/appcache_request_handler.cc
+++ b/content/browser/appcache/appcache_request_handler.cc
@@ -127,19 +127,24 @@
   if (request_->GetURL().GetOrigin() == location.GetOrigin())
     return NULL;
 
-  DCHECK(!job_.get());  // our jobs never generate redirects
+  // In network service land, the existing job initiates a fallback request.
+  if (!base::FeatureList::IsEnabled(features::kNetworkService)) {
+    DCHECK(!job_.get());  // our jobs never generate redirects
+  } else {
+    DCHECK(job_.get());
+  }
 
   std::unique_ptr<AppCacheJob> job;
   if (found_fallback_entry_.has_response_id()) {
+    job = MaybeCreateJobForFallback(network_delegate);
     // 6.9.6, step 4: If this results in a redirect to another origin,
     // get the resource of the fallback entry.
-    job = CreateJob(network_delegate);
     DeliverAppCachedResponse(found_fallback_entry_, found_cache_id_,
                              found_manifest_url_, true,
                              found_namespace_entry_url_);
   } else if (!found_network_namespace_) {
     // 6.9.6, step 6: Fail the resource load.
-    job = CreateJob(network_delegate);
+    job = MaybeCreateJobForFallback(network_delegate);
     DeliverErrorResponse();
   } else {
     // 6.9.6 step 3 and 5: Fetch the resource normally.
@@ -163,7 +168,7 @@
   }
 
   // We don't fallback for responses that we delivered.
-  if (job_.get()) {
+  if (job_.get() && !base::FeatureList::IsEnabled(features::kNetworkService)) {
     DCHECK(!job_->IsDeliveringNetworkResponse());
     return NULL;
   }
@@ -186,7 +191,12 @@
 
   // 6.9.6, step 4: If this results in a 4xx or 5xx status code
   // or there were network errors, get the resource of the fallback entry.
-  std::unique_ptr<AppCacheJob> job = CreateJob(network_delegate);
+
+  // In network service land, the job initiates a fallback request. We reuse
+  // the existing job to deliver the fallback response.
+  std::unique_ptr<AppCacheJob> job =
+      MaybeCreateJobForFallback(network_delegate);
+
   DeliverAppCachedResponse(found_fallback_entry_, found_cache_id_,
                            found_manifest_url_, true,
                            found_namespace_entry_url_);
@@ -342,6 +352,16 @@
   return job;
 }
 
+std::unique_ptr<AppCacheJob> AppCacheRequestHandler::MaybeCreateJobForFallback(
+    net::NetworkDelegate* network_delegate) {
+  if (!base::FeatureList::IsEnabled(features::kNetworkService))
+    return CreateJob(network_delegate);
+  // In network service land, the job initiates a fallback request. We reuse
+  // the existing job to deliver the fallback response.
+  DCHECK(job_.get());
+  return std::unique_ptr<AppCacheJob>(job_.get());
+}
+
 // Main-resource handling ----------------------------------------------
 
 std::unique_ptr<AppCacheJob> AppCacheRequestHandler::MaybeLoadMainResource(
diff --git a/content/browser/appcache/appcache_request_handler.h b/content/browser/appcache/appcache_request_handler.h
index da797b92..24ee0fc 100644
--- a/content/browser/appcache/appcache_request_handler.h
+++ b/content/browser/appcache/appcache_request_handler.h
@@ -124,6 +124,10 @@
   std::unique_ptr<AppCacheJob> CreateJob(
       net::NetworkDelegate* network_delegate);
 
+  // Helper method to create an AppCacheJob for fallback responses.
+  std::unique_ptr<AppCacheJob> MaybeCreateJobForFallback(
+      net::NetworkDelegate* network_delegate);
+
   // Helper to retrieve a pointer to the storage object.
   AppCacheStorage* storage() const;
 
diff --git a/content/browser/appcache/appcache_url_loader_job.cc b/content/browser/appcache/appcache_url_loader_job.cc
index 1d1932f..8ddd92a 100644
--- a/content/browser/appcache/appcache_url_loader_job.cc
+++ b/content/browser/appcache/appcache_url_loader_job.cc
@@ -7,6 +7,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "content/browser/appcache/appcache_histograms.h"
 #include "content/browser/appcache/appcache_subresource_url_factory.h"
+#include "content/browser/appcache/appcache_url_loader_request.h"
 #include "content/browser/url_loader_factory_getter.h"
 #include "content/common/net_adapters.h"
 #include "content/public/common/resource_type.h"
@@ -76,13 +77,16 @@
     // request. The loader callback is valid only for navigation requests.
     std::move(main_resource_loader_callback_).Run(StartLoaderCallback());
   } else {
+    mojom::URLLoaderClientPtr client_ptr;
+    network_loader_client_binding_.Bind(mojo::MakeRequest(&client_ptr));
+
     default_url_loader_factory_getter_->GetNetworkFactory()
         ->get()
         ->CreateLoaderAndStart(
-            mojo::MakeRequest(&network_loader_request_),
+            mojo::MakeRequest(&network_loader_),
             subresource_load_info_->routing_id,
             subresource_load_info_->request_id, subresource_load_info_->options,
-            subresource_load_info_->request, std::move(client_info_),
+            subresource_load_info_->request, std::move(client_ptr),
             subresource_load_info_->traffic_annotation);
   }
 }
@@ -91,7 +95,7 @@
   delivery_type_ = ERROR_DELIVERY;
 
   // We expect the URLLoaderClient pointer to be valid at this point.
-  DCHECK(client_info_);
+  DCHECK(client_);
 
   // AppCacheURLRequestJob uses ERR_FAILED as the error code here. That seems
   // to map to HTTP_INTERNAL_SERVER_ERROR.
@@ -103,7 +107,7 @@
 
   ResourceResponseHead response;
   response.headers = new net::HttpResponseHeaders(status);
-  client_info_->OnReceiveResponse(response, base::nullopt, nullptr);
+  client_->OnReceiveResponse(response, base::nullopt, nullptr);
 
   NotifyCompleted(net::ERR_FAILED);
 
@@ -120,14 +124,90 @@
 }
 
 void AppCacheURLLoaderJob::FollowRedirect() {
-  if (network_loader_request_)
-    network_loader_request_->FollowRedirect();
+  if (network_loader_)
+    network_loader_->FollowRedirect();
 }
 
 void AppCacheURLLoaderJob::SetPriority(net::RequestPriority priority,
                                        int32_t intra_priority_value) {
-  if (network_loader_request_)
-    network_loader_request_->SetPriority(priority, intra_priority_value);
+  if (network_loader_)
+    network_loader_->SetPriority(priority, intra_priority_value);
+}
+
+void AppCacheURLLoaderJob::OnReceiveResponse(
+    const ResourceResponseHead& response_head,
+    const base::Optional<net::SSLInfo>& ssl_info,
+    mojom::DownloadedTempFilePtr downloaded_file) {
+  appcache_request_->set_response(response_head);
+  // The MaybeLoadFallbackForResponse() call below can pass a fallback
+  // response to us. Reset the delivery_type_ to ensure that we can
+  // receive it
+  delivery_type_ = AWAITING_DELIVERY_ORDERS;
+  if (!sub_resource_handler_->MaybeLoadFallbackForResponse(nullptr)) {
+    client_->OnReceiveResponse(response_head, ssl_info,
+                               std::move(downloaded_file));
+  } else {
+    // Disconnect from the network loader as we are delivering a fallback
+    // response to the client.
+    DisconnectFromNetworkLoader();
+  }
+}
+
+void AppCacheURLLoaderJob::OnReceiveRedirect(
+    const net::RedirectInfo& redirect_info,
+    const ResourceResponseHead& response_head) {
+  appcache_request_->set_response(response_head);
+  // The MaybeLoadFallbackForRedirect() call below can pass a fallback
+  // response to us. Reset the delivery_type_ to ensure that we can
+  // receive it
+  delivery_type_ = AWAITING_DELIVERY_ORDERS;
+  if (!sub_resource_handler_->MaybeLoadFallbackForRedirect(
+          nullptr, redirect_info.new_url)) {
+    client_->OnReceiveRedirect(redirect_info, response_head);
+  } else {
+    // Disconnect from the network loader as we are delivering a fallback
+    // response to the client.
+    DisconnectFromNetworkLoader();
+  }
+}
+
+void AppCacheURLLoaderJob::OnDataDownloaded(int64_t data_len,
+                                            int64_t encoded_data_len) {
+  client_->OnDataDownloaded(data_len, encoded_data_len);
+}
+
+void AppCacheURLLoaderJob::OnUploadProgress(
+    int64_t current_position,
+    int64_t total_size,
+    OnUploadProgressCallback ack_callback) {
+  client_->OnUploadProgress(current_position, total_size,
+                            std::move(ack_callback));
+}
+
+void AppCacheURLLoaderJob::OnReceiveCachedMetadata(
+    const std::vector<uint8_t>& data) {
+  client_->OnReceiveCachedMetadata(data);
+}
+
+void AppCacheURLLoaderJob::OnTransferSizeUpdated(int32_t transfer_size_diff) {
+  client_->OnTransferSizeUpdated(transfer_size_diff);
+}
+
+void AppCacheURLLoaderJob::OnStartLoadingResponseBody(
+    mojo::ScopedDataPipeConsumerHandle body) {
+  client_->OnStartLoadingResponseBody(std::move(body));
+}
+
+void AppCacheURLLoaderJob::OnComplete(
+    const ResourceRequestCompletionStatus& status) {
+  delivery_type_ = AWAITING_DELIVERY_ORDERS;
+  if (!sub_resource_handler_->MaybeLoadFallbackForResponse(nullptr)) {
+    client_->OnComplete(status);
+  } else {
+    // Disconnect from the network loader as we are delivering a fallback
+    // response to the client.
+    DisconnectFromNetworkLoader();
+  }
 }
 
 void AppCacheURLLoaderJob::SetSubresourceLoadInfo(
@@ -140,7 +220,7 @@
   associated_binding_->set_connection_error_handler(base::Bind(
       &AppCacheURLLoaderJob::OnConnectionError, StaticAsWeakPtr(this)));
 
-  client_info_ = std::move(subresource_load_info_->client);
+  client_ = std::move(subresource_load_info_->client);
   default_url_loader_factory_getter_ = default_url_loader;
 }
 
@@ -152,15 +232,17 @@
   binding_.set_connection_error_handler(base::Bind(
       &AppCacheURLLoaderJob::OnConnectionError, StaticAsWeakPtr(this)));
 
-  client_info_ = std::move(client);
+  client_ = std::move(client);
 
   // Send the cached AppCacheResponse if any.
   if (info_.get())
     SendResponseInfo();
 }
 
-AppCacheURLLoaderJob::AppCacheURLLoaderJob(const ResourceRequest& request,
-                                           AppCacheStorage* storage)
+AppCacheURLLoaderJob::AppCacheURLLoaderJob(
+    const ResourceRequest& request,
+    AppCacheURLLoaderRequest* appcache_request,
+    AppCacheStorage* storage)
     : request_(request),
       storage_(storage->GetWeakPtr()),
       start_time_tick_(base::TimeTicks::Now()),
@@ -168,7 +250,9 @@
       is_fallback_(false),
       binding_(this),
       writable_handle_watcher_(FROM_HERE,
-                               mojo::SimpleWatcher::ArmingPolicy::MANUAL) {}
+                               mojo::SimpleWatcher::ArmingPolicy::MANUAL),
+      network_loader_client_binding_(this),
+      appcache_request_(appcache_request) {}
 
 void AppCacheURLLoaderJob::OnResponseInfoLoaded(
     AppCacheResponseInfo* response_info,
@@ -206,7 +290,7 @@
         base::Bind(&AppCacheURLLoaderJob::OnResponseBodyStreamReady,
                    StaticAsWeakPtr(this)));
 
-    if (client_info_)
+    if (client_)
       SendResponseInfo();
 
     ReadMore();
@@ -260,7 +344,7 @@
 }
 
 void AppCacheURLLoaderJob::SendResponseInfo() {
-  DCHECK(client_info_);
+  DCHECK(client_);
   // If this is null it means the response information was sent to the client.
   if (!data_pipe_.consumer_handle.is_valid())
     return;
@@ -293,11 +377,12 @@
 
   response_head.load_timing = load_timing_info_;
 
-  client_info_->OnReceiveResponse(response_head, http_info->ssl_info,
-                                  mojom::DownloadedTempFilePtr());
+  appcache_request_->set_response(response_head);
 
-  client_info_->OnStartLoadingResponseBody(
-      std::move(data_pipe_.consumer_handle));
+  client_->OnReceiveResponse(response_head, http_info->ssl_info,
+                             mojom::DownloadedTempFilePtr());
+
+  client_->OnStartLoadingResponseBody(std::move(data_pipe_.consumer_handle));
 }
 
 void AppCacheURLLoaderJob::ReadMore() {
@@ -363,7 +448,14 @@
     request_complete_data.decoded_body_length =
         request_complete_data.encoded_body_length;
   }
-  client_info_->OnComplete(request_complete_data);
+  client_->OnComplete(request_complete_data);
+}
+
+void AppCacheURLLoaderJob::DisconnectFromNetworkLoader() {
+  // Close the pipe to the network loader as we are delivering a fallback
+  // response to the client.
+  network_loader_client_binding_.Close();
+  network_loader_ = nullptr;
 }
 
 }  // namespace content
diff --git a/content/browser/appcache/appcache_url_loader_job.h b/content/browser/appcache/appcache_url_loader_job.h
index 59f62035..d7ea5027 100644
--- a/content/browser/appcache/appcache_url_loader_job.h
+++ b/content/browser/appcache/appcache_url_loader_job.h
@@ -26,9 +26,9 @@
 namespace content {
 
 class AppCacheRequest;
+class AppCacheURLLoaderRequest;
 class NetToMojoPendingBuffer;
 class URLLoaderFactoryGetter;
-struct SubresourceLoadInfo;
 
 // Holds information about the subresource load request like the routing id,
 // request id, the client pointer, etc.
@@ -49,7 +49,8 @@
 // responses stored in the AppCache.
 class CONTENT_EXPORT AppCacheURLLoaderJob : public AppCacheJob,
                                             public AppCacheStorage::Delegate,
-                                            public mojom::URLLoader {
+                                            public mojom::URLLoader,
+                                            public mojom::URLLoaderClient {
  public:
   ~AppCacheURLLoaderJob() override;
 
@@ -73,6 +74,25 @@
   void SetPriority(net::RequestPriority priority,
                    int32_t intra_priority_value) override;
 
+  // mojom::URLLoaderClient implementation.
+  // These methods are called by the network loader for subresource requests
+  // which go to the network. We serve fallback content in these methods
+  // if applicable.
+  void OnReceiveResponse(const ResourceResponseHead& response_head,
+                         const base::Optional<net::SSLInfo>& ssl_info,
+                         mojom::DownloadedTempFilePtr downloaded_file) override;
+  void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
+                         const ResourceResponseHead& response_head) override;
+  void OnDataDownloaded(int64_t data_len, int64_t encoded_data_len) override;
+  void OnUploadProgress(int64_t current_position,
+                        int64_t total_size,
+                        OnUploadProgressCallback ack_callback) override;
+  void OnReceiveCachedMetadata(const std::vector<uint8_t>& data) override;
+  void OnTransferSizeUpdated(int32_t transfer_size_diff) override;
+  void OnStartLoadingResponseBody(
+      mojo::ScopedDataPipeConsumerHandle body) override;
+  void OnComplete(const ResourceRequestCompletionStatus& status) override;
+
   void set_main_resource_loader_callback(LoaderCallback callback) {
     main_resource_loader_callback_ = std::move(callback);
   }
@@ -97,6 +117,7 @@
   friend class AppCacheJob;
 
   AppCacheURLLoaderJob(const ResourceRequest& request,
+                       AppCacheURLLoaderRequest* appcache_request,
                        AppCacheStorage* storage);
 
   // AppCacheStorage::Delegate methods
@@ -120,6 +141,10 @@
   // Notifies the client about request completion.
   void NotifyCompleted(int error_code);
 
+  // Disconnects the mojo pipe to the network loader and releases related
+  // resources.
+  void DisconnectFromNetworkLoader();
+
   // The current request.
   ResourceRequest request_;
 
@@ -147,7 +172,7 @@
 
   // The URLLoaderClient pointer. We call this interface with notifications
   // about the URL load
-  mojom::URLLoaderClientPtr client_info_;
+  mojom::URLLoaderClientPtr client_;
 
   // mojo data pipe entities.
   mojo::ScopedDataPipeProducerHandle response_body_stream_;
@@ -173,7 +198,7 @@
   net::LoadTimingInfo load_timing_info_;
 
   // Used for subresource requests which go to the network.
-  mojom::URLLoaderAssociatedPtr network_loader_request_;
+  mojom::URLLoaderAssociatedPtr network_loader_;
 
   // Binds the subresource URLLoaderClient with us. We can use the regular
   // binding_ member above when we remove the need for the associated requests
@@ -181,6 +206,13 @@
   std::unique_ptr<mojo::AssociatedBinding<mojom::URLLoader>>
       associated_binding_;
 
+  // Network URLLoaderClient binding for subresource requests.
+  mojo::Binding<mojom::URLLoaderClient> network_loader_client_binding_;
+
+  // The AppCacheURLLoaderRequest instance. We use this to set the response
+  // info when we receive it.
+  AppCacheURLLoaderRequest* appcache_request_;
+
   DISALLOW_COPY_AND_ASSIGN(AppCacheURLLoaderJob);
 };
 
diff --git a/content/browser/appcache/appcache_url_loader_request.cc b/content/browser/appcache/appcache_url_loader_request.cc
index 11c85ba..4669be9 100644
--- a/content/browser/appcache/appcache_url_loader_request.cc
+++ b/content/browser/appcache/appcache_url_loader_request.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "content/browser/appcache/appcache_url_loader_request.h"
+#include "content/public/common/resource_type.h"
 #include "net/url_request/url_request.h"
 
 namespace content {
@@ -33,7 +34,8 @@
 }
 
 bool AppCacheURLLoaderRequest::IsSuccess() const {
-  return false;
+  int response_code = GetResponseCode();
+  return (response_code >= 200 && response_code <= 226);
 }
 
 bool AppCacheURLLoaderRequest::IsCancelled() const {
@@ -45,6 +47,8 @@
 }
 
 int AppCacheURLLoaderRequest::GetResponseCode() const {
+  if (response_.headers)
+    return response_.headers->response_code();
   return 0;
 }
 
@@ -57,6 +61,10 @@
   return &request_;
 }
 
+AppCacheURLLoaderRequest* AppCacheURLLoaderRequest::AsURLLoaderRequest() {
+  return this;
+}
+
 AppCacheURLLoaderRequest::AppCacheURLLoaderRequest(
     const ResourceRequest& request)
     : request_(request) {}
diff --git a/content/browser/appcache/appcache_url_loader_request.h b/content/browser/appcache/appcache_url_loader_request.h
index 83fca41..d0435c7 100644
--- a/content/browser/appcache/appcache_url_loader_request.h
+++ b/content/browser/appcache/appcache_url_loader_request.h
@@ -7,6 +7,7 @@
 
 #include "content/browser/appcache/appcache_request.h"
 #include "content/public/common/resource_request.h"
+#include "content/public/common/resource_response.h"
 
 namespace content {
 
@@ -39,12 +40,18 @@
   int GetResponseCode() const override;
   std::string GetResponseHeaderByName(const std::string& name) const override;
   ResourceRequest* GetResourceRequest() override;
+  AppCacheURLLoaderRequest* AsURLLoaderRequest() override;
+
+  void set_response(const ResourceResponseHead& response) {
+    response_ = response;
+  }
 
  protected:
   explicit AppCacheURLLoaderRequest(const ResourceRequest& request);
 
  private:
   ResourceRequest request_;
+  ResourceResponseHead response_;
 
   DISALLOW_COPY_AND_ASSIGN(AppCacheURLLoaderRequest);
 };
diff --git a/content/browser/appcache/appcache_url_request.cc b/content/browser/appcache/appcache_url_request.cc
index 56d36ce..da320b4 100644
--- a/content/browser/appcache/appcache_url_request.cc
+++ b/content/browser/appcache/appcache_url_request.cc
@@ -58,6 +58,10 @@
   return url_request_;
 }
 
+AppCacheURLRequest* AppCacheURLRequest::AsURLRequest() {
+  return this;
+}
+
 AppCacheURLRequest::AppCacheURLRequest(net::URLRequest* url_request)
     : url_request_(url_request) {}
 
diff --git a/content/browser/appcache/appcache_url_request.h b/content/browser/appcache/appcache_url_request.h
index 6122e08..35291588 100644
--- a/content/browser/appcache/appcache_url_request.h
+++ b/content/browser/appcache/appcache_url_request.h
@@ -33,8 +33,8 @@
   bool IsError() const override;
   int GetResponseCode() const override;
   std::string GetResponseHeaderByName(const std::string& name) const override;
-
   net::URLRequest* GetURLRequest() override;
+  AppCacheURLRequest* AsURLRequest() override;
 
  protected:
   explicit AppCacheURLRequest(net::URLRequest* url_request);
diff --git a/content/browser/devtools/devtools_agent_host_impl.cc b/content/browser/devtools/devtools_agent_host_impl.cc
index 011befdc..fa98019f 100644
--- a/content/browser/devtools/devtools_agent_host_impl.cc
+++ b/content/browser/devtools/devtools_agent_host_impl.cc
@@ -41,7 +41,6 @@
 char DevToolsAgentHost::kTypeFrame[] = "iframe";
 char DevToolsAgentHost::kTypeSharedWorker[] = "shared_worker";
 char DevToolsAgentHost::kTypeServiceWorker[] = "service_worker";
-char DevToolsAgentHost::kTypeExternal[] = "external";
 char DevToolsAgentHost::kTypeBrowser[] = "browser";
 char DevToolsAgentHost::kTypeGuest[] = "webview";
 char DevToolsAgentHost::kTypeOther[] = "other";
diff --git a/content/browser/devtools/page_navigation_throttle.cc b/content/browser/devtools/page_navigation_throttle.cc
index 013acbc2..bd73a5c63d 100644
--- a/content/browser/devtools/page_navigation_throttle.cc
+++ b/content/browser/devtools/page_navigation_throttle.cc
@@ -52,27 +52,29 @@
   // Makes WillStartRequest and WillRedirectRequest always return
   // ThrottleCheckResult::PROCEED.
   page_handler_.reset();
-
-  if (navigation_deferred_)
-    Resume();
+  Resume();
 }
 
+// Resumes a deferred navigation request. Does nothing if a response isn't
+// expected.
 void PageNavigationThrottle::Resume() {
   if (!navigation_deferred_)
     return;
   navigation_deferred_ = false;
-  navigation_handle()->Resume();
+  content::NavigationThrottle::Resume();
 
   // Do not add code after this as the PageNavigationThrottle may be deleted by
   // the line above.
 }
 
+// Cancels a deferred navigation request. Does nothing if a response isn't
+// expected.
 void PageNavigationThrottle::CancelDeferredNavigation(
     NavigationThrottle::ThrottleCheckResult result) {
   if (!navigation_deferred_)
     return;
   navigation_deferred_ = false;
-  navigation_handle()->CancelDeferredNavigation(result);
+  content::NavigationThrottle::CancelDeferredNavigation(result);
 
   // Do not add code after this as the PageNavigationThrottle may be deleted by
   // the line above.
diff --git a/content/browser/devtools/page_navigation_throttle.h b/content/browser/devtools/page_navigation_throttle.h
index 2dad7dd..6fd23f0 100644
--- a/content/browser/devtools/page_navigation_throttle.h
+++ b/content/browser/devtools/page_navigation_throttle.h
@@ -27,20 +27,15 @@
   NavigationThrottle::ThrottleCheckResult WillStartRequest() override;
   NavigationThrottle::ThrottleCheckResult WillRedirectRequest() override;
   const char* GetNameForLogging() override;
+  void Resume() override;
+  void CancelDeferredNavigation(
+      NavigationThrottle::ThrottleCheckResult result) override;
 
   int navigation_id() const { return navigation_id_; }
 
   // Tells the PageNavigationThrottle to not throttle anything!
   void AlwaysProceed();
 
-  // Resumes a deferred navigation request. Does nothing if a response isn't
-  // expected.
-  void Resume();
-
-  // Cancels a deferred navigation request. Does nothing if a response isn't
-  // expected.
-  void CancelDeferredNavigation(NavigationThrottle::ThrottleCheckResult result);
-
  private:
   // An opaque ID assigned by the PageHandler, used to allow the protocol client
   // to refer to this navigation throttle.
@@ -50,7 +45,7 @@
   base::WeakPtr<protocol::PageHandler> page_handler_;
 
   // Whether or not a navigation was deferred. If deferred we expect a
-  // subsequent call to AlwaysProceed, Resume or CancelDeferredNavigation.
+  // subsequent call to AlwaysProceed, Resume or CancelNavigationIfDeferred.
   bool navigation_deferred_;
 
   DISALLOW_COPY_AND_ASSIGN(PageNavigationThrottle);
diff --git a/content/browser/frame_host/navigation_handle_impl.cc b/content/browser/frame_host/navigation_handle_impl.cc
index 588f4c5..ec9ded6b4 100644
--- a/content/browser/frame_host/navigation_handle_impl.cc
+++ b/content/browser/frame_host/navigation_handle_impl.cc
@@ -356,72 +356,20 @@
   return socket_address_;
 }
 
-void NavigationHandleImpl::Resume() {
-  if (state_ != DEFERRING_START && state_ != DEFERRING_REDIRECT &&
-      state_ != DEFERRING_RESPONSE) {
-    return;
-  }
-  TRACE_EVENT_ASYNC_STEP_INTO0("navigation", "NavigationHandle", this,
-                               "Resume");
-
-  NavigationThrottle::ThrottleCheckResult result = NavigationThrottle::DEFER;
-  if (state_ == DEFERRING_START) {
-    result = CheckWillStartRequest();
-    if (result == NavigationThrottle::DEFER) {
-      // DO NOT ADD CODE: the NavigationHandle might have been destroyed during
-      // one of the NavigationThrottle checks.
-      return;
-    }
-  } else if (state_ == DEFERRING_REDIRECT) {
-    result = CheckWillRedirectRequest();
-    if (result == NavigationThrottle::DEFER) {
-      // DO NOT ADD CODE: the NavigationHandle might have been destroyed during
-      // one of the NavigationThrottle checks.
-      return;
-    }
-  } else {
-    result = CheckWillProcessResponse();
-    if (result == NavigationThrottle::DEFER) {
-      // DO NOT ADD CODE: the NavigationHandle might have been destroyed during
-      // one of the NavigationThrottle checks.
-      return;
-    }
-
-    // If the navigation is about to proceed after having been deferred while
-    // processing the response, then it's ready to commit. Determine which
-    // RenderFrameHost should render the response, based on its site (after any
-    // redirects).
-    // Note: if MaybeTransferAndProceed returns false, this means that this
-    // NavigationHandle was deleted, so return immediately.
-    if (result == NavigationThrottle::PROCEED && !MaybeTransferAndProceed())
-      return;
-  }
-  DCHECK_NE(NavigationThrottle::DEFER, result);
-
-  TRACE_EVENT_ASYNC_STEP_INTO0("navigation", "NavigationHandle", this,
-                               "Resuming");
-  RunCompleteCallback(result);
+void NavigationHandleImpl::Resume(NavigationThrottle* resuming_throttle) {
+  DCHECK(resuming_throttle);
+  // TODO(csharrison): Convert to DCHECK when crbug.com/736249 is resolved.
+  CHECK_EQ(resuming_throttle, GetDeferringThrottle());
+  ResumeInternal();
 }
 
 void NavigationHandleImpl::CancelDeferredNavigation(
+    NavigationThrottle* cancelling_throttle,
     NavigationThrottle::ThrottleCheckResult result) {
-  DCHECK(state_ == DEFERRING_START ||
-         state_ == DEFERRING_REDIRECT ||
-         state_ == DEFERRING_RESPONSE);
-  DCHECK(result == NavigationThrottle::CANCEL_AND_IGNORE ||
-         result == NavigationThrottle::CANCEL ||
-         result == NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE);
-  DCHECK(result != NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE ||
-         state_ == DEFERRING_START ||
-         (state_ == DEFERRING_REDIRECT && IsBrowserSideNavigationEnabled()));
-
-  if (result == NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE)
-    frame_tree_node_->SetCollapsed(true);
-
-  TRACE_EVENT_ASYNC_STEP_INTO0("navigation", "NavigationHandle", this,
-                               "CancelDeferredNavigation");
-  state_ = CANCELING;
-  RunCompleteCallback(result);
+  DCHECK(cancelling_throttle);
+  // TODO(csharrison): Convert to DCHECK when crbug.com/736249 is resolved.
+  CHECK_EQ(cancelling_throttle, GetDeferringThrottle());
+  CancelDeferredNavigationInternal(result);
 }
 
 void NavigationHandleImpl::RegisterThrottleForTesting(
@@ -517,6 +465,10 @@
                       render_frame_host_);
 }
 
+void NavigationHandleImpl::CallResumeForTesting() {
+  ResumeInternal();
+}
+
 bool NavigationHandleImpl::WasStartedFromContextMenu() const {
   return started_from_context_menu_;
 }
@@ -1018,6 +970,72 @@
   return NavigationThrottle::PROCEED;
 }
 
+void NavigationHandleImpl::ResumeInternal() {
+  DCHECK(state_ == DEFERRING_START || state_ == DEFERRING_REDIRECT ||
+         state_ == DEFERRING_RESPONSE)
+      << "Called ResumeInternal() in state " << state_;
+  TRACE_EVENT_ASYNC_STEP_INTO0("navigation", "NavigationHandle", this,
+                               "Resume");
+
+  NavigationThrottle::ThrottleCheckResult result = NavigationThrottle::DEFER;
+  if (state_ == DEFERRING_START) {
+    result = CheckWillStartRequest();
+    if (result == NavigationThrottle::DEFER) {
+      // DO NOT ADD CODE: the NavigationHandle might have been destroyed during
+      // one of the NavigationThrottle checks.
+      return;
+    }
+  } else if (state_ == DEFERRING_REDIRECT) {
+    result = CheckWillRedirectRequest();
+    if (result == NavigationThrottle::DEFER) {
+      // DO NOT ADD CODE: the NavigationHandle might have been destroyed during
+      // one of the NavigationThrottle checks.
+      return;
+    }
+  } else {
+    result = CheckWillProcessResponse();
+    if (result == NavigationThrottle::DEFER) {
+      // DO NOT ADD CODE: the NavigationHandle might have been destroyed during
+      // one of the NavigationThrottle checks.
+      return;
+    }
+
+    // If the navigation is about to proceed after having been deferred while
+    // processing the response, then it's ready to commit. Determine which
+    // RenderFrameHost should render the response, based on its site (after any
+    // redirects).
+    // Note: if MaybeTransferAndProceed returns false, this means that this
+    // NavigationHandle was deleted, so return immediately.
+    if (result == NavigationThrottle::PROCEED && !MaybeTransferAndProceed())
+      return;
+  }
+  DCHECK_NE(NavigationThrottle::DEFER, result);
+
+  TRACE_EVENT_ASYNC_STEP_INTO0("navigation", "NavigationHandle", this,
+                               "Resuming");
+  RunCompleteCallback(result);
+}
+
+void NavigationHandleImpl::CancelDeferredNavigationInternal(
+    NavigationThrottle::ThrottleCheckResult result) {
+  DCHECK(state_ == DEFERRING_START || state_ == DEFERRING_REDIRECT ||
+         state_ == DEFERRING_RESPONSE);
+  DCHECK(result == NavigationThrottle::CANCEL_AND_IGNORE ||
+         result == NavigationThrottle::CANCEL ||
+         result == NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE);
+  DCHECK(result != NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE ||
+         state_ == DEFERRING_START ||
+         (state_ == DEFERRING_REDIRECT && IsBrowserSideNavigationEnabled()));
+
+  if (result == NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE)
+    frame_tree_node_->SetCollapsed(true);
+
+  TRACE_EVENT_ASYNC_STEP_INTO0("navigation", "NavigationHandle", this,
+                               "CancelDeferredNavigation");
+  state_ = CANCELING;
+  RunCompleteCallback(result);
+}
+
 bool NavigationHandleImpl::MaybeTransferAndProceed() {
   DCHECK_EQ(WILL_PROCESS_RESPONSE, state_);
 
@@ -1223,4 +1241,10 @@
   SetExpectedProcess(post_redirect_process);
 }
 
+NavigationThrottle* NavigationHandleImpl::GetDeferringThrottle() const {
+  if (next_index_ == 0)
+    return nullptr;
+  return throttles_[next_index_ - 1].get();
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/navigation_handle_impl.h b/content/browser/frame_host/navigation_handle_impl.h
index 36e89012..fb9bf9e 100644
--- a/content/browser/frame_host/navigation_handle_impl.h
+++ b/content/browser/frame_host/navigation_handle_impl.h
@@ -139,9 +139,6 @@
   net::HostPortPair GetSocketAddress() override;
   const net::HttpResponseHeaders* GetResponseHeaders() override;
   net::HttpResponseInfo::ConnectionInfo GetConnectionInfo() override;
-  void Resume() override;
-  void CancelDeferredNavigation(
-      NavigationThrottle::ThrottleCheckResult result) override;
   void RegisterThrottleForTesting(
       std::unique_ptr<NavigationThrottle> navigation_throttle) override;
   NavigationThrottle::ThrottleCheckResult CallWillStartRequestForTesting(
@@ -159,6 +156,7 @@
       RenderFrameHost* render_frame_host,
       const std::string& raw_response_header) override;
   void CallDidCommitNavigationForTesting(const GURL& url) override;
+  void CallResumeForTesting() override;
   bool WasStartedFromContextMenu() const override;
   const GURL& GetSearchableFormURL() override;
   const std::string& GetSearchableFormEncoding() override;
@@ -167,6 +165,14 @@
   const GURL& GetBaseURLForDataURL() override;
   const GlobalRequestID& GetGlobalRequestID() override;
 
+  // Resume and CancelDeferredNavigation must only be called by the
+  // NavigationThrottle that is currently deferring the navigation.
+  // |resuming_throttle| and |cancelling_throttle| are the throttles calling
+  // these methods.
+  void Resume(NavigationThrottle* resuming_throttle);
+  void CancelDeferredNavigation(NavigationThrottle* cancelling_throttle,
+                                NavigationThrottle::ThrottleCheckResult result);
+
   NavigationData* GetNavigationData() override;
 
   // Used in tests.
@@ -406,6 +412,10 @@
   NavigationThrottle::ThrottleCheckResult CheckWillRedirectRequest();
   NavigationThrottle::ThrottleCheckResult CheckWillProcessResponse();
 
+  void ResumeInternal();
+  void CancelDeferredNavigationInternal(
+      NavigationThrottle::ThrottleCheckResult result);
+
   // Called when WillProcessResponse checks are done, to find the final
   // RenderFrameHost for the navigation. Checks whether the navigation should be
   // transferred. Returns false if the transfer attempt results in the
@@ -444,6 +454,11 @@
   // existing RenderProcessHost. Otherwise, it should be null.
   void UpdateSiteURL(RenderProcessHost* post_redirect_process);
 
+  // Returns the throttle that is currently deferring the navigation (i.e. the
+  // throttle at index |next_index_ -1|). If the handle is not deferred, returns
+  // nullptr;
+  NavigationThrottle* GetDeferringThrottle() const;
+
   // See NavigationHandle for a description of those member variables.
   GURL url_;
   scoped_refptr<SiteInstance> starting_site_instance_;
diff --git a/content/browser/frame_host/navigation_handle_impl_browsertest.cc b/content/browser/frame_host/navigation_handle_impl_browsertest.cc
index 4f8a7b1..4d0811e 100644
--- a/content/browser/frame_host/navigation_handle_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_handle_impl_browsertest.cc
@@ -55,13 +55,15 @@
 
   const char* GetNameForLogging() override { return "TestNavigationThrottle"; }
 
-  void Resume() { navigation_handle()->Resume(); }
-  void Cancel(NavigationThrottle::ThrottleCheckResult result) {
-    navigation_handle()->CancelDeferredNavigation(result);
-  }
-
   RequestContextType request_context_type() { return request_context_type_; }
 
+  // Expose Resume and Cancel to the installer.
+  void ResumeNavigation() { Resume(); }
+
+  void CancelNavigation(NavigationThrottle::ThrottleCheckResult result) {
+    CancelDeferredNavigation(result);
+  }
+
  private:
   // NavigationThrottle implementation.
   NavigationThrottle::ThrottleCheckResult WillStartRequest() override {
@@ -155,9 +157,9 @@
   void Continue(NavigationThrottle::ThrottleCheckResult result) {
     ASSERT_NE(NavigationThrottle::DEFER, result);
     if (result == NavigationThrottle::PROCEED)
-      navigation_throttle()->Resume();
+      navigation_throttle()->ResumeNavigation();
     else
-      navigation_throttle()->Cancel(result);
+      navigation_throttle()->CancelNavigation(result);
   }
 
   int will_start_called() { return will_start_called_; }
@@ -702,21 +704,21 @@
   EXPECT_EQ(1, installer.will_start_called());
   EXPECT_EQ(0, installer.will_redirect_called());
   EXPECT_EQ(0, installer.will_process_called());
-  installer.navigation_throttle()->Resume();
+  installer.navigation_throttle()->ResumeNavigation();
 
   // Wait for WillRedirectRequest.
   installer.WaitForThrottleWillRedirect();
   EXPECT_EQ(1, installer.will_start_called());
   EXPECT_EQ(1, installer.will_redirect_called());
   EXPECT_EQ(0, installer.will_process_called());
-  installer.navigation_throttle()->Resume();
+  installer.navigation_throttle()->ResumeNavigation();
 
   // Wait for WillProcessResponse.
   installer.WaitForThrottleWillProcess();
   EXPECT_EQ(1, installer.will_start_called());
   EXPECT_EQ(1, installer.will_redirect_called());
   EXPECT_EQ(1, installer.will_process_called());
-  installer.navigation_throttle()->Resume();
+  installer.navigation_throttle()->ResumeNavigation();
 
   // Wait for the end of the navigation.
   navigation_observer.Wait();
diff --git a/content/browser/frame_host/navigation_handle_impl_unittest.cc b/content/browser/frame_host/navigation_handle_impl_unittest.cc
index c3bd36f1..3ffd938 100644
--- a/content/browser/frame_host/navigation_handle_impl_unittest.cc
+++ b/content/browser/frame_host/navigation_handle_impl_unittest.cc
@@ -152,6 +152,13 @@
     return test_handle_->state() == NavigationHandleImpl::CANCELING;
   }
 
+  void Resume() { test_handle_->ResumeInternal(); }
+
+  void CancelDeferredNavigation(
+      NavigationThrottle::ThrottleCheckResult result) {
+    test_handle_->CancelDeferredNavigationInternal(result);
+  }
+
   // Helper function to call WillStartRequest on |handle|. If this function
   // returns DEFER, |callback_result_| will be set to the actual result of
   // the throttle checks when they are finished.
@@ -332,14 +339,12 @@
   EXPECT_EQ(net::HttpResponseInfo::CONNECTION_INFO_UNKNOWN,
             test_handle()->GetConnectionInfo());
 
-  test_handle()->Resume();
   SimulateWillRedirectRequest();
   EXPECT_EQ(REQUEST_CONTEXT_TYPE_LOCATION,
             test_handle()->request_context_type());
   EXPECT_EQ(net::HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
             test_handle()->GetConnectionInfo());
 
-  test_handle()->Resume();
   SimulateWillProcessResponse();
   EXPECT_EQ(REQUEST_CONTEXT_TYPE_LOCATION,
             test_handle()->request_context_type());
@@ -352,7 +357,6 @@
   EXPECT_EQ(net::HttpResponseInfo::CONNECTION_INFO_UNKNOWN,
             test_handle()->GetConnectionInfo());
 
-  test_handle()->Resume();
   SimulateWillProcessResponse();
   EXPECT_EQ(net::HttpResponseInfo::CONNECTION_INFO_QUIC_35,
             test_handle()->GetConnectionInfo());
@@ -382,7 +386,7 @@
 
   // Resume the request. It should no longer be deferred and the callback
   // should have been called.
-  test_handle()->Resume();
+  Resume();
   EXPECT_FALSE(IsDeferringStart());
   EXPECT_FALSE(IsDeferringRedirect());
   EXPECT_FALSE(IsDeferringResponse());
@@ -405,7 +409,7 @@
 
   // Resume the request. It should no longer be deferred and the callback
   // should have been called.
-  test_handle()->Resume();
+  Resume();
   EXPECT_FALSE(IsDeferringStart());
   EXPECT_FALSE(IsDeferringRedirect());
   EXPECT_FALSE(IsDeferringResponse());
@@ -428,7 +432,7 @@
 
   // Resume the request. It should no longer be deferred and the callback should
   // have been called.
-  test_handle()->Resume();
+  Resume();
   EXPECT_FALSE(IsDeferringStart());
   EXPECT_FALSE(IsDeferringRedirect());
   EXPECT_FALSE(IsDeferringResponse());
@@ -462,8 +466,7 @@
   EXPECT_EQ(0, test_throttle->will_process_response_calls());
 
   // Cancel the request. The callback should have been called.
-  test_handle()->CancelDeferredNavigation(
-      NavigationThrottle::CANCEL_AND_IGNORE);
+  CancelDeferredNavigation(NavigationThrottle::CANCEL_AND_IGNORE);
   EXPECT_FALSE(IsDeferringStart());
   EXPECT_FALSE(IsDeferringRedirect());
   EXPECT_TRUE(IsCanceling());
@@ -496,8 +499,7 @@
   EXPECT_EQ(0, test_throttle->will_process_response_calls());
 
   // Cancel the request. The callback should have been called.
-  test_handle()->CancelDeferredNavigation(
-      NavigationThrottle::CANCEL_AND_IGNORE);
+  CancelDeferredNavigation(NavigationThrottle::CANCEL_AND_IGNORE);
   EXPECT_FALSE(IsDeferringStart());
   EXPECT_FALSE(IsDeferringRedirect());
   EXPECT_TRUE(IsCanceling());
@@ -530,7 +532,7 @@
 
   // Cancel the request. The callback should have been called with CANCEL, and
   // not CANCEL_AND_IGNORE.
-  test_handle()->CancelDeferredNavigation(NavigationThrottle::CANCEL);
+  CancelDeferredNavigation(NavigationThrottle::CANCEL);
   EXPECT_FALSE(IsDeferringStart());
   EXPECT_FALSE(IsDeferringRedirect());
   EXPECT_TRUE(IsCanceling());
@@ -572,7 +574,7 @@
 
   // Resume the request. It should no longer be deferred and the callback
   // should have been called. The second throttle should have been notified.
-  test_handle()->Resume();
+  Resume();
   EXPECT_FALSE(IsDeferringStart());
   EXPECT_FALSE(IsDeferringRedirect());
   EXPECT_TRUE(was_callback_called());
@@ -598,7 +600,7 @@
 
   // Resume the request. It should no longer be deferred and the callback
   // should have been called. The second throttle should have been notified.
-  test_handle()->Resume();
+  Resume();
   EXPECT_FALSE(IsDeferringStart());
   EXPECT_FALSE(IsDeferringRedirect());
   EXPECT_TRUE(was_callback_called());
@@ -640,7 +642,7 @@
 
   // Resume the request. The callback should have been called. The second
   // throttle should have been notified.
-  test_handle()->Resume();
+  Resume();
   EXPECT_FALSE(IsDeferringStart());
   EXPECT_FALSE(IsDeferringRedirect());
   EXPECT_TRUE(IsCanceling());
@@ -683,7 +685,7 @@
 
   // Resume the request. The callback should have been called. The second
   // throttle should have been notified.
-  test_handle()->Resume();
+  Resume();
   EXPECT_FALSE(IsDeferringStart());
   EXPECT_FALSE(IsDeferringRedirect());
   EXPECT_TRUE(IsCanceling());
@@ -881,7 +883,7 @@
   AddDeletingNavigationThrottle();
   SimulateWillStartRequest();
   EXPECT_NE(nullptr, test_handle());
-  test_handle()->Resume();
+  Resume();
   EXPECT_EQ(nullptr, test_handle());
   if (IsBrowserSideNavigationEnabled()) {
     EXPECT_FALSE(was_callback_called());
@@ -908,7 +910,7 @@
   AddDeletingNavigationThrottle();
   SimulateWillRedirectRequest();
   EXPECT_NE(nullptr, test_handle());
-  test_handle()->Resume();
+  Resume();
   EXPECT_EQ(nullptr, test_handle());
   if (IsBrowserSideNavigationEnabled()) {
     EXPECT_FALSE(was_callback_called());
@@ -935,7 +937,7 @@
   AddDeletingNavigationThrottle();
   SimulateWillProcessResponse();
   EXPECT_NE(nullptr, test_handle());
-  test_handle()->Resume();
+  Resume();
   EXPECT_EQ(nullptr, test_handle());
   if (IsBrowserSideNavigationEnabled()) {
     EXPECT_FALSE(was_callback_called());
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index fba3353..7ed45ca 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -906,6 +906,8 @@
     IPC_MESSAGE_HANDLER(AccessibilityHostMsg_SnapshotResponse,
                         OnAccessibilitySnapshotResponse)
     IPC_MESSAGE_HANDLER(FrameHostMsg_ToggleFullscreen, OnToggleFullscreen)
+    IPC_MESSAGE_HANDLER(FrameHostMsg_SuddenTerminationDisablerChanged,
+                        OnSuddenTerminationDisablerChanged)
     IPC_MESSAGE_HANDLER(FrameHostMsg_DidStartLoading, OnDidStartLoading)
     IPC_MESSAGE_HANDLER(FrameHostMsg_DidStopLoading, OnDidStopLoading)
     IPC_MESSAGE_HANDLER(FrameHostMsg_DidChangeLoadProgress,
@@ -2576,6 +2578,22 @@
   }
 }
 
+void RenderFrameHostImpl::OnSuddenTerminationDisablerChanged(
+    bool present,
+    blink::WebSuddenTerminationDisablerType disabler_type) {
+  DCHECK_NE(GetSuddenTerminationDisablerState(disabler_type), present);
+  if (present) {
+    sudden_termination_disabler_types_enabled_ |= disabler_type;
+  } else {
+    sudden_termination_disabler_types_enabled_ &= ~disabler_type;
+  }
+}
+
+bool RenderFrameHostImpl::GetSuddenTerminationDisablerState(
+    blink::WebSuddenTerminationDisablerType disabler_type) {
+  return (sudden_termination_disabler_types_enabled_ & disabler_type) != 0;
+}
+
 void RenderFrameHostImpl::OnDidStopLoading() {
   TRACE_EVENT1("navigation", "RenderFrameHostImpl::OnDidStopLoading",
                "frame_tree_node", frame_tree_node_->frame_tree_node_id());
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index ebe6e6f..39ebd9c 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -53,6 +53,7 @@
 #include "services/device/public/interfaces/wake_lock_context.mojom.h"
 #include "third_party/WebKit/public/platform/WebFocusType.h"
 #include "third_party/WebKit/public/platform/WebInsecureRequestPolicy.h"
+#include "third_party/WebKit/public/platform/WebSuddenTerminationDisablerType.h"
 #include "third_party/WebKit/public/platform/modules/bluetooth/web_bluetooth.mojom.h"
 #include "third_party/WebKit/public/web/WebTextDirection.h"
 #include "third_party/WebKit/public/web/WebTreeScopeType.h"
@@ -193,6 +194,9 @@
   void ResumeBlockedRequestsForFrame() override;
   void DisableBeforeUnloadHangMonitorForTesting() override;
   bool IsBeforeUnloadHangMonitorDisabledForTesting() override;
+  bool GetSuddenTerminationDisablerState(
+      blink::WebSuddenTerminationDisablerType disabler_type) override;
+
   bool IsFeatureEnabled(blink::WebFeaturePolicyFeature feature) override;
 
   // mojom::FrameHostInterfaceBroker
@@ -788,6 +792,9 @@
                                 base::string16 text,
                                 base::string16 html);
   void OnToggleFullscreen(bool enter_fullscreen);
+  void OnSuddenTerminationDisablerChanged(
+      bool present,
+      blink::WebSuddenTerminationDisablerType disabler_type);
   void OnDidStartLoading(bool to_different_document);
   void OnDidStopLoading();
   void OnDidChangeLoadProgress(double load_progress);
@@ -1220,6 +1227,10 @@
       PendingNavigation;
   std::unique_ptr<PendingNavigation> pendinging_navigate_;
 
+  // Bitfield for renderer-side state that blocks fast shutdown of the frame.
+  blink::WebSuddenTerminationDisablerType
+      sudden_termination_disabler_types_enabled_ = 0;
+
   // Callback for responding when
   // |FrameHostMsg_TextSurroundingSelectionResponse| message comes.
   TextSurroundingSelectionCallback text_surrounding_selection_callback_;
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.cc b/content/browser/frame_host/render_widget_host_view_child_frame.cc
index 8e8aac3b..c6be8a2 100644
--- a/content/browser/frame_host/render_widget_host_view_child_frame.cc
+++ b/content/browser/frame_host/render_widget_host_view_child_frame.cc
@@ -735,8 +735,8 @@
 
   std::unique_ptr<cc::CopyOutputRequest> request =
       cc::CopyOutputRequest::CreateRequest(
-          base::Bind(&CopyFromCompositingSurfaceHasResult, output_size,
-                     preferred_color_type, callback));
+          base::BindOnce(&CopyFromCompositingSurfaceHasResult, output_size,
+                         preferred_color_type, callback));
   if (!src_subrect.IsEmpty())
     request->set_area(src_subrect);
 
diff --git a/content/browser/media/capture/aura_window_capture_machine.cc b/content/browser/media/capture/aura_window_capture_machine.cc
index 45a04b9..0531e14 100644
--- a/content/browser/media/capture/aura_window_capture_machine.cc
+++ b/content/browser/media/capture/aura_window_capture_machine.cc
@@ -229,9 +229,9 @@
           event, gfx::Rect(), event_time, &frame, &capture_frame_cb)) {
     std::unique_ptr<cc::CopyOutputRequest> request =
         cc::CopyOutputRequest::CreateRequest(
-            base::Bind(&AuraWindowCaptureMachine::DidCopyOutput,
-                       weak_factory_.GetWeakPtr(), std::move(frame), event_time,
-                       start_time, capture_frame_cb));
+            base::BindOnce(&AuraWindowCaptureMachine::DidCopyOutput,
+                           weak_factory_.GetWeakPtr(), std::move(frame),
+                           event_time, start_time, capture_frame_cb));
     gfx::Rect window_rect = gfx::Rect(desktop_window_->bounds().width(),
                                       desktop_window_->bounds().height());
     request->set_area(window_rect);
diff --git a/content/browser/renderer_host/DEPS b/content/browser/renderer_host/DEPS
index ecc46881..7a39379 100644
--- a/content/browser/renderer_host/DEPS
+++ b/content/browser/renderer_host/DEPS
@@ -31,10 +31,6 @@
     "+content/browser/frame_host",
     "+content/public/browser/web_contents.h",
   ],
-  "ime_adapter_android\.cc": [
-    "+content/browser/frame_host",
-    "+content/public/browser/web_contents.h",
-  ],
   # TODO(nasko): Remove these exceptions once we've untangled the dependency
   # of RenderViewHost on the FrameTree.
   "render_view_host_impl\.(cc|h)": [
diff --git a/content/browser/renderer_host/delegated_frame_host.cc b/content/browser/renderer_host/delegated_frame_host.cc
index 44a3a36..198c90d 100644
--- a/content/browser/renderer_host/delegated_frame_host.cc
+++ b/content/browser/renderer_host/delegated_frame_host.cc
@@ -127,8 +127,8 @@
 
   std::unique_ptr<cc::CopyOutputRequest> request =
       cc::CopyOutputRequest::CreateRequest(
-          base::Bind(&CopyFromCompositingSurfaceHasResult, output_size,
-                     preferred_color_type, callback));
+          base::BindOnce(&CopyFromCompositingSurfaceHasResult, output_size,
+                         preferred_color_type, callback));
   if (!src_subrect.IsEmpty())
     request->set_area(src_subrect);
   RequestCopyOfOutput(std::move(request));
@@ -144,7 +144,7 @@
   }
 
   std::unique_ptr<cc::CopyOutputRequest> request =
-      cc::CopyOutputRequest::CreateRequest(base::Bind(
+      cc::CopyOutputRequest::CreateRequest(base::BindOnce(
           &DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo,
           AsWeakPtr(),  // For caching the ReadbackYUVInterface on this class.
           nullptr, std::move(target), callback));
@@ -347,7 +347,7 @@
   }
 
   std::unique_ptr<cc::CopyOutputRequest> request =
-      cc::CopyOutputRequest::CreateRequest(base::Bind(
+      cc::CopyOutputRequest::CreateRequest(base::BindOnce(
           &DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo,
           AsWeakPtr(), subscriber_texture, frame,
           base::Bind(callback, present_time)));
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index fea1eb6..0570818 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -938,6 +938,57 @@
 }
 
 namespace {
+void NavigateToDataURLAndCheckForTerminationDisabler(
+    Shell* shell,
+    const std::string& html,
+    bool expect_onunload,
+    bool expect_onbeforeunload) {
+  NavigateToURL(shell, GURL("data:text/html," + html));
+  RenderFrameHostImpl* rfh =
+      static_cast<RenderFrameHostImpl*>(shell->web_contents()->GetMainFrame());
+  EXPECT_EQ(expect_onunload,
+            rfh->GetSuddenTerminationDisablerState(blink::kUnloadHandler));
+  EXPECT_EQ(expect_onbeforeunload, rfh->GetSuddenTerminationDisablerState(
+                                       blink::kBeforeUnloadHandler));
+}
+}  // namespace
+
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
+                       SuddenTerminationDisablerNone) {
+  const std::string NO_HANDLERS_HTML = "<html><body>foo</body></html>";
+  NavigateToDataURLAndCheckForTerminationDisabler(shell(), NO_HANDLERS_HTML,
+                                                  false, false);
+}
+
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
+                       SuddenTerminationDisablerOnUnload) {
+  const std::string UNLOAD_HTML =
+      "<html><body><script>window.onunload=function(e) {}</script>"
+      "</body></html>";
+  NavigateToDataURLAndCheckForTerminationDisabler(shell(), UNLOAD_HTML, true,
+                                                  false);
+}
+
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
+                       SuddenTerminationDisablerOnBeforeUnload) {
+  const std::string BEFORE_UNLOAD_HTML =
+      "<html><body><script>window.onbeforeunload=function(e) {}</script>"
+      "</body></html>";
+  NavigateToDataURLAndCheckForTerminationDisabler(shell(), BEFORE_UNLOAD_HTML,
+                                                  false, true);
+}
+
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
+                       SuddenTerminationDisablerOnUnloadAndBeforeUnload) {
+  const std::string UNLOAD_AND_BEFORE_UNLOAD_HTML =
+      "<html><body><script>window.onunload=function(e) {};"
+      "window.onbeforeunload=function(e) {}</script>"
+      "</body></html>";
+  NavigateToDataURLAndCheckForTerminationDisabler(
+      shell(), UNLOAD_AND_BEFORE_UNLOAD_HTML, true, true);
+}
+
+namespace {
 
 class TestJavaScriptDialogManager : public JavaScriptDialogManager,
                                     public WebContentsDelegate {
diff --git a/content/common/DEPS b/content/common/DEPS
index a7b3f43..9538e1d 100644
--- a/content/common/DEPS
+++ b/content/common/DEPS
@@ -35,6 +35,7 @@
   "+third_party/WebKit/public/platform/WebScreenInfo.h",
   "+third_party/WebKit/public/platform/WebScrollbarButtonsPlacement.h",
   "+third_party/WebKit/public/platform/WebStorageArea.h",
+  "+third_party/WebKit/public/platform/WebSuddenTerminationDisablerType.h",
   "+third_party/WebKit/public/platform/WebTouchEvent.h",
   "+third_party/WebKit/public/platform/linux/WebFallbackFont.h",
   "+third_party/WebKit/public/platform/mac/WebScrollbarTheme.h",
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index e2788736..168d64f 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -54,6 +54,7 @@
 #include "third_party/WebKit/public/platform/WebFeaturePolicy.h"
 #include "third_party/WebKit/public/platform/WebFocusType.h"
 #include "third_party/WebKit/public/platform/WebInsecureRequestPolicy.h"
+#include "third_party/WebKit/public/platform/WebSuddenTerminationDisablerType.h"
 #include "third_party/WebKit/public/web/WebFindOptions.h"
 #include "third_party/WebKit/public/web/WebFrameOwnerProperties.h"
 #include "third_party/WebKit/public/web/WebFrameSerializerCacheControlPolicy.h"
@@ -1578,6 +1579,12 @@
 // See the comment in chrome/browser/ui/browser.h for more details.
 IPC_MESSAGE_ROUTED1(FrameHostMsg_ToggleFullscreen, bool /* enter_fullscreen */)
 
+// Sent when a new sudden termination disabler condition is either introduced or
+// removed.
+IPC_MESSAGE_ROUTED2(FrameHostMsg_SuddenTerminationDisablerChanged,
+                    bool /* present */,
+                    blink::WebSuddenTerminationDisablerType /* disabler_type */)
+
 // Dispatch a load event for this frame in the iframe element of an
 // out-of-process parent frame.
 IPC_MESSAGE_ROUTED0(FrameHostMsg_DispatchLoad)
diff --git a/content/network/network_service_impl.cc b/content/network/network_service_impl.cc
index d2b53be..5ba93017 100644
--- a/content/network/network_service_impl.cc
+++ b/content/network/network_service_impl.cc
@@ -25,23 +25,26 @@
 
 class NetworkServiceImpl::MojoNetLog : public net::NetLog {
  public:
-  MojoNetLog() {
-    const base::CommandLine* command_line =
-        base::CommandLine::ForCurrentProcess();
+  MojoNetLog() {}
 
-    // If specified by the command line, stream network events (NetLog) to a
-    // file on disk. This will last for the duration of the process.
-    if (command_line->HasSwitch(switches::kLogNetLog)) {
-      base::FilePath log_path =
-          command_line->GetSwitchValuePath(switches::kLogNetLog);
-      net::NetLogCaptureMode capture_mode =
-          net::NetLogCaptureMode::IncludeCookiesAndCredentials();
+  // If specified by the command line, stream network events (NetLog) to a
+  // file on disk. This will last for the duration of the process.
+  void ProcessCommandLine(const base::CommandLine& command_line) {
+    if (!command_line.HasSwitch(switches::kLogNetLog))
+      return;
 
-      file_net_log_observer_ =
-          net::FileNetLogObserver::CreateUnbounded(log_path, nullptr);
-      file_net_log_observer_->StartObserving(this, capture_mode);
-    }
+    base::FilePath log_path =
+        command_line.GetSwitchValuePath(switches::kLogNetLog);
+
+    // TODO(eroman): Should get capture mode from the command line.
+    net::NetLogCaptureMode capture_mode =
+        net::NetLogCaptureMode::IncludeCookiesAndCredentials();
+
+    file_net_log_observer_ =
+        net::FileNetLogObserver::CreateUnbounded(log_path, nullptr);
+    file_net_log_observer_->StartObserving(this, capture_mode);
   }
+
   ~MojoNetLog() override {
     if (file_net_log_observer_)
       file_net_log_observer_->StopObserving(nullptr, base::OnceClosure());
@@ -62,6 +65,11 @@
   if (registry_) {
     registry_->AddInterface<mojom::NetworkService>(
         base::Bind(&NetworkServiceImpl::Create, base::Unretained(this)));
+
+    // Note: The command line switches are only checked when running out of
+    // process, since in in-process mode other code may already be writing to
+    // the destination log file.
+    net_log_->ProcessCommandLine(*base::CommandLine::ForCurrentProcess());
   }
 }
 
diff --git a/content/public/browser/devtools_agent_host.h b/content/public/browser/devtools_agent_host.h
index 93f6f1a2..40ca6457 100644
--- a/content/public/browser/devtools_agent_host.h
+++ b/content/public/browser/devtools_agent_host.h
@@ -41,7 +41,6 @@
   static char kTypeFrame[];
   static char kTypeSharedWorker[];
   static char kTypeServiceWorker[];
-  static char kTypeExternal[];
   static char kTypeBrowser[];
   static char kTypeGuest[];
   static char kTypeOther[];
diff --git a/content/public/browser/navigation_handle.h b/content/public/browser/navigation_handle.h
index 82efc45..479b1e00 100644
--- a/content/public/browser/navigation_handle.h
+++ b/content/public/browser/navigation_handle.h
@@ -228,21 +228,6 @@
   // encountering a server redirect).
   virtual net::HttpResponseInfo::ConnectionInfo GetConnectionInfo() = 0;
 
-  // Resumes a navigation that was previously deferred by a NavigationThrottle.
-  // Note: this may lead to the deletion of the NavigationHandle and its
-  // associated NavigationThrottles.
-  virtual void Resume() = 0;
-
-  // Cancels a navigation that was previously deferred by a NavigationThrottle.
-  // |result| should be equal to either:
-  //  - NavigationThrottle::CANCEL,
-  //  - NavigationThrottle::CANCEL_AND_IGNORE, or
-  //  - NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE.
-  // Note: this may lead to the deletion of the NavigationHandle and its
-  // associated NavigationThrottles.
-  virtual void CancelDeferredNavigation(
-      NavigationThrottle::ThrottleCheckResult result) = 0;
-
   // Returns the ID of the URLRequest associated with this navigation. Can only
   // be called from NavigationThrottle::WillProcessResponse and
   // WebContentsObserver::ReadyToCommitNavigation.
@@ -296,6 +281,10 @@
   // Simulates the navigation being committed.
   virtual void CallDidCommitNavigationForTesting(const GURL& url) = 0;
 
+  // Simulates the navigation resuming. Most callers should just let the
+  // deferring NavigationThrottle do the resuming.
+  virtual void CallResumeForTesting() = 0;
+
   // The NavigationData that the embedder returned from
   // ResourceDispatcherHostDelegate::GetNavigationData during commit. This will
   // be a clone of the NavigationData.
diff --git a/content/public/browser/navigation_throttle.cc b/content/public/browser/navigation_throttle.cc
index 5c795d65..0e71b15 100644
--- a/content/public/browser/navigation_throttle.cc
+++ b/content/public/browser/navigation_throttle.cc
@@ -4,6 +4,8 @@
 
 #include "content/public/browser/navigation_throttle.h"
 
+#include "content/browser/frame_host/navigation_handle_impl.h"
+
 namespace content {
 
 NavigationThrottle::NavigationThrottle(NavigationHandle* navigation_handle)
@@ -25,4 +27,14 @@
   return NavigationThrottle::PROCEED;
 }
 
+void NavigationThrottle::Resume() {
+  static_cast<NavigationHandleImpl*>(navigation_handle_)->Resume(this);
+}
+
+void NavigationThrottle::CancelDeferredNavigation(
+    NavigationThrottle::ThrottleCheckResult result) {
+  static_cast<NavigationHandleImpl*>(navigation_handle_)
+      ->CancelDeferredNavigation(this, result);
+}
+
 }  // namespace content
diff --git a/content/public/browser/navigation_throttle.h b/content/public/browser/navigation_throttle.h
index f505c86..bfc8062 100644
--- a/content/public/browser/navigation_throttle.h
+++ b/content/public/browser/navigation_throttle.h
@@ -91,6 +91,22 @@
   // navigation.
   NavigationHandle* navigation_handle() const { return navigation_handle_; }
 
+ protected:
+  // Resumes a navigation that was previously deferred by this
+  // NavigationThrottle.
+  // Note: this may lead to the deletion of the NavigationHandle and its
+  // associated NavigationThrottles, including this one.
+  virtual void Resume();
+
+  // Cancels a navigation that was previously deferred by this
+  // NavigationThrottle. |result| should be equal to either:
+  //  - NavigationThrottle::CANCEL,
+  //  - NavigationThrottle::CANCEL_AND_IGNORE, or
+  //  - NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE.
+  // Note: this may lead to the deletion of the NavigationHandle and its
+  // associated NavigationThrottles, including this one.
+  virtual void CancelDeferredNavigation(ThrottleCheckResult result);
+
  private:
   NavigationHandle* navigation_handle_;
 };
diff --git a/content/public/browser/render_frame_host.h b/content/public/browser/render_frame_host.h
index c155b229..11f5f90 100644
--- a/content/public/browser/render_frame_host.h
+++ b/content/public/browser/render_frame_host.h
@@ -16,6 +16,7 @@
 #include "ipc/ipc_sender.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
 #include "third_party/WebKit/public/platform/WebPageVisibilityState.h"
+#include "third_party/WebKit/public/platform/WebSuddenTerminationDisablerType.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/native_widget_types.h"
 #include "url/gurl.h"
@@ -284,6 +285,11 @@
   virtual void DisableBeforeUnloadHangMonitorForTesting() = 0;
   virtual bool IsBeforeUnloadHangMonitorDisabledForTesting() = 0;
 
+  // Check whether the specific Blink feature is currently preventing fast
+  // shutdown of the frame.
+  virtual bool GetSuddenTerminationDisablerState(
+      blink::WebSuddenTerminationDisablerType disabler_type) = 0;
+
   // Returns true if the given Feature Policy |feature| is enabled for this
   // RenderFrameHost and is allowed to be used by it. Use this in the browser
   // process to determine whether access to a feature is allowed.
diff --git a/content/public/renderer/content_renderer_client.cc b/content/public/renderer/content_renderer_client.cc
index 46eda3d5..62e2a4e 100644
--- a/content/public/renderer/content_renderer_client.cc
+++ b/content/public/renderer/content_renderer_client.cc
@@ -258,7 +258,7 @@
   return nullptr;
 }
 
-bool ContentRendererClient::AllowMediaSuspend() {
+bool ContentRendererClient::AllowIdleMediaSuspend() {
   return true;
 }
 
diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h
index 9246fd8..915dc35 100644
--- a/content/public/renderer/content_renderer_client.h
+++ b/content/public/renderer/content_renderer_client.h
@@ -375,8 +375,9 @@
   virtual std::unique_ptr<base::TaskScheduler::InitParams>
   GetTaskSchedulerInitParams();
 
-  // Returns true if the media pipeline can be suspended, or false otherwise.
-  virtual bool AllowMediaSuspend();
+  // Whether the renderer allows idle media players to be automatically
+  // suspended after a period of inactivity.
+  virtual bool AllowIdleMediaSuspend();
 };
 
 }  // namespace content
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index 4bad5b2..50bdcdb 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -1870,7 +1870,7 @@
 
 TestNavigationManager::~TestNavigationManager() {
   if (navigation_paused_)
-    handle_->Resume();
+    handle_->CallResumeForTesting();
 }
 
 bool TestNavigationManager::WaitForRequestStart() {
@@ -1927,6 +1927,8 @@
   OnNavigationStateChanged();
 }
 
+// TODO(csharrison): Remove CallResumeForTesting method calls in favor of doing
+// it through the throttle.
 bool TestNavigationManager::WaitForDesiredState() {
   // If the desired state has laready been reached, just return.
   if (current_state_ == desired_state_)
@@ -1934,7 +1936,7 @@
 
   // Resume the navigation if it was paused.
   if (navigation_paused_)
-     handle_->Resume();
+    handle_->CallResumeForTesting();
 
   // Wait for the desired state if needed.
   if (current_state_ < desired_state_) {
@@ -1960,7 +1962,7 @@
 
   // Otherwise, the navigation should be resumed if it was previously paused.
   if (navigation_paused_)
-    handle_->Resume();
+    handle_->CallResumeForTesting();
 }
 
 bool TestNavigationManager::ShouldMonitorNavigation(NavigationHandle* handle) {
diff --git a/content/public/test/cancelling_navigation_throttle.cc b/content/public/test/cancelling_navigation_throttle.cc
index 961641c..a0331c4 100644
--- a/content/public/test/cancelling_navigation_throttle.cc
+++ b/content/public/test/cancelling_navigation_throttle.cc
@@ -55,9 +55,9 @@
 
 void CancellingNavigationThrottle::MaybeCancel(bool cancel) {
   if (cancel)
-    navigation_handle()->CancelDeferredNavigation(NavigationThrottle::CANCEL);
+    CancelDeferredNavigation(NavigationThrottle::CANCEL);
   else
-    navigation_handle()->Resume();
+    Resume();
 }
 
 }  // namespace content
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc
index 476888c..c181f48a 100644
--- a/content/renderer/gpu/render_widget_compositor.cc
+++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -1013,7 +1013,7 @@
   scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner =
       layer_tree_host_->GetTaskRunnerProvider()->MainThreadTaskRunner();
   std::unique_ptr<cc::CopyOutputRequest> request =
-      cc::CopyOutputRequest::CreateBitmapRequest(base::Bind(
+      cc::CopyOutputRequest::CreateBitmapRequest(base::BindOnce(
           [](blink::WebCompositeAndReadbackAsyncCallback* callback,
              scoped_refptr<base::SingleThreadTaskRunner> task_runner,
              std::unique_ptr<cc::CopyOutputResult> result) {
diff --git a/content/renderer/media/media_factory.cc b/content/renderer/media/media_factory.cc
index 156cc3e..ba453bd 100644
--- a/content/renderer/media/media_factory.cc
+++ b/content/renderer/media/media_factory.cc
@@ -248,7 +248,6 @@
           media_observer, max_keyframe_distance_to_disable_background_video,
           max_keyframe_distance_to_disable_background_video_mse,
           enable_instant_source_buffer_gc,
-          GetContentClient()->renderer()->AllowMediaSuspend(),
           embedded_media_experience_enabled));
 
   media::WebMediaPlayerImpl* media_player = new media::WebMediaPlayerImpl(
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate.cc b/content/renderer/media/renderer_webmediaplayer_delegate.cc
index 7a9bb970..5f57b78 100644
--- a/content/renderer/media/renderer_webmediaplayer_delegate.cc
+++ b/content/renderer/media/renderer_webmediaplayer_delegate.cc
@@ -11,6 +11,8 @@
 #include "base/metrics/user_metrics_action.h"
 #include "base/sys_info.h"
 #include "content/common/media/media_player_delegate_messages.h"
+#include "content/public/common/content_client.h"
+#include "content/public/renderer/content_renderer_client.h"
 #include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_thread.h"
 #include "third_party/WebKit/public/platform/WebMediaPlayer.h"
@@ -34,6 +36,8 @@
 RendererWebMediaPlayerDelegate::RendererWebMediaPlayerDelegate(
     content::RenderFrame* render_frame)
     : RenderFrameObserver(render_frame),
+      allow_idle_cleanup_(
+          content::GetContentClient()->renderer()->AllowIdleMediaSuspend()),
       default_tick_clock_(new base::DefaultTickClock()),
       tick_clock_(default_tick_clock_.get()) {
   idle_cleanup_interval_ = base::TimeDelta::FromSeconds(5);
@@ -317,6 +321,9 @@
   // Record UMAs for background video playback.
   RecordBackgroundVideoPlayback();
 
+  if (!allow_idle_cleanup_)
+    return;
+
   // Clean up idle players.
   bool aggressive_cleanup = false;
 
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate.h b/content/renderer/media/renderer_webmediaplayer_delegate.h
index 17b6935..5ccfae4a 100644
--- a/content/renderer/media/renderer_webmediaplayer_delegate.h
+++ b/content/renderer/media/renderer_webmediaplayer_delegate.h
@@ -114,6 +114,10 @@
 
   IDMap<Observer*> id_map_;
 
+  // Flag for gating if players should ever transition to a stale state after a
+  // period of inactivity.
+  bool allow_idle_cleanup_ = true;
+
   // Tracks which players have entered an idle state. After some period of
   // inactivity these players will be notified and become stale.
   std::map<int, base::TimeTicks> idle_player_map_;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index e29e6f1..1153000a 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4707,6 +4707,13 @@
   Send(new FrameHostMsg_ToggleFullscreen(routing_id_, false));
 }
 
+void RenderFrameImpl::SuddenTerminationDisablerChanged(
+    bool present,
+    blink::WebSuddenTerminationDisablerType disabler_type) {
+  Send(new FrameHostMsg_SuddenTerminationDisablerChanged(routing_id_, present,
+                                                         disabler_type));
+}
+
 void RenderFrameImpl::RegisterProtocolHandler(const WebString& scheme,
                                               const WebURL& url,
                                               const WebString& title) {
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 6f6388c..39309d0a 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -662,6 +662,9 @@
   void DidChangeManifest() override;
   void EnterFullscreen() override;
   void ExitFullscreen() override;
+  void SuddenTerminationDisablerChanged(
+      bool present,
+      blink::WebSuddenTerminationDisablerType disabler_type) override;
   void RegisterProtocolHandler(const blink::WebString& scheme,
                                const blink::WebURL& url,
                                const blink::WebString& title) override;
diff --git a/extensions/browser/api/cast_channel/cast_channel_api.cc b/extensions/browser/api/cast_channel/cast_channel_api.cc
index 94f90eb..f764164 100644
--- a/extensions/browser/api/cast_channel/cast_channel_api.cc
+++ b/extensions/browser/api/cast_channel/cast_channel_api.cc
@@ -80,10 +80,8 @@
   channel_info->connect_info.port = ip_endpoint.port();
   channel_info->connect_info.auth =
       api::cast_channel::CHANNEL_AUTH_TYPE_SSL_VERIFIED;
-  channel_info->ready_state =
-      api::cast_channel::ToReadyState(socket.ready_state());
-  channel_info->error_state =
-      api::cast_channel::ToChannelError(socket.error_state());
+  channel_info->ready_state = ToReadyState(socket.ready_state());
+  channel_info->error_state = ToChannelError(socket.error_state());
   channel_info->keep_alive = socket.keep_alive();
   channel_info->audio_only = socket.audio_only();
 }
@@ -192,8 +190,7 @@
     const CastSocket& socket) {
   ChannelInfo channel_info;
   FillChannelInfo(socket, &channel_info);
-  api::cast_channel::ChannelError error =
-      api::cast_channel::ToChannelError(socket.error_state());
+  api::cast_channel::ChannelError error = ToChannelError(socket.error_state());
   if (error != api::cast_channel::CHANNEL_ERROR_NONE) {
     SetError("Channel socket error = " + base::IntToString(error));
   }
@@ -445,7 +442,7 @@
 
   ChannelInfo channel_info;
   FillChannelInfo(socket, &channel_info);
-  channel_info.error_state = api::cast_channel::ToChannelError(error_state);
+  channel_info.error_state = ToChannelError(error_state);
   ErrorInfo error_info;
   FillErrorInfo(channel_info.error_state, logger_->GetLastError(socket.id()),
                 &error_info);
diff --git a/extensions/browser/api/cast_channel/cast_channel_api_unittest.cc b/extensions/browser/api/cast_channel/cast_channel_api_unittest.cc
index 0797716e..d19dbccf 100644
--- a/extensions/browser/api/cast_channel/cast_channel_api_unittest.cc
+++ b/extensions/browser/api/cast_channel/cast_channel_api_unittest.cc
@@ -10,8 +10,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace extensions {
-namespace api {
-namespace cast_channel {
 
 // Tests parsing of ConnectInfo.
 TEST(CastChannelOpenFunctionTest, TestParseConnectInfo) {
@@ -19,16 +17,14 @@
   std::unique_ptr<net::IPEndPoint> ip_endpoint;
 
   // Valid ConnectInfo
-  ConnectInfo connect_info;
+  api::cast_channel::ConnectInfo connect_info;
   connect_info.ip_address = "192.0.0.1";
   connect_info.port = 8009;
-  connect_info.auth = CHANNEL_AUTH_TYPE_SSL_VERIFIED;
+  connect_info.auth = api::cast_channel::CHANNEL_AUTH_TYPE_SSL_VERIFIED;
 
   ip_endpoint.reset(ccof::ParseConnectInfo(connect_info));
   EXPECT_TRUE(ip_endpoint);
   EXPECT_EQ(ip_endpoint->ToString(), "192.0.0.1:8009");
 }
 
-}  // namespace cast_channel
-}  // namespace api
 }  // namespace extensions
diff --git a/extensions/browser/api/cast_channel/cast_channel_apitest.cc b/extensions/browser/api/cast_channel/cast_channel_apitest.cc
index a93e7b54..ab3cb769 100644
--- a/extensions/browser/api/cast_channel/cast_channel_apitest.cc
+++ b/extensions/browser/api/cast_channel/cast_channel_apitest.cc
@@ -108,9 +108,9 @@
       InSequence sequence;
 
       EXPECT_CALL(*mock_cast_socket_, AddObserver(_));
-      EXPECT_CALL(*mock_cast_socket_, Connect(_))
+      EXPECT_CALL(*mock_cast_socket_, ConnectInternal(_))
           .WillOnce(WithArgs<0>(
-              Invoke([&](const CastSocket::OnOpenCallback& callback) {
+              Invoke([&](const MockCastSocket::MockOnOpenCallback& callback) {
                 callback.Run(mock_cast_socket_->id(), ChannelError::NONE);
               })));
       EXPECT_CALL(*mock_cast_socket_, ready_state())
@@ -135,9 +135,9 @@
       InSequence sequence;
       EXPECT_CALL(*mock_cast_socket_, AddObserver(_))
           .WillOnce(SaveArg<0>(&message_observer_));
-      EXPECT_CALL(*mock_cast_socket_, Connect(_))
+      EXPECT_CALL(*mock_cast_socket_, ConnectInternal(_))
           .WillOnce(WithArgs<0>(
-              Invoke([&](const CastSocket::OnOpenCallback& callback) {
+              Invoke([&](const MockCastSocket::MockOnOpenCallback& callback) {
                 callback.Run(mock_cast_socket_->id(), ChannelError::NONE);
               })));
       EXPECT_CALL(*mock_cast_socket_, ready_state())
@@ -303,9 +303,9 @@
     InSequence sequence;
     EXPECT_CALL(*mock_cast_socket_, AddObserver(_))
         .WillOnce(SaveArg<0>(&message_observer_));
-    EXPECT_CALL(*mock_cast_socket_, Connect(_))
-        .WillOnce(
-            WithArgs<0>(Invoke([&](const CastSocket::OnOpenCallback& callback) {
+    EXPECT_CALL(*mock_cast_socket_, ConnectInternal(_))
+        .WillOnce(WithArgs<0>(
+            Invoke([&](const MockCastSocket::MockOnOpenCallback& callback) {
               callback.Run(mock_cast_socket_->id(), ChannelError::NONE);
             })));
     EXPECT_CALL(*mock_cast_socket_, ready_state())
@@ -340,9 +340,9 @@
   EXPECT_CALL(*mock_cast_socket_, AddObserver(_))
       .WillOnce(DoAll(SaveArg<0>(&message_observer_),
                       InvokeObserverOnError(this, GetCastSocketService())));
-  EXPECT_CALL(*mock_cast_socket_, Connect(_))
-      .WillOnce(
-          WithArgs<0>(Invoke([&](const CastSocket::OnOpenCallback& callback) {
+  EXPECT_CALL(*mock_cast_socket_, ConnectInternal(_))
+      .WillOnce(WithArgs<0>(
+          Invoke([&](const MockCastSocket::MockOnOpenCallback& callback) {
             callback.Run(mock_cast_socket_->id(), ChannelError::CONNECT_ERROR);
           })));
   mock_cast_socket_->SetErrorState(ChannelError::CONNECT_ERROR);
diff --git a/extensions/browser/api/cast_channel/cast_channel_enum_util.cc b/extensions/browser/api/cast_channel/cast_channel_enum_util.cc
index 10064aa0..46edeb1 100644
--- a/extensions/browser/api/cast_channel/cast_channel_enum_util.cc
+++ b/extensions/browser/api/cast_channel/cast_channel_enum_util.cc
@@ -5,58 +5,54 @@
 #include "extensions/browser/api/cast_channel/cast_channel_enum_util.h"
 
 namespace extensions {
-namespace api {
-namespace cast_channel {
 
 api::cast_channel::ReadyState ToReadyState(
     ::cast_channel::ReadyState ready_state) {
   switch (ready_state) {
     case ::cast_channel::ReadyState::NONE:
-      return READY_STATE_NONE;
+      return api::cast_channel::READY_STATE_NONE;
     case ::cast_channel::ReadyState::CONNECTING:
-      return READY_STATE_CONNECTING;
+      return api::cast_channel::READY_STATE_CONNECTING;
     case ::cast_channel::ReadyState::OPEN:
-      return READY_STATE_OPEN;
+      return api::cast_channel::READY_STATE_OPEN;
     case ::cast_channel::ReadyState::CLOSING:
-      return READY_STATE_CLOSING;
+      return api::cast_channel::READY_STATE_CLOSING;
     case ::cast_channel::ReadyState::CLOSED:
-      return READY_STATE_CLOSED;
+      return api::cast_channel::READY_STATE_CLOSED;
   }
   NOTREACHED() << "Unknown ready_state " << ReadyStateToString(ready_state);
-  return READY_STATE_NONE;
+  return api::cast_channel::READY_STATE_NONE;
 }
 
 api::cast_channel::ChannelError ToChannelError(
     ::cast_channel::ChannelError channel_error) {
   switch (channel_error) {
     case ::cast_channel::ChannelError::NONE:
-      return CHANNEL_ERROR_NONE;
+      return api::cast_channel::CHANNEL_ERROR_NONE;
     case ::cast_channel::ChannelError::CHANNEL_NOT_OPEN:
-      return CHANNEL_ERROR_CHANNEL_NOT_OPEN;
+      return api::cast_channel::CHANNEL_ERROR_CHANNEL_NOT_OPEN;
     case ::cast_channel::ChannelError::AUTHENTICATION_ERROR:
-      return CHANNEL_ERROR_AUTHENTICATION_ERROR;
+      return api::cast_channel::CHANNEL_ERROR_AUTHENTICATION_ERROR;
     case ::cast_channel::ChannelError::CONNECT_ERROR:
-      return CHANNEL_ERROR_CONNECT_ERROR;
+      return api::cast_channel::CHANNEL_ERROR_CONNECT_ERROR;
     case ::cast_channel::ChannelError::CAST_SOCKET_ERROR:
-      return CHANNEL_ERROR_SOCKET_ERROR;
+      return api::cast_channel::CHANNEL_ERROR_SOCKET_ERROR;
     case ::cast_channel::ChannelError::TRANSPORT_ERROR:
-      return CHANNEL_ERROR_TRANSPORT_ERROR;
+      return api::cast_channel::CHANNEL_ERROR_TRANSPORT_ERROR;
     case ::cast_channel::ChannelError::INVALID_MESSAGE:
-      return CHANNEL_ERROR_INVALID_MESSAGE;
+      return api::cast_channel::CHANNEL_ERROR_INVALID_MESSAGE;
     case ::cast_channel::ChannelError::INVALID_CHANNEL_ID:
-      return CHANNEL_ERROR_INVALID_CHANNEL_ID;
+      return api::cast_channel::CHANNEL_ERROR_INVALID_CHANNEL_ID;
     case ::cast_channel::ChannelError::CONNECT_TIMEOUT:
-      return CHANNEL_ERROR_CONNECT_TIMEOUT;
+      return api::cast_channel::CHANNEL_ERROR_CONNECT_TIMEOUT;
     case ::cast_channel::ChannelError::PING_TIMEOUT:
-      return CHANNEL_ERROR_PING_TIMEOUT;
+      return api::cast_channel::CHANNEL_ERROR_PING_TIMEOUT;
     case ::cast_channel::ChannelError::UNKNOWN:
-      return CHANNEL_ERROR_UNKNOWN;
+      return api::cast_channel::CHANNEL_ERROR_UNKNOWN;
   }
   NOTREACHED() << "Unknown channel_error "
                << ChannelErrorToString(channel_error);
-  return CHANNEL_ERROR_NONE;
+  return api::cast_channel::CHANNEL_ERROR_NONE;
 }
 
-}  // namespace cast_channel
-}  // namespace api
 }  // namespace extensions
diff --git a/extensions/browser/api/cast_channel/cast_channel_enum_util.h b/extensions/browser/api/cast_channel/cast_channel_enum_util.h
index 9dede07..f803769 100644
--- a/extensions/browser/api/cast_channel/cast_channel_enum_util.h
+++ b/extensions/browser/api/cast_channel/cast_channel_enum_util.h
@@ -9,16 +9,12 @@
 #include "extensions/common/api/cast_channel.h"
 
 namespace extensions {
-namespace api {
-namespace cast_channel {
 
 api::cast_channel::ReadyState ToReadyState(
     ::cast_channel::ReadyState ready_state);
 api::cast_channel::ChannelError ToChannelError(
     ::cast_channel::ChannelError channel_error);
 
-}  // namespace cast_channel
-}  // namespace api
 }  // namespace extensions
 
 #endif  // EXTENSIONS_BROWSER_API_CAST_CHANNEL_CAST_CHANNEL_TYPE_UTIL_H_
diff --git a/extensions/browser/api/cast_channel/cast_channel_enum_util_unittest.cc b/extensions/browser/api/cast_channel/cast_channel_enum_util_unittest.cc
index bb7bf633c..041a773 100644
--- a/extensions/browser/api/cast_channel/cast_channel_enum_util_unittest.cc
+++ b/extensions/browser/api/cast_channel/cast_channel_enum_util_unittest.cc
@@ -7,47 +7,43 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace extensions {
-namespace api {
-namespace cast_channel {
-namespace {
 
 TEST(CastChannelEnumUtilTest, TestToReadyState) {
-  EXPECT_EQ(READY_STATE_NONE, ToReadyState(::cast_channel::ReadyState::NONE));
-  EXPECT_EQ(READY_STATE_CONNECTING,
+  EXPECT_EQ(api::cast_channel::READY_STATE_NONE,
+            ToReadyState(::cast_channel::ReadyState::NONE));
+  EXPECT_EQ(api::cast_channel::READY_STATE_CONNECTING,
             ToReadyState(::cast_channel::ReadyState::CONNECTING));
-  EXPECT_EQ(READY_STATE_OPEN, ToReadyState(::cast_channel::ReadyState::OPEN));
-  EXPECT_EQ(READY_STATE_CLOSING,
+  EXPECT_EQ(api::cast_channel::READY_STATE_OPEN,
+            ToReadyState(::cast_channel::ReadyState::OPEN));
+  EXPECT_EQ(api::cast_channel::READY_STATE_CLOSING,
             ToReadyState(::cast_channel::ReadyState::CLOSING));
-  EXPECT_EQ(READY_STATE_CLOSED,
+  EXPECT_EQ(api::cast_channel::READY_STATE_CLOSED,
             ToReadyState(::cast_channel::ReadyState::CLOSED));
 }
 
 TEST(CastChannelEnumUtilTest, TestToChannelError) {
-  EXPECT_EQ(CHANNEL_ERROR_NONE,
+  EXPECT_EQ(api::cast_channel::CHANNEL_ERROR_NONE,
             ToChannelError(::cast_channel::ChannelError::NONE));
-  EXPECT_EQ(CHANNEL_ERROR_CHANNEL_NOT_OPEN,
+  EXPECT_EQ(api::cast_channel::CHANNEL_ERROR_CHANNEL_NOT_OPEN,
             ToChannelError(::cast_channel::ChannelError::CHANNEL_NOT_OPEN));
-  EXPECT_EQ(CHANNEL_ERROR_AUTHENTICATION_ERROR,
+  EXPECT_EQ(api::cast_channel::CHANNEL_ERROR_AUTHENTICATION_ERROR,
             ToChannelError(::cast_channel::ChannelError::AUTHENTICATION_ERROR));
-  EXPECT_EQ(CHANNEL_ERROR_CONNECT_ERROR,
+  EXPECT_EQ(api::cast_channel::CHANNEL_ERROR_CONNECT_ERROR,
             ToChannelError(::cast_channel::ChannelError::CONNECT_ERROR));
-  EXPECT_EQ(CHANNEL_ERROR_SOCKET_ERROR,
+  EXPECT_EQ(api::cast_channel::CHANNEL_ERROR_SOCKET_ERROR,
             ToChannelError(::cast_channel::ChannelError::CAST_SOCKET_ERROR));
-  EXPECT_EQ(CHANNEL_ERROR_TRANSPORT_ERROR,
+  EXPECT_EQ(api::cast_channel::CHANNEL_ERROR_TRANSPORT_ERROR,
             ToChannelError(::cast_channel::ChannelError::TRANSPORT_ERROR));
-  EXPECT_EQ(CHANNEL_ERROR_INVALID_MESSAGE,
+  EXPECT_EQ(api::cast_channel::CHANNEL_ERROR_INVALID_MESSAGE,
             ToChannelError(::cast_channel::ChannelError::INVALID_MESSAGE));
-  EXPECT_EQ(CHANNEL_ERROR_INVALID_CHANNEL_ID,
+  EXPECT_EQ(api::cast_channel::CHANNEL_ERROR_INVALID_CHANNEL_ID,
             ToChannelError(::cast_channel::ChannelError::INVALID_CHANNEL_ID));
-  EXPECT_EQ(CHANNEL_ERROR_CONNECT_TIMEOUT,
+  EXPECT_EQ(api::cast_channel::CHANNEL_ERROR_CONNECT_TIMEOUT,
             ToChannelError(::cast_channel::ChannelError::CONNECT_TIMEOUT));
-  EXPECT_EQ(CHANNEL_ERROR_PING_TIMEOUT,
+  EXPECT_EQ(api::cast_channel::CHANNEL_ERROR_PING_TIMEOUT,
             ToChannelError(::cast_channel::ChannelError::PING_TIMEOUT));
-  EXPECT_EQ(CHANNEL_ERROR_UNKNOWN,
+  EXPECT_EQ(api::cast_channel::CHANNEL_ERROR_UNKNOWN,
             ToChannelError(::cast_channel::ChannelError::UNKNOWN));
 }
 
-}  // namespace
-}  // namespace cast_channel
-}  // namespace api
 }  // namespace extensions
diff --git a/extensions/browser/api/cast_channel/cast_message_util.cc b/extensions/browser/api/cast_channel/cast_message_util.cc
index 2d15891..5ae4e5c 100644
--- a/extensions/browser/api/cast_channel/cast_message_util.cc
+++ b/extensions/browser/api/cast_channel/cast_message_util.cc
@@ -13,10 +13,8 @@
 #include "extensions/common/api/cast_channel.h"
 
 namespace extensions {
-namespace api {
-namespace cast_channel {
 
-bool MessageInfoToCastMessage(const MessageInfo& message,
+bool MessageInfoToCastMessage(const api::cast_channel::MessageInfo& message,
                               ::cast_channel::CastMessage* message_proto) {
   DCHECK(message_proto);
   if (!message.data)
@@ -55,7 +53,7 @@
 }
 
 bool CastMessageToMessageInfo(const ::cast_channel::CastMessage& message_proto,
-                              MessageInfo* message) {
+                              api::cast_channel::MessageInfo* message) {
   DCHECK(message);
   message->source_id = message_proto.source_id();
   message->destination_id = message_proto.destination_id();
@@ -86,6 +84,4 @@
   }
 }
 
-}  // namespace cast_channel
-}  // namespace api
 }  // namespace extensions
diff --git a/extensions/browser/api/cast_channel/cast_message_util.h b/extensions/browser/api/cast_channel/cast_message_util.h
index f9fe4e5..290de957 100644
--- a/extensions/browser/api/cast_channel/cast_message_util.h
+++ b/extensions/browser/api/cast_channel/cast_message_util.h
@@ -12,21 +12,23 @@
 }  // namespace cast_channel
 
 namespace extensions {
+
 namespace api {
 namespace cast_channel {
-
 struct MessageInfo;
-
-// Fills |message_proto| from |message| and returns true on success.
-bool MessageInfoToCastMessage(const MessageInfo& message,
-                              ::cast_channel::CastMessage* message_proto);
-
-// Fills |message| from |message_proto| and returns true on success.
-bool CastMessageToMessageInfo(const ::cast_channel::CastMessage& message_proto,
-                              MessageInfo* message);
-
 }  // namespace cast_channel
 }  // namespace api
+
+// Fills |message_proto| from |message| and returns true on success.
+bool MessageInfoToCastMessage(
+    const extensions::api::cast_channel::MessageInfo& message,
+    ::cast_channel::CastMessage* message_proto);
+
+// Fills |message| from |message_proto| and returns true on success.
+bool CastMessageToMessageInfo(
+    const ::cast_channel::CastMessage& message_proto,
+    extensions::api::cast_channel::MessageInfo* message);
+
 }  // namespace extensions
 
 #endif  // EXTENSIONS_BROWSER_API_CAST_CHANNEL_CAST_MESSAGE_UTIL_H_
diff --git a/extensions/common/manifest_constants.cc b/extensions/common/manifest_constants.cc
index d34920c4..9e6e250 100644
--- a/extensions/common/manifest_constants.cc
+++ b/extensions/common/manifest_constants.cc
@@ -291,6 +291,7 @@
     "Cannot claim all URLs in an extent.";
 const char kCannotScriptGallery[] =
     "The extensions gallery cannot be scripted.";
+const char kCannotScriptNtp[] = "The New Tab Page cannot be scripted.";
 const char kCannotScriptSigninPage[] =
     "The sign-in page cannot be scripted.";
 const char kChromeVersionTooLow[] =
diff --git a/extensions/common/manifest_constants.h b/extensions/common/manifest_constants.h
index 4ec5964..a8daa1c 100644
--- a/extensions/common/manifest_constants.h
+++ b/extensions/common/manifest_constants.h
@@ -265,6 +265,7 @@
 extern const char kCannotClaimAllHostsInExtent[];
 extern const char kCannotClaimAllURLsInExtent[];
 extern const char kCannotScriptGallery[];
+extern const char kCannotScriptNtp[];
 extern const char kCannotScriptSigninPage[];
 extern const char kCannotUninstallManagedExtension[];
 extern const char kChromeVersionTooLow[];
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc
index 661997a..b7fa979 100644
--- a/extensions/renderer/dispatcher.cc
+++ b/extensions/renderer/dispatcher.cc
@@ -185,53 +185,6 @@
   }
 };
 
-// Sends a notification to the browser that an event either has or no longer has
-// listeners associated with it. Note that we only do this for the first added/
-// last removed listener, rather than for each subsequent listener; the browser
-// only cares if an event has >0 associated listeners.
-// TODO(devlin): Use this in EventBindings, too, and add logic for lazy
-// background pages.
-void SendEventListenersIPC(binding::EventListenersChanged changed,
-                           ScriptContext* context,
-                           const std::string& event_name,
-                           const base::DictionaryValue* filter,
-                           bool was_manual) {
-  bool lazy = ExtensionFrameHelper::IsContextForEventPage(context);
-  // TODO(lazyboy): For service workers, use worker specific IPC::Sender
-  // instead of |render_thread|.
-  const int worker_thread_id = content::WorkerThread::GetCurrentId();
-  std::string extension_id = context->GetExtensionID();
-  content::RenderThread* render_thread = content::RenderThread::Get();
-
-  if (filter) {
-    if (changed == binding::EventListenersChanged::HAS_LISTENERS) {
-      render_thread->Send(new ExtensionHostMsg_AddFilteredListener(
-          extension_id, event_name, *filter, lazy));
-    } else {
-      DCHECK_EQ(binding::EventListenersChanged::NO_LISTENERS, changed);
-      render_thread->Send(new ExtensionHostMsg_RemoveFilteredListener(
-          extension_id, event_name, *filter, lazy));
-    }
-  } else {
-    if (changed == binding::EventListenersChanged::HAS_LISTENERS) {
-      render_thread->Send(new ExtensionHostMsg_AddListener(
-          extension_id, context->url(), event_name, worker_thread_id));
-      if (lazy) {
-        render_thread->Send(
-            new ExtensionHostMsg_AddLazyListener(extension_id, event_name));
-      }
-    } else {
-      DCHECK_EQ(binding::EventListenersChanged::NO_LISTENERS, changed);
-      render_thread->Send(new ExtensionHostMsg_RemoveListener(
-          extension_id, context->url(), event_name, worker_thread_id));
-      if (lazy && was_manual) {
-        render_thread->Send(
-            new ExtensionHostMsg_RemoveLazyListener(extension_id, event_name));
-      }
-    }
-  }
-}
-
 base::LazyInstance<WorkerScriptContextSet>::DestructorAtExit
     g_worker_script_context_set = LAZY_INSTANCE_INITIALIZER;
 
@@ -255,7 +208,7 @@
     // This Unretained is safe because the IPCMessageSender is guaranteed to
     // outlive the bindings system.
     auto system = base::MakeUnique<NativeExtensionBindingsSystem>(
-        std::move(ipc_message_sender), base::Bind(&SendEventListenersIPC));
+        std::move(ipc_message_sender));
     delegate_->InitializeBindingsSystem(this, system->api_system());
     bindings_system_ = std::move(system);
   } else {
@@ -833,7 +786,10 @@
       std::unique_ptr<NativeHandler>(new V8ContextNativeHandler(context)));
   module_system->RegisterNativeHandler(
       "event_natives",
-      std::unique_ptr<NativeHandler>(new EventBindings(context)));
+      base::MakeUnique<EventBindings>(
+          context,
+          // Note: |bindings_system| can be null in unit tests.
+          bindings_system ? bindings_system->GetIPCMessageSender() : nullptr));
   module_system->RegisterNativeHandler(
       "messaging_natives", base::MakeUnique<MessagingBindings>(context));
   module_system->RegisterNativeHandler(
diff --git a/extensions/renderer/event_bindings.cc b/extensions/renderer/event_bindings.cc
index 2643847..40e9ffd 100644
--- a/extensions/renderer/event_bindings.cc
+++ b/extensions/renderer/event_bindings.cc
@@ -25,6 +25,7 @@
 #include "extensions/common/extension_urls.h"
 #include "extensions/common/value_counter.h"
 #include "extensions/renderer/extension_frame_helper.h"
+#include "extensions/renderer/ipc_message_sender.h"
 #include "extensions/renderer/script_context.h"
 #include "extensions/renderer/worker_thread_dispatcher.h"
 #include "gin/converter.h"
@@ -150,10 +151,19 @@
   return array;
 }
 
+bool IsLazyContext(ScriptContext* context) {
+  // Note: Check context type first so that ExtensionFrameHelper isn't accessed
+  // on a worker thread.
+  return context->context_type() == Feature::SERVICE_WORKER_CONTEXT ||
+         ExtensionFrameHelper::IsContextForEventPage(context);
+}
+
 }  // namespace
 
-EventBindings::EventBindings(ScriptContext* context)
-    : ObjectBackedNativeHandler(context) {
+EventBindings::EventBindings(ScriptContext* context,
+                             IPCMessageSender* ipc_message_sender)
+    : ObjectBackedNativeHandler(context),
+      ipc_message_sender_(ipc_message_sender) {
   RouteFunction("AttachEvent", base::Bind(&EventBindings::AttachEventHandler,
                                           base::Unretained(this)));
   RouteFunction("DetachEvent", base::Bind(&EventBindings::DetachEventHandler,
@@ -246,33 +256,17 @@
   // chrome/test/data/extensions/api_test/events/background.js.
   attached_event_names_.insert(event_name);
 
-  const int worker_thread_id = content::WorkerThread::GetCurrentId();
-  const std::string& extension_id = context()->GetExtensionID();
-  const bool is_service_worker_context =
-      context()->context_type() == Feature::SERVICE_WORKER_CONTEXT;
-  IPC::Sender* sender = GetIPCSender();
   if (IncrementEventListenerCount(context(), event_name) == 1) {
-    sender->Send(new ExtensionHostMsg_AddListener(
-        extension_id,
-        is_service_worker_context ? context()->service_worker_scope()
-                                  : context()->url(),
-        event_name, worker_thread_id));
+    ipc_message_sender_->SendAddUnfilteredEventListenerIPC(context(),
+                                                           event_name);
   }
 
   // This is called the first time the page has added a listener. Since
   // the background page is the only lazy page, we know this is the first
   // time this listener has been registered.
-  bool is_lazy_context =
-      ExtensionFrameHelper::IsContextForEventPage(context()) ||
-      context()->context_type() == Feature::SERVICE_WORKER_CONTEXT;
-  if (is_lazy_context) {
-    if (is_service_worker_context) {
-      sender->Send(new ExtensionHostMsg_AddLazyServiceWorkerListener(
-          extension_id, event_name, context()->service_worker_scope()));
-    } else {
-      sender->Send(
-          new ExtensionHostMsg_AddLazyListener(extension_id, event_name));
-    }
+  if (IsLazyContext(context())) {
+    ipc_message_sender_->SendAddUnfilteredLazyEventListenerIPC(context(),
+                                                               event_name);
   }
 }
 
@@ -288,36 +282,18 @@
   // See comment in AttachEvent().
   attached_event_names_.erase(event_name);
 
-  int worker_thread_id = content::WorkerThread::GetCurrentId();
-  const bool is_service_worker_context = worker_thread_id != kNonWorkerThreadId;
-  IPC::Sender* sender = GetIPCSender();
-  const std::string& extension_id = context()->GetExtensionID();
-
   if (DecrementEventListenerCount(context(), event_name) == 0) {
-    sender->Send(new ExtensionHostMsg_RemoveListener(
-        extension_id,
-        is_service_worker_context ? context()->service_worker_scope()
-                                  : context()->url(),
-        event_name, worker_thread_id));
+    ipc_message_sender_->SendRemoveUnfilteredEventListenerIPC(context(),
+                                                              event_name);
   }
 
   // DetachEvent is called when the last listener for the context is
   // removed. If the context is the background page or service worker, and it
   // removes the last listener manually, then we assume that it is no longer
   // interested in being awakened for this event.
-  if (is_manual) {
-    bool is_lazy_context =
-        ExtensionFrameHelper::IsContextForEventPage(context()) ||
-        context()->context_type() == Feature::SERVICE_WORKER_CONTEXT;
-    if (is_lazy_context) {
-      if (is_service_worker_context) {
-        sender->Send(new ExtensionHostMsg_RemoveLazyServiceWorkerListener(
-            extension_id, event_name, context()->service_worker_scope()));
-      } else {
-        sender->Send(
-            new ExtensionHostMsg_RemoveLazyListener(extension_id, event_name));
-      }
-    }
+  if (is_manual && IsLazyContext(context())) {
+    ipc_message_sender_->SendRemoveUnfilteredLazyEventListenerIPC(context(),
+                                                                  event_name);
   }
 }
 
@@ -362,11 +338,11 @@
   const EventMatcher* matcher = g_event_filter.Get().GetEventMatcher(id);
   DCHECK(matcher);
   base::DictionaryValue* filter_weak = matcher->value();
-  std::string extension_id = context()->GetExtensionID();
+  const ExtensionId& extension_id = context()->GetExtensionID();
   if (AddFilter(event_name, extension_id, *filter_weak)) {
     bool lazy = ExtensionFrameHelper::IsContextForEventPage(context());
-    content::RenderThread::Get()->Send(new ExtensionHostMsg_AddFilteredListener(
-        extension_id, event_name, *filter_weak, lazy));
+    ipc_message_sender_->SendAddFilteredEventListenerIPC(context(), event_name,
+                                                         *filter_weak, lazy);
   }
 
   args.GetReturnValue().Set(static_cast<int32_t>(id));
@@ -387,13 +363,12 @@
   const std::string& event_name = event_filter.GetEventName(matcher_id);
 
   // Only send IPCs the last time a filter gets removed.
-  std::string extension_id = context()->GetExtensionID();
+  const ExtensionId& extension_id = context()->GetExtensionID();
   if (RemoveFilter(event_name, extension_id, event_matcher->value())) {
     bool remove_lazy =
         is_manual && ExtensionFrameHelper::IsContextForEventPage(context());
-    content::RenderThread::Get()->Send(
-        new ExtensionHostMsg_RemoveFilteredListener(
-            extension_id, event_name, *event_matcher->value(), remove_lazy));
+    ipc_message_sender_->SendRemoveFilteredEventListenerIPC(
+        context(), event_name, *event_matcher->value(), remove_lazy);
   }
 
   event_filter.RemoveEventMatcher(matcher_id);
@@ -420,16 +395,6 @@
   g_unmanaged_listeners.Get()[context()].erase(event_name);
 }
 
-IPC::Sender* EventBindings::GetIPCSender() {
-  const bool is_service_worker_context =
-      context()->context_type() == Feature::SERVICE_WORKER_CONTEXT;
-  DCHECK_EQ(is_service_worker_context,
-            content::WorkerThread::GetCurrentId() != kNonWorkerThreadId);
-  return is_service_worker_context
-             ? static_cast<IPC::Sender*>(WorkerThreadDispatcher::Get())
-             : static_cast<IPC::Sender*>(content::RenderThread::Get());
-}
-
 void EventBindings::OnInvalidated() {
   // Detach all attached events that weren't attached. Iterate over a copy
   // because it will be mutated.
diff --git a/extensions/renderer/event_bindings.h b/extensions/renderer/event_bindings.h
index 61b140e..f58b006 100644
--- a/extensions/renderer/event_bindings.h
+++ b/extensions/renderer/event_bindings.h
@@ -13,21 +13,18 @@
 #include "extensions/renderer/object_backed_native_handler.h"
 #include "v8/include/v8.h"
 
-namespace IPC {
-class Sender;
-}
-
 namespace base {
 class ListValue;
 }
 
 namespace extensions {
+class IPCMessageSender;
 struct EventFilteringInfo;
 
 // This class deals with the javascript bindings related to Event objects.
 class EventBindings : public ObjectBackedNativeHandler {
  public:
-  explicit EventBindings(ScriptContext* context);
+  EventBindings(ScriptContext* context, IPCMessageSender* ipc_message_sender);
   ~EventBindings() override;
 
   // Returns true if there is a listener for the given |event| in the given
@@ -87,11 +84,12 @@
   void AttachUnmanagedEvent(const v8::FunctionCallbackInfo<v8::Value>& args);
   void DetachUnmanagedEvent(const v8::FunctionCallbackInfo<v8::Value>& args);
 
-  IPC::Sender* GetIPCSender();
-
   // Called when our context, and therefore us, is invalidated. Run any cleanup.
   void OnInvalidated();
 
+  // The associated message sender. Guaranteed to outlive this object.
+  IPCMessageSender* const ipc_message_sender_;
+
   // The set of attached events and filtered events. Maintain these so that we
   // can detch them on unload.
   std::set<std::string> attached_event_names_;
diff --git a/extensions/renderer/ipc_message_sender.cc b/extensions/renderer/ipc_message_sender.cc
index 321954bf..6ee7645 100644
--- a/extensions/renderer/ipc_message_sender.cc
+++ b/extensions/renderer/ipc_message_sender.cc
@@ -9,6 +9,7 @@
 #include "base/guid.h"
 #include "content/public/child/worker_thread.h"
 #include "content/public/renderer/render_frame.h"
+#include "content/public/renderer/render_thread.h"
 #include "extensions/common/extension_messages.h"
 #include "extensions/common/features/feature.h"
 #include "extensions/renderer/script_context.h"
@@ -22,7 +23,7 @@
 
 class MainThreadIPCMessageSender : public IPCMessageSender {
  public:
-  MainThreadIPCMessageSender() {}
+  MainThreadIPCMessageSender() : render_thread_(content::RenderThread::Get()) {}
   ~MainThreadIPCMessageSender() override {}
 
   void SendRequestIPC(ScriptContext* context,
@@ -46,7 +47,71 @@
 
   void SendOnRequestResponseReceivedIPC(int request_id) override {}
 
+  void SendAddUnfilteredEventListenerIPC(
+      ScriptContext* context,
+      const std::string& event_name) override {
+    DCHECK_NE(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
+    DCHECK_EQ(kMainThreadId, content::WorkerThread::GetCurrentId());
+
+    render_thread_->Send(new ExtensionHostMsg_AddListener(
+        context->GetExtensionID(), context->url(), event_name, kMainThreadId));
+  }
+
+  void SendRemoveUnfilteredEventListenerIPC(
+      ScriptContext* context,
+      const std::string& event_name) override {
+    DCHECK_NE(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
+    DCHECK_EQ(kMainThreadId, content::WorkerThread::GetCurrentId());
+
+    render_thread_->Send(new ExtensionHostMsg_RemoveListener(
+        context->GetExtensionID(), context->url(), event_name, kMainThreadId));
+  }
+
+  void SendAddUnfilteredLazyEventListenerIPC(
+      ScriptContext* context,
+      const std::string& event_name) override {
+    DCHECK_NE(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
+    DCHECK_EQ(kMainThreadId, content::WorkerThread::GetCurrentId());
+
+    render_thread_->Send(new ExtensionHostMsg_AddLazyListener(
+        context->GetExtensionID(), event_name));
+  }
+
+  void SendRemoveUnfilteredLazyEventListenerIPC(
+      ScriptContext* context,
+      const std::string& event_name) override {
+    DCHECK_NE(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
+    DCHECK_EQ(kMainThreadId, content::WorkerThread::GetCurrentId());
+
+    render_thread_->Send(new ExtensionHostMsg_RemoveLazyListener(
+        context->GetExtensionID(), event_name));
+  }
+
+  void SendAddFilteredEventListenerIPC(ScriptContext* context,
+                                       const std::string& event_name,
+                                       const base::DictionaryValue& filter,
+                                       bool is_lazy) override {
+    DCHECK_NE(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
+    DCHECK_EQ(kMainThreadId, content::WorkerThread::GetCurrentId());
+
+    render_thread_->Send(new ExtensionHostMsg_AddFilteredListener(
+        context->GetExtensionID(), event_name, filter, is_lazy));
+  }
+
+  void SendRemoveFilteredEventListenerIPC(ScriptContext* context,
+                                          const std::string& event_name,
+                                          const base::DictionaryValue& filter,
+                                          bool remove_lazy_listener) override {
+    DCHECK_NE(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
+    DCHECK_EQ(kMainThreadId, content::WorkerThread::GetCurrentId());
+
+    render_thread_->Send(new ExtensionHostMsg_RemoveFilteredListener(
+        context->GetExtensionID(), event_name, filter, remove_lazy_listener));
+  }
+
  private:
+  content::RenderThread* const render_thread_;
+
   DISALLOW_COPY_AND_ASSIGN(MainThreadIPCMessageSender);
 };
 
@@ -90,6 +155,68 @@
     request_id_to_guid_.erase(iter);
   }
 
+  void SendAddUnfilteredEventListenerIPC(
+      ScriptContext* context,
+      const std::string& event_name) override {
+    DCHECK_EQ(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
+    DCHECK_NE(kMainThreadId, content::WorkerThread::GetCurrentId());
+
+    dispatcher_->Send(new ExtensionHostMsg_AddListener(
+        context->GetExtensionID(), context->service_worker_scope(), event_name,
+        content::WorkerThread::GetCurrentId()));
+  }
+
+  void SendRemoveUnfilteredEventListenerIPC(
+      ScriptContext* context,
+      const std::string& event_name) override {
+    DCHECK_EQ(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
+    DCHECK_NE(kMainThreadId, content::WorkerThread::GetCurrentId());
+
+    dispatcher_->Send(new ExtensionHostMsg_RemoveListener(
+        context->GetExtensionID(), context->service_worker_scope(), event_name,
+        content::WorkerThread::GetCurrentId()));
+  }
+
+  void SendAddUnfilteredLazyEventListenerIPC(
+      ScriptContext* context,
+      const std::string& event_name) override {
+    DCHECK_EQ(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
+    DCHECK_NE(kMainThreadId, content::WorkerThread::GetCurrentId());
+
+    dispatcher_->Send(new ExtensionHostMsg_AddLazyServiceWorkerListener(
+        context->GetExtensionID(), event_name,
+        context->service_worker_scope()));
+  }
+
+  void SendRemoveUnfilteredLazyEventListenerIPC(
+      ScriptContext* context,
+      const std::string& event_name) override {
+    DCHECK_EQ(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
+    DCHECK_NE(kMainThreadId, content::WorkerThread::GetCurrentId());
+
+    dispatcher_->Send(new ExtensionHostMsg_RemoveLazyServiceWorkerListener(
+        context->GetExtensionID(), event_name,
+        context->service_worker_scope()));
+  }
+
+  void SendAddFilteredEventListenerIPC(ScriptContext* context,
+                                       const std::string& event_name,
+                                       const base::DictionaryValue& filter,
+                                       bool is_lazy) override {
+    DCHECK_EQ(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
+    DCHECK_NE(kMainThreadId, content::WorkerThread::GetCurrentId());
+    NOTIMPLEMENTED();
+  }
+
+  void SendRemoveFilteredEventListenerIPC(ScriptContext* context,
+                                          const std::string& event_name,
+                                          const base::DictionaryValue& filter,
+                                          bool remove_lazy_listener) override {
+    DCHECK_EQ(Feature::SERVICE_WORKER_CONTEXT, context->context_type());
+    DCHECK_NE(kMainThreadId, content::WorkerThread::GetCurrentId());
+    NOTIMPLEMENTED();
+  }
+
  private:
   WorkerThreadDispatcher* const dispatcher_;
   const int64_t service_worker_version_id_;
diff --git a/extensions/renderer/ipc_message_sender.h b/extensions/renderer/ipc_message_sender.h
index 783228b0..0ac8b0c 100644
--- a/extensions/renderer/ipc_message_sender.h
+++ b/extensions/renderer/ipc_message_sender.h
@@ -14,6 +14,10 @@
 
 struct ExtensionHostMsg_Request_Params;
 
+namespace base {
+class DictionaryValue;
+}
+
 namespace extensions {
 class ScriptContext;
 class WorkerThreadDispatcher;
@@ -34,7 +38,33 @@
   // to a request.
   virtual void SendOnRequestResponseReceivedIPC(int request_id) = 0;
 
-  // TODO(devlin): Move event IPC messaging here, too.
+  // Send a message to add/remove an unfiltered listener.
+  virtual void SendAddUnfilteredEventListenerIPC(
+      ScriptContext* context,
+      const std::string& event_name) = 0;
+  virtual void SendRemoveUnfilteredEventListenerIPC(
+      ScriptContext* context,
+      const std::string& event_name) = 0;
+
+  // Send a message to add/remove a lazy unfiltered listener.
+  virtual void SendAddUnfilteredLazyEventListenerIPC(
+      ScriptContext* context,
+      const std::string& event_name) = 0;
+  virtual void SendRemoveUnfilteredLazyEventListenerIPC(
+      ScriptContext* context,
+      const std::string& event_name) = 0;
+
+  // Send a message to add/remove a filtered listener.
+  virtual void SendAddFilteredEventListenerIPC(
+      ScriptContext* context,
+      const std::string& event_name,
+      const base::DictionaryValue& filter,
+      bool is_lazy) = 0;
+  virtual void SendRemoveFilteredEventListenerIPC(
+      ScriptContext* context,
+      const std::string& event_name,
+      const base::DictionaryValue& filter,
+      bool remove_lazy_listener) = 0;
 
   // Creates an IPCMessageSender for use on the main thread.
   static std::unique_ptr<IPCMessageSender> CreateMainThreadIPCMessageSender();
diff --git a/extensions/renderer/native_extension_bindings_system.cc b/extensions/renderer/native_extension_bindings_system.cc
index b0b4727..fd29b60 100644
--- a/extensions/renderer/native_extension_bindings_system.cc
+++ b/extensions/renderer/native_extension_bindings_system.cc
@@ -4,6 +4,7 @@
 
 #include "extensions/renderer/native_extension_bindings_system.h"
 
+#include "base/callback.h"
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
 #include "content/public/common/console_message_level.h"
@@ -21,6 +22,7 @@
 #include "extensions/renderer/console.h"
 #include "extensions/renderer/content_setting.h"
 #include "extensions/renderer/declarative_content_hooks_delegate.h"
+#include "extensions/renderer/extension_frame_helper.h"
 #include "extensions/renderer/ipc_message_sender.h"
 #include "extensions/renderer/module_system.h"
 #include "extensions/renderer/script_context.h"
@@ -350,10 +352,8 @@
 }  // namespace
 
 NativeExtensionBindingsSystem::NativeExtensionBindingsSystem(
-    std::unique_ptr<IPCMessageSender> ipc_message_sender,
-    const SendEventListenerIPCMethod& send_event_listener_ipc)
+    std::unique_ptr<IPCMessageSender> ipc_message_sender)
     : ipc_message_sender_(std::move(ipc_message_sender)),
-      send_event_listener_ipc_(send_event_listener_ipc),
       api_system_(
           base::Bind(&CallJsFunction),
           base::Bind(&CallJsFunctionSync),
@@ -749,9 +749,51 @@
     const base::DictionaryValue* filter,
     bool was_manual,
     v8::Local<v8::Context> context) {
-  send_event_listener_ipc_.Run(change,
-                               ScriptContextSet::GetContextByV8Context(context),
-                               event_name, filter, was_manual);
+  ScriptContext* script_context =
+      ScriptContextSet::GetContextByV8Context(context);
+  // Note: Check context_type() first to avoid accessing ExtensionFrameHelper on
+  // a worker thread.
+  bool is_lazy =
+      script_context->context_type() == Feature::SERVICE_WORKER_CONTEXT ||
+      ExtensionFrameHelper::IsContextForEventPage(script_context);
+  // We only remove a lazy listener if the listener removal was triggered
+  // manually by the extension.
+  bool remove_lazy_listener = is_lazy && was_manual;
+
+  if (filter) {  // Filtered event listeners.
+    DCHECK(filter);
+    if (change == binding::EventListenersChanged::HAS_LISTENERS) {
+      ipc_message_sender_->SendAddFilteredEventListenerIPC(
+          script_context, event_name, *filter, is_lazy);
+    } else {
+      DCHECK_EQ(binding::EventListenersChanged::NO_LISTENERS, change);
+      ipc_message_sender_->SendRemoveFilteredEventListenerIPC(
+          script_context, event_name, *filter, remove_lazy_listener);
+    }
+  } else {  // Unfiltered event listeners.
+    if (change == binding::EventListenersChanged::HAS_LISTENERS) {
+      // TODO(devlin): The JS bindings code only adds one listener per extension
+      // per event per process, whereas this is one listener per context per
+      // event per process. Typically, this won't make a difference, but it
+      // could if there are multiple contexts for the same extension (e.g.,
+      // multiple frames). In that case, it would result in extra IPCs being
+      // sent. I'm not sure it's a big enough deal to warrant refactoring.
+      ipc_message_sender_->SendAddUnfilteredEventListenerIPC(script_context,
+                                                             event_name);
+      if (is_lazy) {
+        ipc_message_sender_->SendAddUnfilteredLazyEventListenerIPC(
+            script_context, event_name);
+      }
+    } else {
+      DCHECK_EQ(binding::EventListenersChanged::NO_LISTENERS, change);
+      ipc_message_sender_->SendRemoveUnfilteredEventListenerIPC(script_context,
+                                                                event_name);
+      if (remove_lazy_listener) {
+        ipc_message_sender_->SendRemoveUnfilteredLazyEventListenerIPC(
+            script_context, event_name);
+      }
+    }
+  }
 }
 
 void NativeExtensionBindingsSystem::GetJSBindingUtil(
diff --git a/extensions/renderer/native_extension_bindings_system.h b/extensions/renderer/native_extension_bindings_system.h
index ff71317..51dd126 100644
--- a/extensions/renderer/native_extension_bindings_system.h
+++ b/extensions/renderer/native_extension_bindings_system.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <string>
 
-#include "base/callback.h"
 #include "base/memory/weak_ptr.h"
 #include "extensions/renderer/bindings/api_binding_types.h"
 #include "extensions/renderer/bindings/api_bindings_system.h"
@@ -28,16 +27,8 @@
 // Designed to be used in a single thread, but for all contexts on that thread.
 class NativeExtensionBindingsSystem : public ExtensionBindingsSystem {
  public:
-  using SendEventListenerIPCMethod =
-      base::Callback<void(binding::EventListenersChanged,
-                          ScriptContext*,
-                          const std::string& event_name,
-                          const base::DictionaryValue* filter,
-                          bool was_manual)>;
-
-  NativeExtensionBindingsSystem(
-      std::unique_ptr<IPCMessageSender> ipc_message_sender,
-      const SendEventListenerIPCMethod& send_event_listener_ipc);
+  explicit NativeExtensionBindingsSystem(
+      std::unique_ptr<IPCMessageSender> ipc_message_sender);
   ~NativeExtensionBindingsSystem() override;
 
   // ExtensionBindingsSystem:
@@ -98,10 +89,6 @@
 
   std::unique_ptr<IPCMessageSender> ipc_message_sender_;
 
-  // Handler to notify the browser of event registrations. Abstracted out for
-  // testing purposes.
-  SendEventListenerIPCMethod send_event_listener_ipc_;
-
   // The APIBindingsSystem associated with this class.
   APIBindingsSystem api_system_;
 
diff --git a/extensions/renderer/native_extension_bindings_system_unittest.cc b/extensions/renderer/native_extension_bindings_system_unittest.cc
index 3c45e0bb..9ebd8c36 100644
--- a/extensions/renderer/native_extension_bindings_system_unittest.cc
+++ b/extensions/renderer/native_extension_bindings_system_unittest.cc
@@ -101,6 +101,30 @@
     last_params_ = std::move(params);
   }
   void SendOnRequestResponseReceivedIPC(int request_id) override {}
+  // The event listener methods are less of a pain to mock (since they don't
+  // have complex parameters like ExtensionHostMsg_Request_Params).
+  MOCK_METHOD2(SendAddUnfilteredEventListenerIPC,
+               void(ScriptContext* context, const std::string& event_name));
+  MOCK_METHOD2(SendRemoveUnfilteredEventListenerIPC,
+               void(ScriptContext* context, const std::string& event_name));
+
+  // Send a message to add/remove a lazy unfiltered listener.
+  MOCK_METHOD2(SendAddUnfilteredLazyEventListenerIPC,
+               void(ScriptContext* context, const std::string& event_name));
+  MOCK_METHOD2(SendRemoveUnfilteredLazyEventListenerIPC,
+               void(ScriptContext* context, const std::string& event_name));
+
+  // Send a message to add/remove a filtered listener.
+  MOCK_METHOD4(SendAddFilteredEventListenerIPC,
+               void(ScriptContext* context,
+                    const std::string& event_name,
+                    const base::DictionaryValue& filter,
+                    bool is_lazy));
+  MOCK_METHOD4(SendRemoveFilteredEventListenerIPC,
+               void(ScriptContext* context,
+                    const std::string& event_name,
+                    const base::DictionaryValue& filter,
+                    bool remove_lazy_listener));
 
   const ExtensionHostMsg_Request_Params* last_params() const {
     return last_params_.get();
@@ -132,9 +156,7 @@
     auto ipc_message_sender = base::MakeUnique<TestIPCMessageSender>();
     ipc_message_sender_ = ipc_message_sender.get();
     bindings_system_ = base::MakeUnique<NativeExtensionBindingsSystem>(
-        std::move(ipc_message_sender),
-        base::Bind(&NativeExtensionBindingsSystemUnittest::MockSendListenerIPC,
-                   base::Unretained(this)));
+        std::move(ipc_message_sender));
     APIBindingTest::SetUp();
   }
 
@@ -156,17 +178,6 @@
     APIBindingTest::TearDown();
   }
 
-  void MockSendListenerIPC(binding::EventListenersChanged changed,
-                           ScriptContext* context,
-                           const std::string& event_name,
-                           const base::DictionaryValue* filter,
-                           bool was_manual) {
-    if (event_change_handler_) {
-      event_change_handler_->OnChange(changed, context, event_name, filter,
-                                      was_manual);
-    }
-  }
-
   ScriptContext* CreateScriptContext(v8::Local<v8::Context> v8_context,
                                      Extension* extension,
                                      Feature::Context context_type) {
@@ -199,7 +210,6 @@
   }
 
   void InitEventChangeHandler() {
-    event_change_handler_ = base::MakeUnique<MockEventChangeHandler>();
   }
 
   NativeExtensionBindingsSystem* bindings_system() {
@@ -210,9 +220,7 @@
     return *ipc_message_sender_->last_params();
   }
   StringSourceMap* source_map() { return &source_map_; }
-  MockEventChangeHandler* event_change_handler() {
-    return event_change_handler_.get();
-  }
+  TestIPCMessageSender* ipc_message_sender() { return ipc_message_sender_; }
 
  private:
   ExtensionIdSet extension_ids_;
@@ -618,13 +626,12 @@
       "});";
   v8::Local<v8::Function> add_listener =
       FunctionFromString(context, kAddListener);
-  EXPECT_CALL(*event_change_handler(),
-              OnChange(binding::EventListenersChanged::HAS_LISTENERS,
-                       script_context, kEventName, nullptr, true))
+  EXPECT_CALL(*ipc_message_sender(),
+              SendAddUnfilteredEventListenerIPC(script_context, kEventName))
       .Times(1);
   v8::Local<v8::Value> argv[] = {listener};
   RunFunction(add_listener, context, arraysize(argv), argv);
-  ::testing::Mock::VerifyAndClearExpectations(event_change_handler());
+  ::testing::Mock::VerifyAndClearExpectations(ipc_message_sender());
   EXPECT_TRUE(bindings_system()->HasEventListenerInContext(
       "idle.onStateChanged", script_context));
 
@@ -633,14 +640,13 @@
       "(function(listener) {\n"
       "  chrome.idle.onStateChanged.removeListener(listener);\n"
       "});";
-  EXPECT_CALL(*event_change_handler(),
-              OnChange(binding::EventListenersChanged::NO_LISTENERS,
-                       script_context, kEventName, nullptr, true))
+  EXPECT_CALL(*ipc_message_sender(),
+              SendRemoveUnfilteredEventListenerIPC(script_context, kEventName))
       .Times(1);
   v8::Local<v8::Function> remove_listener =
       FunctionFromString(context, kRemoveListener);
   RunFunction(remove_listener, context, arraysize(argv), argv);
-  ::testing::Mock::VerifyAndClearExpectations(event_change_handler());
+  ::testing::Mock::VerifyAndClearExpectations(ipc_message_sender());
   EXPECT_FALSE(bindings_system()->HasEventListenerInContext(
       "idle.onStateChanged", script_context));
 }
@@ -678,12 +684,12 @@
       "});";
   v8::Local<v8::Function> use_app_runtime =
       FunctionFromString(context, kUseAppRuntime);
-  EXPECT_CALL(*event_change_handler(),
-              OnChange(binding::EventListenersChanged::HAS_LISTENERS,
-                       script_context, "app.runtime.onLaunched", nullptr, true))
+  EXPECT_CALL(*ipc_message_sender(),
+              SendAddUnfilteredEventListenerIPC(script_context,
+                                                "app.runtime.onLaunched"))
       .Times(1);
   RunFunctionOnGlobal(use_app_runtime, context, 0, nullptr);
-  ::testing::Mock::VerifyAndClearExpectations(event_change_handler());
+  ::testing::Mock::VerifyAndClearExpectations(ipc_message_sender());
 }
 
 TEST_F(NativeExtensionBindingsSystemUnittest,
@@ -1108,7 +1114,7 @@
 
   // We should have no notifications for event listeners added (since the
   // mock is a strict mock, this will fail if anything was called).
-  ::testing::Mock::VerifyAndClearExpectations(event_change_handler());
+  ::testing::Mock::VerifyAndClearExpectations(ipc_message_sender());
 }
 
 }  // namespace extensions
diff --git a/extensions/renderer/worker_thread_dispatcher.cc b/extensions/renderer/worker_thread_dispatcher.cc
index 8455c10..a5171c3 100644
--- a/extensions/renderer/worker_thread_dispatcher.cc
+++ b/extensions/renderer/worker_thread_dispatcher.cc
@@ -35,14 +35,6 @@
   return data;
 }
 
-void SendEventListenersIPC(binding::EventListenersChanged changed,
-                           ScriptContext* context,
-                           const std::string& event_name,
-                           const base::DictionaryValue* filter,
-                           bool was_manual) {
-  // TODO(devlin/lazyboy): Wire this up once extension workers support events.
-}
-
 }  // namespace
 
 WorkerThreadDispatcher::WorkerThreadDispatcher() {}
@@ -164,7 +156,7 @@
       // The Unretained below is safe since the IPC message sender outlives the
       // bindings system.
       bindings_system = base::MakeUnique<NativeExtensionBindingsSystem>(
-          std::move(ipc_message_sender), base::Bind(&SendEventListenersIPC));
+          std::move(ipc_message_sender));
     } else {
       bindings_system = base::MakeUnique<JsExtensionBindingsSystem>(
           source_map, std::move(ipc_message_sender));
diff --git a/headless/BUILD.gn b/headless/BUILD.gn
index cda14cd..d723d94 100644
--- a/headless/BUILD.gn
+++ b/headless/BUILD.gn
@@ -267,6 +267,8 @@
     "lib/browser/headless_permission_manager.h",
     "lib/browser/headless_platform_event_source.cc",
     "lib/browser/headless_platform_event_source.h",
+    "lib/browser/headless_quota_permission_context.cc",
+    "lib/browser/headless_quota_permission_context.h",
     "lib/browser/headless_resource_dispatcher_host_delegate.cc",
     "lib/browser/headless_resource_dispatcher_host_delegate.h",
     "lib/browser/headless_shell_application_mac.h",
diff --git a/headless/lib/browser/DEPS b/headless/lib/browser/DEPS
index 25bce98..a332019 100644
--- a/headless/lib/browser/DEPS
+++ b/headless/lib/browser/DEPS
@@ -4,6 +4,7 @@
   "+components/security_state",
   "+printing",
   "+storage/browser/quota",
+  "+storage/common/quota",
   "+ui/aura",
 ]
 specific_include_rules = {
diff --git a/headless/lib/browser/headless_content_browser_client.cc b/headless/lib/browser/headless_content_browser_client.cc
index 5001094..bce11ce 100644
--- a/headless/lib/browser/headless_content_browser_client.cc
+++ b/headless/lib/browser/headless_content_browser_client.cc
@@ -26,6 +26,7 @@
 #include "headless/lib/browser/headless_browser_impl.h"
 #include "headless/lib/browser/headless_browser_main_parts.h"
 #include "headless/lib/browser/headless_devtools_manager_delegate.h"
+#include "headless/lib/browser/headless_quota_permission_context.h"
 #include "headless/lib/headless_macros.h"
 #include "storage/browser/quota/quota_settings.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -178,6 +179,11 @@
   return base::JSONReader::Read(manifest_template);
 }
 
+content::QuotaPermissionContext*
+HeadlessContentBrowserClient::CreateQuotaPermissionContext() {
+  return new HeadlessQuotaPermissionContext();
+}
+
 void HeadlessContentBrowserClient::GetQuotaSettings(
     content::BrowserContext* context,
     content::StoragePartition* partition,
diff --git a/headless/lib/browser/headless_content_browser_client.h b/headless/lib/browser/headless_content_browser_client.h
index 4bd0934..5efc353 100644
--- a/headless/lib/browser/headless_content_browser_client.h
+++ b/headless/lib/browser/headless_content_browser_client.h
@@ -25,6 +25,7 @@
   content::DevToolsManagerDelegate* GetDevToolsManagerDelegate() override;
   std::unique_ptr<base::Value> GetServiceManifestOverlay(
       base::StringPiece name) override;
+  content::QuotaPermissionContext* CreateQuotaPermissionContext() override;
   void GetQuotaSettings(
       content::BrowserContext* context,
       content::StoragePartition* partition,
diff --git a/headless/lib/browser/headless_quota_permission_context.cc b/headless/lib/browser/headless_quota_permission_context.cc
new file mode 100644
index 0000000..618cbe5c
--- /dev/null
+++ b/headless/lib/browser/headless_quota_permission_context.cc
@@ -0,0 +1,29 @@
+// Copyright 2017 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 "headless/lib/browser/headless_quota_permission_context.h"
+
+#include "storage/common/quota/quota_types.h"
+
+namespace headless {
+
+HeadlessQuotaPermissionContext::HeadlessQuotaPermissionContext() {}
+
+void HeadlessQuotaPermissionContext::RequestQuotaPermission(
+    const content::StorageQuotaParams& params,
+    int render_process_id,
+    const PermissionCallback& callback) {
+  if (params.storage_type != storage::kStorageTypePersistent) {
+    // For now we only support requesting quota with this interface
+    // for Persistent storage type.
+    callback.Run(QUOTA_PERMISSION_RESPONSE_DISALLOW);
+    return;
+  }
+
+  callback.Run(QUOTA_PERMISSION_RESPONSE_ALLOW);
+}
+
+HeadlessQuotaPermissionContext::~HeadlessQuotaPermissionContext() {}
+
+}  // namespace headless
diff --git a/headless/lib/browser/headless_quota_permission_context.h b/headless/lib/browser/headless_quota_permission_context.h
new file mode 100644
index 0000000..a767704
--- /dev/null
+++ b/headless/lib/browser/headless_quota_permission_context.h
@@ -0,0 +1,30 @@
+// Copyright 2017 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 HEADLESS_LIB_BROWSER_HEADLESS_QUOTA_PERMISSION_CONTEXT_H_
+#define HEADLESS_LIB_BROWSER_HEADLESS_QUOTA_PERMISSION_CONTEXT_H_
+
+#include "base/macros.h"
+#include "content/public/browser/quota_permission_context.h"
+
+namespace headless {
+
+class HeadlessQuotaPermissionContext : public content::QuotaPermissionContext {
+ public:
+  HeadlessQuotaPermissionContext();
+
+  // The callback will be dispatched on the IO thread.
+  void RequestQuotaPermission(const content::StorageQuotaParams& params,
+                              int render_process_id,
+                              const PermissionCallback& callback) override;
+
+ private:
+  ~HeadlessQuotaPermissionContext() override;
+
+  DISALLOW_COPY_AND_ASSIGN(HeadlessQuotaPermissionContext);
+};
+
+}  // namespace headless
+
+#endif  // HEADLESS_LIB_BROWSER_HEADLESS_QUOTA_PERMISSION_CONTEXT_H_
diff --git a/headless/lib/headless_web_contents_browsertest.cc b/headless/lib/headless_web_contents_browsertest.cc
index 5284ccb6..0f2ed053 100644
--- a/headless/lib/headless_web_contents_browsertest.cc
+++ b/headless/lib/headless_web_contents_browsertest.cc
@@ -832,4 +832,32 @@
 HEADLESS_ASYNC_DEVTOOLED_TEST_F(
     SingleTabMultipleIsolatedWorldsHeadlessTabSocketTest);
 
+// Regression test for https://crbug.com/733569.
+class HeadlessWebContentsRequestStorageQuotaTest
+    : public HeadlessAsyncDevTooledBrowserTest,
+      public runtime::Observer {
+ public:
+  void RunDevTooledTest() override {
+    EXPECT_TRUE(embedded_test_server()->Start());
+
+    base::RunLoop run_loop;
+    base::MessageLoop::ScopedNestableTaskAllower nest_loop(
+        base::MessageLoop::current());
+    devtools_client_->GetRuntime()->AddObserver(this);
+    devtools_client_->GetRuntime()->Enable(run_loop.QuitClosure());
+    run_loop.Run();
+
+    // Should not crash and call console.log() if quota request succeeds.
+    devtools_client_->GetPage()->Navigate(
+        embedded_test_server()->GetURL("/request_storage_quota.html").spec());
+  }
+
+  void OnConsoleAPICalled(
+      const runtime::ConsoleAPICalledParams& params) override {
+    FinishAsynchronousTest();
+  }
+};
+
+HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessWebContentsRequestStorageQuotaTest);
+
 }  // namespace headless
diff --git a/headless/test/data/request_storage_quota.html b/headless/test/data/request_storage_quota.html
new file mode 100644
index 0000000..1c50ad55
--- /dev/null
+++ b/headless/test/data/request_storage_quota.html
@@ -0,0 +1,3 @@
+<script type="application/javascript">
+navigator.webkitPersistentStorage.requestQuota(10, () => { console.log('success'); })
+</script>
diff --git a/ios/chrome/browser/ui/payments/BUILD.gn b/ios/chrome/browser/ui/payments/BUILD.gn
index 21f86ef..8267074 100644
--- a/ios/chrome/browser/ui/payments/BUILD.gn
+++ b/ios/chrome/browser/ui/payments/BUILD.gn
@@ -167,6 +167,8 @@
     "payment_request_error_view_controller_unittest.mm",
     "payment_request_mediator_unittest.mm",
     "payment_request_selector_view_controller_unittest.mm",
+    "payment_request_unittest_base.h",
+    "payment_request_unittest_base.mm",
     "payment_request_view_controller_unittest.mm",
     "region_data_loader_unittest.mm",
     "shipping_address_selection_coordinator_unittest.mm",
diff --git a/ios/chrome/browser/ui/payments/billing_address_selection_coordinator_unittest.mm b/ios/chrome/browser/ui/payments/billing_address_selection_coordinator_unittest.mm
index 3558927..1967df8 100644
--- a/ios/chrome/browser/ui/payments/billing_address_selection_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/payments/billing_address_selection_coordinator_unittest.mm
@@ -5,22 +5,15 @@
 #import "ios/chrome/browser/ui/payments/billing_address_selection_coordinator.h"
 
 #include "base/mac/foundation_util.h"
-#include "base/memory/ptr_util.h"
 #include "base/test/ios/wait_util.h"
-#include "base/test/scoped_task_environment.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/browser/field_types.h"
-#include "components/autofill/core/browser/test_personal_data_manager.h"
 #include "components/autofill/core/browser/test_region_data_loader.h"
-#include "components/prefs/pref_service.h"
-#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/chrome/browser/payments/payment_request_test_util.h"
-#include "ios/chrome/browser/payments/test_payment_request.h"
 #import "ios/chrome/browser/ui/payments/payment_request_selector_view_controller.h"
-#import "ios/web/public/test/fakes/test_web_state.h"
-#include "testing/gtest/include/gtest/gtest.h"
+#import "ios/chrome/browser/ui/payments/payment_request_unittest_base.h"
 #include "testing/platform_test.h"
 #include "third_party/ocmock/OCMock/OCMock.h"
 #include "third_party/ocmock/gtest_support.h"
@@ -30,45 +23,40 @@
 #endif
 
 class PaymentRequestBillingAddressSelectionCoordinatorTest
-    : public PlatformTest {
+    : public PaymentRequestUnitTestBase,
+      public PlatformTest {
  protected:
-  PaymentRequestBillingAddressSelectionCoordinatorTest()
-      : autofill_profile1_(autofill::test::GetFullProfile()),
-        autofill_profile2_(autofill::test::GetFullProfile2()),
-        pref_service_(autofill::test::PrefServiceForTesting()),
-        chrome_browser_state_(TestChromeBrowserState::Builder().Build()) {
-    personal_data_manager_.SetTestingPrefService(pref_service_.get());
-    // Add testing profiles to autofill::TestPersonalDataManager. Make the less
-    // frequently used one incomplete.
-    autofill_profile1_.set_use_count(10U);
-    personal_data_manager_.AddTestingProfile(&autofill_profile1_);
-    autofill_profile2_.set_use_count(5U);
-    autofill_profile2_.SetInfo(
-        autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER),
-        base::string16(), "en-US");
-    personal_data_manager_.AddTestingProfile(&autofill_profile2_);
+  void SetUp() override {
+    PaymentRequestUnitTestBase::SetUp();
 
-    payment_request_ = base::MakeUnique<payments::TestPaymentRequest>(
-        payment_request_test_util::CreateTestWebPaymentRequest(),
-        chrome_browser_state_.get(), &web_state_, &personal_data_manager_);
+    // Add testing profiles to the database. Make the less frequently used one
+    // incomplete.
+    autofill::AutofillProfile profile = autofill::test::GetFullProfile();
+    profile.set_use_count(10U);
+    AddAutofillProfile(std::move(profile));
+
+    autofill::AutofillProfile profile2 = autofill::test::GetFullProfile2();
+    profile2.set_use_count(5U);
+    profile2.SetInfo(autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER),
+                     base::string16(), "en-US");
+    AddAutofillProfile(std::move(profile2));
+
+    CreateTestPaymentRequest();
 
     test_region_data_loader_.set_synchronous_callback(true);
-    payment_request_->SetRegionDataLoader(&test_region_data_loader_);
-  }
+    payment_request()->SetRegionDataLoader(&test_region_data_loader_);
 
-  void SetUp() override {
+    // Create the controller and coordinator under test.
     UIViewController* base_view_controller = [[UIViewController alloc] init];
     navigation_controller_ = [[UINavigationController alloc]
         initWithRootViewController:base_view_controller];
 
     coordinator_ = [[BillingAddressSelectionCoordinator alloc]
         initWithBaseViewController:base_view_controller];
-    [coordinator_ setPaymentRequest:payment_request_.get()];
+    [coordinator_ setPaymentRequest:payment_request()];
   }
 
-  void TearDown() override {
-    personal_data_manager_.SetTestingPrefService(nullptr);
-  }
+  void TearDown() override { PaymentRequestUnitTestBase::TearDown(); }
 
   UINavigationController* GetNavigationController() {
     return navigation_controller_;
@@ -76,19 +64,10 @@
 
   BillingAddressSelectionCoordinator* GetCoordinator() { return coordinator_; }
 
-  base::test::ScopedTaskEnvironment scoped_task_evironment_;
-
+ private:
+  autofill::TestRegionDataLoader test_region_data_loader_;
   UINavigationController* navigation_controller_;
   BillingAddressSelectionCoordinator* coordinator_;
-
-  autofill::AutofillProfile autofill_profile1_;
-  autofill::AutofillProfile autofill_profile2_;
-  web::TestWebState web_state_;
-  std::unique_ptr<PrefService> pref_service_;
-  autofill::TestPersonalDataManager personal_data_manager_;
-  autofill::TestRegionDataLoader test_region_data_loader_;
-  std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
-  std::unique_ptr<payments::TestPaymentRequest> payment_request_;
 };
 
 // Tests that invoking start and stop on the coordinator presents and dismisses
@@ -122,11 +101,11 @@
       mockForProtocol:@protocol(BillingAddressSelectionCoordinatorDelegate)];
   [[delegate expect]
       billingAddressSelectionCoordinator:GetCoordinator()
-                 didSelectBillingAddress:payment_request_
+                 didSelectBillingAddress:payment_request()
                                              ->billing_profiles()[0]];
   [[delegate reject]
       billingAddressSelectionCoordinator:GetCoordinator()
-                 didSelectBillingAddress:payment_request_
+                 didSelectBillingAddress:payment_request()
                                              ->billing_profiles()[1]];
   [GetCoordinator() setDelegate:delegate];
 
diff --git a/ios/chrome/browser/ui/payments/billing_address_selection_mediator_unittest.mm b/ios/chrome/browser/ui/payments/billing_address_selection_mediator_unittest.mm
index ec3af68..2f80e04 100644
--- a/ios/chrome/browser/ui/payments/billing_address_selection_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/payments/billing_address_selection_mediator_unittest.mm
@@ -6,20 +6,14 @@
 
 #include "base/mac/foundation_util.h"
 #include "base/memory/ptr_util.h"
-#include "base/test/scoped_task_environment.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
-#include "components/autofill/core/browser/test_personal_data_manager.h"
 #include "components/payments/core/payments_profile_comparator.h"
-#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/chrome/browser/payments/payment_request_test_util.h"
 #import "ios/chrome/browser/payments/payment_request_util.h"
-#include "ios/chrome/browser/payments/test_payment_request.h"
 #import "ios/chrome/browser/ui/payments/cells/autofill_profile_item.h"
-#import "ios/web/public/test/fakes/test_web_state.h"
-#include "testing/gtest/include/gtest/gtest.h"
+#import "ios/chrome/browser/ui/payments/payment_request_unittest_base.h"
 #include "testing/platform_test.h"
-#include "third_party/ocmock/gtest_support.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -40,119 +34,101 @@
       : PaymentsProfileComparator(app_locale, options) {}
 };
 
-class PaymentRequestBillingAddressSelectionMediatorTest : public PlatformTest {
+class PaymentRequestBillingAddressSelectionMediatorTest
+    : public PaymentRequestUnitTestBase,
+      public PlatformTest {
  protected:
-  PaymentRequestBillingAddressSelectionMediatorTest()
-      : autofill_profile_1_(autofill::test::GetFullProfile()),
-        autofill_profile_2_(autofill::test::GetFullProfile2()),
-        autofill_profile_3_(autofill::test::GetIncompleteProfile1()),
-        autofill_profile_4_(autofill::test::GetIncompleteProfile2()),
-        chrome_browser_state_(TestChromeBrowserState::Builder().Build()) {
-    // Add testing profiles to autofill::TestPersonalDataManager.
-    personal_data_manager_.AddTestingProfile(&autofill_profile_1_);
-    personal_data_manager_.AddTestingProfile(&autofill_profile_2_);
-    personal_data_manager_.AddTestingProfile(&autofill_profile_3_);
-    personal_data_manager_.AddTestingProfile(&autofill_profile_4_);
-
-    payment_request_ = base::MakeUnique<payments::TestPaymentRequest>(
-        payment_request_test_util::CreateTestWebPaymentRequest(),
-        chrome_browser_state_.get(), &web_state_, &personal_data_manager_);
-    profile_comparator_ = base::MakeUnique<FakePaymentsProfileComparator>(
-        payment_request_->GetApplicationLocale(), *payment_request_.get());
-    payment_request_->SetProfileComparator(profile_comparator_.get());
-  }
-
   void SetUp() override {
+    PaymentRequestUnitTestBase::SetUp();
+
+    AddAutofillProfile(std::move(autofill::test::GetFullProfile()));
+    AddAutofillProfile(std::move(autofill::test::GetFullProfile2()));
+    AddAutofillProfile(std::move(autofill::test::GetIncompleteProfile1()));
+    AddAutofillProfile(std::move(autofill::test::GetIncompleteProfile2()));
+
+    CreateTestPaymentRequest();
+
+    profile_comparator_ = base::MakeUnique<FakePaymentsProfileComparator>(
+        payment_request()->GetApplicationLocale(), *payment_request());
+    payment_request()->SetProfileComparator(profile_comparator_.get());
+
     mediator_ = [[BillingAddressSelectionMediator alloc]
-        initWithPaymentRequest:payment_request_.get()
-        selectedBillingProfile:payment_request_->billing_profiles()[1]];
+        initWithPaymentRequest:payment_request()
+        selectedBillingProfile:payment_request()->billing_profiles()[1]];
   }
 
-  BillingAddressSelectionMediator* GetMediator() { return mediator_; }
+  void TearDown() override { PaymentRequestUnitTestBase::TearDown(); }
 
-  base::test::ScopedTaskEnvironment scoped_task_evironment_;
+  BillingAddressSelectionMediator* mediator() const { return mediator_; }
 
   BillingAddressSelectionMediator* mediator_;
 
-  autofill::AutofillProfile autofill_profile_1_;
-  autofill::AutofillProfile autofill_profile_2_;
-  autofill::AutofillProfile autofill_profile_3_;
-  autofill::AutofillProfile autofill_profile_4_;
-  web::TestWebState web_state_;
-  autofill::TestPersonalDataManager personal_data_manager_;
-  std::unique_ptr<FakePaymentsProfileComparator> profile_comparator_;
-  std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
-  std::unique_ptr<payments::TestPaymentRequest> payment_request_;
+  std::unique_ptr<payments::PaymentsProfileComparator> profile_comparator_;
 };
 
 // Tests that the expected selectable items are created and that the index of
 // the selected item is properly set.
 TEST_F(PaymentRequestBillingAddressSelectionMediatorTest, TestSelectableItems) {
-  NSArray<CollectionViewItem*>* selectable_items =
-      [GetMediator() selectableItems];
+  NSArray<CollectionViewItem*>* selectable_items = [mediator() selectableItems];
 
   ASSERT_EQ(4U, selectable_items.count);
 
   // The second item must be selected.
-  EXPECT_EQ(1U, GetMediator().selectedItemIndex);
+  EXPECT_EQ(1U, mediator().selectedItemIndex);
 
-  CollectionViewItem* item_1 =
-      [[GetMediator() selectableItems] objectAtIndex:0];
+  CollectionViewItem* item_1 = [[mediator() selectableItems] objectAtIndex:0];
   DCHECK([item_1 isKindOfClass:[AutofillProfileItem class]]);
   AutofillProfileItem* profile_item_1 =
       base::mac::ObjCCastStrict<AutofillProfileItem>(item_1);
   EXPECT_TRUE([profile_item_1.name
       isEqualToString:GetNameLabelFromAutofillProfile(
-                          *payment_request_->billing_profiles()[0])]);
+                          *payment_request()->billing_profiles()[0])]);
   EXPECT_TRUE([profile_item_1.address
       isEqualToString:GetBillingAddressLabelFromAutofillProfile(
-                          *payment_request_->billing_profiles()[0])]);
+                          *payment_request()->billing_profiles()[0])]);
   EXPECT_TRUE([profile_item_1.phoneNumber
       isEqualToString:GetPhoneNumberLabelFromAutofillProfile(
-                          *payment_request_->billing_profiles()[0])]);
+                          *payment_request()->billing_profiles()[0])]);
   EXPECT_EQ(nil, profile_item_1.email);
   EXPECT_EQ(nil, profile_item_1.notification);
   EXPECT_TRUE(profile_item_1.complete);
 
-  CollectionViewItem* item_2 =
-      [[GetMediator() selectableItems] objectAtIndex:1];
+  CollectionViewItem* item_2 = [[mediator() selectableItems] objectAtIndex:1];
   DCHECK([item_2 isKindOfClass:[AutofillProfileItem class]]);
   AutofillProfileItem* profile_item_2 =
       base::mac::ObjCCastStrict<AutofillProfileItem>(item_2);
   EXPECT_TRUE([profile_item_2.name
       isEqualToString:GetNameLabelFromAutofillProfile(
-                          *payment_request_->billing_profiles()[1])]);
+                          *payment_request()->billing_profiles()[1])]);
   EXPECT_TRUE([profile_item_2.address
       isEqualToString:GetBillingAddressLabelFromAutofillProfile(
-                          *payment_request_->billing_profiles()[1])]);
+                          *payment_request()->billing_profiles()[1])]);
   EXPECT_TRUE([profile_item_2.phoneNumber
       isEqualToString:GetPhoneNumberLabelFromAutofillProfile(
-                          *payment_request_->billing_profiles()[1])]);
+                          *payment_request()->billing_profiles()[1])]);
   EXPECT_EQ(nil, profile_item_2.email);
   EXPECT_EQ(nil, profile_item_2.notification);
   EXPECT_TRUE(profile_item_2.complete);
 
-  CollectionViewItem* item_3 =
-      [[GetMediator() selectableItems] objectAtIndex:2];
+  CollectionViewItem* item_3 = [[mediator() selectableItems] objectAtIndex:2];
   DCHECK([item_3 isKindOfClass:[AutofillProfileItem class]]);
   AutofillProfileItem* profile_item_3 =
       base::mac::ObjCCastStrict<AutofillProfileItem>(item_3);
   EXPECT_TRUE([profile_item_3.name
       isEqualToString:GetNameLabelFromAutofillProfile(
-                          *payment_request_->billing_profiles()[2])]);
+                          *payment_request()->billing_profiles()[2])]);
   EXPECT_TRUE([profile_item_3.address
       isEqualToString:GetBillingAddressLabelFromAutofillProfile(
-                          *payment_request_->billing_profiles()[2])]);
+                          *payment_request()->billing_profiles()[2])]);
   EXPECT_EQ(nil, profile_item_3.phoneNumber);
   EXPECT_EQ(nil, profile_item_3.email);
   EXPECT_TRUE([profile_item_3.notification
       isEqualToString:GetAddressNotificationLabelFromAutofillProfile(
-                          *payment_request_.get(),
-                          *payment_request_->billing_profiles()[2])]);
+                          *payment_request(),
+                          *payment_request()->billing_profiles()[2])]);
   EXPECT_FALSE(profile_item_3.complete);
 
-  CollectionViewItem* item_4 =
-      [[GetMediator() selectableItems] objectAtIndex:3];
+  CollectionViewItem* item_4 = [[mediator() selectableItems] objectAtIndex:3];
   DCHECK([item_4 isKindOfClass:[AutofillProfileItem class]]);
   AutofillProfileItem* profile_item_4 =
       base::mac::ObjCCastStrict<AutofillProfileItem>(item_4);
@@ -162,8 +138,8 @@
   EXPECT_EQ(nil, profile_item_4.email);
   EXPECT_TRUE([profile_item_4.notification
       isEqualToString:GetAddressNotificationLabelFromAutofillProfile(
-                          *payment_request_.get(),
-                          *payment_request_->billing_profiles()[3])]);
+                          *payment_request(),
+                          *payment_request()->billing_profiles()[3])]);
   EXPECT_FALSE(profile_item_4.complete);
 }
 
@@ -171,14 +147,13 @@
 // selected billing profile.
 TEST_F(PaymentRequestBillingAddressSelectionMediatorTest, TestNoSelectedItem) {
   mediator_ = [[BillingAddressSelectionMediator alloc]
-      initWithPaymentRequest:payment_request_.get()
+      initWithPaymentRequest:payment_request()
       selectedBillingProfile:nil];
 
-  NSArray<CollectionViewItem*>* selectable_items =
-      [GetMediator() selectableItems];
+  NSArray<CollectionViewItem*>* selectable_items = [mediator() selectableItems];
 
   ASSERT_EQ(4U, selectable_items.count);
 
   // The selected item index must be invalid.
-  EXPECT_EQ(NSUIntegerMax, GetMediator().selectedItemIndex);
+  EXPECT_EQ(NSUIntegerMax, mediator().selectedItemIndex);
 }
diff --git a/ios/chrome/browser/ui/payments/contact_info_edit_mediator_unittest.mm b/ios/chrome/browser/ui/payments/contact_info_edit_mediator_unittest.mm
index 0dbdd7b..35400c26 100644
--- a/ios/chrome/browser/ui/payments/contact_info_edit_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/payments/contact_info_edit_mediator_unittest.mm
@@ -5,20 +5,14 @@
 #import "ios/chrome/browser/ui/payments/contact_info_edit_mediator.h"
 
 #include "base/mac/foundation_util.h"
-#include "base/memory/ptr_util.h"
-#include "base/test/scoped_task_environment.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
-#include "components/autofill/core/browser/test_personal_data_manager.h"
 #include "components/strings/grit/components_strings.h"
-#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/chrome/browser/payments/payment_request_test_util.h"
-#include "ios/chrome/browser/payments/test_payment_request.h"
 #import "ios/chrome/browser/ui/autofill/autofill_ui_type_util.h"
 #import "ios/chrome/browser/ui/payments/payment_request_edit_consumer.h"
 #import "ios/chrome/browser/ui/payments/payment_request_editor_field.h"
-#import "ios/web/public/test/fakes/test_web_state.h"
-#include "testing/gtest/include/gtest/gtest.h"
+#import "ios/chrome/browser/ui/payments/payment_request_unittest_base.h"
 #include "testing/platform_test.h"
 #include "third_party/ocmock/OCMock/OCMock.h"
 #include "third_party/ocmock/gtest_support.h"
@@ -28,22 +22,17 @@
 #error "This file requires ARC support."
 #endif
 
-class PaymentRequestContactInfoEditMediatorTest : public PlatformTest {
+class PaymentRequestContactInfoEditMediatorTest
+    : public PaymentRequestUnitTestBase,
+      public PlatformTest {
  protected:
-  PaymentRequestContactInfoEditMediatorTest()
-      : chrome_browser_state_(TestChromeBrowserState::Builder().Build()),
-        payment_request_(base::MakeUnique<payments::TestPaymentRequest>(
-            payment_request_test_util::CreateTestWebPaymentRequest(),
-            chrome_browser_state_.get(),
-            &web_state_,
-            &personal_data_manager_)) {}
+  void SetUp() override {
+    PaymentRequestUnitTestBase::SetUp();
 
-  base::test::ScopedTaskEnvironment scoped_task_evironment_;
+    CreateTestPaymentRequest();
+  }
 
-  web::TestWebState web_state_;
-  autofill::TestPersonalDataManager personal_data_manager_;
-  std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
-  std::unique_ptr<payments::TestPaymentRequest> payment_request_;
+  void TearDown() override { PaymentRequestUnitTestBase::TearDown(); }
 };
 
 // Tests that the expected editor fields are created when creating a profile.
@@ -92,9 +81,9 @@
       [OCMockObject mockForProtocol:@protocol(PaymentRequestEditConsumer)];
   [[consumer expect] setEditorFields:[OCMArg checkWithBlock:check_block]];
 
-  ContactInfoEditMediator* mediator = [[ContactInfoEditMediator alloc]
-      initWithPaymentRequest:payment_request_.get()
-                     profile:nil];
+  ContactInfoEditMediator* mediator =
+      [[ContactInfoEditMediator alloc] initWithPaymentRequest:payment_request()
+                                                      profile:nil];
   [mediator setConsumer:consumer];
 
   EXPECT_OCMOCK_VERIFY(consumer);
@@ -132,7 +121,7 @@
 
   autofill::AutofillProfile autofill_profile = autofill::test::GetFullProfile();
   ContactInfoEditMediator* mediator = [[ContactInfoEditMediator alloc]
-      initWithPaymentRequest:payment_request_.get()
+      initWithPaymentRequest:payment_request()
                      profile:&autofill_profile];
   [mediator setConsumer:consumer];
 
@@ -155,17 +144,17 @@
     return YES;
   };
 
-  payment_request_->web_payment_request().options.request_payer_phone = false;
-  payment_request_->web_payment_request().options.request_payer_email = false;
+  payment_request()->web_payment_request().options.request_payer_phone = false;
+  payment_request()->web_payment_request().options.request_payer_email = false;
 
   // Mock the consumer.
   id consumer =
       [OCMockObject mockForProtocol:@protocol(PaymentRequestEditConsumer)];
   [[consumer expect] setEditorFields:[OCMArg checkWithBlock:check_block]];
 
-  ContactInfoEditMediator* mediator = [[ContactInfoEditMediator alloc]
-      initWithPaymentRequest:payment_request_.get()
-                     profile:nil];
+  ContactInfoEditMediator* mediator =
+      [[ContactInfoEditMediator alloc] initWithPaymentRequest:payment_request()
+                                                      profile:nil];
   [mediator setConsumer:consumer];
 
   EXPECT_OCMOCK_VERIFY(consumer);
@@ -193,16 +182,16 @@
     return YES;
   };
 
-  payment_request_->web_payment_request().options.request_payer_name = false;
+  payment_request()->web_payment_request().options.request_payer_name = false;
 
   // Mock the consumer.
   id consumer =
       [OCMockObject mockForProtocol:@protocol(PaymentRequestEditConsumer)];
   [[consumer expect] setEditorFields:[OCMArg checkWithBlock:check_block]];
 
-  ContactInfoEditMediator* mediator = [[ContactInfoEditMediator alloc]
-      initWithPaymentRequest:payment_request_.get()
-                     profile:nil];
+  ContactInfoEditMediator* mediator =
+      [[ContactInfoEditMediator alloc] initWithPaymentRequest:payment_request()
+                                                      profile:nil];
   [mediator setConsumer:consumer];
 
   EXPECT_OCMOCK_VERIFY(consumer);
diff --git a/ios/chrome/browser/ui/payments/contact_info_selection_coordinator_unittest.mm b/ios/chrome/browser/ui/payments/contact_info_selection_coordinator_unittest.mm
index 9aff5c258..5b0f0c90 100644
--- a/ios/chrome/browser/ui/payments/contact_info_selection_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/payments/contact_info_selection_coordinator_unittest.mm
@@ -5,19 +5,13 @@
 #import "ios/chrome/browser/ui/payments/contact_info_selection_coordinator.h"
 
 #include "base/mac/foundation_util.h"
-#include "base/memory/ptr_util.h"
 #include "base/test/ios/wait_util.h"
-#include "base/test/scoped_task_environment.h"
+
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
-#include "components/autofill/core/browser/test_personal_data_manager.h"
-#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
-#include "ios/chrome/browser/payments/payment_request.h"
 #include "ios/chrome/browser/payments/payment_request_test_util.h"
-#include "ios/chrome/browser/payments/test_payment_request.h"
 #import "ios/chrome/browser/ui/payments/payment_request_selector_view_controller.h"
-#import "ios/web/public/test/fakes/test_web_state.h"
-#include "testing/gtest/include/gtest/gtest.h"
+#import "ios/chrome/browser/ui/payments/payment_request_unittest_base.h"
 #include "testing/platform_test.h"
 #include "third_party/ocmock/OCMock/OCMock.h"
 #include "third_party/ocmock/gtest_support.h"
@@ -31,29 +25,21 @@
 const int kIncompleteProfileIndex = 1;
 }  // namespace
 
-class PaymentRequestContactInfoSelectionCoordinatorTest : public PlatformTest {
+class PaymentRequestContactInfoSelectionCoordinatorTest
+    : public PaymentRequestUnitTestBase,
+      public PlatformTest {
  protected:
-  PaymentRequestContactInfoSelectionCoordinatorTest()
-      : autofill_profile_1_(autofill::test::GetFullProfile()),
-        autofill_profile_2_(autofill::test::GetIncompleteProfile2()),
-        chrome_browser_state_(TestChromeBrowserState::Builder().Build()) {
-    // Add testing profiles to autofill::TestPersonalDataManager.
-    personal_data_manager_.AddTestingProfile(&autofill_profile_1_);
-    personal_data_manager_.AddTestingProfile(&autofill_profile_2_);
+  void SetUp() override {
+    PaymentRequestUnitTestBase::SetUp();
 
-    payment_request_ = base::MakeUnique<payments::TestPaymentRequest>(
-        payment_request_test_util::CreateTestWebPaymentRequest(),
-        chrome_browser_state_.get(), &web_state_, &personal_data_manager_);
+    // One profile is incomplete.
+    AddAutofillProfile(autofill::test::GetFullProfile());
+    AddAutofillProfile(autofill::test::GetIncompleteProfile2());
+
+    CreateTestPaymentRequest();
   }
 
-  base::test::ScopedTaskEnvironment scoped_task_evironment_;
-
-  autofill::AutofillProfile autofill_profile_1_;
-  autofill::AutofillProfile autofill_profile_2_;
-  web::TestWebState web_state_;
-  autofill::TestPersonalDataManager personal_data_manager_;
-  std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
-  std::unique_ptr<payments::TestPaymentRequest> payment_request_;
+  void TearDown() override { PaymentRequestUnitTestBase::TearDown(); }
 };
 
 // Tests that invoking start and stop on the coordinator presents and dismisses
@@ -67,7 +53,7 @@
   ContactInfoSelectionCoordinator* coordinator =
       [[ContactInfoSelectionCoordinator alloc]
           initWithBaseViewController:base_view_controller];
-  [coordinator setPaymentRequest:payment_request_.get()];
+  [coordinator setPaymentRequest:payment_request()];
 
   EXPECT_EQ(1u, navigation_controller.viewControllers.count);
 
@@ -99,18 +85,18 @@
   ContactInfoSelectionCoordinator* coordinator =
       [[ContactInfoSelectionCoordinator alloc]
           initWithBaseViewController:base_view_controller];
-  [coordinator setPaymentRequest:payment_request_.get()];
+  [coordinator setPaymentRequest:payment_request()];
 
   // Mock the coordinator delegate.
   id delegate = [OCMockObject
       mockForProtocol:@protocol(ContactInfoSelectionCoordinatorDelegate)];
   [[delegate expect]
       contactInfoSelectionCoordinator:coordinator
-              didSelectContactProfile:payment_request_->contact_profiles()
+              didSelectContactProfile:payment_request()->contact_profiles()
                                           [kCompleteProfileIndex]];
   [[delegate reject]
       contactInfoSelectionCoordinator:coordinator
-              didSelectContactProfile:payment_request_->contact_profiles()
+              didSelectContactProfile:payment_request()->contact_profiles()
                                           [kIncompleteProfileIndex]];
   [coordinator setDelegate:delegate];
 
@@ -150,7 +136,7 @@
   ContactInfoSelectionCoordinator* coordinator =
       [[ContactInfoSelectionCoordinator alloc]
           initWithBaseViewController:base_view_controller];
-  [coordinator setPaymentRequest:payment_request_.get()];
+  [coordinator setPaymentRequest:payment_request()];
 
   // Mock the coordinator delegate.
   id delegate = [OCMockObject
diff --git a/ios/chrome/browser/ui/payments/contact_info_selection_mediator_unittest.mm b/ios/chrome/browser/ui/payments/contact_info_selection_mediator_unittest.mm
index e1c3bc9..25cda71 100644
--- a/ios/chrome/browser/ui/payments/contact_info_selection_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/payments/contact_info_selection_mediator_unittest.mm
@@ -5,21 +5,14 @@
 #import "ios/chrome/browser/ui/payments/contact_info_selection_mediator.h"
 
 #include "base/mac/foundation_util.h"
-#include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_task_environment.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
-#include "components/autofill/core/browser/test_personal_data_manager.h"
-#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/chrome/browser/payments/payment_request_test_util.h"
 #import "ios/chrome/browser/payments/payment_request_util.h"
-#include "ios/chrome/browser/payments/test_payment_request.h"
 #import "ios/chrome/browser/ui/payments/cells/autofill_profile_item.h"
-#import "ios/web/public/test/fakes/test_web_state.h"
-#include "testing/gtest/include/gtest/gtest.h"
+#import "ios/chrome/browser/ui/payments/payment_request_unittest_base.h"
 #include "testing/platform_test.h"
-#include "third_party/ocmock/gtest_support.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -32,65 +25,51 @@
 using ::payment_request_util::GetContactNotificationLabelFromAutofillProfile;
 }  // namespace
 
-class PaymentRequestContactInfoSelectionMediatorTest : public PlatformTest {
+class PaymentRequestContactInfoSelectionMediatorTest
+    : public PaymentRequestUnitTestBase,
+      public PlatformTest {
  protected:
-  PaymentRequestContactInfoSelectionMediatorTest()
-      : autofill_profile_1_(autofill::test::GetFullProfile()),
-        autofill_profile_2_(autofill::test::GetFullProfile2()),
-        autofill_profile_3_(autofill::test::GetFullProfile()),
-        chrome_browser_state_(TestChromeBrowserState::Builder().Build()) {
+  void SetUp() override {
+    PaymentRequestUnitTestBase::SetUp();
+
+    AddAutofillProfile(autofill::test::GetFullProfile());
+    AddAutofillProfile(autofill::test::GetFullProfile2());
+    autofill::AutofillProfile profile3 = autofill::test::GetFullProfile();
     // Change the name of the third profile (to avoid deduplication), and make
     // it incomplete by removing the phone number.
-    autofill_profile_3_.SetInfo(autofill::AutofillType(autofill::NAME_FULL),
-                                base::ASCIIToUTF16("Richard Roe"), "en-US");
-    autofill_profile_3_.SetInfo(
-        autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER),
-        base::string16(), "en-US");
+    profile3.SetInfo(autofill::AutofillType(autofill::NAME_FULL),
+                     base::ASCIIToUTF16("Richard Roe"), "en-US");
+    profile3.SetInfo(autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER),
+                     base::string16(), "en-US");
+    AddAutofillProfile(std::move(profile3));
 
-    // Add testing profiles to autofill::TestPersonalDataManager.
-    personal_data_manager_.AddTestingProfile(&autofill_profile_1_);
-    personal_data_manager_.AddTestingProfile(&autofill_profile_2_);
-    personal_data_manager_.AddTestingProfile(&autofill_profile_3_);
-    payment_request_ = base::MakeUnique<payments::TestPaymentRequest>(
-        payment_request_test_util::CreateTestWebPaymentRequest(),
-        chrome_browser_state_.get(), &web_state_, &personal_data_manager_);
+    CreateTestPaymentRequest();
 
     // Override the selected contact profile.
-    payment_request_->set_selected_contact_profile(
-        payment_request_->contact_profiles()[1]);
-  }
+    payment_request()->set_selected_contact_profile(
+        payment_request()->contact_profiles()[1]);
 
-  void SetUp() override {
     mediator_ = [[ContactInfoSelectionMediator alloc]
-        initWithPaymentRequest:payment_request_.get()];
+        initWithPaymentRequest:payment_request()];
   }
 
-  ContactInfoSelectionMediator* GetMediator() { return mediator_; }
+  void TearDown() override { PaymentRequestUnitTestBase::TearDown(); }
 
-  base::test::ScopedTaskEnvironment scoped_task_evironment_;
+  ContactInfoSelectionMediator* mediator() const { return mediator_; }
 
   ContactInfoSelectionMediator* mediator_;
-
-  autofill::AutofillProfile autofill_profile_1_;
-  autofill::AutofillProfile autofill_profile_2_;
-  autofill::AutofillProfile autofill_profile_3_;
-  web::TestWebState web_state_;
-  autofill::TestPersonalDataManager personal_data_manager_;
-  std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
-  std::unique_ptr<payments::TestPaymentRequest> payment_request_;
 };
 
 // Tests that the expected selectable items are created and that the index of
 // the selected item is properly set.
 TEST_F(PaymentRequestContactInfoSelectionMediatorTest, TestSelectableItems) {
-  NSArray<CollectionViewItem*>* selectable_items =
-      [GetMediator() selectableItems];
+  NSArray<CollectionViewItem*>* selectable_items = [mediator() selectableItems];
 
   // There must be three selectable items.
   ASSERT_EQ(3U, selectable_items.count);
 
   // The second item must be selected.
-  EXPECT_EQ(1U, GetMediator().selectedItemIndex);
+  EXPECT_EQ(1U, mediator().selectedItemIndex);
 
   CollectionViewItem* item_1 = [selectable_items objectAtIndex:0];
   DCHECK([item_1 isKindOfClass:[AutofillProfileItem class]]);
@@ -98,13 +77,13 @@
       base::mac::ObjCCastStrict<AutofillProfileItem>(item_1);
   EXPECT_TRUE([profile_item_1.name
       isEqualToString:GetNameLabelFromAutofillProfile(
-                          *payment_request_->contact_profiles()[0])]);
+                          *payment_request()->contact_profiles()[0])]);
   EXPECT_TRUE([profile_item_1.email
       isEqualToString:GetEmailLabelFromAutofillProfile(
-                          *payment_request_->contact_profiles()[0])]);
+                          *payment_request()->contact_profiles()[0])]);
   EXPECT_TRUE([profile_item_1.phoneNumber
       isEqualToString:GetPhoneNumberLabelFromAutofillProfile(
-                          *payment_request_->contact_profiles()[0])]);
+                          *payment_request()->contact_profiles()[0])]);
   EXPECT_EQ(nil, profile_item_1.address);
   EXPECT_EQ(nil, profile_item_1.notification);
 
@@ -114,13 +93,13 @@
       base::mac::ObjCCastStrict<AutofillProfileItem>(item_2);
   EXPECT_TRUE([profile_item_2.name
       isEqualToString:GetNameLabelFromAutofillProfile(
-                          *payment_request_->contact_profiles()[1])]);
+                          *payment_request()->contact_profiles()[1])]);
   EXPECT_TRUE([profile_item_2.email
       isEqualToString:GetEmailLabelFromAutofillProfile(
-                          *payment_request_->contact_profiles()[1])]);
+                          *payment_request()->contact_profiles()[1])]);
   EXPECT_TRUE([profile_item_2.phoneNumber
       isEqualToString:GetPhoneNumberLabelFromAutofillProfile(
-                          *payment_request_->contact_profiles()[1])]);
+                          *payment_request()->contact_profiles()[1])]);
   EXPECT_EQ(nil, profile_item_2.address);
   EXPECT_EQ(nil, profile_item_2.notification);
 
@@ -130,44 +109,42 @@
       base::mac::ObjCCastStrict<AutofillProfileItem>(item_3);
   EXPECT_TRUE([profile_item_3.name
       isEqualToString:GetNameLabelFromAutofillProfile(
-                          *payment_request_->contact_profiles()[2])]);
+                          *payment_request()->contact_profiles()[2])]);
   EXPECT_TRUE([profile_item_3.email
       isEqualToString:GetEmailLabelFromAutofillProfile(
-                          *payment_request_->contact_profiles()[2])]);
+                          *payment_request()->contact_profiles()[2])]);
   EXPECT_EQ(nil, profile_item_3.phoneNumber);
   EXPECT_EQ(nil, profile_item_3.address);
   EXPECT_TRUE([profile_item_3.notification
       isEqualToString:GetContactNotificationLabelFromAutofillProfile(
-                          *payment_request_.get(),
-                          *payment_request_->contact_profiles()[2])]);
+                          *payment_request(),
+                          *payment_request()->contact_profiles()[2])]);
 }
 
 // Tests that the index of the selected item is as expected when there is no
 // selected contact profile.
 TEST_F(PaymentRequestContactInfoSelectionMediatorTest, TestNoSelectedItem) {
   // Reset the selected contact profile.
-  payment_request_->set_selected_contact_profile(nullptr);
+  payment_request()->set_selected_contact_profile(nullptr);
   mediator_ = [[ContactInfoSelectionMediator alloc]
-      initWithPaymentRequest:payment_request_.get()];
+      initWithPaymentRequest:payment_request()];
 
-  NSArray<CollectionViewItem*>* selectable_items =
-      [GetMediator() selectableItems];
+  NSArray<CollectionViewItem*>* selectable_items = [mediator() selectableItems];
 
   // There must be three selectable items.
   ASSERT_EQ(3U, selectable_items.count);
 
   // The selected item index must be invalid.
-  EXPECT_EQ(NSUIntegerMax, GetMediator().selectedItemIndex);
+  EXPECT_EQ(NSUIntegerMax, mediator().selectedItemIndex);
 }
 
 // Tests that only the requested fields are displayed.
 TEST_F(PaymentRequestContactInfoSelectionMediatorTest, TestOnlyRequestedData) {
   // Update the web_payment_request and reload the items.
-  payment_request_->web_payment_request().options.request_payer_name = false;
-  [GetMediator() loadItems];
+  payment_request()->web_payment_request().options.request_payer_name = false;
+  [mediator() loadItems];
 
-  NSArray<CollectionViewItem*>* selectable_items =
-      [GetMediator() selectableItems];
+  NSArray<CollectionViewItem*>* selectable_items = [mediator() selectableItems];
 
   CollectionViewItem* item = [selectable_items objectAtIndex:0];
   DCHECK([item isKindOfClass:[AutofillProfileItem class]]);
@@ -188,10 +165,10 @@
   EXPECT_NE(nil, incomplete_profile_item.notification);
 
   // Update the web_payment_request and reload the items.
-  payment_request_->web_payment_request().options.request_payer_email = false;
-  [GetMediator() loadItems];
+  payment_request()->web_payment_request().options.request_payer_email = false;
+  [mediator() loadItems];
 
-  selectable_items = [GetMediator() selectableItems];
+  selectable_items = [mediator() selectableItems];
 
   item = [selectable_items objectAtIndex:0];
   DCHECK([item isKindOfClass:[AutofillProfileItem class]]);
@@ -203,12 +180,12 @@
   EXPECT_EQ(nil, profile_item.notification);
 
   // Update the web_payment_request and reload the items.
-  payment_request_->web_payment_request().options.request_payer_name = true;
-  payment_request_->web_payment_request().options.request_payer_email = true;
-  payment_request_->web_payment_request().options.request_payer_phone = false;
-  [GetMediator() loadItems];
+  payment_request()->web_payment_request().options.request_payer_name = true;
+  payment_request()->web_payment_request().options.request_payer_email = true;
+  payment_request()->web_payment_request().options.request_payer_phone = false;
+  [mediator() loadItems];
 
-  selectable_items = [GetMediator() selectableItems];
+  selectable_items = [mediator() selectableItems];
 
   item = [selectable_items objectAtIndex:0];
   DCHECK([item isKindOfClass:[AutofillProfileItem class]]);
diff --git a/ios/chrome/browser/ui/payments/payment_items_display_coordinator_unittest.mm b/ios/chrome/browser/ui/payments/payment_items_display_coordinator_unittest.mm
index 5f6ebbe2..3fe2f04c 100644
--- a/ios/chrome/browser/ui/payments/payment_items_display_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/payments/payment_items_display_coordinator_unittest.mm
@@ -5,20 +5,11 @@
 #import "ios/chrome/browser/ui/payments/payment_items_display_coordinator.h"
 
 #include "base/mac/foundation_util.h"
-#include "base/memory/ptr_util.h"
 #include "base/test/ios/wait_util.h"
-#include "base/test/scoped_task_environment.h"
-#include "components/autofill/core/browser/autofill_profile.h"
-#include "components/autofill/core/browser/credit_card.h"
-#include "components/autofill/core/browser/test_personal_data_manager.h"
-#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/chrome/browser/payments/payment_request.h"
 #include "ios/chrome/browser/payments/payment_request_test_util.h"
-#include "ios/chrome/browser/payments/test_payment_request.h"
 #import "ios/chrome/browser/ui/payments/payment_items_display_view_controller.h"
-#include "ios/web/public/payments/payment_request.h"
-#import "ios/web/public/test/fakes/test_web_state.h"
-#include "testing/gtest/include/gtest/gtest.h"
+#import "ios/chrome/browser/ui/payments/payment_request_unittest_base.h"
 #include "testing/platform_test.h"
 #include "third_party/ocmock/OCMock/OCMock.h"
 #include "third_party/ocmock/gtest_support.h"
@@ -27,21 +18,17 @@
 #error "This file requires ARC support."
 #endif
 
-class PaymentRequestPaymentItemsDisplayCoordinatorTest : public PlatformTest {
+class PaymentRequestPaymentItemsDisplayCoordinatorTest
+    : public PaymentRequestUnitTestBase,
+      public PlatformTest {
  protected:
-  PaymentRequestPaymentItemsDisplayCoordinatorTest()
-      : chrome_browser_state_(TestChromeBrowserState::Builder().Build()) {
-    payment_request_ = base::MakeUnique<payments::TestPaymentRequest>(
-        payment_request_test_util::CreateTestWebPaymentRequest(),
-        chrome_browser_state_.get(), &web_state_, &personal_data_manager_);
+  void SetUp() override {
+    PaymentRequestUnitTestBase::SetUp();
+
+    CreateTestPaymentRequest();
   }
 
-  base::test::ScopedTaskEnvironment scoped_task_evironment_;
-
-  web::TestWebState web_state_;
-  autofill::TestPersonalDataManager personal_data_manager_;
-  std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
-  std::unique_ptr<payments::TestPaymentRequest> payment_request_;
+  void TearDown() override { PaymentRequestUnitTestBase::TearDown(); }
 };
 
 // Tests that invoking start and stop on the coordinator presents and dismisses
@@ -55,7 +42,7 @@
   PaymentItemsDisplayCoordinator* coordinator =
       [[PaymentItemsDisplayCoordinator alloc]
           initWithBaseViewController:base_view_controller];
-  [coordinator setPaymentRequest:payment_request_.get()];
+  [coordinator setPaymentRequest:payment_request()];
 
   EXPECT_EQ(1u, navigation_controller.viewControllers.count);
 
@@ -82,7 +69,7 @@
   PaymentItemsDisplayCoordinator* coordinator =
       [[PaymentItemsDisplayCoordinator alloc]
           initWithBaseViewController:base_view_controller];
-  [coordinator setPaymentRequest:payment_request_.get()];
+  [coordinator setPaymentRequest:payment_request()];
 
   // Mock the coordinator delegate.
   id delegate = [OCMockObject
@@ -118,7 +105,7 @@
   PaymentItemsDisplayCoordinator* coordinator =
       [[PaymentItemsDisplayCoordinator alloc]
           initWithBaseViewController:base_view_controller];
-  [coordinator setPaymentRequest:payment_request_.get()];
+  [coordinator setPaymentRequest:payment_request()];
 
   // Mock the coordinator delegate.
   id delegate = [OCMockObject
diff --git a/ios/chrome/browser/ui/payments/payment_items_display_view_controller_unittest.mm b/ios/chrome/browser/ui/payments/payment_items_display_view_controller_unittest.mm
index ef7d488..8d78a176 100644
--- a/ios/chrome/browser/ui/payments/payment_items_display_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/payments/payment_items_display_view_controller_unittest.mm
@@ -5,21 +5,13 @@
 #import "ios/chrome/browser/ui/payments/payment_items_display_view_controller.h"
 
 #include "base/mac/foundation_util.h"
-#include "base/memory/ptr_util.h"
-#include "base/test/scoped_task_environment.h"
-#include "components/autofill/core/browser/test_personal_data_manager.h"
 #include "components/strings/grit/components_strings.h"
-#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
-#include "ios/chrome/browser/payments/payment_request.h"
 #import "ios/chrome/browser/payments/payment_request_test_util.h"
-#include "ios/chrome/browser/payments/test_payment_request.h"
 #import "ios/chrome/browser/ui/collection_view/collection_view_controller_test.h"
 #import "ios/chrome/browser/ui/payments/cells/price_item.h"
 #import "ios/chrome/browser/ui/payments/payment_items_display_view_controller_data_source.h"
+#import "ios/chrome/browser/ui/payments/payment_request_unittest_base.h"
 #include "ios/chrome/grit/ios_strings.h"
-#include "ios/web/public/payments/payment_request.h"
-#import "ios/web/public/test/fakes/test_web_state.h"
-#include "testing/gtest/include/gtest/gtest.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -45,15 +37,17 @@
 @end
 
 class PaymentRequestPaymentItemsDisplayViewControllerTest
-    : public CollectionViewControllerTest {
+    : public CollectionViewControllerTest,
+      public PaymentRequestUnitTestBase {
  protected:
-  PaymentRequestPaymentItemsDisplayViewControllerTest()
-      : chrome_browser_state_(TestChromeBrowserState::Builder().Build()) {}
+  void SetUp() override {
+    PaymentRequestUnitTestBase::SetUp();
+    CollectionViewControllerTest::SetUp();
+  }
+
+  void TearDown() override { PaymentRequestUnitTestBase::TearDown(); }
 
   CollectionViewController* InstantiateController() override {
-    payment_request_ = base::MakeUnique<payments::TestPaymentRequest>(
-        payment_request_test_util::CreateTestWebPaymentRequest(),
-        chrome_browser_state_.get(), &web_state_, &personal_data_manager_);
     mediator_ = [[TestPaymentItemsDisplayMediator alloc] init];
     PaymentItemsDisplayViewController* viewController = [
         [PaymentItemsDisplayViewController alloc] initWithPayButtonEnabled:YES];
@@ -66,12 +60,7 @@
         controller());
   }
 
-  base::test::ScopedTaskEnvironment scoped_task_evironment_;
-
-  web::TestWebState web_state_;
-  autofill::TestPersonalDataManager personal_data_manager_;
-  std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
-  std::unique_ptr<payments::TestPaymentRequest> payment_request_;
+ private:
   TestPaymentItemsDisplayMediator* mediator_ = nil;
 };
 
diff --git a/ios/chrome/browser/ui/payments/payment_method_selection_coordinator_unittest.mm b/ios/chrome/browser/ui/payments/payment_method_selection_coordinator_unittest.mm
index d3c6296..d0a651e 100644
--- a/ios/chrome/browser/ui/payments/payment_method_selection_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/payments/payment_method_selection_coordinator_unittest.mm
@@ -5,22 +5,15 @@
 #import "ios/chrome/browser/ui/payments/payment_method_selection_coordinator.h"
 
 #include "base/mac/foundation_util.h"
-#include "base/memory/ptr_util.h"
 #include "base/test/ios/wait_util.h"
 #include "base/test/scoped_task_environment.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/credit_card.h"
-#include "components/autofill/core/browser/test_personal_data_manager.h"
 #include "components/payments/core/payment_instrument.h"
-#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
-#include "ios/chrome/browser/payments/payment_request.h"
 #include "ios/chrome/browser/payments/payment_request_test_util.h"
-#include "ios/chrome/browser/payments/test_payment_request.h"
 #import "ios/chrome/browser/ui/payments/payment_request_selector_view_controller.h"
-#include "ios/web/public/payments/payment_request.h"
-#import "ios/web/public/test/fakes/test_web_state.h"
-#include "testing/gtest/include/gtest/gtest.h"
+#import "ios/chrome/browser/ui/payments/payment_request_unittest_base.h"
 #include "testing/platform_test.h"
 #include "third_party/ocmock/OCMock/OCMock.h"
 #include "third_party/ocmock/gtest_support.h"
@@ -30,35 +23,28 @@
 #endif
 
 class PaymentRequestPaymentMethodSelectionCoordinatorTest
-    : public PlatformTest {
+    : public PaymentRequestUnitTestBase,
+      public PlatformTest {
  protected:
-  PaymentRequestPaymentMethodSelectionCoordinatorTest()
-      : autofill_profile_(autofill::test::GetFullProfile()),
-        credit_card1_(autofill::test::GetCreditCard()),
-        credit_card2_(autofill::test::GetCreditCard2()),
-        chrome_browser_state_(TestChromeBrowserState::Builder().Build()) {
-    // Add testing credit cards to autofill::TestPersonalDataManager. Make the
-    // less frequently used one incomplete.
-    credit_card1_.set_use_count(10U);
-    personal_data_manager_.AddTestingProfile(&autofill_profile_);
-    credit_card1_.set_billing_address_id(autofill_profile_.guid());
-    personal_data_manager_.AddTestingCreditCard(&credit_card1_);
-    credit_card2_.set_use_count(5U);
-    personal_data_manager_.AddTestingCreditCard(&credit_card2_);
-    payment_request_ = base::MakeUnique<payments::TestPaymentRequest>(
-        payment_request_test_util::CreateTestWebPaymentRequest(),
-        chrome_browser_state_.get(), &web_state_, &personal_data_manager_);
+  void SetUp() override {
+    PaymentRequestUnitTestBase::SetUp();
+
+    // Add testing credit cards to the database. Make the less frequently used
+    // one incomplete.
+    autofill::AutofillProfile profile = autofill::test::GetFullProfile();
+    autofill::CreditCard card = autofill::test::GetCreditCard();  // Visa.
+    card.set_use_count(10U);
+    card.set_billing_address_id(profile.guid());
+    AddAutofillProfile(std::move(profile));
+    AddCreditCard(std::move(card));
+    // Incomplete because it's missing a billing address.
+    autofill::CreditCard card2 = autofill::test::GetCreditCard2();  // Amex.
+    AddCreditCard(std::move(card2));
+
+    CreateTestPaymentRequest();
   }
 
-  base::test::ScopedTaskEnvironment scoped_task_evironment_;
-
-  autofill::AutofillProfile autofill_profile_;
-  autofill::CreditCard credit_card1_;
-  autofill::CreditCard credit_card2_;
-  web::TestWebState web_state_;
-  autofill::TestPersonalDataManager personal_data_manager_;
-  std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
-  std::unique_ptr<payments::TestPaymentRequest> payment_request_;
+  void TearDown() override { PaymentRequestUnitTestBase::TearDown(); }
 };
 
 // Tests that invoking start and stop on the coordinator presents and dismisses
@@ -72,7 +58,7 @@
   PaymentMethodSelectionCoordinator* coordinator =
       [[PaymentMethodSelectionCoordinator alloc]
           initWithBaseViewController:base_view_controller];
-  [coordinator setPaymentRequest:payment_request_.get()];
+  [coordinator setPaymentRequest:payment_request()];
 
   EXPECT_EQ(1u, navigation_controller.viewControllers.count);
 
@@ -105,17 +91,19 @@
   PaymentMethodSelectionCoordinator* coordinator =
       [[PaymentMethodSelectionCoordinator alloc]
           initWithBaseViewController:base_view_controller];
-  [coordinator setPaymentRequest:payment_request_.get()];
+  [coordinator setPaymentRequest:payment_request()];
 
   // Mock the coordinator delegate.
   id delegate = [OCMockObject
       mockForProtocol:@protocol(PaymentMethodSelectionCoordinatorDelegate)];
   [[delegate expect]
       paymentMethodSelectionCoordinator:coordinator
-                 didSelectPaymentMethod:payment_request_->payment_methods()[0]];
+                 didSelectPaymentMethod:payment_request()
+                                            ->payment_methods()[0]];
   [[delegate reject]
       paymentMethodSelectionCoordinator:coordinator
-                 didSelectPaymentMethod:payment_request_->payment_methods()[1]];
+                 didSelectPaymentMethod:payment_request()
+                                            ->payment_methods()[1]];
   [coordinator setDelegate:delegate];
 
   EXPECT_EQ(1u, navigation_controller.viewControllers.count);
@@ -151,7 +139,7 @@
   PaymentMethodSelectionCoordinator* coordinator =
       [[PaymentMethodSelectionCoordinator alloc]
           initWithBaseViewController:base_view_controller];
-  [coordinator setPaymentRequest:payment_request_.get()];
+  [coordinator setPaymentRequest:payment_request()];
 
   // Mock the coordinator delegate.
   id delegate = [OCMockObject
diff --git a/ios/chrome/browser/ui/payments/payment_request_coordinator_unittest.mm b/ios/chrome/browser/ui/payments/payment_request_coordinator_unittest.mm
index 266bb6b..2bd636ca 100644
--- a/ios/chrome/browser/ui/payments/payment_request_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_coordinator_unittest.mm
@@ -7,33 +7,21 @@
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "base/mac/foundation_util.h"
-#include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/ios/wait_util.h"
-#include "base/test/scoped_task_environment.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/credit_card.h"
-#include "components/autofill/core/browser/test_personal_data_manager.h"
 #include "components/payments/core/autofill_payment_instrument.h"
 #include "components/payments/core/payment_address.h"
 #include "components/payments/core/payment_instrument.h"
 #include "components/payments/core/payment_request_data_util.h"
 #include "components/payments/core/payments_test_util.h"
-#include "components/prefs/pref_service.h"
-#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
-#include "ios/chrome/browser/payments/payment_request.h"
 #include "ios/chrome/browser/payments/payment_request_test_util.h"
-#include "ios/chrome/browser/payments/test_payment_request.h"
-#include "ios/chrome/browser/signin/fake_signin_manager_builder.h"
-#include "ios/chrome/browser/signin/signin_manager_factory.h"
+#import "ios/chrome/browser/ui/payments/payment_request_unittest_base.h"
 #import "ios/chrome/browser/ui/payments/payment_request_view_controller.h"
 #import "ios/chrome/test/scoped_key_window.h"
 #import "ios/testing/ocmock_complex_type_helper.h"
-#include "ios/web/public/payments/payment_request.h"
-#import "ios/web/public/test/fakes/test_web_state.h"
-#import "ios/web/public/test/test_web_thread_bundle.h"
-#include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 #include "third_party/ocmock/OCMock/OCMock.h"
 #include "third_party/ocmock/gtest_support.h"
@@ -88,36 +76,22 @@
 
 @end
 
-class PaymentRequestCoordinatorTest : public PlatformTest {
+class PaymentRequestCoordinatorTest : public PaymentRequestUnitTestBase,
+                                      public PlatformTest {
  protected:
-  PaymentRequestCoordinatorTest()
-      : autofill_profile_(autofill::test::GetFullProfile()),
-        credit_card_(autofill::test::GetCreditCard()),
-        pref_service_(payments::test::PrefServiceForTesting()) {
-    // Add testing profile and credit card to autofill::TestPersonalDataManager.
-    personal_data_manager_.AddTestingProfile(&autofill_profile_);
-    personal_data_manager_.AddTestingCreditCard(&credit_card_);
+  void SetUp() override {
+    PaymentRequestUnitTestBase::SetUp();
 
-    TestChromeBrowserState::Builder test_cbs_builder;
-    test_cbs_builder.AddTestingFactory(ios::SigninManagerFactory::GetInstance(),
-                                       &ios::BuildFakeSigninManager);
-    chrome_browser_state_ = test_cbs_builder.Build();
+    autofill::AutofillProfile profile = autofill::test::GetFullProfile();
+    autofill::CreditCard card = autofill::test::GetCreditCard();  // Visa.
+    card.set_billing_address_id(profile.guid());
+    AddAutofillProfile(std::move(profile));
+    AddCreditCard(std::move(card));
 
-    payment_request_ = base::MakeUnique<payments::TestPaymentRequest>(
-        payment_request_test_util::CreateTestWebPaymentRequest(),
-        chrome_browser_state_.get(), &web_state_, &personal_data_manager_);
-    payment_request_->SetPrefService(pref_service_.get());
+    CreateTestPaymentRequest();
   }
 
-  base::test::ScopedTaskEnvironment scoped_task_evironment_;
-
-  autofill::AutofillProfile autofill_profile_;
-  autofill::CreditCard credit_card_;
-  web::TestWebState web_state_;
-  std::unique_ptr<PrefService> pref_service_;
-  autofill::TestPersonalDataManager personal_data_manager_;
-  std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
-  std::unique_ptr<payments::TestPaymentRequest> payment_request_;
+  void TearDown() override { PaymentRequestUnitTestBase::TearDown(); }
 };
 
 // Tests that invoking start and stop on the coordinator presents and
@@ -130,8 +104,8 @@
 
   PaymentRequestCoordinator* coordinator = [[PaymentRequestCoordinator alloc]
       initWithBaseViewController:base_view_controller];
-  [coordinator setPaymentRequest:payment_request_.get()];
-  [coordinator setBrowserState:chrome_browser_state_.get()];
+  [coordinator setPaymentRequest:payment_request()];
+  [coordinator setBrowserState:browser_state()];
 
   [coordinator start];
   // Spin the run loop to trigger the animation.
@@ -164,7 +138,7 @@
 
   PaymentRequestCoordinator* coordinator = [[PaymentRequestCoordinator alloc]
       initWithBaseViewController:base_view_controller];
-  [coordinator setPaymentRequest:payment_request_.get()];
+  [coordinator setPaymentRequest:payment_request()];
 
   id delegate = [OCMockObject
       mockForProtocol:@protocol(PaymentMethodSelectionCoordinatorDelegate)];
@@ -194,7 +168,8 @@
 
   std::unique_ptr<base::DictionaryValue> response_value =
       payments::data_util::GetBasicCardResponseFromAutofillCreditCard(
-          credit_card_, base::ASCIIToUTF16("123"), autofill_profile_, appLocale)
+          *credit_cards().back(), base::ASCIIToUTF16("123"), *profiles().back(),
+          appLocale)
           .ToDictionaryValue();
   std::string stringifiedDetails;
   base::JSONWriter::Write(*response_value, &stringifiedDetails);
@@ -214,7 +189,7 @@
 
   PaymentRequestCoordinator* coordinator = [[PaymentRequestCoordinator alloc]
       initWithBaseViewController:base_view_controller];
-  [coordinator setPaymentRequest:payment_request_.get()];
+  [coordinator setPaymentRequest:payment_request()];
 
   // Mock the coordinator delegate.
   id delegate = [OCMockObject
@@ -226,14 +201,14 @@
                 onSelector:selector
       callBlockExpectation:^(PaymentRequestCoordinator* callerCoordinator,
                              const autofill::AutofillProfile& shippingAddress) {
-        EXPECT_EQ(autofill_profile_, shippingAddress);
+        EXPECT_EQ(*profiles().back(), shippingAddress);
         EXPECT_EQ(coordinator, callerCoordinator);
       }];
   [coordinator setDelegate:delegate_mock];
 
   // Call the ShippingAddressSelectionCoordinator delegate method.
   [coordinator shippingAddressSelectionCoordinator:nil
-                          didSelectShippingAddress:&autofill_profile_];
+                          didSelectShippingAddress:profiles().back().get()];
 }
 
 // Tests that calling the ShippingOptionSelectionCoordinator delegate method
@@ -246,7 +221,7 @@
 
   PaymentRequestCoordinator* coordinator = [[PaymentRequestCoordinator alloc]
       initWithBaseViewController:base_view_controller];
-  [coordinator setPaymentRequest:payment_request_.get()];
+  [coordinator setPaymentRequest:payment_request()];
 
   web::PaymentShippingOption shipping_option;
   shipping_option.id = base::ASCIIToUTF16("123456");
@@ -285,7 +260,7 @@
 
   PaymentRequestCoordinator* coordinator = [[PaymentRequestCoordinator alloc]
       initWithBaseViewController:base_view_controller];
-  [coordinator setPaymentRequest:payment_request_.get()];
+  [coordinator setPaymentRequest:payment_request()];
 
   // Mock the coordinator delegate.
   id delegate = [OCMockObject
@@ -298,7 +273,7 @@
          EXPECT_EQ(coordinator, callerCoordinator);
        }];
   [coordinator setDelegate:delegate_mock];
-  [coordinator setBrowserState:chrome_browser_state_.get()];
+  [coordinator setBrowserState:browser_state()];
 
   [coordinator start];
   // Spin the run loop to trigger the animation.
diff --git a/ios/chrome/browser/ui/payments/payment_request_mediator_unittest.mm b/ios/chrome/browser/ui/payments/payment_request_mediator_unittest.mm
index 4a5bbdb..99f9ce1 100644
--- a/ios/chrome/browser/ui/payments/payment_request_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_mediator_unittest.mm
@@ -7,35 +7,25 @@
 #import <Foundation/Foundation.h>
 
 #include "base/mac/foundation_util.h"
-#include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_task_environment.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/credit_card.h"
-#include "components/autofill/core/browser/test_personal_data_manager.h"
 #include "components/payments/core/payment_instrument.h"
 #include "components/payments/core/payment_prefs.h"
-#include "components/payments/core/payments_test_util.h"
 #include "components/payments/core/strings_util.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/core/browser/signin_manager.h"
 #include "components/strings/grit/components_strings.h"
-#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
-#include "ios/chrome/browser/payments/payment_request_test_util.h"
 #include "ios/chrome/browser/payments/payment_request_util.h"
 #include "ios/chrome/browser/payments/test_payment_request.h"
-#include "ios/chrome/browser/signin/fake_signin_manager_builder.h"
-#include "ios/chrome/browser/signin/signin_manager_factory.h"
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_detail_item.h"
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item.h"
 #import "ios/chrome/browser/ui/payments/cells/autofill_profile_item.h"
 #import "ios/chrome/browser/ui/payments/cells/payment_method_item.h"
 #import "ios/chrome/browser/ui/payments/cells/payments_text_item.h"
 #import "ios/chrome/browser/ui/payments/cells/price_item.h"
-#include "ios/web/public/payments/payment_request.h"
-#import "ios/web/public/test/fakes/test_web_state.h"
-#include "testing/gtest/include/gtest/gtest.h"
+#import "ios/chrome/browser/ui/payments/payment_request_unittest_base.h"
 #include "testing/platform_test.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -51,114 +41,101 @@
 using ::payment_request_util::GetShippingAddressLabelFromAutofillProfile;
 }  // namespace
 
-class PaymentRequestMediatorTest : public PlatformTest {
+class PaymentRequestMediatorTest : public PaymentRequestUnitTestBase,
+                                   public PlatformTest {
  protected:
-  PaymentRequestMediatorTest()
-      : autofill_profile_(autofill::test::GetFullProfile()),
-        credit_card_(autofill::test::GetCreditCard()),
-        pref_service_(payments::test::PrefServiceForTesting()) {
-    // Add testing profile and credit card to autofill::TestPersonalDataManager.
-    personal_data_manager_.AddTestingProfile(&autofill_profile_);
-    credit_card_.set_billing_address_id(autofill_profile_.guid());
-    personal_data_manager_.AddTestingCreditCard(&credit_card_);
+  void SetUp() override {
+    PaymentRequestUnitTestBase::SetUp();
 
-    TestChromeBrowserState::Builder test_cbs_builder;
-    test_cbs_builder.AddTestingFactory(ios::SigninManagerFactory::GetInstance(),
-                                       &ios::BuildFakeSigninManager);
-    chrome_browser_state_ = test_cbs_builder.Build();
+    autofill::AutofillProfile profile = autofill::test::GetFullProfile();
+    autofill::CreditCard card = autofill::test::GetCreditCard();  // Visa.
+    card.set_billing_address_id(profile.guid());
+    AddAutofillProfile(std::move(profile));
+    AddCreditCard(std::move(card));
 
-    payment_request_ = base::MakeUnique<payments::TestPaymentRequest>(
-        payment_request_test_util::CreateTestWebPaymentRequest(),
-        chrome_browser_state_.get(), &web_state_, &personal_data_manager_);
-    payment_request_->SetPrefService(pref_service_.get());
+    CreateTestPaymentRequest();
 
     mediator_ = [[PaymentRequestMediator alloc]
-        initWithPaymentRequest:payment_request_.get()];
+        initWithPaymentRequest:payment_request()];
   }
 
-  PaymentRequestMediator* GetPaymentRequestMediator() { return mediator_; }
+  void TearDown() override { PaymentRequestUnitTestBase::TearDown(); }
 
-  base::test::ScopedTaskEnvironment scoped_task_evironment_;
+  PaymentRequestMediator* mediator() { return mediator_; }
 
-  autofill::AutofillProfile autofill_profile_;
-  autofill::CreditCard credit_card_;
-  web::TestWebState web_state_;
-  std::unique_ptr<PrefService> pref_service_;
-  autofill::TestPersonalDataManager personal_data_manager_;
-  std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
-  std::unique_ptr<payments::TestPaymentRequest> payment_request_;
+ private:
   PaymentRequestMediator* mediator_;
 };
 
 // Tests whether payment can be completed when expected.
 TEST_F(PaymentRequestMediatorTest, TestCanPay) {
-  EXPECT_TRUE(payment_request_->selected_payment_method());
-  EXPECT_TRUE(payment_request_->selected_shipping_profile());
-  EXPECT_TRUE(payment_request_->selected_shipping_option());
-  EXPECT_TRUE(payment_request_->selected_contact_profile());
-  EXPECT_TRUE([GetPaymentRequestMediator() canPay]);
+  EXPECT_TRUE(payment_request()->selected_payment_method());
+  EXPECT_TRUE(payment_request()->selected_shipping_profile());
+  EXPECT_TRUE(payment_request()->selected_shipping_option());
+  EXPECT_TRUE(payment_request()->selected_contact_profile());
+  EXPECT_TRUE([mediator() canPay]);
 
   // Payment cannot be completed if there is no selected payment method.
   payments::PaymentInstrument* selected_payment_method =
-      payment_request_->selected_payment_method();
-  payment_request_->set_selected_payment_method(nullptr);
-  EXPECT_FALSE([GetPaymentRequestMediator() canPay]);
+      payment_request()->selected_payment_method();
+  payment_request()->set_selected_payment_method(nullptr);
+  EXPECT_FALSE([mediator() canPay]);
 
   // Restore the selected payment method.
-  payment_request_->set_selected_payment_method(selected_payment_method);
-  EXPECT_TRUE([GetPaymentRequestMediator() canPay]);
+  payment_request()->set_selected_payment_method(selected_payment_method);
+  EXPECT_TRUE([mediator() canPay]);
 
   // Payment cannot be completed if there is no selected shipping profile,
   // unless no shipping information is requested.
   autofill::AutofillProfile* selected_shipping_profile =
-      payment_request_->selected_shipping_profile();
-  payment_request_->set_selected_shipping_profile(nullptr);
-  EXPECT_FALSE([GetPaymentRequestMediator() canPay]);
-  payment_request_->web_payment_request().options.request_shipping = false;
-  EXPECT_FALSE([GetPaymentRequestMediator() requestShipping]);
-  EXPECT_TRUE([GetPaymentRequestMediator() canPay]);
+      payment_request()->selected_shipping_profile();
+  payment_request()->set_selected_shipping_profile(nullptr);
+  EXPECT_FALSE([mediator() canPay]);
+  payment_request()->web_payment_request().options.request_shipping = false;
+  EXPECT_FALSE([mediator() requestShipping]);
+  EXPECT_TRUE([mediator() canPay]);
 
   // Restore the selected shipping profile and request for shipping information.
-  payment_request_->set_selected_shipping_profile(selected_shipping_profile);
-  payment_request_->web_payment_request().options.request_shipping = true;
-  EXPECT_TRUE([GetPaymentRequestMediator() requestShipping]);
-  EXPECT_TRUE([GetPaymentRequestMediator() canPay]);
+  payment_request()->set_selected_shipping_profile(selected_shipping_profile);
+  payment_request()->web_payment_request().options.request_shipping = true;
+  EXPECT_TRUE([mediator() requestShipping]);
+  EXPECT_TRUE([mediator() canPay]);
 
   // Payment cannot be completed if there is no selected shipping option,
   // unless no shipping information is requested.
   web::PaymentShippingOption* selected_shipping_option =
-      payment_request_->selected_shipping_option();
-  payment_request_->set_selected_shipping_option(nullptr);
-  EXPECT_FALSE([GetPaymentRequestMediator() canPay]);
-  payment_request_->web_payment_request().options.request_shipping = false;
-  EXPECT_TRUE([GetPaymentRequestMediator() canPay]);
+      payment_request()->selected_shipping_option();
+  payment_request()->set_selected_shipping_option(nullptr);
+  EXPECT_FALSE([mediator() canPay]);
+  payment_request()->web_payment_request().options.request_shipping = false;
+  EXPECT_TRUE([mediator() canPay]);
 
   // Restore the selected shipping option and request for shipping information.
-  payment_request_->set_selected_shipping_option(selected_shipping_option);
-  payment_request_->web_payment_request().options.request_shipping = true;
-  EXPECT_TRUE([GetPaymentRequestMediator() canPay]);
+  payment_request()->set_selected_shipping_option(selected_shipping_option);
+  payment_request()->web_payment_request().options.request_shipping = true;
+  EXPECT_TRUE([mediator() canPay]);
 
   // Payment cannot be completed if there is no selected contact profile, unless
   // no contact information is requested.
-  payment_request_->set_selected_contact_profile(nullptr);
-  EXPECT_FALSE([GetPaymentRequestMediator() canPay]);
-  payment_request_->web_payment_request().options.request_payer_name = false;
-  EXPECT_TRUE([GetPaymentRequestMediator() requestContactInfo]);
-  EXPECT_FALSE([GetPaymentRequestMediator() canPay]);
-  payment_request_->web_payment_request().options.request_payer_phone = false;
-  EXPECT_TRUE([GetPaymentRequestMediator() requestContactInfo]);
-  EXPECT_FALSE([GetPaymentRequestMediator() canPay]);
-  payment_request_->web_payment_request().options.request_payer_email = false;
-  EXPECT_FALSE([GetPaymentRequestMediator() requestContactInfo]);
-  EXPECT_TRUE([GetPaymentRequestMediator() canPay]);
+  payment_request()->set_selected_contact_profile(nullptr);
+  EXPECT_FALSE([mediator() canPay]);
+  payment_request()->web_payment_request().options.request_payer_name = false;
+  EXPECT_TRUE([mediator() requestContactInfo]);
+  EXPECT_FALSE([mediator() canPay]);
+  payment_request()->web_payment_request().options.request_payer_phone = false;
+  EXPECT_TRUE([mediator() requestContactInfo]);
+  EXPECT_FALSE([mediator() canPay]);
+  payment_request()->web_payment_request().options.request_payer_email = false;
+  EXPECT_FALSE([mediator() requestContactInfo]);
+  EXPECT_TRUE([mediator() canPay]);
 }
 
 // Tests that the Payment Summary item is created as expected.
 TEST_F(PaymentRequestMediatorTest, TestPaymentSummaryItem) {
-  EXPECT_TRUE([GetPaymentRequestMediator() hasPaymentItems]);
+  EXPECT_TRUE([mediator() hasPaymentItems]);
 
   // Payment Summary item should be of type PriceItem.
-  id item = [GetPaymentRequestMediator() paymentSummaryItem];
+  id item = [mediator() paymentSummaryItem];
   ASSERT_TRUE([item isMemberOfClass:[PriceItem class]]);
   PriceItem* payment_summary_item = base::mac::ObjCCastStrict<PriceItem>(item);
   EXPECT_TRUE([payment_summary_item.item isEqualToString:@"Total"]);
@@ -168,27 +145,27 @@
             payment_summary_item.accessoryType);
 
   // A label should indicate if the total value was changed.
-  GetPaymentRequestMediator().totalValueChanged = YES;
-  item = [GetPaymentRequestMediator() paymentSummaryItem];
+  mediator().totalValueChanged = YES;
+  item = [mediator() paymentSummaryItem];
   payment_summary_item = base::mac::ObjCCastStrict<PriceItem>(item);
   EXPECT_TRUE([payment_summary_item.notification
       isEqualToString:l10n_util::GetNSString(IDS_PAYMENTS_UPDATED_LABEL)]);
 
   // The next time the data source is queried for the Payment Summary item, the
   // label should disappear.
-  item = [GetPaymentRequestMediator() paymentSummaryItem];
+  item = [mediator() paymentSummaryItem];
   payment_summary_item = base::mac::ObjCCastStrict<PriceItem>(item);
   EXPECT_EQ(nil, payment_summary_item.notification);
 
   // Remove the display items.
   web::PaymentRequest web_payment_request =
-      payment_request_->web_payment_request();
+      payment_request()->web_payment_request();
   web_payment_request.details.display_items.clear();
-  payment_request_->UpdatePaymentDetails(web_payment_request.details);
-  EXPECT_FALSE([GetPaymentRequestMediator() hasPaymentItems]);
+  payment_request()->UpdatePaymentDetails(web_payment_request.details);
+  EXPECT_FALSE([mediator() hasPaymentItems]);
 
   // No accessory view indicates there are no display items.
-  item = [GetPaymentRequestMediator() paymentSummaryItem];
+  item = [mediator() paymentSummaryItem];
   payment_summary_item = base::mac::ObjCCastStrict<PriceItem>(item);
   EXPECT_EQ(MDCCollectionViewCellAccessoryNone,
             payment_summary_item.accessoryType);
@@ -197,7 +174,7 @@
 // Tests that the Shipping section header item is created as expected.
 TEST_F(PaymentRequestMediatorTest, TestShippingHeaderItem) {
   // Shipping section header item should be of type PaymentsTextItem.
-  id item = [GetPaymentRequestMediator() shippingSectionHeaderItem];
+  id item = [mediator() shippingSectionHeaderItem];
   ASSERT_TRUE([item isMemberOfClass:[PaymentsTextItem class]]);
   PaymentsTextItem* shipping_section_header_item =
       base::mac::ObjCCastStrict<PaymentsTextItem>(item);
@@ -210,28 +187,28 @@
 // Tests that the Shipping Address item is created as expected.
 TEST_F(PaymentRequestMediatorTest, TestShippingAddressItem) {
   // Shipping Address item should be of type AutofillProfileItem.
-  id item = [GetPaymentRequestMediator() shippingAddressItem];
+  id item = [mediator() shippingAddressItem];
   ASSERT_TRUE([item isMemberOfClass:[AutofillProfileItem class]]);
   AutofillProfileItem* shipping_address_item =
       base::mac::ObjCCastStrict<AutofillProfileItem>(item);
   EXPECT_TRUE([shipping_address_item.name
       isEqualToString:GetNameLabelFromAutofillProfile(
-                          *payment_request_->selected_shipping_profile())]);
+                          *payment_request()->selected_shipping_profile())]);
   EXPECT_TRUE([shipping_address_item.address
       isEqualToString:GetShippingAddressLabelFromAutofillProfile(
-                          *payment_request_->selected_shipping_profile())]);
+                          *payment_request()->selected_shipping_profile())]);
   EXPECT_TRUE([shipping_address_item.phoneNumber
       isEqualToString:GetPhoneNumberLabelFromAutofillProfile(
-                          *payment_request_->selected_shipping_profile())]);
+                          *payment_request()->selected_shipping_profile())]);
   EXPECT_EQ(MDCCollectionViewCellAccessoryDisclosureIndicator,
             shipping_address_item.accessoryType);
 
   // Reset the selected shipping profile.
-  payment_request_->set_selected_shipping_profile(nullptr);
+  payment_request()->set_selected_shipping_profile(nullptr);
 
   // When there is no selected shipping address, the Shipping Address item
   // should be of type CollectionViewDetailItem.
-  item = [GetPaymentRequestMediator() shippingAddressItem];
+  item = [mediator() shippingAddressItem];
   ASSERT_TRUE([item isMemberOfClass:[CollectionViewDetailItem class]]);
   CollectionViewDetailItem* add_shipping_address_item =
       base::mac::ObjCCastStrict<CollectionViewDetailItem>(item);
@@ -243,10 +220,10 @@
             add_shipping_address_item.accessoryType);
 
   // Remove the shipping profiles.
-  payment_request_->ClearShippingProfiles();
+  payment_request()->ClearShippingProfiles();
 
   // No accessory view indicates there are no shipping profiles to choose from.
-  item = [GetPaymentRequestMediator() shippingAddressItem];
+  item = [mediator() shippingAddressItem];
   add_shipping_address_item =
       base::mac::ObjCCastStrict<CollectionViewDetailItem>(item);
   EXPECT_TRUE([add_shipping_address_item.detailText
@@ -259,7 +236,7 @@
 // Tests that the Shipping Option item is created as expected.
 TEST_F(PaymentRequestMediatorTest, TestShippingOptionItem) {
   // Shipping Option item should be of type PaymentsTextItem.
-  id item = [GetPaymentRequestMediator() shippingOptionItem];
+  id item = [mediator() shippingOptionItem];
   ASSERT_TRUE([item isMemberOfClass:[PaymentsTextItem class]]);
   PaymentsTextItem* shipping_option_item =
       base::mac::ObjCCastStrict<PaymentsTextItem>(item);
@@ -269,11 +246,11 @@
             shipping_option_item.accessoryType);
 
   // Reset the selected shipping option.
-  payment_request_->set_selected_shipping_option(nullptr);
+  payment_request()->set_selected_shipping_option(nullptr);
 
   // When there is no selected shipping option, the Shipping Option item should
   // be of type CollectionViewDetailItem.
-  item = [GetPaymentRequestMediator() shippingOptionItem];
+  item = [mediator() shippingOptionItem];
   ASSERT_TRUE([item isMemberOfClass:[CollectionViewDetailItem class]]);
   CollectionViewDetailItem* add_shipping_option_item =
       base::mac::ObjCCastStrict<CollectionViewDetailItem>(item);
@@ -288,7 +265,7 @@
 // Tests that the Payment Method section header item is created as expected.
 TEST_F(PaymentRequestMediatorTest, TestPaymentMethodHeaderItem) {
   // Payment Method section header item should be of type PaymentsTextItem.
-  id item = [GetPaymentRequestMediator() paymentMethodSectionHeaderItem];
+  id item = [mediator() paymentMethodSectionHeaderItem];
   ASSERT_TRUE([item isMemberOfClass:[PaymentsTextItem class]]);
   PaymentsTextItem* payment_method_section_header_item =
       base::mac::ObjCCastStrict<PaymentsTextItem>(item);
@@ -301,7 +278,7 @@
 // Tests that the Payment Method item is created as expected.
 TEST_F(PaymentRequestMediatorTest, TestPaymentMethodItem) {
   // Payment Method item should be of type PaymentsTextItem.
-  id item = [GetPaymentRequestMediator() paymentMethodItem];
+  id item = [mediator() paymentMethodItem];
   ASSERT_TRUE([item isMemberOfClass:[PaymentMethodItem class]]);
   PaymentMethodItem* payment_method_item =
       base::mac::ObjCCastStrict<PaymentMethodItem>(item);
@@ -312,11 +289,11 @@
             payment_method_item.accessoryType);
 
   // Reset the selected payment method.
-  payment_request_->set_selected_payment_method(nullptr);
+  payment_request()->set_selected_payment_method(nullptr);
 
   // When there is no selected payment method, the Payment Method item should be
   // of type CollectionViewDetailItem.
-  item = [GetPaymentRequestMediator() paymentMethodItem];
+  item = [mediator() paymentMethodItem];
   ASSERT_TRUE([item isMemberOfClass:[CollectionViewDetailItem class]]);
   CollectionViewDetailItem* add_payment_method_item =
       base::mac::ObjCCastStrict<CollectionViewDetailItem>(item);
@@ -328,10 +305,10 @@
             add_payment_method_item.accessoryType);
 
   // Remove the payment methods.
-  payment_request_->ClearPaymentMethods();
+  payment_request()->ClearPaymentMethods();
 
   // No accessory view indicates there are no payment methods to choose from.
-  item = [GetPaymentRequestMediator() paymentMethodItem];
+  item = [mediator() paymentMethodItem];
   add_payment_method_item =
       base::mac::ObjCCastStrict<CollectionViewDetailItem>(item);
   EXPECT_TRUE([add_payment_method_item.detailText
@@ -344,7 +321,7 @@
 // Tests that the Contact Info section header item is created as expected.
 TEST_F(PaymentRequestMediatorTest, TestContactInfoHeaderItem) {
   // Contact Info section header item should be of type PaymentsTextItem.
-  id item = [GetPaymentRequestMediator() contactInfoSectionHeaderItem];
+  id item = [mediator() contactInfoSectionHeaderItem];
   ASSERT_TRUE([item isMemberOfClass:[PaymentsTextItem class]]);
   PaymentsTextItem* contact_info_section_header_item =
       base::mac::ObjCCastStrict<PaymentsTextItem>(item);
@@ -357,43 +334,43 @@
 // Tests that the Contact Info item is created as expected.
 TEST_F(PaymentRequestMediatorTest, TestContactInfoItem) {
   // Contact Info item should be of type AutofillProfileItem.
-  id item = [GetPaymentRequestMediator() contactInfoItem];
+  id item = [mediator() contactInfoItem];
   ASSERT_TRUE([item isMemberOfClass:[AutofillProfileItem class]]);
   AutofillProfileItem* contact_info_item =
       base::mac::ObjCCastStrict<AutofillProfileItem>(item);
   EXPECT_TRUE([contact_info_item.name
       isEqualToString:GetNameLabelFromAutofillProfile(
-                          *payment_request_->selected_contact_profile())]);
+                          *payment_request()->selected_contact_profile())]);
   EXPECT_TRUE([contact_info_item.phoneNumber
       isEqualToString:GetPhoneNumberLabelFromAutofillProfile(
-                          *payment_request_->selected_contact_profile())]);
+                          *payment_request()->selected_contact_profile())]);
   EXPECT_TRUE([contact_info_item.email
       isEqualToString:GetEmailLabelFromAutofillProfile(
-                          *payment_request_->selected_contact_profile())]);
+                          *payment_request()->selected_contact_profile())]);
   EXPECT_EQ(MDCCollectionViewCellAccessoryDisclosureIndicator,
             contact_info_item.accessoryType);
 
   // Contact Info item should only show requested fields.
-  payment_request_->web_payment_request().options.request_payer_name = false;
-  item = [GetPaymentRequestMediator() contactInfoItem];
+  payment_request()->web_payment_request().options.request_payer_name = false;
+  item = [mediator() contactInfoItem];
   ASSERT_TRUE([item isMemberOfClass:[AutofillProfileItem class]]);
   contact_info_item = base::mac::ObjCCastStrict<AutofillProfileItem>(item);
   EXPECT_EQ(nil, contact_info_item.name);
   EXPECT_NE(nil, contact_info_item.phoneNumber);
   EXPECT_NE(nil, contact_info_item.email);
 
-  payment_request_->web_payment_request().options.request_payer_phone = false;
-  item = [GetPaymentRequestMediator() contactInfoItem];
+  payment_request()->web_payment_request().options.request_payer_phone = false;
+  item = [mediator() contactInfoItem];
   ASSERT_TRUE([item isMemberOfClass:[AutofillProfileItem class]]);
   contact_info_item = base::mac::ObjCCastStrict<AutofillProfileItem>(item);
   EXPECT_EQ(nil, contact_info_item.name);
   EXPECT_EQ(nil, contact_info_item.phoneNumber);
   EXPECT_NE(nil, contact_info_item.email);
 
-  payment_request_->web_payment_request().options.request_payer_name = true;
-  payment_request_->web_payment_request().options.request_payer_phone = false;
-  payment_request_->web_payment_request().options.request_payer_email = false;
-  item = [GetPaymentRequestMediator() contactInfoItem];
+  payment_request()->web_payment_request().options.request_payer_name = true;
+  payment_request()->web_payment_request().options.request_payer_phone = false;
+  payment_request()->web_payment_request().options.request_payer_email = false;
+  item = [mediator() contactInfoItem];
   ASSERT_TRUE([item isMemberOfClass:[AutofillProfileItem class]]);
   contact_info_item = base::mac::ObjCCastStrict<AutofillProfileItem>(item);
   EXPECT_NE(nil, contact_info_item.name);
@@ -401,11 +378,11 @@
   EXPECT_EQ(nil, contact_info_item.email);
 
   // Reset the selected contact profile.
-  payment_request_->set_selected_contact_profile(nullptr);
+  payment_request()->set_selected_contact_profile(nullptr);
 
   // When there is no selected contact profile, the Payment Method item should
   // be of type CollectionViewDetailItem.
-  item = [GetPaymentRequestMediator() contactInfoItem];
+  item = [mediator() contactInfoItem];
   ASSERT_TRUE([item isMemberOfClass:[CollectionViewDetailItem class]]);
   CollectionViewDetailItem* add_contact_info_item =
       base::mac::ObjCCastStrict<CollectionViewDetailItem>(item);
@@ -417,10 +394,10 @@
             add_contact_info_item.accessoryType);
 
   // Remove the contact profiles.
-  payment_request_->ClearContactProfiles();
+  payment_request()->ClearContactProfiles();
 
   // No accessory view indicates there are no contact profiles to choose from.
-  item = [GetPaymentRequestMediator() contactInfoItem];
+  item = [mediator() contactInfoItem];
   add_contact_info_item =
       base::mac::ObjCCastStrict<CollectionViewDetailItem>(item);
   EXPECT_TRUE([add_contact_info_item.detailText
@@ -433,19 +410,17 @@
 // Tests that the Footer item is created as expected.
 TEST_F(PaymentRequestMediatorTest, TestFooterItem) {
   // Make sure the first transaction has not completed yet.
-  pref_service_->SetBoolean(payments::kPaymentsFirstTransactionCompleted,
-                            false);
+  pref_service()->SetBoolean(payments::kPaymentsFirstTransactionCompleted,
+                             false);
 
   // Make sure the user is signed out.
-  SigninManager* signin_manager = ios::SigninManagerFactory::GetForBrowserState(
-      chrome_browser_state_.get());
-  if (signin_manager->IsAuthenticated()) {
-    signin_manager->SignOut(signin_metrics::SIGNOUT_TEST,
-                            signin_metrics::SignoutDelete::IGNORE_METRIC);
+  if (GetSigninManager()->IsAuthenticated()) {
+    GetSigninManager()->SignOut(signin_metrics::SIGNOUT_TEST,
+                                signin_metrics::SignoutDelete::IGNORE_METRIC);
   }
 
   // Footer item should be of type CollectionViewFooterItem.
-  id item = [GetPaymentRequestMediator() footerItem];
+  id item = [mediator() footerItem];
   ASSERT_TRUE([item isMemberOfClass:[CollectionViewFooterItem class]]);
   CollectionViewFooterItem* footer_item =
       base::mac::ObjCCastStrict<CollectionViewFooterItem>(item);
@@ -454,9 +429,10 @@
                           IDS_PAYMENTS_CARD_AND_ADDRESS_SETTINGS_SIGNED_OUT)]);
 
   // Fake a signed in user.
-  signin_manager->SetAuthenticatedAccountInfo("12345", "username@example.com");
+  GetSigninManager()->SetAuthenticatedAccountInfo("12345",
+                                                  "username@example.com");
 
-  item = [GetPaymentRequestMediator() footerItem];
+  item = [mediator() footerItem];
   footer_item = base::mac::ObjCCastStrict<CollectionViewFooterItem>(item);
   EXPECT_TRUE([footer_item.text
       isEqualToString:l10n_util::GetNSStringF(
@@ -464,17 +440,18 @@
                           base::ASCIIToUTF16("username@example.com"))]);
 
   // Record that the first transaction completed.
-  pref_service_->SetBoolean(payments::kPaymentsFirstTransactionCompleted, true);
+  pref_service()->SetBoolean(payments::kPaymentsFirstTransactionCompleted,
+                             true);
 
-  item = [GetPaymentRequestMediator() footerItem];
+  item = [mediator() footerItem];
   footer_item = base::mac::ObjCCastStrict<CollectionViewFooterItem>(item);
   EXPECT_TRUE([footer_item.text
       isEqualToString:l10n_util::GetNSString(
                           IDS_PAYMENTS_CARD_AND_ADDRESS_SETTINGS)]);
 
   // Sign the user out.
-  signin_manager->SignOut(signin_metrics::SIGNOUT_TEST,
-                          signin_metrics::SignoutDelete::IGNORE_METRIC);
+  GetSigninManager()->SignOut(signin_metrics::SIGNOUT_TEST,
+                              signin_metrics::SignoutDelete::IGNORE_METRIC);
 
   // The signed in state has no effect on the footer text if the first
   // transaction has completed.
diff --git a/ios/chrome/browser/ui/payments/payment_request_unittest_base.h b/ios/chrome/browser/ui/payments/payment_request_unittest_base.h
new file mode 100644
index 0000000..3e0e341
--- /dev/null
+++ b/ios/chrome/browser/ui/payments/payment_request_unittest_base.h
@@ -0,0 +1,78 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_PAYMENTS_PAYMENT_REQUEST_UNITTEST_BASE_H_
+#define IOS_CHROME_BROWSER_UI_PAYMENTS_PAYMENT_REQUEST_UNITTEST_BASE_H_
+
+#import <Foundation/Foundation.h>
+
+#include <memory>
+
+#include "base/test/scoped_task_environment.h"
+#include "components/autofill/core/browser/test_personal_data_manager.h"
+#include "components/prefs/pref_service.h"
+#import "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
+#import "ios/chrome/browser/payments/test_payment_request.h"
+#import "ios/web/public/test/fakes/test_web_state.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace autofill {
+class AutofillProfile;
+class CreditCard;
+}  // namespace autofill
+
+class SigninManager;
+
+// Base class for various payment request related unit tests. This purposedly
+// does not inherit from PlatformTest (testing::Test) so that it can be used
+// by ViewController unit tests.
+class PaymentRequestUnitTestBase {
+ protected:
+  PaymentRequestUnitTestBase();
+  ~PaymentRequestUnitTestBase();
+
+  void SetUp();
+  void TearDown();
+
+  // Should be called after data is added to the database via AddAutofillProfile
+  // and/or AddCreditCard.
+  void CreateTestPaymentRequest();
+
+  void AddAutofillProfile(autofill::AutofillProfile profile);
+  void AddCreditCard(autofill::CreditCard card);
+
+  SigninManager* GetSigninManager();
+
+  payments::TestPaymentRequest* payment_request() {
+    return payment_request_.get();
+  }
+  PrefService* pref_service() { return pref_service_.get(); }
+  TestChromeBrowserState* browser_state() {
+    return chrome_browser_state_.get();
+  }
+  const std::vector<std::unique_ptr<autofill::AutofillProfile>>& profiles()
+      const {
+    return profiles_;
+  }
+  const std::vector<std::unique_ptr<autofill::CreditCard>>& credit_cards()
+      const {
+    return cards_;
+  }
+
+ private:
+  std::vector<std::unique_ptr<autofill::AutofillProfile>> profiles_;
+  std::vector<std::unique_ptr<autofill::CreditCard>> cards_;
+
+  base::test::ScopedTaskEnvironment scoped_task_evironment_;
+  web::TestWebState web_state_;
+  std::unique_ptr<PrefService> pref_service_;
+  autofill::TestPersonalDataManager personal_data_manager_;
+  std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
+  std::unique_ptr<payments::TestPaymentRequest> payment_request_;
+};
+
+#endif  // IOS_CHROME_BROWSER_UI_PAYMENTS_PAYMENT_REQUEST_UNITTEST_BASE_H_
diff --git a/ios/chrome/browser/ui/payments/payment_request_unittest_base.mm b/ios/chrome/browser/ui/payments/payment_request_unittest_base.mm
new file mode 100644
index 0000000..1d5cbbb
--- /dev/null
+++ b/ios/chrome/browser/ui/payments/payment_request_unittest_base.mm
@@ -0,0 +1,58 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/ui/payments/payment_request_unittest_base.h"
+
+#include "base/memory/ptr_util.h"
+#include "components/payments/core/payment_prefs.h"
+#include "components/payments/core/payments_test_util.h"
+#include "components/signin/core/browser/signin_manager.h"
+#include "ios/chrome/browser/payments/payment_request_test_util.h"
+#include "ios/chrome/browser/signin/fake_signin_manager_builder.h"
+#include "ios/chrome/browser/signin/signin_manager_factory.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+PaymentRequestUnitTestBase::PaymentRequestUnitTestBase()
+    : pref_service_(payments::test::PrefServiceForTesting()) {}
+
+PaymentRequestUnitTestBase::~PaymentRequestUnitTestBase() {}
+
+void PaymentRequestUnitTestBase::SetUp() {
+  TestChromeBrowserState::Builder test_cbs_builder;
+  test_cbs_builder.AddTestingFactory(ios::SigninManagerFactory::GetInstance(),
+                                     &ios::BuildFakeSigninManager);
+  chrome_browser_state_ = test_cbs_builder.Build();
+  personal_data_manager_.SetTestingPrefService(pref_service_.get());
+}
+
+void PaymentRequestUnitTestBase::TearDown() {
+  personal_data_manager_.SetTestingPrefService(nullptr);
+}
+
+void PaymentRequestUnitTestBase::CreateTestPaymentRequest() {
+  payment_request_ = base::MakeUnique<payments::TestPaymentRequest>(
+      payment_request_test_util::CreateTestWebPaymentRequest(),
+      chrome_browser_state_.get(), &web_state_, &personal_data_manager_);
+  payment_request_->SetPrefService(pref_service_.get());
+}
+
+void PaymentRequestUnitTestBase::AddAutofillProfile(
+    autofill::AutofillProfile profile) {
+  profiles_.push_back(
+      base::MakeUnique<autofill::AutofillProfile>(std::move(profile)));
+  personal_data_manager_.AddTestingProfile(profiles_.back().get());
+}
+
+void PaymentRequestUnitTestBase::AddCreditCard(autofill::CreditCard card) {
+  cards_.push_back(base::MakeUnique<autofill::CreditCard>(std::move(card)));
+  personal_data_manager_.AddTestingCreditCard(cards_.back().get());
+}
+
+SigninManager* PaymentRequestUnitTestBase::GetSigninManager() {
+  return ios::SigninManagerFactory::GetForBrowserState(
+      chrome_browser_state_.get());
+}
diff --git a/ios/chrome/browser/ui/payments/payment_request_view_controller_unittest.mm b/ios/chrome/browser/ui/payments/payment_request_view_controller_unittest.mm
index b944235..be2fc92 100644
--- a/ios/chrome/browser/ui/payments/payment_request_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_view_controller_unittest.mm
@@ -7,17 +7,12 @@
 #import <Foundation/Foundation.h>
 
 #include "base/mac/foundation_util.h"
-#include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_task_environment.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/credit_card.h"
-#include "components/autofill/core/browser/test_personal_data_manager.h"
 #include "components/strings/grit/components_strings.h"
-#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/chrome/browser/payments/payment_request_test_util.h"
-#include "ios/chrome/browser/payments/test_payment_request.h"
 #import "ios/chrome/browser/ui/autofill/cells/status_item.h"
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_detail_item.h"
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item.h"
@@ -27,11 +22,9 @@
 #import "ios/chrome/browser/ui/payments/cells/payment_method_item.h"
 #import "ios/chrome/browser/ui/payments/cells/payments_text_item.h"
 #import "ios/chrome/browser/ui/payments/cells/price_item.h"
+#import "ios/chrome/browser/ui/payments/payment_request_unittest_base.h"
 #import "ios/chrome/browser/ui/payments/payment_request_view_controller_data_source.h"
 #include "ios/chrome/grit/ios_strings.h"
-#include "ios/web/public/payments/payment_request.h"
-#import "ios/web/public/test/fakes/test_web_state.h"
-#include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -139,23 +132,18 @@
 
 @end
 
-class PaymentRequestViewControllerTest : public CollectionViewControllerTest {
+class PaymentRequestViewControllerTest : public CollectionViewControllerTest,
+                                         public PaymentRequestUnitTestBase {
  protected:
-  PaymentRequestViewControllerTest()
-      : autofill_profile_(autofill::test::GetFullProfile()),
-        credit_card_(autofill::test::GetCreditCard()),
-        chrome_browser_state_(TestChromeBrowserState::Builder().Build()) {
-    // Add testing profile and credit card to autofill::TestPersonalDataManager.
-    personal_data_manager_.AddTestingProfile(&autofill_profile_);
-    personal_data_manager_.AddTestingCreditCard(&credit_card_);
-
-    payment_request_ = base::MakeUnique<payments::TestPaymentRequest>(
-        payment_request_test_util::CreateTestWebPaymentRequest(),
-        chrome_browser_state_.get(), &web_state_, &personal_data_manager_);
+  void SetUp() override {
+    CollectionViewControllerTest::SetUp();
+    PaymentRequestUnitTestBase::SetUp();
 
     mediator_ = [[TestPaymentRequestMediator alloc] init];
   }
 
+  void TearDown() override { PaymentRequestUnitTestBase::TearDown(); }
+
   CollectionViewController* InstantiateController() override {
     PaymentRequestViewController* viewController =
         [[PaymentRequestViewController alloc] init];
@@ -168,14 +156,6 @@
         controller());
   }
 
-  base::test::ScopedTaskEnvironment scoped_task_evironment_;
-
-  autofill::AutofillProfile autofill_profile_;
-  autofill::CreditCard credit_card_;
-  web::TestWebState web_state_;
-  autofill::TestPersonalDataManager personal_data_manager_;
-  std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
-  std::unique_ptr<payments::TestPaymentRequest> payment_request_;
   TestPaymentRequestMediator* mediator_;
 };
 
diff --git a/ios/chrome/browser/ui/payments/shipping_address_selection_coordinator_unittest.mm b/ios/chrome/browser/ui/payments/shipping_address_selection_coordinator_unittest.mm
index 7c94a2e..1500c42d 100644
--- a/ios/chrome/browser/ui/payments/shipping_address_selection_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/payments/shipping_address_selection_coordinator_unittest.mm
@@ -5,22 +5,15 @@
 #import "ios/chrome/browser/ui/payments/shipping_address_selection_coordinator.h"
 
 #include "base/mac/foundation_util.h"
-#include "base/memory/ptr_util.h"
 #include "base/test/ios/wait_util.h"
-#include "base/test/scoped_task_environment.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/browser/field_types.h"
-#include "components/autofill/core/browser/test_personal_data_manager.h"
 #include "components/autofill/core/browser/test_region_data_loader.h"
-#include "components/prefs/pref_service.h"
-#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/chrome/browser/payments/payment_request_test_util.h"
-#include "ios/chrome/browser/payments/test_payment_request.h"
 #import "ios/chrome/browser/ui/payments/payment_request_selector_view_controller.h"
-#import "ios/web/public/test/fakes/test_web_state.h"
-#include "testing/gtest/include/gtest/gtest.h"
+#import "ios/chrome/browser/ui/payments/payment_request_unittest_base.h"
 #include "testing/platform_test.h"
 #include "third_party/ocmock/OCMock/OCMock.h"
 #include "third_party/ocmock/gtest_support.h"
@@ -30,46 +23,34 @@
 #endif
 
 class PaymentRequestShippingAddressSelectionCoordinatorTest
-    : public PlatformTest {
+    : public PaymentRequestUnitTestBase,
+      public PlatformTest {
  protected:
-  PaymentRequestShippingAddressSelectionCoordinatorTest()
-      : autofill_profile1_(autofill::test::GetFullProfile()),
-        autofill_profile2_(autofill::test::GetFullProfile2()),
-        pref_service_(autofill::test::PrefServiceForTesting()),
-        chrome_browser_state_(TestChromeBrowserState::Builder().Build()) {
-    personal_data_manager_.SetTestingPrefService(pref_service_.get());
-    // Add testing profiles to autofill::TestPersonalDataManager. Make the less
-    // frequently used one incomplete.
-    autofill_profile1_.set_use_count(10U);
-    personal_data_manager_.AddTestingProfile(&autofill_profile1_);
-    autofill_profile2_.set_use_count(5U);
-    autofill_profile2_.SetInfo(
-        autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER),
-        base::string16(), "en-US");
-    personal_data_manager_.AddTestingProfile(&autofill_profile2_);
+  void SetUp() override {
+    PaymentRequestUnitTestBase::SetUp();
 
-    payment_request_ = base::MakeUnique<payments::TestPaymentRequest>(
-        payment_request_test_util::CreateTestWebPaymentRequest(),
-        chrome_browser_state_.get(), &web_state_, &personal_data_manager_);
+    // Add testing profiles to the database. Make the less frequently used one
+    // incomplete.
+    autofill::AutofillProfile profile = autofill::test::GetFullProfile();
+    profile.set_use_count(10U);
+    AddAutofillProfile(std::move(profile));
+
+    autofill::AutofillProfile profile2 = autofill::test::GetFullProfile2();
+    profile2.set_use_count(5U);
+    profile2.SetInfo(autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER),
+                     base::string16(), "en-US");
+    AddAutofillProfile(std::move(profile2));
+
+    CreateTestPaymentRequest();
 
     test_region_data_loader_.set_synchronous_callback(true);
-    payment_request_->SetRegionDataLoader(&test_region_data_loader_);
+    payment_request()->SetRegionDataLoader(&test_region_data_loader_);
   }
 
-  void TearDown() override {
-    personal_data_manager_.SetTestingPrefService(nullptr);
-  }
+  void TearDown() override { PaymentRequestUnitTestBase::TearDown(); }
 
-  base::test::ScopedTaskEnvironment scoped_task_evironment_;
-
-  autofill::AutofillProfile autofill_profile1_;
-  autofill::AutofillProfile autofill_profile2_;
-  web::TestWebState web_state_;
-  std::unique_ptr<PrefService> pref_service_;
-  autofill::TestPersonalDataManager personal_data_manager_;
+ private:
   autofill::TestRegionDataLoader test_region_data_loader_;
-  std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
-  std::unique_ptr<payments::TestPaymentRequest> payment_request_;
 };
 
 // Tests that invoking start and stop on the coordinator presents and dismisses
@@ -83,7 +64,7 @@
   ShippingAddressSelectionCoordinator* coordinator =
       [[ShippingAddressSelectionCoordinator alloc]
           initWithBaseViewController:base_view_controller];
-  [coordinator setPaymentRequest:payment_request_.get()];
+  [coordinator setPaymentRequest:payment_request()];
 
   EXPECT_EQ(1u, navigation_controller.viewControllers.count);
 
@@ -116,18 +97,18 @@
   ShippingAddressSelectionCoordinator* coordinator =
       [[ShippingAddressSelectionCoordinator alloc]
           initWithBaseViewController:base_view_controller];
-  [coordinator setPaymentRequest:payment_request_.get()];
+  [coordinator setPaymentRequest:payment_request()];
 
   // Mock the coordinator delegate.
   id delegate = [OCMockObject
       mockForProtocol:@protocol(ShippingAddressSelectionCoordinatorDelegate)];
   [[delegate expect]
       shippingAddressSelectionCoordinator:coordinator
-                 didSelectShippingAddress:payment_request_
+                 didSelectShippingAddress:payment_request()
                                               ->shipping_profiles()[0]];
   [[delegate reject]
       shippingAddressSelectionCoordinator:coordinator
-                 didSelectShippingAddress:payment_request_
+                 didSelectShippingAddress:payment_request()
                                               ->shipping_profiles()[1]];
   [coordinator setDelegate:delegate];
 
@@ -164,7 +145,7 @@
   ShippingAddressSelectionCoordinator* coordinator =
       [[ShippingAddressSelectionCoordinator alloc]
           initWithBaseViewController:base_view_controller];
-  [coordinator setPaymentRequest:payment_request_.get()];
+  [coordinator setPaymentRequest:payment_request()];
 
   // Mock the coordinator delegate.
   id delegate = [OCMockObject
diff --git a/ios/chrome/browser/ui/payments/shipping_option_selection_coordinator_unittest.mm b/ios/chrome/browser/ui/payments/shipping_option_selection_coordinator_unittest.mm
index e65ce1b5..779b65a3 100644
--- a/ios/chrome/browser/ui/payments/shipping_option_selection_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/payments/shipping_option_selection_coordinator_unittest.mm
@@ -5,21 +5,13 @@
 #import "ios/chrome/browser/ui/payments/shipping_option_selection_coordinator.h"
 
 #include "base/mac/foundation_util.h"
-#include "base/memory/ptr_util.h"
 #include "base/test/ios/wait_util.h"
-#include "base/test/scoped_task_environment.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/credit_card.h"
-#include "components/autofill/core/browser/test_personal_data_manager.h"
-#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
-#include "ios/chrome/browser/payments/payment_request.h"
 #include "ios/chrome/browser/payments/payment_request_test_util.h"
 #include "ios/chrome/browser/payments/test_payment_request.h"
 #import "ios/chrome/browser/ui/payments/payment_request_selector_view_controller.h"
-#include "ios/web/public/payments/payment_request.h"
-#import "ios/web/public/test/fakes/test_web_state.h"
-#include "ios/web/public/test/test_web_thread_bundle.h"
-#include "testing/gtest/include/gtest/gtest.h"
+#import "ios/chrome/browser/ui/payments/payment_request_unittest_base.h"
 #include "testing/platform_test.h"
 #include "third_party/ocmock/OCMock/OCMock.h"
 #include "third_party/ocmock/gtest_support.h"
@@ -29,21 +21,16 @@
 #endif
 
 class PaymentRequestShippingOptionSelectionCoordinatorTest
-    : public PlatformTest {
+    : public PaymentRequestUnitTestBase,
+      public PlatformTest {
  protected:
-  PaymentRequestShippingOptionSelectionCoordinatorTest()
-      : chrome_browser_state_(TestChromeBrowserState::Builder().Build()) {
-    payment_request_ = base::MakeUnique<payments::TestPaymentRequest>(
-        payment_request_test_util::CreateTestWebPaymentRequest(),
-        chrome_browser_state_.get(), &web_state_, &personal_data_manager_);
+  void SetUp() override {
+    PaymentRequestUnitTestBase::SetUp();
+
+    CreateTestPaymentRequest();
   }
 
-  base::test::ScopedTaskEnvironment scoped_task_evironment_;
-
-  web::TestWebState web_state_;
-  autofill::TestPersonalDataManager personal_data_manager_;
-  std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
-  std::unique_ptr<payments::TestPaymentRequest> payment_request_;
+  void TearDown() override { PaymentRequestUnitTestBase::TearDown(); }
 };
 
 // Tests that invoking start and stop on the coordinator presents and dismisses
@@ -57,7 +44,7 @@
   ShippingOptionSelectionCoordinator* coordinator =
       [[ShippingOptionSelectionCoordinator alloc]
           initWithBaseViewController:base_view_controller];
-  [coordinator setPaymentRequest:payment_request_.get()];
+  [coordinator setPaymentRequest:payment_request()];
 
   EXPECT_EQ(1u, navigation_controller.viewControllers.count);
 
@@ -90,12 +77,12 @@
   ShippingOptionSelectionCoordinator* coordinator =
       [[ShippingOptionSelectionCoordinator alloc]
           initWithBaseViewController:base_view_controller];
-  [coordinator setPaymentRequest:payment_request_.get()];
+  [coordinator setPaymentRequest:payment_request()];
 
   // Mock the coordinator delegate.
   id delegate = [OCMockObject
       mockForProtocol:@protocol(ShippingOptionSelectionCoordinatorDelegate)];
-  web::PaymentShippingOption* option = payment_request_->shipping_options()[1];
+  web::PaymentShippingOption* option = payment_request()->shipping_options()[1];
   [[delegate expect] shippingOptionSelectionCoordinator:coordinator
                                 didSelectShippingOption:option];
   [coordinator setDelegate:delegate];
@@ -132,7 +119,7 @@
   ShippingOptionSelectionCoordinator* coordinator =
       [[ShippingOptionSelectionCoordinator alloc]
           initWithBaseViewController:base_view_controller];
-  [coordinator setPaymentRequest:payment_request_.get()];
+  [coordinator setPaymentRequest:payment_request()];
 
   // Mock the coordinator delegate.
   id delegate = [OCMockObject
diff --git a/ios/chrome/browser/ui/webui/net_export/net_export_ui.cc b/ios/chrome/browser/ui/webui/net_export/net_export_ui.cc
index d5358ea..d7d7bd6 100644
--- a/ios/chrome/browser/ui/webui/net_export/net_export_ui.cc
+++ b/ios/chrome/browser/ui/webui/net_export/net_export_ui.cc
@@ -135,14 +135,24 @@
 
 void NetExportMessageHandler::OnStartNetLog(const base::ListValue* list) {
   DCHECK_CURRENTLY_ON(web::WebThread::UI);
-  std::string capture_mode_string;
-  bool result = list->GetString(0, &capture_mode_string);
-  DCHECK(result);
 
-  net::NetLogCaptureMode capture_mode =
-      net_log::NetExportFileWriter::CaptureModeFromString(capture_mode_string);
+  const base::Value::ListStorage& params = list->GetList();
+
+  // Determine the capture mode.
+  net::NetLogCaptureMode capture_mode = net::NetLogCaptureMode::Default();
+  if (params.size() > 0 && params[0].is_string()) {
+    capture_mode = net_log::NetExportFileWriter::CaptureModeFromString(
+        params[0].GetString());
+  }
+
+  // Determine the max file size.
+  size_t max_log_file_size = net_log::NetExportFileWriter::kNoLimit;
+  if (params.size() > 1 && params[1].is_int() && params[1].GetInt() > 0) {
+    max_log_file_size = params[1].GetInt();
+  }
+
   file_writer_->StartNetLog(
-      base::FilePath(), capture_mode,
+      base::FilePath(), capture_mode, max_log_file_size,
       base::CommandLine::ForCurrentProcess()->GetCommandLineString(),
       GetChannelString(),
       {GetApplicationContext()->GetSystemURLRequestContext()});
diff --git a/ios/chrome/browser/web/forms_egtest.mm b/ios/chrome/browser/web/forms_egtest.mm
index 7cd2562..aaceaba 100644
--- a/ios/chrome/browser/web/forms_egtest.mm
+++ b/ios/chrome/browser/web/forms_egtest.mm
@@ -369,12 +369,13 @@
 // Tests that pressing the button on a POST-based form with same-page action
 // does not change the page URL and that the back button works as expected
 // afterwards.
-- (void)testPostFormToSamePage {
 // TODO(crbug.com/714303): Re-enable this test on devices.
-#if !TARGET_IPHONE_SIMULATOR
-  EARL_GREY_TEST_DISABLED(@"Test disabled on device.");
+#if TARGET_IPHONE_SIMULATOR
+#define MAYBE_testPostFormToSamePage testPostFormToSamePage
+#else
+#define MAYBE_testPostFormToSamePage FLAKY_testPostFormToSamePage
 #endif
-
+- (void)MAYBE_testPostFormToSamePage {
   web::test::SetUpHttpServer(base::MakeUnique<TestFormResponseProvider>());
   const GURL formURL = GetFormPostOnSamePageUrl();
 
diff --git a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm
index cc51c6b..4c0df86e 100644
--- a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm
+++ b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm
@@ -178,6 +178,7 @@
       self.browser->browser_state());
   std::unique_ptr<web::WebState> webState =
       web::WebState::Create(webStateCreateParams);
+  webState->SetWebUsageEnabled(true);
   self.webStateList.InsertWebState(self.webStateList.count(),
                                    std::move(webState));
   [self showTabGridTabAtIndex:self.webStateList.count() - 1];
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index de80abc..ce14ab8 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -201,6 +201,8 @@
     "url_scheme_util.mm",
     "url_util.cc",
     "web_kit_constants.cc",
+    "web_state/context_menu_constants.h",
+    "web_state/context_menu_constants.mm",
     "web_state/context_menu_params.mm",
     "web_state/context_menu_params_utils.h",
     "web_state/context_menu_params_utils.mm",
@@ -252,6 +254,16 @@
     "web_state/ui/wk_web_view_configuration_provider.mm",
     "web_state/web_controller_observer_bridge.h",
     "web_state/web_controller_observer_bridge.mm",
+    "web_state/web_state.mm",
+    "web_state/web_state_delegate.mm",
+    "web_state/web_state_delegate_bridge.mm",
+    "web_state/web_state_impl.h",
+    "web_state/web_state_impl.mm",
+    "web_state/web_state_observer.mm",
+    "web_state/web_state_observer_bridge.mm",
+    "web_state/web_state_policy_decider.mm",
+    "web_state/web_state_weak_ptr_factory.h",
+    "web_state/web_state_weak_ptr_factory.mm",
     "web_state/web_view_internal_creation_util.h",
     "web_state/web_view_internal_creation_util.mm",
     "web_state/wk_web_view_security_util.h",
@@ -326,16 +338,6 @@
     "web_state/ui/crw_web_controller.mm",
     "web_state/ui/crw_web_controller_container_view.h",
     "web_state/ui/crw_web_controller_container_view.mm",
-    "web_state/web_state.mm",
-    "web_state/web_state_delegate.mm",
-    "web_state/web_state_delegate_bridge.mm",
-    "web_state/web_state_impl.h",
-    "web_state/web_state_impl.mm",
-    "web_state/web_state_observer.mm",
-    "web_state/web_state_observer_bridge.mm",
-    "web_state/web_state_policy_decider.mm",
-    "web_state/web_state_weak_ptr_factory.h",
-    "web_state/web_state_weak_ptr_factory.mm",
   ]
 
   libs = [
diff --git a/ios/web/web_state/context_menu_constants.h b/ios/web/web_state/context_menu_constants.h
new file mode 100644
index 0000000..34b602d
--- /dev/null
+++ b/ios/web/web_state/context_menu_constants.h
@@ -0,0 +1,37 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_WEB_STATE_CONTEXT_MENU_CONSTANTS_H_
+#define IOS_WEB_WEB_STATE_CONTEXT_MENU_CONSTANTS_H_
+
+#import <Foundation/Foundation.h>
+
+// Contains keys present in dictionary returned by __gCrWeb.getElementFromPoint
+// JS API.
+
+namespace web {
+
+// Optional key. Represents element's href attribute if present or parent's href
+// if element is an image.
+extern NSString* const kContextMenuElementHyperlink;
+
+// Optional key. Represents element's src attribute if present (<img> element
+// only).
+extern NSString* const kContextMenuElementSource;
+
+// Optional key. Represents element's title attribute if present (<img> element
+// only).
+extern NSString* const kContextMenuElementTitle;
+
+// Optional key. Represents referrer policy to use for navigations away from the
+// current page. Key is present if |kContextMenuElementError| is |NO_ERROR|.
+extern NSString* const kContextMenuElementReferrerPolicy;
+
+// Optional key. Represents element's innerText attribute if present (<a>
+// elements with href only).
+extern NSString* const kContextMenuElementInnerText;
+
+}  // namespace web
+
+#endif  // IOS_WEB_WEB_STATE_CONTEXT_MENU_CONSTANTS_H_
diff --git a/ios/web/web_state/context_menu_constants.mm b/ios/web/web_state/context_menu_constants.mm
new file mode 100644
index 0000000..6f2ab8f
--- /dev/null
+++ b/ios/web/web_state/context_menu_constants.mm
@@ -0,0 +1,19 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/web/web_state/context_menu_constants.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace web {
+
+NSString* const kContextMenuElementHyperlink = @"href";
+NSString* const kContextMenuElementSource = @"src";
+NSString* const kContextMenuElementTitle = @"title";
+NSString* const kContextMenuElementReferrerPolicy = @"referrerPolicy";
+NSString* const kContextMenuElementInnerText = @"innerText";
+
+}  // namespace web
diff --git a/ios/web/web_state/context_menu_params_utils.mm b/ios/web/web_state/context_menu_params_utils.mm
index 3acabb5e6..2e3074b7 100644
--- a/ios/web/web_state/context_menu_params_utils.mm
+++ b/ios/web/web_state/context_menu_params_utils.mm
@@ -7,17 +7,19 @@
 #include "base/strings/sys_string_conversions.h"
 #include "components/url_formatter/url_formatter.h"
 #include "ios/web/public/referrer_util.h"
+#import "ios/web/web_state/context_menu_constants.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
 namespace web {
+
 ContextMenuParams ContextMenuParamsFromElementDictionary(
     NSDictionary* element) {
   ContextMenuParams params;
   NSString* title = nil;
-  NSString* href = element[@"href"];
+  NSString* href = element[kContextMenuElementHyperlink];
   if (href) {
     params.link_url = GURL(base::SysNSStringToUTF8(href));
     if (params.link_url.SchemeIs(url::kJavaScriptScheme)) {
@@ -27,7 +29,7 @@
       title = base::SysUTF16ToNSString(URLText);
     }
   }
-  NSString* src = element[@"src"];
+  NSString* src = element[kContextMenuElementSource];
   if (src) {
     params.src_url = GURL(base::SysNSStringToUTF8(src));
     if (!title)
@@ -35,18 +37,18 @@
     if ([title hasPrefix:base::SysUTF8ToNSString(url::kDataScheme)])
       title = nil;
   }
-  NSString* titleAttribute = element[@"title"];
+  NSString* titleAttribute = element[kContextMenuElementTitle];
   if (titleAttribute)
     title = titleAttribute;
   if (title) {
     params.menu_title.reset([title copy]);
   }
-  NSString* referrerPolicy = element[@"referrerPolicy"];
+  NSString* referrerPolicy = element[kContextMenuElementReferrerPolicy];
   if (referrerPolicy) {
     params.referrer_policy =
         web::ReferrerPolicyFromString(base::SysNSStringToUTF8(referrerPolicy));
   }
-  NSString* innerText = element[@"innerText"];
+  NSString* innerText = element[kContextMenuElementInnerText];
   if ([innerText length] > 0) {
     params.link_text.reset([innerText copy]);
   }
diff --git a/ios/web/web_state/context_menu_params_utils_unittest.mm b/ios/web/web_state/context_menu_params_utils_unittest.mm
index 838f468..fefd076 100644
--- a/ios/web/web_state/context_menu_params_utils_unittest.mm
+++ b/ios/web/web_state/context_menu_params_utils_unittest.mm
@@ -8,6 +8,7 @@
 #include "components/url_formatter/url_formatter.h"
 #include "ios/web/public/referrer_util.h"
 #import "ios/web/public/web_state/context_menu_params.h"
+#import "ios/web/web_state/context_menu_constants.h"
 #import "net/base/mac/url_conversions.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
@@ -19,15 +20,17 @@
 
 namespace {
 // Text values for the tapped element triggering the context menu.
-const char* kLinkUrl = "http://link.url/";
-const char* kSrcUrl = "http://src.url/";
-const char* kTitle = "title";
-const char* kReferrerPolicy = "always";
-const char* kLinkText = "link text";
-const char* kJavaScriptLinkUrl = "javascript://src.url/";
-const char* kDataUrl = "data://foo.bar/";
+const char kLinkUrl[] = "http://link.url/";
+const char kSrcUrl[] = "http://src.url/";
+const char kTitle[] = "title";
+const char kReferrerPolicy[] = "always";
+const char kLinkText[] = "link text";
+const char kJavaScriptLinkUrl[] = "javascript://src.url/";
+const char kDataUrl[] = "data://foo.bar/";
 }
 
+namespace web {
+
 // Test fixture for error translation testing.
 typedef PlatformTest ContextMenuParamsUtilsTest;
 
@@ -46,11 +49,11 @@
 // Tests the the parsing of the element NSDictionary.
 TEST_F(ContextMenuParamsUtilsTest, DictionaryConstructorTest) {
   web::ContextMenuParams params = web::ContextMenuParamsFromElementDictionary(@{
-    @"href" : @(kLinkUrl),
-    @"src" : @(kSrcUrl),
-    @"title" : @(kTitle),
-    @"referrerPolicy" : @(kReferrerPolicy),
-    @"innerText" : @(kLinkText),
+    kContextMenuElementHyperlink : @(kLinkUrl),
+    kContextMenuElementSource : @(kSrcUrl),
+    kContextMenuElementTitle : @(kTitle),
+    kContextMenuElementReferrerPolicy : @(kReferrerPolicy),
+    kContextMenuElementInnerText : @(kLinkText),
   });
 
   EXPECT_NSEQ(params.menu_title.get(), @(kTitle));
@@ -67,7 +70,7 @@
 // Tests title is set as the formatted URL there is no title.
 TEST_F(ContextMenuParamsUtilsTest, DictionaryConstructorTestNoTitle) {
   web::ContextMenuParams params = web::ContextMenuParamsFromElementDictionary(@{
-    @"href" : @(kLinkUrl),
+    kContextMenuElementHyperlink : @(kLinkUrl),
   });
   base::string16 urlText = url_formatter::FormatUrl(GURL(kLinkUrl));
   NSString* title = base::SysUTF16ToNSString(urlText);
@@ -79,7 +82,7 @@
 // JavaScript URL.
 TEST_F(ContextMenuParamsUtilsTest, DictionaryConstructorTestJavascriptTitle) {
   web::ContextMenuParams params = web::ContextMenuParamsFromElementDictionary(@{
-    @"href" : @(kJavaScriptLinkUrl),
+    kContextMenuElementHyperlink : @(kJavaScriptLinkUrl),
   });
   EXPECT_NSEQ(params.menu_title.get(), @"JavaScript");
 }
@@ -87,7 +90,7 @@
 // Tests title is set to |src_url| if there is no title.
 TEST_F(ContextMenuParamsUtilsTest, DictionaryConstructorTestSrcTitle) {
   web::ContextMenuParams params = web::ContextMenuParamsFromElementDictionary(@{
-    @"src" : @(kSrcUrl),
+    kContextMenuElementSource : @(kSrcUrl),
   });
   EXPECT_EQ(params.src_url, GURL(kSrcUrl));
   EXPECT_NSEQ(params.menu_title.get(), @(kSrcUrl));
@@ -96,8 +99,10 @@
 // Tests title is set to nil if there is no title and src is a data URL.
 TEST_F(ContextMenuParamsUtilsTest, DictionaryConstructorTestDataTitle) {
   web::ContextMenuParams params = web::ContextMenuParamsFromElementDictionary(@{
-    @"src" : @(kDataUrl),
+    kContextMenuElementSource : @(kDataUrl),
   });
   EXPECT_EQ(params.src_url, GURL(kDataUrl));
   EXPECT_NSEQ(params.menu_title.get(), nil);
 }
+
+}  // namespace web
diff --git a/ios/web/web_state/js/context_menu_js_unittest.mm b/ios/web/web_state/js/context_menu_js_unittest.mm
index c1bb972..7f0c7a2 100644
--- a/ios/web/web_state/js/context_menu_js_unittest.mm
+++ b/ios/web/web_state/js/context_menu_js_unittest.mm
@@ -13,6 +13,7 @@
 #import "ios/web/public/web_state/ui/crw_web_view_proxy.h"
 #import "ios/web/public/web_state/ui/crw_web_view_scroll_view_proxy.h"
 #import "ios/web/public/web_state/web_state.h"
+#import "ios/web/web_state/context_menu_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
 
@@ -91,8 +92,8 @@
   NSString* html =
       @"<img id='foo' style='width:200;height:200;' src='file:///bogus'/>";
   NSDictionary* expected_value = @{
-    @"src" : @"file:///bogus",
-    @"referrerPolicy" : @"default",
+    kContextMenuElementSource : @"file:///bogus",
+    kContextMenuElementReferrerPolicy : @"default",
   };
   ImageTesterHelper(html, expected_value);
 }
@@ -102,9 +103,9 @@
   NSString* html = @"<img id='foo' title='Hello world!'"
                     "style='width:200;height:200;' src='file:///bogus'/>";
   NSDictionary* expected_value = @{
-    @"src" : @"file:///bogus",
-    @"referrerPolicy" : @"default",
-    @"title" : @"Hello world!",
+    kContextMenuElementSource : @"file:///bogus",
+    kContextMenuElementReferrerPolicy : @"default",
+    kContextMenuElementTitle : @"Hello world!",
   };
   ImageTesterHelper(html, expected_value);
 }
@@ -116,9 +117,9 @@
        "<img id='foo' style='width:200;height:200;' src='file:///bogus'/>"
        "</a>";
   NSDictionary* expected_value = @{
-    @"src" : @"file:///bogus",
-    @"referrerPolicy" : @"default",
-    @"href" : @"file:///linky",
+    kContextMenuElementSource : @"file:///bogus",
+    kContextMenuElementReferrerPolicy : @"default",
+    kContextMenuElementHyperlink : @"file:///linky",
   };
   ImageTesterHelper(html, expected_value);
 }
@@ -136,8 +137,8 @@
        "</div></body> </html>";
 
   NSDictionary* success = @{
-    @"src" : @"file:///bogus",
-    @"referrerPolicy" : @"default",
+    kContextMenuElementSource : @"file:///bogus",
+    kContextMenuElementReferrerPolicy : @"default",
   };
   NSDictionary* failure = @{};
 
@@ -164,9 +165,10 @@
   LoadHtml(base::StringPrintf(image, "http://destination"));
   id result = ExecuteGetElementFromPointJavaScript(20, 20);
   NSDictionary* expected_result = @{
-    @"src" : [NSString stringWithFormat:@"%sfoo", BaseUrl().c_str()],
-    @"referrerPolicy" : @"default",
-    @"href" : @"http://destination/",
+    kContextMenuElementSource :
+        [NSString stringWithFormat:@"%sfoo", BaseUrl().c_str()],
+    kContextMenuElementReferrerPolicy : @"default",
+    kContextMenuElementHyperlink : @"http://destination/",
   };
   EXPECT_NSEQ(expected_result, result);
 
@@ -174,9 +176,10 @@
   LoadHtml(base::StringPrintf(image, "javascript:console.log('whatever')"));
   result = ExecuteGetElementFromPointJavaScript(20, 20);
   expected_result = @{
-    @"src" : [NSString stringWithFormat:@"%sfoo", BaseUrl().c_str()],
-    @"referrerPolicy" : @"default",
-    @"href" : @"javascript:console.log(",
+    kContextMenuElementSource :
+        [NSString stringWithFormat:@"%sfoo", BaseUrl().c_str()],
+    kContextMenuElementReferrerPolicy : @"default",
+    kContextMenuElementHyperlink : @"javascript:console.log(",
   };
   EXPECT_NSEQ(expected_result, result);
 
@@ -192,8 +195,9 @@
     LoadHtml(base::StringPrintf(image, javascript.c_str()));
     result = ExecuteGetElementFromPointJavaScript(20, 20);
     expected_result = @{
-      @"src" : [NSString stringWithFormat:@"%sfoo", BaseUrl().c_str()],
-      @"referrerPolicy" : @"default",
+      kContextMenuElementSource :
+          [NSString stringWithFormat:@"%sfoo", BaseUrl().c_str()],
+      kContextMenuElementReferrerPolicy : @"default",
     };
     // Make sure the returned JSON does not have an 'href' key.
     EXPECT_NSEQ(expected_result, result);
diff --git a/ios/web/web_state/ui/crw_context_menu_controller.mm b/ios/web/web_state/ui/crw_context_menu_controller.mm
index 2e7d1dd0..362c2226 100644
--- a/ios/web/web_state/ui/crw_context_menu_controller.mm
+++ b/ios/web/web_state/ui/crw_context_menu_controller.mm
@@ -14,6 +14,7 @@
 #import "ios/web/public/web_state/context_menu_params.h"
 #import "ios/web/public/web_state/js/crw_js_injection_evaluator.h"
 #import "ios/web/public/web_state/ui/crw_context_menu_delegate.h"
+#import "ios/web/web_state/context_menu_constants.h"
 #import "ios/web/web_state/context_menu_params_utils.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -77,8 +78,8 @@
   // DOM element information for the point where the user made the last touch.
   // Can be nil if has not been calculated yet. Precalculation is necessary
   // because retreiving DOM element relies on async API so element info can not
-  // be built on demand. May contain the following keys: @"href", @"src",
-  // @"title", @"referrerPolicy". All values are strings.
+  // be built on demand. May contain the keys defined in
+  // ios/web/web_state/context_menu_constants.h. All values are strings.
   NSDictionary* _DOMElementForLastTouch;
 }
 
diff --git a/ios/web/web_state/web_state.mm b/ios/web/web_state/web_state.mm
index ad5791d..55ece67 100644
--- a/ios/web/web_state/web_state.mm
+++ b/ios/web/web_state/web_state.mm
@@ -4,6 +4,10 @@
 
 #import "ios/web/public/web_state/web_state.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace web {
 
 WebState::CreateParams::CreateParams(web::BrowserState* browser_state)
diff --git a/ios/web/web_state/web_state_delegate.mm b/ios/web/web_state/web_state_delegate.mm
index c6a2def0..2c58355 100644
--- a/ios/web/web_state/web_state_delegate.mm
+++ b/ios/web/web_state/web_state_delegate.mm
@@ -6,6 +6,10 @@
 
 #import "ios/web/public/web_state/web_state.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace web {
 
 WebStateDelegate::WebStateDelegate() {}
diff --git a/ios/web/web_state/web_state_delegate_bridge.mm b/ios/web/web_state/web_state_delegate_bridge.mm
index 797e9f46..b4c1255 100644
--- a/ios/web/web_state/web_state_delegate_bridge.mm
+++ b/ios/web/web_state/web_state_delegate_bridge.mm
@@ -7,6 +7,10 @@
 #include "base/logging.h"
 #import "ios/web/public/web_state/context_menu_params.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace web {
 
 WebStateDelegateBridge::WebStateDelegateBridge(id<CRWWebStateDelegate> delegate)
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm
index 676b8af..c6a673e 100644
--- a/ios/web/web_state/web_state_impl.mm
+++ b/ios/web/web_state/web_state_impl.mm
@@ -44,6 +44,10 @@
 #include "net/http/http_response_headers.h"
 #include "ui/gfx/image/image.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace web {
 
 /* static */
@@ -173,7 +177,7 @@
 
 void WebStateImpl::SetWebController(CRWWebController* web_controller) {
   [web_controller_ close];
-  web_controller_.reset([web_controller retain]);
+  web_controller_.reset(web_controller);
 }
 
 void WebStateImpl::OnTitleChanged() {
diff --git a/ios/web/web_state/web_state_observer.mm b/ios/web/web_state/web_state_observer.mm
index 1408a6e8..4c24630 100644
--- a/ios/web/web_state/web_state_observer.mm
+++ b/ios/web/web_state/web_state_observer.mm
@@ -7,6 +7,10 @@
 #include "ios/web/public/load_committed_details.h"
 #import "ios/web/public/web_state/web_state.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace web {
 
 WebStateObserver::WebStateObserver(WebState* web_state) : web_state_(nullptr) {
diff --git a/ios/web/web_state/web_state_observer_bridge.mm b/ios/web/web_state/web_state_observer_bridge.mm
index 73982ff..12de262 100644
--- a/ios/web/web_state/web_state_observer_bridge.mm
+++ b/ios/web/web_state/web_state_observer_bridge.mm
@@ -4,6 +4,10 @@
 
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace web {
 
 WebStateObserverBridge::WebStateObserverBridge(web::WebState* webState,
diff --git a/ios/web/web_state/web_state_policy_decider.mm b/ios/web/web_state/web_state_policy_decider.mm
index f061dfa12..5f3e69d 100644
--- a/ios/web/web_state/web_state_policy_decider.mm
+++ b/ios/web/web_state/web_state_policy_decider.mm
@@ -7,6 +7,10 @@
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/web_state/web_state_impl.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace web {
 
 WebStatePolicyDecider::WebStatePolicyDecider(WebState* web_state)
diff --git a/ios/web/web_state/web_state_weak_ptr_factory.mm b/ios/web/web_state/web_state_weak_ptr_factory.mm
index 3b93e4b..2b94ef4 100644
--- a/ios/web/web_state/web_state_weak_ptr_factory.mm
+++ b/ios/web/web_state/web_state_weak_ptr_factory.mm
@@ -6,6 +6,10 @@
 
 #import "ios/web/public/web_state/web_state.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace web {
 
 // static
diff --git a/ios/web/webui/web_ui_mojo_inttest.mm b/ios/web/webui/web_ui_mojo_inttest.mm
index 0d240d8c..4e64d41e 100644
--- a/ios/web/webui/web_ui_mojo_inttest.mm
+++ b/ios/web/webui/web_ui_mojo_inttest.mm
@@ -147,6 +147,23 @@
         new TestWebUIControllerFactory(ui_handler_.get()));
   }
 
+  void TearDown() override {
+    @autoreleasepool {
+      // WebState owns CRWWebUIManager. When WebState is destroyed,
+      // CRWWebUIManager is autoreleased and will be destroyed upon autorelease
+      // pool purge. However in this test, WebTest destructor is called before
+      // PlatformTest, thus CRWWebUIManager outlives the WebThreadBundle.
+      // However, CRWWebUIManager owns a URLFetcherImpl, which DCHECKs that its
+      // destructor is called on UI web thread. Hence, URLFetcherImpl has to
+      // outlive the WebThreadBundle, since [NSThread mainThread] will not be
+      // WebThread::UI once WebThreadBundle is destroyed.
+      web_state_.reset();
+      ui_handler_.reset();
+    }
+
+    WebIntTest::TearDown();
+  }
+
   // Returns WebState which loads test WebUI page.
   WebStateImpl* web_state() { return web_state_.get(); }
   // Returns UI handler which communicates with WebUI page.
@@ -167,31 +184,33 @@
 #endif
 // TODO(crbug.com/720098): Enable this test on device.
 TEST_F(WebUIMojoTest, MAYBE_MessageExchange) {
-  web_state()->SetWebUsageEnabled(true);
-  web_state()->GetView();  // WebState won't load URL without view.
-  GURL url(
-      url::SchemeHostPort(kTestWebUIScheme, kTestWebUIURLHost, 0).Serialize());
-  NavigationManager::WebLoadParams load_params(url);
-  web_state()->GetNavigationManager()->LoadURLWithParams(load_params);
+  @autoreleasepool {
+    web_state()->SetWebUsageEnabled(true);
+    web_state()->GetView();  // WebState won't load URL without view.
+    GURL url(url::SchemeHostPort(kTestWebUIScheme, kTestWebUIURLHost, 0)
+                 .Serialize());
+    NavigationManager::WebLoadParams load_params(url);
+    web_state()->GetNavigationManager()->LoadURLWithParams(load_params);
 
-  // Wait until |TestUIHandler| receives "fin" message from WebUI page.
-  bool fin_received = testing::WaitUntilConditionOrTimeout(kMessageTimeout, ^{
-    // Flush any pending tasks. Don't RunUntilIdle() because
-    // RunUntilIdle() is incompatible with mojo::SimpleWatcher's
-    // automatic arming behavior, which Mojo JS still depends upon.
-    //
-    // TODO(crbug.com/701875): Introduce the full watcher API to JS and get rid
-    // of this hack.
-    base::RunLoop loop;
-    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
-                                                  loop.QuitClosure());
-    loop.Run();
-    return test_ui_handler()->IsFinReceived();
-  });
+    // Wait until |TestUIHandler| receives "fin" message from WebUI page.
+    bool fin_received = testing::WaitUntilConditionOrTimeout(kMessageTimeout, ^{
+      // Flush any pending tasks. Don't RunUntilIdle() because
+      // RunUntilIdle() is incompatible with mojo::SimpleWatcher's
+      // automatic arming behavior, which Mojo JS still depends upon.
+      //
+      // TODO(crbug.com/701875): Introduce the full watcher API to JS and get
+      // rid of this hack.
+      base::RunLoop loop;
+      base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                    loop.QuitClosure());
+      loop.Run();
+      return test_ui_handler()->IsFinReceived();
+    });
 
-  ASSERT_TRUE(fin_received);
-  EXPECT_FALSE(web_state()->IsLoading());
-  EXPECT_EQ(url, web_state()->GetLastCommittedURL());
+    ASSERT_TRUE(fin_received);
+    EXPECT_FALSE(web_state()->IsLoading());
+    EXPECT_EQ(url, web_state()->GetLastCommittedURL());
+  }
 }
 
 }  // namespace web
diff --git a/ipc/BUILD.gn b/ipc/BUILD.gn
index 5046a63..5c2e209 100644
--- a/ipc/BUILD.gn
+++ b/ipc/BUILD.gn
@@ -7,6 +7,7 @@
 import("//mojo/public/tools/bindings/mojom.gni")
 import("//testing/test.gni")
 import("//tools/ipc_fuzzer/ipc_fuzzer.gni")
+import("//third_party/protobuf/proto_library.gni")
 
 declare_args() {
   # Enabling debug builds automatically sets enable_ipc_logging to true.
@@ -122,6 +123,17 @@
     "//mojo/public/cpp/bindings",
     "//mojo/public/cpp/system",
   ]
+
+  if (!is_nacl_nonsfi) {
+    sources += [
+      "ipc_message_protobuf_utils.h",
+    ]
+
+    public_deps += [
+      "//third_party/protobuf:protobuf_lite",
+    ]
+  }
+
   deps = [
     "//base",
   ]
@@ -177,6 +189,12 @@
     ]
   }
 
+  proto_library("test_proto") {
+    sources = [
+      "test_proto.proto",
+    ]
+  }
+
   test("ipc_tests") {
     sources = [
       "ipc_channel_mojo_unittest.cc",
@@ -204,6 +222,7 @@
       ":ipc",
       ":run_all_unittests",
       ":test_interfaces",
+      ":test_proto",
       ":test_support",
       "//base",
       "//base:i18n",
@@ -224,6 +243,12 @@
         "sync_socket_unittest.cc",
       ]
     }
+
+    if (!is_nacl_nonsfi) {
+      sources += [
+        "ipc_message_protobuf_utils_unittest.cc",
+      ]
+    }
   }
 
   test("ipc_perftests") {
diff --git a/ipc/DEPS b/ipc/DEPS
index 5f929e9..f8d30bb 100644
--- a/ipc/DEPS
+++ b/ipc/DEPS
@@ -20,5 +20,9 @@
   "run_all_(unit|perf)tests\.cc": [
     "+mojo/edk/embedder",
     "+mojo/edk/test",
-  ]
+  ],
+  "ipc_message_protobuf_utils\.h": [
+    # Support serializing RepeatedField / RepeatedPtrField:
+    "+third_party/protobuf/src/google/protobuf/repeated_field.h",
+  ],
 }
diff --git a/ipc/ipc_channel_proxy.cc b/ipc/ipc_channel_proxy.cc
index d35328e4..f48e44c 100644
--- a/ipc/ipc_channel_proxy.cc
+++ b/ipc/ipc_channel_proxy.cc
@@ -517,6 +517,12 @@
 }
 
 bool ChannelProxy::Send(Message* message) {
+  DCHECK(!message->is_sync()) << "Need to use IPC::SyncChannel";
+  SendInternal(message);
+  return true;
+}
+
+void ChannelProxy::SendInternal(Message* message) {
   DCHECK(did_init_);
 
   // TODO(alexeypa): add DCHECK(CalledOnValidThread()) here. Currently there are
@@ -535,7 +541,6 @@
 #endif
 
   context_->Send(message);
-  return true;
 }
 
 void ChannelProxy::AddFilter(MessageFilter* filter) {
diff --git a/ipc/ipc_channel_proxy.h b/ipc/ipc_channel_proxy.h
index 85cf510a..f95e4dd 100644
--- a/ipc/ipc_channel_proxy.h
+++ b/ipc/ipc_channel_proxy.h
@@ -377,9 +377,11 @@
   }
 #endif
 
- protected:
   bool did_init() const { return did_init_; }
 
+  // A Send() which doesn't DCHECK if the message is synchronous.
+  void SendInternal(Message* message);
+
  private:
   friend class IpcSecurityTestUtil;
 
diff --git a/ipc/ipc_fuzzing_tests.cc b/ipc/ipc_fuzzing_tests.cc
index 8e385bc..5744135 100644
--- a/ipc/ipc_fuzzing_tests.cc
+++ b/ipc/ipc_fuzzing_tests.cc
@@ -126,6 +126,20 @@
   EXPECT_FALSE(ReadParam(&m, &iter, &vec));
 }
 
+// This test needs ~20 seconds in Debug mode, or ~4 seconds in Release mode.
+// See http://crbug.com/741866 for details.
+TEST(IPCMessageIntegrity, DISABLED_ReadVectorTooLarge3) {
+  base::Pickle pickle;
+  IPC::WriteParam(&pickle, 256 * 1024 * 1024);
+  IPC::WriteParam(&pickle, 0);
+  IPC::WriteParam(&pickle, 1);
+  IPC::WriteParam(&pickle, 2);
+
+  base::PickleIterator iter(pickle);
+  std::vector<int> vec;
+  EXPECT_FALSE(IPC::ReadParam(&pickle, &iter, &vec));
+}
+
 class SimpleListener : public IPC::Listener {
  public:
   SimpleListener() : other_(NULL) {
diff --git a/ipc/ipc_message_protobuf_utils.h b/ipc/ipc_message_protobuf_utils.h
new file mode 100644
index 0000000..8cacfe8
--- /dev/null
+++ b/ipc/ipc_message_protobuf_utils.h
@@ -0,0 +1,72 @@
+// Copyright 2017 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 IPC_IPC_MESSAGE_PROTOBUF_UTILS_H_
+#define IPC_IPC_MESSAGE_PROTOBUF_UTILS_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_NACL_NONSFI)
+static_assert(false,
+              "ipc_message_protobuf_utils is not able to work with "
+              "nacl_nonsfi configuration.");
+#endif
+
+#include "base/pickle.h"
+#include "ipc/ipc_param_traits.h"
+#include "ipc/ipc_message_utils.h"
+#include "third_party/protobuf/src/google/protobuf/repeated_field.h"
+
+namespace IPC {
+
+template <class RepeatedFieldLike, class StorageType>
+struct RepeatedFieldParamTraits {
+  typedef RepeatedFieldLike param_type;
+  static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+    GetParamSize(sizer, p.size());
+    for (int i = 0; i < p.size(); i++)
+      GetParamSize(sizer, p.Get(i));
+  }
+  static void Write(base::Pickle* m, const param_type& p) {
+    WriteParam(m, p.size());
+    for (int i = 0; i < p.size(); i++)
+      WriteParam(m, p.Get(i));
+  }
+  static bool Read(const base::Pickle* m,
+                   base::PickleIterator* iter,
+                   param_type* r) {
+    int size;
+    // ReadLength() checks for < 0 itself.
+    if (!iter->ReadLength(&size))
+      return false;
+    // Avoid integer overflow / assertion failure in Reserve() function.
+    if (INT_MAX / sizeof(StorageType) <= static_cast<size_t>(size))
+      return false;
+    r->Reserve(size);
+    for (int i = 0; i < size; i++) {
+      if (!ReadParam(m, iter, r->Add()))
+        return false;
+    }
+    return true;
+  }
+  static void Log(const param_type& p, std::string* l) {
+    for (int i = 0; i < p.size(); ++i) {
+      if (i != 0)
+        l->append(" ");
+      LogParam(p.Get(i), l);
+    }
+  }
+};
+
+template <class P>
+struct ParamTraits<google::protobuf::RepeatedField<P>> :
+    RepeatedFieldParamTraits<google::protobuf::RepeatedField<P>, P> {};
+
+template <class P>
+struct ParamTraits<google::protobuf::RepeatedPtrField<P>> :
+    RepeatedFieldParamTraits<google::protobuf::RepeatedPtrField<P>, void*> {};
+
+}  // namespace IPC
+
+#endif  // IPC_IPC_MESSAGE_PROTOBUF_UTILS_H_
diff --git a/ipc/ipc_message_protobuf_utils_unittest.cc b/ipc/ipc_message_protobuf_utils_unittest.cc
new file mode 100644
index 0000000..5c01a7f
--- /dev/null
+++ b/ipc/ipc_message_protobuf_utils_unittest.cc
@@ -0,0 +1,193 @@
+// Copyright 2017 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 "build/build_config.h"
+
+#if defined(OS_NACL_NONSFI)
+static_assert(false,
+              "ipc_message_protobuf_utils is not able to work with nacl_nonsfi "
+              "configuration.");
+#endif
+
+#include "ipc/ipc_message_protobuf_utils.h"
+
+#include <initializer_list>
+
+#include "ipc/test_proto.pb.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_message_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace IPC {
+
+template <>
+struct ParamTraits<ipc_message_utils_test::TestMessage1> {
+  typedef ipc_message_utils_test::TestMessage1 param_type;
+  static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+    GetParamSize(sizer, p.number());
+  }
+  static void Write(base::Pickle* m, const param_type& p) {
+    WriteParam(m, p.number());
+  }
+  static bool Read(const base::Pickle* m,
+                   base::PickleIterator* iter,
+                   param_type* r) {
+    int number;
+    if (!iter->ReadInt(&number))
+      return false;
+    r->set_number(number);
+    return true;
+  }
+};
+
+template <>
+struct ParamTraits<ipc_message_utils_test::TestMessage2> {
+  typedef ipc_message_utils_test::TestMessage2 param_type;
+  static void GetSize(base::PickleSizer* sizer, const param_type& p) {
+    GetParamSize(sizer, p.numbers());
+    GetParamSize(sizer, p.strings());
+    GetParamSize(sizer, p.messages());
+  }
+  static void Write(base::Pickle* m, const param_type& p) {
+    WriteParam(m, p.numbers());
+    WriteParam(m, p.strings());
+    WriteParam(m, p.messages());
+  }
+  static bool Read(const base::Pickle* m,
+                   base::PickleIterator* iter,
+                   param_type* r) {
+    return ReadParam(m, iter, r->mutable_numbers()) &&
+           ReadParam(m, iter, r->mutable_strings()) &&
+           ReadParam(m, iter, r->mutable_messages());
+  }
+};
+
+namespace {
+
+template <class P1, class P2>
+void AssertEqual(const P1& left, const P2& right) {
+  ASSERT_EQ(left, right);
+}
+
+template<>
+void AssertEqual(const int& left,
+                 const ipc_message_utils_test::TestMessage1& right) {
+  ASSERT_EQ(left, right.number());
+}
+
+template <template<class> class RepeatedFieldLike, class P1, class P2>
+void AssertRepeatedFieldEquals(std::initializer_list<P1> expected,
+                               const RepeatedFieldLike<P2>& fields) {
+  ASSERT_EQ(static_cast<int>(expected.size()), fields.size());
+  auto it = expected.begin();
+  int i = 0;
+  for (; it != expected.end(); it++, i++) {
+    AssertEqual(*it, fields.Get(i));
+  }
+}
+
+TEST(IPCMessageRepeatedFieldUtilsTest, RepeatedFieldShouldBeSerialized) {
+  ipc_message_utils_test::TestMessage2 message;
+  message.add_numbers(1);
+  message.add_numbers(100);
+  message.add_strings("abc");
+  message.add_strings("def");
+  message.add_messages()->set_number(1000);
+  message.add_messages()->set_number(10000);
+
+  base::Pickle pickle;
+  IPC::WriteParam(&pickle, message);
+
+  base::PickleSizer sizer;
+  IPC::GetParamSize(&sizer, message);
+
+  ASSERT_EQ(sizer.payload_size(), pickle.payload_size());
+
+  base::PickleIterator iter(pickle);
+  ipc_message_utils_test::TestMessage2 output;
+  ASSERT_TRUE(IPC::ReadParam(&pickle, &iter, &output));
+
+  AssertRepeatedFieldEquals({1, 100}, output.numbers());
+  AssertRepeatedFieldEquals({"abc", "def"}, output.strings());
+  AssertRepeatedFieldEquals({1000, 10000}, output.messages());
+}
+
+TEST(IPCMessageRepeatedFieldUtilsTest,
+     PartialEmptyRepeatedFieldShouldBeSerialized) {
+  ipc_message_utils_test::TestMessage2 message;
+  message.add_numbers(1);
+  message.add_numbers(100);
+  message.add_messages()->set_number(1000);
+  message.add_messages()->set_number(10000);
+
+  base::Pickle pickle;
+  IPC::WriteParam(&pickle, message);
+
+  base::PickleSizer sizer;
+  IPC::GetParamSize(&sizer, message);
+
+  ASSERT_EQ(sizer.payload_size(), pickle.payload_size());
+
+  base::PickleIterator iter(pickle);
+  ipc_message_utils_test::TestMessage2 output;
+  ASSERT_TRUE(IPC::ReadParam(&pickle, &iter, &output));
+
+  AssertRepeatedFieldEquals({1, 100}, output.numbers());
+  ASSERT_EQ(0, output.strings_size());
+  AssertRepeatedFieldEquals({1000, 10000}, output.messages());
+}
+
+TEST(IPCMessageRepeatedFieldUtilsTest, EmptyRepeatedFieldShouldBeSerialized) {
+  ipc_message_utils_test::TestMessage2 message;
+
+  base::Pickle pickle;
+  IPC::WriteParam(&pickle, message);
+
+  base::PickleSizer sizer;
+  IPC::GetParamSize(&sizer, message);
+
+  ASSERT_EQ(sizer.payload_size(), pickle.payload_size());
+
+  base::PickleIterator iter(pickle);
+  ipc_message_utils_test::TestMessage2 output;
+  ASSERT_TRUE(IPC::ReadParam(&pickle, &iter, &output));
+
+  ASSERT_EQ(0, output.numbers_size());
+  ASSERT_EQ(0, output.strings_size());
+  ASSERT_EQ(0, output.messages_size());
+}
+
+TEST(IPCMessageRepeatedFieldUtilsTest,
+     InvalidPickleShouldNotCrashRepeatedFieldDeserialization) {
+  base::Pickle pickle;
+  IPC::WriteParam(&pickle, INT_MAX);
+  IPC::WriteParam(&pickle, 0);
+  IPC::WriteParam(&pickle, INT_MAX);
+  IPC::WriteParam(&pickle, std::string());
+  IPC::WriteParam(&pickle, 0);
+
+  base::PickleIterator iter(pickle);
+  ipc_message_utils_test::TestMessage2 output;
+  ASSERT_FALSE(IPC::ReadParam(&pickle, &iter, &output));
+}
+
+// This test needs ~20 seconds in Debug mode, or ~4 seconds in Release mode.
+// See http://crbug.com/741866 for details.
+TEST(IPCMessageRepeatedFieldUtilsTest,
+     DISABLED_InvalidPickleShouldNotCrashRepeatedFieldDeserialization2) {
+  base::Pickle pickle;
+  IPC::WriteParam(&pickle, 256 * 1024 * 1024);
+  IPC::WriteParam(&pickle, 0);
+  IPC::WriteParam(&pickle, INT_MAX);
+  IPC::WriteParam(&pickle, std::string());
+  IPC::WriteParam(&pickle, 0);
+
+  base::PickleIterator iter(pickle);
+  ipc_message_utils_test::TestMessage2 output;
+  ASSERT_FALSE(IPC::ReadParam(&pickle, &iter, &output));
+}
+
+}  // namespace
+
+}  // namespace IPC
diff --git a/ipc/ipc_param_traits.h b/ipc/ipc_param_traits.h
index 45e975c..9aaeb5e 100644
--- a/ipc/ipc_param_traits.h
+++ b/ipc/ipc_param_traits.h
@@ -9,8 +9,19 @@
 // a data type is read, written and logged in the IPC system.
 
 namespace IPC {
+namespace internal {
+
+template <typename T>
+struct AlwaysFalse {
+  static const bool value = false;
+};
+
+}  // namespace internal
 
 template <class P> struct ParamTraits {
+  static_assert(internal::AlwaysFalse<P>::value,
+                "Cannot find the IPC::ParamTraits specialization. Did you "
+                "forget to include the corresponding header file?");
 };
 
 template <class P>
diff --git a/ipc/ipc_sync_channel.cc b/ipc/ipc_sync_channel.cc
index 36effbc..7c1c44d8 100644
--- a/ipc/ipc_sync_channel.cc
+++ b/ipc/ipc_sync_channel.cc
@@ -599,7 +599,7 @@
                "line", IPC_MESSAGE_ID_LINE(message->type()));
 #endif
   if (!message->is_sync()) {
-    ChannelProxy::Send(message);
+    ChannelProxy::SendInternal(message);
     return true;
   }
 
@@ -614,7 +614,7 @@
     return false;
   }
 
-  ChannelProxy::Send(message);
+  ChannelProxy::SendInternal(message);
 
   // Wait for reply, or for any other incoming synchronous messages.
   // |this| might get deleted, so only call static functions at this point.
diff --git a/ipc/test_proto.proto b/ipc/test_proto.proto
new file mode 100644
index 0000000..98525ede
--- /dev/null
+++ b/ipc/test_proto.proto
@@ -0,0 +1,20 @@
+// Copyright 2017 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.
+
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+package ipc_message_utils_test;
+
+// This is a simple dummy protocol buffer that is used for testing handling of
+// protocol buffers in ipc_message_utils.
+
+message TestMessage1 {
+    optional int32 number = 1;
+}
+
+message TestMessage2 {
+    repeated int32 numbers = 1;
+    repeated string strings = 2;
+    repeated TestMessage1 messages = 3;
+}
diff --git a/mash/BUILD.gn b/mash/BUILD.gn
index 7172fc6..5a085be1 100644
--- a/mash/BUILD.gn
+++ b/mash/BUILD.gn
@@ -107,10 +107,10 @@
       "test/mash_unittests.cc",
     ]
     deps = [
+      "//ash:test_support_without_content",
       "//ash/mus:resources",
       "//ash/mus:unittests",
       "//ash/public/cpp:ash_public_cpp",
-      "//ash/test:test_support_without_content",
       "//base",
       "//base/test:test_support",
       "//cc",
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index 0c00b97..327edad 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -248,7 +248,6 @@
       surface_manager_(params->surface_manager()),
       overlay_surface_id_(SurfaceManager::kNoSurfaceID),
       suppress_destruction_errors_(false),
-      suspend_enabled_(params->allow_suspend()),
       is_encrypted_(false),
       preroll_attempt_pending_(false),
       observer_(params->media_observer()),
@@ -2185,10 +2184,6 @@
 
 void WebMediaPlayerImpl::SetSuspendState(bool is_suspended) {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
-  if (!suspend_enabled_) {
-    DCHECK(!pipeline_controller_.IsSuspended());
-    return;
-  }
 
   // Do not change the state after an error has occurred.
   // TODO(sandersd): Update PipelineController to remove the need for this.
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h
index 58d9ff31..f86a8b4 100644
--- a/media/blink/webmediaplayer_impl.h
+++ b/media/blink/webmediaplayer_impl.h
@@ -688,9 +688,6 @@
   // unimportant.
   bool suppress_destruction_errors_;
 
-  // If true, the media pipeline can be suspended.
-  const bool suspend_enabled_;
-
   // Used for HLS playback and in certain fallback paths (e.g. on older devices
   // that can't support the unified media pipeline).
   GURL loaded_url_;
diff --git a/media/blink/webmediaplayer_impl_unittest.cc b/media/blink/webmediaplayer_impl_unittest.cc
index 3718c0e..cf4efcd 100644
--- a/media/blink/webmediaplayer_impl_unittest.cc
+++ b/media/blink/webmediaplayer_impl_unittest.cc
@@ -219,7 +219,7 @@
     media_thread_.StartAndWaitForTesting();
   }
 
-  void InitializeWebMediaPlayerImpl(bool allow_suspend) {
+  void InitializeWebMediaPlayerImpl() {
     std::unique_ptr<MediaLog> media_log(new MediaLog());
 
     auto factory_selector = base::MakeUnique<RendererFactorySelector>();
@@ -242,8 +242,7 @@
             base::Bind(&OnAdjustAllocatedMemory), nullptr, nullptr,
             RequestRoutingTokenCallback(), nullptr,
             kMaxKeyframeDistanceToDisableBackgroundVideo,
-            kMaxKeyframeDistanceToDisableBackgroundVideoMSE, false,
-            allow_suspend, false));
+            kMaxKeyframeDistanceToDisableBackgroundVideoMSE, false, false));
   }
 
   ~WebMediaPlayerImplTest() override {
@@ -396,12 +395,12 @@
 };
 
 TEST_F(WebMediaPlayerImplTest, ConstructAndDestroy) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   EXPECT_FALSE(IsSuspended());
 }
 
 TEST_F(WebMediaPlayerImplTest, IdleSuspendIsEnabledBeforeLoadingBegins) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   EXPECT_TRUE(delegate_.ExpireForTesting());
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(IsSuspended());
@@ -409,7 +408,7 @@
 
 TEST_F(WebMediaPlayerImplTest,
        IdleSuspendIsDisabledIfLoadingProgressedRecently) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   base::SimpleTestTickClock* clock = new base::SimpleTestTickClock();
   clock->Advance(base::TimeDelta::FromSeconds(1));
   SetTickClock(clock);
@@ -423,7 +422,7 @@
 }
 
 TEST_F(WebMediaPlayerImplTest, IdleSuspendIsEnabledIfLoadingHasStalled) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   base::SimpleTestTickClock* clock = new base::SimpleTestTickClock();
   clock->Advance(base::TimeDelta::FromSeconds(1));
   SetTickClock(clock);
@@ -436,16 +435,9 @@
   EXPECT_TRUE(IsSuspended());
 }
 
-TEST_F(WebMediaPlayerImplTest, DisableSuspend) {
-  InitializeWebMediaPlayerImpl(false);
-  EXPECT_TRUE(delegate_.ExpireForTesting());
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(IsSuspended());
-}
-
 TEST_F(WebMediaPlayerImplTest, DidLoadingProgressTriggersResume) {
   // Same setup as IdleSuspendIsEnabledBeforeLoadingBegins.
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   EXPECT_TRUE(delegate_.ExpireForTesting());
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(IsSuspended());
@@ -460,7 +452,7 @@
 }
 
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_Constructed) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   WebMediaPlayerImpl::PlayState state = ComputePlayState();
   EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state);
   EXPECT_TRUE(state.is_idle);
@@ -469,7 +461,7 @@
 }
 
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_HaveMetadata) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
   WebMediaPlayerImpl::PlayState state = ComputePlayState();
   EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state);
@@ -479,7 +471,7 @@
 }
 
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_HaveFutureData) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
   SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
   WebMediaPlayerImpl::PlayState state = ComputePlayState();
@@ -490,7 +482,7 @@
 }
 
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_Playing) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
   SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
   SetPaused(false);
@@ -502,7 +494,7 @@
 }
 
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_PlayingVideoOnly) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   SetMetadata(false, true);
   SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
   SetPaused(false);
@@ -514,7 +506,7 @@
 }
 
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_Underflow) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
   SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
   SetPaused(false);
@@ -527,7 +519,7 @@
 }
 
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_FrameHidden) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
   SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
   SetPaused(false);
@@ -540,7 +532,7 @@
 }
 
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_FrameHiddenAudioOnly) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
   SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
   SetPaused(false);
@@ -558,7 +550,7 @@
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndDisableFeature(kResumeBackgroundVideo);
 
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
   SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
   SetPaused(false);
@@ -581,7 +573,7 @@
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(kResumeBackgroundVideo);
 
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
   SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
   SetPaused(false);
@@ -594,7 +586,7 @@
 }
 
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_FrameClosed) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
   SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
   SetPaused(false);
@@ -607,7 +599,7 @@
 }
 
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_PausedSeek) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
   SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
   SetSeeking(true);
@@ -619,7 +611,7 @@
 }
 
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_Ended) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
   SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
   SetPaused(false);
@@ -643,7 +635,7 @@
 }
 
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_StaysSuspended) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
   SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
 
@@ -656,7 +648,7 @@
 }
 
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_Remote) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
   SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
 
@@ -669,7 +661,7 @@
 }
 
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_Fullscreen) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
   SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
   SetFullscreen(true);
@@ -685,7 +677,7 @@
 }
 
 TEST_F(WebMediaPlayerImplTest, ComputePlayState_Streaming) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
   SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
   SetPaused(true);
@@ -710,7 +702,7 @@
 }
 
 TEST_F(WebMediaPlayerImplTest, AutoplayMuted_StartsAndStops) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
   SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
   SetPaused(false);
@@ -725,7 +717,7 @@
 }
 
 TEST_F(WebMediaPlayerImplTest, AutoplayMuted_SetVolume) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   SetMetadata(true, true);
   SetReadyState(blink::WebMediaPlayer::kReadyStateHaveFutureData);
   SetPaused(false);
@@ -740,7 +732,7 @@
 }
 
 TEST_F(WebMediaPlayerImplTest, NoStreams) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   PipelineMetadata metadata;
 
   // Nothing should happen.  In particular, no assertions should fail.
@@ -748,7 +740,7 @@
 }
 
 TEST_F(WebMediaPlayerImplTest, NaturalSizeChange) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   PipelineMetadata metadata;
   metadata.has_video = true;
   metadata.natural_size = gfx::Size(320, 240);
@@ -762,7 +754,7 @@
 }
 
 TEST_F(WebMediaPlayerImplTest, NaturalSizeChange_Rotated) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   PipelineMetadata metadata;
   metadata.has_video = true;
   metadata.natural_size = gfx::Size(320, 240);
@@ -777,7 +769,7 @@
 }
 
 TEST_F(WebMediaPlayerImplTest, VideoLockedWhenPausedWhenHidden) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
 
   // Setting metadata initializes |watch_time_reporter_| used in play().
   PipelineMetadata metadata;
@@ -818,7 +810,7 @@
 }
 
 TEST_F(WebMediaPlayerImplTest, BackgroundIdlePauseTimerDependsOnAudio) {
-  InitializeWebMediaPlayerImpl(true);
+  InitializeWebMediaPlayerImpl();
   SetSuspendState(true);
   SetPaused(false);
 
@@ -883,7 +875,7 @@
 
     feature_list_.InitFromCommandLine(enabled_features, disabled_features);
 
-    InitializeWebMediaPlayerImpl(true);
+    InitializeWebMediaPlayerImpl();
     bool is_media_source = std::get<kIsMediaSource>(GetParam());
     SetLoadType(is_media_source ? blink::WebMediaPlayer::kLoadTypeMediaSource
                                 : blink::WebMediaPlayer::kLoadTypeURL);
diff --git a/media/blink/webmediaplayer_params.cc b/media/blink/webmediaplayer_params.cc
index 98a7b5eb..caf24d8 100644
--- a/media/blink/webmediaplayer_params.cc
+++ b/media/blink/webmediaplayer_params.cc
@@ -26,7 +26,6 @@
     base::TimeDelta max_keyframe_distance_to_disable_background_video,
     base::TimeDelta max_keyframe_distance_to_disable_background_video_mse,
     bool enable_instant_source_buffer_gc,
-    bool allow_suspend,
     bool embedded_media_experience_enabled)
     : defer_load_cb_(defer_load_cb),
       audio_renderer_sink_(audio_renderer_sink),
@@ -45,7 +44,6 @@
       max_keyframe_distance_to_disable_background_video_mse_(
           max_keyframe_distance_to_disable_background_video_mse),
       enable_instant_source_buffer_gc_(enable_instant_source_buffer_gc),
-      allow_suspend_(allow_suspend),
       embedded_media_experience_enabled_(embedded_media_experience_enabled) {}
 
 WebMediaPlayerParams::~WebMediaPlayerParams() {}
diff --git a/media/blink/webmediaplayer_params.h b/media/blink/webmediaplayer_params.h
index ef3f174..8dcbfba 100644
--- a/media/blink/webmediaplayer_params.h
+++ b/media/blink/webmediaplayer_params.h
@@ -64,7 +64,6 @@
       base::TimeDelta max_keyframe_distance_to_disable_background_video,
       base::TimeDelta max_keyframe_distance_to_disable_background_video_mse,
       bool enable_instant_source_buffer_gc,
-      bool allow_suspend,
       bool embedded_media_experience_enabled);
 
   ~WebMediaPlayerParams();
@@ -120,8 +119,6 @@
     return enable_instant_source_buffer_gc_;
   }
 
-  bool allow_suspend() const { return allow_suspend_; }
-
   bool embedded_media_experience_enabled() const {
     return embedded_media_experience_enabled_;
   }
@@ -147,7 +144,6 @@
   base::TimeDelta max_keyframe_distance_to_disable_background_video_;
   base::TimeDelta max_keyframe_distance_to_disable_background_video_mse_;
   bool enable_instant_source_buffer_gc_;
-  const bool allow_suspend_;
   const bool embedded_media_experience_enabled_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(WebMediaPlayerParams);
diff --git a/media/gpu/surface_texture_gl_owner.cc b/media/gpu/surface_texture_gl_owner.cc
index dda8cd75..1a40c60 100644
--- a/media/gpu/surface_texture_gl_owner.cc
+++ b/media/gpu/surface_texture_gl_owner.cc
@@ -73,12 +73,6 @@
   // Make sure that the SurfaceTexture isn't using the GL objects.
   surface_texture_ = nullptr;
 
-  if (gl::GLSurface::GetCurrent() == nullptr) {
-    // This happens during GpuCommandBufferStub teardown.  Just leave -- the gpu
-    // process is going away.  crbug.com/718117 .
-    return;
-  }
-
   ui::ScopedMakeCurrent scoped_make_current(context_.get(), surface_.get());
   if (scoped_make_current.Succeeded()) {
     glDeleteTextures(1, &texture_id_);
diff --git a/mojo/public/cpp/bindings/BUILD.gn b/mojo/public/cpp/bindings/BUILD.gn
index f68242a..f427466 100644
--- a/mojo/public/cpp/bindings/BUILD.gn
+++ b/mojo/public/cpp/bindings/BUILD.gn
@@ -22,7 +22,6 @@
     "$interfaces_bindings_gen_dir/pipe_control_messages.mojom.cc",
     "$interfaces_bindings_gen_dir/pipe_control_messages.mojom.h",
     "array_data_view.h",
-    "array_traits.h",
     "array_traits_carray.h",
     "array_traits_stl.h",
     "associated_binding.h",
@@ -110,7 +109,6 @@
     "lib/sync_handle_watcher.cc",
     "lib/task_runner_helper.cc",
     "lib/task_runner_helper.h",
-    "lib/template_util.h",
     "lib/unserialized_message_context.cc",
     "lib/unserialized_message_context.h",
     "lib/validate_params.h",
@@ -122,7 +120,6 @@
     "lib/validation_util.h",
     "map.h",
     "map_data_view.h",
-    "map_traits.h",
     "map_traits_stl.h",
     "message.h",
     "message_header_validator.h",
@@ -135,7 +132,6 @@
     "raw_ptr_impl_ref_traits.h",
     "scoped_interface_endpoint_handle.h",
     "string_data_view.h",
-    "string_traits.h",
     "string_traits_stl.h",
     "string_traits_string16.h",
     "string_traits_string_piece.h",
@@ -149,7 +145,6 @@
     "sync_handle_watcher.h",
     "thread_safe_interface_ptr.h",
     "type_converter.h",
-    "union_traits.h",
     "unique_ptr_impl_ref_traits.h",
   ]
 
@@ -171,8 +166,13 @@
 
 source_set("struct_traits") {
   sources = [
+    "array_traits.h",
     "enum_traits.h",
+    "lib/template_util.h",
+    "map_traits.h",
+    "string_traits.h",
     "struct_traits.h",
+    "union_traits.h",
   ]
 }
 
diff --git a/mojo/public/cpp/bindings/array_traits.h b/mojo/public/cpp/bindings/array_traits.h
index 594b2e07..67fe4931 100644
--- a/mojo/public/cpp/bindings/array_traits.h
+++ b/mojo/public/cpp/bindings/array_traits.h
@@ -5,6 +5,8 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_H_
 
+#include "mojo/public/cpp/bindings/lib/template_util.h"
+
 namespace mojo {
 
 // This must be specialized for any type |T| to be serialized/deserialized as
@@ -64,7 +66,11 @@
 //   };
 //
 template <typename T>
-struct ArrayTraits;
+struct ArrayTraits {
+  static_assert(internal::AlwaysFalse<T>::value,
+                "Cannot find the mojo::ArrayTraits specialization. Did you "
+                "forget to include the corresponding header file?");
+};
 
 }  // namespace mojo
 
diff --git a/mojo/public/cpp/bindings/enum_traits.h b/mojo/public/cpp/bindings/enum_traits.h
index 2c528f3..f4ba5a2 100644
--- a/mojo/public/cpp/bindings/enum_traits.h
+++ b/mojo/public/cpp/bindings/enum_traits.h
@@ -5,6 +5,8 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_ENUM_TRAITS_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_ENUM_TRAITS_H_
 
+#include "mojo/public/cpp/bindings/lib/template_util.h"
+
 namespace mojo {
 
 // This must be specialized for any type |T| to be serialized/deserialized as a
@@ -20,7 +22,11 @@
 //   };
 //
 template <typename MojomType, typename T>
-struct EnumTraits;
+struct EnumTraits {
+  static_assert(internal::AlwaysFalse<T>::value,
+                "Cannot find the mojo::EnumTraits specialization. Did you "
+                "forget to include the corresponding header file?");
+};
 
 }  // namespace mojo
 
diff --git a/mojo/public/cpp/bindings/lib/string_traits_wtf.cc b/mojo/public/cpp/bindings/lib/string_traits_wtf.cc
index 3f53f4b..a58bb1b 100644
--- a/mojo/public/cpp/bindings/lib/string_traits_wtf.cc
+++ b/mojo/public/cpp/bindings/lib/string_traits_wtf.cc
@@ -8,6 +8,7 @@
 
 #include "base/logging.h"
 #include "mojo/public/cpp/bindings/lib/array_internal.h"
+#include "mojo/public/cpp/bindings/string_data_view.h"
 #include "third_party/WebKit/Source/platform/wtf/text/StringUTF8Adaptor.h"
 
 namespace mojo {
diff --git a/mojo/public/cpp/bindings/lib/template_util.h b/mojo/public/cpp/bindings/lib/template_util.h
index 5151123..383eb91 100644
--- a/mojo/public/cpp/bindings/lib/template_util.h
+++ b/mojo/public/cpp/bindings/lib/template_util.h
@@ -114,6 +114,11 @@
   typedef F type;
 };
 
+template <typename T>
+struct AlwaysFalse {
+  static const bool value = false;
+};
+
 }  // namespace internal
 }  // namespace mojo
 
diff --git a/mojo/public/cpp/bindings/map_traits.h b/mojo/public/cpp/bindings/map_traits.h
index 5c0d8b2..c8f979d 100644
--- a/mojo/public/cpp/bindings/map_traits.h
+++ b/mojo/public/cpp/bindings/map_traits.h
@@ -5,6 +5,8 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_MAP_TRAITS_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_MAP_TRAITS_H_
 
+#include "mojo/public/cpp/bindings/lib/template_util.h"
+
 namespace mojo {
 
 // This must be specialized for any type |T| to be serialized/deserialized as
@@ -49,7 +51,11 @@
 //   };
 //
 template <typename T>
-struct MapTraits;
+struct MapTraits {
+  static_assert(internal::AlwaysFalse<T>::value,
+                "Cannot find the mojo::MapTraits specialization. Did you "
+                "forget to include the corresponding header file?");
+};
 
 }  // namespace mojo
 
diff --git a/mojo/public/cpp/bindings/string_traits.h b/mojo/public/cpp/bindings/string_traits.h
index 7d3075a5..165c9fa 100644
--- a/mojo/public/cpp/bindings/string_traits.h
+++ b/mojo/public/cpp/bindings/string_traits.h
@@ -5,7 +5,7 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_STRING_TRAITS_H_
 
-#include "mojo/public/cpp/bindings/string_data_view.h"
+#include "mojo/public/cpp/bindings/lib/template_util.h"
 
 namespace mojo {
 
@@ -47,7 +47,11 @@
 // so that you can do any necessary cleanup.
 //
 template <typename T>
-struct StringTraits;
+struct StringTraits {
+  static_assert(internal::AlwaysFalse<T>::value,
+                "Cannot find the mojo::StringTraits specialization. Did you "
+                "forget to include the corresponding header file?");
+};
 
 }  // namespace mojo
 
diff --git a/mojo/public/cpp/bindings/string_traits_string16.h b/mojo/public/cpp/bindings/string_traits_string16.h
index f96973a..ceef8f7a 100644
--- a/mojo/public/cpp/bindings/string_traits_string16.h
+++ b/mojo/public/cpp/bindings/string_traits_string16.h
@@ -7,6 +7,7 @@
 
 #include "base/strings/string16.h"
 #include "mojo/public/cpp/bindings/bindings_export.h"
+#include "mojo/public/cpp/bindings/string_data_view.h"
 #include "mojo/public/cpp/bindings/string_traits.h"
 
 namespace mojo {
diff --git a/mojo/public/cpp/bindings/struct_traits.h b/mojo/public/cpp/bindings/struct_traits.h
index 6cc070f..e27e0cd 100644
--- a/mojo/public/cpp/bindings/struct_traits.h
+++ b/mojo/public/cpp/bindings/struct_traits.h
@@ -5,6 +5,8 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_STRUCT_TRAITS_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_STRUCT_TRAITS_H_
 
+#include "mojo/public/cpp/bindings/lib/template_util.h"
+
 namespace mojo {
 
 // This must be specialized for any type |T| to be serialized/deserialized as
@@ -158,7 +160,11 @@
 //   };
 //
 template <typename DataViewType, typename T>
-struct StructTraits;
+struct StructTraits {
+  static_assert(internal::AlwaysFalse<T>::value,
+                "Cannot find the mojo::StructTraits specialization. Did you "
+                "forget to include the corresponding header file?");
+};
 
 }  // namespace mojo
 
diff --git a/mojo/public/cpp/bindings/union_traits.h b/mojo/public/cpp/bindings/union_traits.h
index 292ee58f..243addd 100644
--- a/mojo/public/cpp/bindings/union_traits.h
+++ b/mojo/public/cpp/bindings/union_traits.h
@@ -5,6 +5,8 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_UNION_TRAITS_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_UNION_TRAITS_H_
 
+#include "mojo/public/cpp/bindings/lib/template_util.h"
+
 namespace mojo {
 
 // This must be specialized for any type |T| to be serialized/deserialized as
@@ -32,7 +34,11 @@
 //      will be called.
 //
 template <typename DataViewType, typename T>
-struct UnionTraits;
+struct UnionTraits {
+  static_assert(internal::AlwaysFalse<T>::value,
+                "Cannot find the mojo::UnionTraits specialization. Did you "
+                "forget to include the corresponding header file?");
+};
 
 }  // namespace mojo
 
diff --git a/net/http/bidirectional_stream.cc b/net/http/bidirectional_stream.cc
index dbd25301..176f140 100644
--- a/net/http/bidirectional_stream.cc
+++ b/net/http/bidirectional_stream.cc
@@ -213,6 +213,12 @@
   *load_timing_info = load_timing_info_;
 }
 
+void BidirectionalStream::PopulateNetErrorDetails(NetErrorDetails* details) {
+  DCHECK(details);
+  if (stream_impl_)
+    stream_impl_->PopulateNetErrorDetails(details);
+}
+
 void BidirectionalStream::OnStreamReady(bool request_headers_sent) {
   request_headers_sent_ = request_headers_sent;
   if (net_log_.IsCapturing()) {
diff --git a/net/http/bidirectional_stream.h b/net/http/bidirectional_stream.h
index e72e7fe4..043ce80b 100644
--- a/net/http/bidirectional_stream.h
+++ b/net/http/bidirectional_stream.h
@@ -31,6 +31,7 @@
 class ProxyInfo;
 class SpdyHeaderBlock;
 struct BidirectionalStreamRequestInfo;
+struct NetErrorDetails;
 struct SSLConfig;
 
 // A class to do HTTP/2 bidirectional streaming. Note that at most one each of
@@ -170,6 +171,11 @@
   // Gets LoadTimingInfo of this stream.
   void GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const;
 
+  // Get the network error details this stream is encountering.
+  // Fills in |details| if it is available; leaves |details| unchanged if it
+  // is unavailable.
+  void PopulateNetErrorDetails(NetErrorDetails* details);
+
  private:
   // BidirectionalStreamImpl::Delegate implementation:
   void OnStreamReady(bool request_headers_sent) override;
diff --git a/net/http/bidirectional_stream_impl.h b/net/http/bidirectional_stream_impl.h
index 9b5ffab7..b5228f25 100644
--- a/net/http/bidirectional_stream_impl.h
+++ b/net/http/bidirectional_stream_impl.h
@@ -26,6 +26,7 @@
 class NetLogWithSource;
 class SpdyHeaderBlock;
 struct BidirectionalStreamRequestInfo;
+struct NetErrorDetails;
 
 // Exposes an interface to do HTTP/2 bidirectional streaming.
 // Note that only one ReadData or SendData should be in flight until the
@@ -152,6 +153,11 @@
   // and false otherwise.
   virtual bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const = 0;
 
+  // Get the network error details this stream is encountering.
+  // Fills in |details| if it is available; leaves |details| unchanged if it
+  // is unavailable.
+  virtual void PopulateNetErrorDetails(NetErrorDetails* details) = 0;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(BidirectionalStreamImpl);
 };
diff --git a/net/log/file_net_log_observer.cc b/net/log/file_net_log_observer.cc
index 49f462f..b95b203 100644
--- a/net/log/file_net_log_observer.cc
+++ b/net/log/file_net_log_observer.cc
@@ -4,10 +4,10 @@
 
 #include "net/log/file_net_log_observer.h"
 
+#include <algorithm>
 #include <limits>
 #include <memory>
 #include <queue>
-#include <set>
 #include <string>
 #include <utility>
 
@@ -25,6 +25,8 @@
 #include "net/log/net_log_util.h"
 #include "net/url_request/url_request_context.h"
 
+// TODO(eroman): Move implementations to match declaration order.
+
 namespace {
 
 // Number of events that can build up in |write_queue_| before a task is posted
@@ -45,15 +47,15 @@
 // Opens |path| in write mode. Returns the file handle on success, or nullptr on
 // failure.
 base::ScopedFILE OpenFileForWrite(const base::FilePath& path) {
-  base::ScopedFILE result(base::OpenFile(path, "w"));
+  base::ScopedFILE result(base::OpenFile(path, "wb"));
   LOG_IF(ERROR, !result) << "Failed opening: " << path.value();
   return result;
 }
 
-// Helper to write data to a file. The |file| handle may optionally be null, in
-// which case nothing will be written. Returns the number of bytes successfully
-// written (may be less than input data in case of errors).
-size_t WriteToFile(const base::ScopedFILE& file,
+// Helper that writes data to a file. The |file| handle may optionally be null,
+// in which case nothing will be written. Returns the number of bytes
+// successfully written (may be less than input data in case of errors).
+size_t WriteToFile(FILE* file,
                    base::StringPiece data1,
                    base::StringPiece data2 = base::StringPiece(),
                    base::StringPiece data3 = base::StringPiece()) {
@@ -62,20 +64,46 @@
   if (file) {
     // Append each of data1, data2 and data3.
     if (!data1.empty())
-      bytes_written += fwrite(data1.data(), 1, data1.size(), file.get());
+      bytes_written += fwrite(data1.data(), 1, data1.size(), file);
     if (!data2.empty())
-      bytes_written += fwrite(data2.data(), 1, data2.size(), file.get());
+      bytes_written += fwrite(data2.data(), 1, data2.size(), file);
     if (!data3.empty())
-      bytes_written += fwrite(data3.data(), 1, data3.size(), file.get());
+      bytes_written += fwrite(data3.data(), 1, data3.size(), file);
   }
 
   return bytes_written;
 }
 
+// Copies all of the data at |source_path| and appends it to |destination_file|,
+// then deletes |source_path|.
+void AppendToFileThenDelete(const base::FilePath& source_path,
+                            FILE* destination_file,
+                            char* read_buffer,
+                            size_t read_buffer_size) {
+  base::ScopedFILE source_file(base::OpenFile(source_path, "rb"));
+  if (!source_file)
+    return;
+
+  // Read |source_path|'s contents in chunks of read_buffer_size and append
+  // to |destination_file|.
+  size_t num_bytes_read;
+  while ((num_bytes_read =
+              fread(read_buffer, 1, read_buffer_size, source_file.get())) > 0) {
+    WriteToFile(destination_file,
+                base::StringPiece(read_buffer, num_bytes_read));
+  }
+
+  // Now that it has been copied, delete the source file.
+  source_file.reset();
+  base::DeleteFile(source_path, false);
+}
+
 }  // namespace
 
 namespace net {
 
+const size_t FileNetLogObserver::kNoLimit = std::numeric_limits<size_t>::max();
+
 // Used to store events to be written to file.
 using EventQueue = std::queue<std::unique_ptr<std::string>>;
 
@@ -148,63 +176,59 @@
   DISALLOW_COPY_AND_ASSIGN(WriteQueue);
 };
 
-// FileWriter is an interface describing an object that drains events from a
-// WriteQueue and writes them to disk.
+// FileWriter is responsible for draining events from a WriteQueue and writing
+// them to disk. FileWriter can be constructed on any thread, and
+// afterwards is only accessed on the file task runner.
 class FileNetLogObserver::FileWriter {
  public:
-  virtual ~FileWriter();
+  // If max_event_file_size == kNoLimit, then no limit is enforced.
+  FileWriter(const base::FilePath& log_path,
+             size_t max_event_file_size,
+             size_t total_num_event_files,
+             scoped_refptr<base::SequencedTaskRunner> task_runner);
+
+  ~FileWriter();
 
   // Writes |constants_value| to disk and opens the events array (closed in
   // Stop()).
-  virtual void Initialize(std::unique_ptr<base::Value> constants_value) = 0;
+  void Initialize(std::unique_ptr<base::Value> constants_value);
 
   // Closes the events array opened in Initialize() and writes |polled_data| to
   // disk. If |polled_data| cannot be converted to proper JSON, then it
   // is ignored.
-  virtual void Stop(std::unique_ptr<base::Value> polled_data) = 0;
+  void Stop(std::unique_ptr<base::Value> polled_data);
 
   // Drains |queue_| from WriteQueue into a local file queue and writes the
   // events in the queue to disk.
-  virtual void Flush(scoped_refptr<WriteQueue> write_queue) = 0;
+  void Flush(scoped_refptr<WriteQueue> write_queue);
 
   // Deletes all netlog files. It is not valid to call any method of
   // FileNetLogObserver after DeleteAllFiles().
-  virtual void DeleteAllFiles() = 0;
+  void DeleteAllFiles();
 
   void FlushThenStop(scoped_refptr<WriteQueue> write_queue,
                      std::unique_ptr<base::Value> polled_data);
-};
-
-// This implementation of FileWriter is used when the observer is in bounded
-// mode.
-// BoundedFileWriter can be constructed on any thread, and afterwards is only
-// accessed on the file task runner.
-class FileNetLogObserver::BoundedFileWriter
-    : public FileNetLogObserver::FileWriter {
- public:
-  BoundedFileWriter(const base::FilePath& directory,
-                    size_t max_file_size,
-                    size_t total_num_files,
-                    scoped_refptr<base::SequencedTaskRunner> task_runner);
-
-  ~BoundedFileWriter() override;
-
-  // FileNetLogObserver::FileWriter implementation
-  void Initialize(std::unique_ptr<base::Value> constants_value) override;
-  void Stop(std::unique_ptr<base::Value> polled_data) override;
-  void Flush(scoped_refptr<WriteQueue> write_queue) override;
-  void DeleteAllFiles() override;
 
  private:
-  // Increments |current_file_idx_|, and handles the and opening of
-  // the new current file. Also sets |current_event_file_| to point to the new
-  // file.
-  void IncrementCurrentFile();
+  // Returns true if there is no file size bound to enforce.
+  //
+  // When operating in unbounded mode, the implementation is optimized to stream
+  // writes to a single file, rather than chunking them across temporary event
+  // files.
+  bool IsUnbounded() const;
+  bool IsBounded() const;
 
-  // Sets the current events file to |index| and opens the file for writing.
-  void SetCurrentFile(size_t index);
+  // Increments |current_event_file_number_|, and updates all state relating to
+  // the current event file (open file handle, num bytes written, current file
+  // number).
+  void IncrementCurrentEventFile();
 
-  // Returns the path to the event file numbered |index|. This looks like
+  // Gets the path to a (temporary) directory where files are written in bounded
+  // mode. When logging is stopped these files are stitched together and written
+  // to the final log path.
+  base::FilePath GetInprogressDirectory() const;
+
+  // Returns the path to the event file having |index|. This looks like
   // "LOGDIR/event_file_<index>.json".
   base::FilePath GetEventFilePath(size_t index) const;
 
@@ -216,89 +240,111 @@
   // This looks like "LOGDIR/end_netlog.json".
   base::FilePath GetClosingFilePath() const;
 
+  // Returns the corresponding index for |file_number|. File "numbers" are a
+  // monotonically increasing identifier that start at 1 (a value of zero means
+  // it is uninitialized), whereas the file "index" is a bounded value that
+  // wraps and identifies the file path to use.
+  //
+  // Keeping track of the current number rather than index makes it a bit easier
+  // to assemble a file at the end, since it is unambiguous which paths have
+  // been used/re-used.
+  size_t FileNumberToIndex(size_t file_number) const;
+
+  // Writes |constants_value| to a file.
+  static void WriteConstantsToFile(std::unique_ptr<base::Value> constants_value,
+                                   FILE* file);
+
+  // Writes |polled_data| to a file.
+  static void WritePolledDataToFile(std::unique_ptr<base::Value> polled_data,
+                                    FILE* file);
+
+  // If any events were written (wrote_event_bytes_), rewinds |file| by 2 bytes
+  // in order to overwrite the trailing ",\n" that was written by the last event
+  // line.
+  void RewindIfWroteEventBytes(FILE* file) const;
+
+  // Concatenates all the log files to assemble the final
+  // |final_log_file_|. This single "stitched" file is what other
+  // log ingesting tools expect.
+  void StitchFinalLogFile();
+
+  // Creates the .inprogress directory used by bounded mode.
+  void CreateInprogressDirectory() const;
+
+  // The path (and associated file handle) where the final netlog is written. In
+  // bounded mode this is mostly written to once logging is stopped, whereas in
+  // unbounded mode events will be directly written to it.
+  const base::FilePath final_log_path_;
+  base::ScopedFILE final_log_file_;
+
   // Holds the file handle for the numbered events file where data is currently
   // being written to. The file path of this file is
-  // GetEventFilePath(current_file_idx_). The file handle may be null if an
-  // error previously occurred opening the file, or logging has been stopped.
+  // GetEventFilePath(current_event_file_number_). The
+  // file handle may be null if an error previously occurred opening the file,
+  // or logging has been stopped.
   base::ScopedFILE current_event_file_;
   size_t current_event_file_size_;
 
-  // The directory where the netlog files are created.
-  const base::FilePath directory_;
-
   // Indicates the total number of netlog event files allowed.
-  // This does not count the constants file (GetConstantsFilePath()), or the
-  // closing file (GetClosingFilePath()) against the total.
-  const size_t total_num_files_;
+  // (The files GetConstantsFilePath() and GetClosingFilePath() do
+  // not count against the total.)
+  const size_t total_num_event_files_;
 
-  // Indicates the index of the events file currently being written into.
-  size_t current_file_idx_;
+  // Counter for the events file currently being written into. See
+  // FileNumberToIndex() for an explanation of what "number" vs "index" mean.
+  size_t current_event_file_number_;
 
-  // Indicates the maximum size of each individual events file.
-  const size_t max_file_size_;
+  // Indicates the maximum size of each individual events file. May be kNoLimit
+  // to indicate that it can grow arbitrarily large.
+  const size_t max_event_file_size_;
+
+  // Whether any bytes were written for events. This is used to properly format
+  // JSON (events list shouldn't end with a comma).
+  bool wrote_event_bytes_;
 
   // Task runner for doing file operations.
   const scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
-  DISALLOW_COPY_AND_ASSIGN(BoundedFileWriter);
-};
-
-// This implementation of FileWriter is used when the observer is in unbounded
-// mode.
-// UnboundedFileWriter can be constructed on any thread, and afterwards is only
-// accessed on the file task runner.
-class FileNetLogObserver::UnboundedFileWriter
-    : public FileNetLogObserver::FileWriter {
- public:
-  UnboundedFileWriter(const base::FilePath& path,
-                      scoped_refptr<base::SequencedTaskRunner> task_runner);
-
-  ~UnboundedFileWriter() override;
-
-  // FileNetLogObserver::FileWriter implementation
-  void Initialize(std::unique_ptr<base::Value> constants_value) override;
-  void Stop(std::unique_ptr<base::Value> polled_data) override;
-  void Flush(scoped_refptr<WriteQueue> write_queue) override;
-  void DeleteAllFiles() override;
-
- private:
-  base::FilePath file_path_;
-  base::ScopedFILE file_;
-
-  // Is set to true after the first event is written to the log file.
-  bool first_event_written_;
-
-  // Task runner for doing file operations.
-  const scoped_refptr<base::SequencedTaskRunner> task_runner_;
-
-  DISALLOW_COPY_AND_ASSIGN(UnboundedFileWriter);
+  DISALLOW_COPY_AND_ASSIGN(FileWriter);
 };
 
 std::unique_ptr<FileNetLogObserver> FileNetLogObserver::CreateBounded(
-    const base::FilePath& directory,
+    const base::FilePath& log_path,
     size_t max_total_size,
-    size_t total_num_files,
     std::unique_ptr<base::Value> constants) {
-  DCHECK_GT(total_num_files, 0u);
+  // TODO(eroman): Should use something other than 10 for number of files?
+  return CreateBoundedInternal(log_path, max_total_size, 10,
+                               std::move(constants));
+}
+
+std::unique_ptr<FileNetLogObserver> FileNetLogObserver::CreateBoundedInternal(
+    const base::FilePath& log_path,
+    size_t max_total_size,
+    size_t total_num_event_files,
+    std::unique_ptr<base::Value> constants) {
+  DCHECK_GT(total_num_event_files, 0u);
 
   scoped_refptr<base::SequencedTaskRunner> file_task_runner =
       CreateFileTaskRunner();
 
-  // The BoundedFileWriter uses a soft limit to write events to file that allows
+  const size_t max_event_file_size =
+      max_total_size == kNoLimit ? kNoLimit
+                                 : max_total_size / total_num_event_files;
+
+  // The FileWriter uses a soft limit to write events to file that allows
   // the size of the file to exceed the limit, but the WriteQueue uses a hard
   // limit which the size of |WriteQueue::queue_| cannot exceed. Thus, the
-  // BoundedFileWriter may write more events to file than can be contained by
+  // FileWriter may write more events to file than can be contained by
   // the WriteQueue if they have the same size limit. The maximum size of the
   // WriteQueue is doubled to allow |WriteQueue::queue_| to hold enough events
-  // for the BoundedFileWriter to fill all files. As long as all events have
+  // for the FileWriter to fill all files. As long as all events have
   // sizes <= the size of an individual event file, the discrepancy between the
   // hard limit and the soft limit will not cause an issue.
   // TODO(dconnol): Handle the case when the WriteQueue  still doesn't
   // contain enough events to fill all files, because of very large events
   // relative to file size.
-  std::unique_ptr<FileWriter> file_writer(
-      new BoundedFileWriter(directory, max_total_size / total_num_files,
-                            total_num_files, file_task_runner));
+  std::unique_ptr<FileWriter> file_writer(new FileWriter(
+      log_path, max_event_file_size, total_num_event_files, file_task_runner));
 
   scoped_refptr<WriteQueue> write_queue(new WriteQueue(max_total_size * 2));
 
@@ -310,18 +356,7 @@
 std::unique_ptr<FileNetLogObserver> FileNetLogObserver::CreateUnbounded(
     const base::FilePath& log_path,
     std::unique_ptr<base::Value> constants) {
-  scoped_refptr<base::SequencedTaskRunner> file_task_runner =
-      CreateFileTaskRunner();
-
-  std::unique_ptr<FileWriter> file_writer(
-      new UnboundedFileWriter(log_path, file_task_runner));
-
-  scoped_refptr<WriteQueue> write_queue(
-      new WriteQueue(std::numeric_limits<size_t>::max()));
-
-  return std::unique_ptr<FileNetLogObserver>(
-      new FileNetLogObserver(file_task_runner, std::move(file_writer),
-                             std::move(write_queue), std::move(constants)));
+  return CreateBounded(log_path, kNoLimit, std::move(constants));
 }
 
 FileNetLogObserver::~FileNetLogObserver() {
@@ -380,6 +415,15 @@
   }
 }
 
+std::unique_ptr<FileNetLogObserver> FileNetLogObserver::CreateBoundedForTests(
+    const base::FilePath& log_path,
+    size_t max_total_size,
+    size_t total_num_event_files,
+    std::unique_ptr<base::Value> constants) {
+  return CreateBoundedInternal(log_path, max_total_size, total_num_event_files,
+                               std::move(constants));
+}
+
 FileNetLogObserver::FileNetLogObserver(
     scoped_refptr<base::SequencedTaskRunner> file_task_runner,
     std::unique_ptr<FileWriter> file_writer,
@@ -425,8 +469,6 @@
 
 FileNetLogObserver::WriteQueue::~WriteQueue() {}
 
-FileNetLogObserver::FileWriter::~FileWriter() {}
-
 void FileNetLogObserver::FileWriter::FlushThenStop(
     scoped_refptr<FileNetLogObserver::WriteQueue> write_queue,
     std::unique_ptr<base::Value> polled_data) {
@@ -434,91 +476,157 @@
   Stop(std::move(polled_data));
 }
 
-FileNetLogObserver::BoundedFileWriter::BoundedFileWriter(
-    const base::FilePath& directory,
-    size_t max_file_size,
-    size_t total_num_files,
+FileNetLogObserver::FileWriter::FileWriter(
+    const base::FilePath& log_path,
+    size_t max_event_file_size,
+    size_t total_num_event_files,
     scoped_refptr<base::SequencedTaskRunner> task_runner)
-    : directory_(directory),
-      total_num_files_(total_num_files),
-      current_file_idx_(0),
-      max_file_size_(max_file_size),
-      task_runner_(std::move(task_runner)) {
-}
+    : final_log_path_(log_path),
+      total_num_event_files_(total_num_event_files),
+      current_event_file_number_(0),
+      max_event_file_size_(max_event_file_size),
+      wrote_event_bytes_(false),
+      task_runner_(std::move(task_runner)) {}
 
-FileNetLogObserver::BoundedFileWriter::~BoundedFileWriter() {}
+FileNetLogObserver::FileWriter::~FileWriter() {}
 
-void FileNetLogObserver::BoundedFileWriter::Initialize(
+void FileNetLogObserver::FileWriter::Initialize(
     std::unique_ptr<base::Value> constants_value) {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
-  // Open the initial events file.
-  SetCurrentFile(0);
+  // Open the final log file, and keep it open for the duration of logging (even
+  // in bounded mode).
+  final_log_file_ = OpenFileForWrite(final_log_path_);
 
-  base::ScopedFILE constants_file = OpenFileForWrite(GetConstantsFilePath());
+  if (IsBounded()) {
+    CreateInprogressDirectory();
+    base::ScopedFILE constants_file = OpenFileForWrite(GetConstantsFilePath());
+    WriteConstantsToFile(std::move(constants_value), constants_file.get());
+  } else {
+    WriteConstantsToFile(std::move(constants_value), final_log_file_.get());
+  }
+}
 
+void FileNetLogObserver::FileWriter::WriteConstantsToFile(
+    std::unique_ptr<base::Value> constants_value,
+    FILE* file) {
   // Print constants to file and open events array.
   std::string json;
 
   // It should always be possible to convert constants to JSON.
   if (!base::JSONWriter::Write(*constants_value, &json))
     DCHECK(false);
-  WriteToFile(constants_file, "{\"constants\":", json, ",\n\"events\": [\n");
+  WriteToFile(file, "{\"constants\":", json, ",\n\"events\": [\n");
 }
 
-void FileNetLogObserver::BoundedFileWriter::Stop(
+void FileNetLogObserver::FileWriter::CreateInprogressDirectory() const {
+  DCHECK(IsBounded());
+
+  // base::CreateDirectory() creates missing parent directories. Since the
+  // target directory is a sibling to |final_log_path_|, if that file couldn't
+  // be opened don't attempt to create the directory either.
+  if (!final_log_file_)
+    return;
+
+  if (!base::CreateDirectory(GetInprogressDirectory())) {
+    LOG(WARNING) << "Failed creating directory: "
+                 << GetInprogressDirectory().value();
+    return;
+  }
+
+  // Since |final_log_file_| will not be written to until the very end, leave
+  // some data in it explaining that the real data is currently in the
+  // .inprogress directory. This ordinarily won't be visible (overwritten when
+  // stopping) however if logging does not end gracefully the comments are
+  // useful for recovery.
+  //
+  // TODO(eroman): Give a better description, including instructions on how
+  // to stitch the files manually if logging did not end gracefully.
+  WriteToFile(final_log_file_.get(),
+              "Log data is being written to the XXX.inprogress directory");
+  fflush(final_log_file_.get());
+}
+
+void FileNetLogObserver::FileWriter::Stop(
     std::unique_ptr<base::Value> polled_data) {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
-  base::ScopedFILE closing_file = OpenFileForWrite(GetClosingFilePath());
+  // Write out the polled data.
+  if (IsBounded()) {
+    base::ScopedFILE closing_file = OpenFileForWrite(GetClosingFilePath());
+    WritePolledDataToFile(std::move(polled_data), closing_file.get());
+  } else {
+    RewindIfWroteEventBytes(final_log_file_.get());
+    WritePolledDataToFile(std::move(polled_data), final_log_file_.get());
+  }
 
-  std::string json;
-  if (polled_data)
-    base::JSONWriter::Write(*polled_data, &json);
+  // If operating in bounded mode, the events were written to separate files
+  // within GetInprogressDirectory(). Assemble them into the final destination
+  // file.
+  if (IsBounded())
+    StitchFinalLogFile();
 
-  WriteToFile(closing_file, "]");
-  if (!json.empty())
-    WriteToFile(closing_file, ",\n\"polledData\": ", json, "\n");
-  WriteToFile(closing_file, "}\n");
-
-  // Close the current event file handle to ensure it flushes its writes. When
-  // the callback runs caller expects all the log files to be written and safe
-  // to read from. (Don't require the stronger guarantees of fsync() - may not
-  // be persisted to storage.).
-  current_event_file_.reset();
+  // Ensure the final log file has been flushed.
+  final_log_file_.reset();
 }
 
-void FileNetLogObserver::BoundedFileWriter::IncrementCurrentFile() {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  SetCurrentFile((current_file_idx_ + 1) % total_num_files_);
+void FileNetLogObserver::FileWriter::WritePolledDataToFile(
+    std::unique_ptr<base::Value> polled_data,
+    FILE* file) {
+  // Close the events array.
+  WriteToFile(file, "]");
+
+  // Write the polled data (if any).
+  if (polled_data) {
+    std::string polled_data_json;
+    base::JSONWriter::Write(*polled_data, &polled_data_json);
+    if (!polled_data_json.empty())
+      WriteToFile(file, ",\n\"polledData\": ", polled_data_json, "\n");
+  }
+
+  // Close the log.
+  WriteToFile(file, "}\n");
 }
 
-void FileNetLogObserver::BoundedFileWriter::SetCurrentFile(size_t index) {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  DCHECK_LT(current_file_idx_, total_num_files_);
+bool FileNetLogObserver::FileWriter::IsUnbounded() const {
+  return max_event_file_size_ == kNoLimit;
+}
 
-  current_file_idx_ = index;
-  current_event_file_ = OpenFileForWrite(GetEventFilePath(current_file_idx_));
+bool FileNetLogObserver::FileWriter::IsBounded() const {
+  return !IsUnbounded();
+}
+
+void FileNetLogObserver::FileWriter::IncrementCurrentEventFile() {
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  DCHECK(IsBounded());
+
+  current_event_file_number_++;
+  current_event_file_ = OpenFileForWrite(
+      GetEventFilePath(FileNumberToIndex(current_event_file_number_)));
   current_event_file_size_ = 0;
 }
 
-base::FilePath FileNetLogObserver::BoundedFileWriter::GetEventFilePath(
+base::FilePath FileNetLogObserver::FileWriter::GetInprogressDirectory() const {
+  return final_log_path_.AddExtension(FILE_PATH_LITERAL(".inprogress"));
+}
+
+base::FilePath FileNetLogObserver::FileWriter::GetEventFilePath(
     size_t index) const {
-  return directory_.AppendASCII("event_file_" + base::SizeTToString(index) +
-                                ".json");
+  DCHECK_LT(index, total_num_event_files_);
+  DCHECK(IsBounded());
+  return GetInprogressDirectory().AppendASCII(
+      "event_file_" + base::SizeTToString(index) + ".json");
 }
 
-base::FilePath FileNetLogObserver::BoundedFileWriter::GetConstantsFilePath()
-    const {
-  return directory_.AppendASCII("constants.json");
+base::FilePath FileNetLogObserver::FileWriter::GetConstantsFilePath() const {
+  return GetInprogressDirectory().AppendASCII("constants.json");
 }
 
-base::FilePath FileNetLogObserver::BoundedFileWriter::GetClosingFilePath()
-    const {
-  return directory_.AppendASCII("end_netlog.json");
+base::FilePath FileNetLogObserver::FileWriter::GetClosingFilePath() const {
+  return GetInprogressDirectory().AppendASCII("end_netlog.json");
 }
 
-void FileNetLogObserver::BoundedFileWriter::Flush(
+void FileNetLogObserver::FileWriter::Flush(
     scoped_refptr<FileNetLogObserver::WriteQueue> write_queue) {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
@@ -526,94 +634,102 @@
   write_queue->SwapQueue(&local_file_queue);
 
   while (!local_file_queue.empty()) {
-    if (current_event_file_size_ >= max_file_size_) {
-      // The current file is full. Start a new current file.
-      IncrementCurrentFile();
+    FILE* output_file;
+
+    // If in bounded mode, output events to the current event file. Otherwise
+    // output events to the final log path.
+    if (IsBounded()) {
+      if (current_event_file_number_ == 0 ||
+          current_event_file_size_ >= max_event_file_size_) {
+        IncrementCurrentEventFile();
+      }
+      output_file = current_event_file_.get();
+    } else {
+      output_file = final_log_file_.get();
     }
-    current_event_file_size_ +=
-        WriteToFile(current_event_file_, *local_file_queue.front(), ",\n");
+
+    size_t bytes_written =
+        WriteToFile(output_file, *local_file_queue.front(), ",\n");
+
+    wrote_event_bytes_ |= bytes_written > 0;
+
+    // Keep track of the filesize for current event file when in bounded mode.
+    if (IsBounded())
+      current_event_file_size_ += bytes_written;
+
     local_file_queue.pop();
   }
 }
 
-void FileNetLogObserver::BoundedFileWriter::DeleteAllFiles() {
+void FileNetLogObserver::FileWriter::DeleteAllFiles() {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
 
-  // Reset |current_event_file_| so base::DeleteFile() can unlink it.
+  final_log_file_.reset();
+
+  if (IsBounded()) {
+    current_event_file_.reset();
+    base::DeleteFile(GetInprogressDirectory(), true);
+  }
+
+  base::DeleteFile(final_log_path_, false);
+}
+
+size_t FileNetLogObserver::FileWriter::FileNumberToIndex(
+    size_t file_number) const {
+  DCHECK_GT(file_number, 0u);
+  // Note that "file numbers" start at 1 not 0.
+  return (file_number - 1) % total_num_event_files_;
+}
+
+void FileNetLogObserver::FileWriter::RewindIfWroteEventBytes(FILE* file) const {
+  if (file && wrote_event_bytes_) {
+    // To be valid JSON the events array should not end with a comma. If events
+    // were written though, they will have been terminated with "\n," so strip
+    // it before closing the events array.
+    fseek(file, -2, SEEK_END);
+  }
+}
+
+void FileNetLogObserver::FileWriter::StitchFinalLogFile() {
+  // Make sure all the events files are flushed (as will read them next).
   current_event_file_.reset();
 
-  base::DeleteFile(GetConstantsFilePath(), false);
-  base::DeleteFile(GetClosingFilePath(), false);
-  for (size_t i = 0; i < total_num_files_; i++)
-    base::DeleteFile(GetEventFilePath(i), false);
-}
+  // Allocate a 64K buffer used for reading the files. At most kReadBufferSize
+  // bytes will be in memory at a time.
+  const size_t kReadBufferSize = 1 << 16;  // 64KiB
+  std::unique_ptr<char[]> read_buffer(new char[kReadBufferSize]);
 
-FileNetLogObserver::UnboundedFileWriter::UnboundedFileWriter(
-    const base::FilePath& path,
-    scoped_refptr<base::SequencedTaskRunner> task_runner)
-    : file_path_(path), task_runner_(std::move(task_runner)) {}
+  // Re-open the final log file in order to truncate it.
+  final_log_file_ = OpenFileForWrite(final_log_path_);
 
-FileNetLogObserver::UnboundedFileWriter::~UnboundedFileWriter() {}
+  // Append the constants file.
+  AppendToFileThenDelete(GetConstantsFilePath(), final_log_file_.get(),
+                         read_buffer.get(), kReadBufferSize);
 
-void FileNetLogObserver::UnboundedFileWriter::Initialize(
-    std::unique_ptr<base::Value> constants_value) {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-
-  file_ = OpenFileForWrite(file_path_);
-  first_event_written_ = false;
-
-  // Print constants to file and open events array.
-  std::string json;
-
-  // It should always be possible to convert constants to JSON.
-  if (!base::JSONWriter::Write(*constants_value, &json))
-    DCHECK(false);
-  WriteToFile(file_, "{\"constants\":", json, ",\n\"events\": [\n");
-}
-
-void FileNetLogObserver::UnboundedFileWriter::Stop(
-    std::unique_ptr<base::Value> polled_data) {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-
-  std::string json;
-  if (polled_data)
-    base::JSONWriter::Write(*polled_data, &json);
-
-  WriteToFile(file_, "]");
-  if (!json.empty())
-    WriteToFile(file_, ",\n\"polledData\": ", json, "\n");
-  WriteToFile(file_, "}\n");
-
-  // Flush all writes to disk so that the file can be safely accessed on
-  // callback.
-  file_.reset();
-}
-
-void FileNetLogObserver::UnboundedFileWriter::Flush(
-    scoped_refptr<FileNetLogObserver::WriteQueue> write_queue) {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-
-  EventQueue local_file_queue;
-  write_queue->SwapQueue(&local_file_queue);
-
-  while (!local_file_queue.empty()) {
-    if (first_event_written_) {
-      WriteToFile(file_, ",\n");
-    } else {
-      first_event_written_ = true;
-    }
-    WriteToFile(file_, *local_file_queue.front());
-    local_file_queue.pop();
+  // Iterate over the events files, from oldest to most recent, and append them
+  // to the final destination. Note that "file numbers" start at 1 not 0.
+  size_t end_filenumber = current_event_file_number_ + 1;
+  size_t begin_filenumber = current_event_file_number_ <= total_num_event_files_
+                                ? 1
+                                : end_filenumber - total_num_event_files_;
+  for (size_t filenumber = begin_filenumber; filenumber < end_filenumber;
+       ++filenumber) {
+    AppendToFileThenDelete(GetEventFilePath(FileNumberToIndex(filenumber)),
+                           final_log_file_.get(), read_buffer.get(),
+                           kReadBufferSize);
   }
-}
 
-void FileNetLogObserver::UnboundedFileWriter::DeleteAllFiles() {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  // Account for the final event line ending in a ",\n". Strip it to form valid
+  // JSON.
+  RewindIfWroteEventBytes(final_log_file_.get());
 
-  // Reset |file_| to release the file handle so base::DeleteFile can
-  // safely access it.
-  file_.reset();
-  base::DeleteFile(file_path_, false);
+  // Append the polled data.
+  AppendToFileThenDelete(GetClosingFilePath(), final_log_file_.get(),
+                         read_buffer.get(), kReadBufferSize);
+
+  // Delete the inprogress directory (and anything that may still be left inside
+  // it).
+  base::DeleteFile(GetInprogressDirectory(), true);
 }
 
 }  // namespace net
diff --git a/net/log/file_net_log_observer.h b/net/log/file_net_log_observer.h
index 004b2763..18b22900 100644
--- a/net/log/file_net_log_observer.h
+++ b/net/log/file_net_log_observer.h
@@ -23,56 +23,42 @@
 class NetLogCaptureMode;
 
 // FileNetLogObserver watches the NetLog event stream and sends all entries to
-// either a group of files in a directory (bounded mode) or to a single file
-// (unbounded mode).
+// a file.
 //
-// Bounded mode:
-// The events are written to a single JSON object that is split across the
-// files, and the files must be stitched together once the observation period
-// is over. The first file is constants.json, followed by a consumer-specified
-// number of event files named event_file_<index>.json, and the last file is
-// end_netlog.json.
-//
-// The user is able to specify an approximate maximum cumulative size for the
-// netlog files and the observer overwrites old events when the maximum file
-// size is reached.
-//
-// Unbounded mode:
-// The entire JSON object is put into one file. There is no size limit to how
-// large this file can grow; all events added will be written to the file.
-//
-// The consumer must call StartObserving before calling StopObserving, and must
+// Consumers must call StartObserving before calling StopObserving, and must
 // call each method exactly once in the lifetime of the observer.
+//
+// The log will not be completely written until StopObserving is called.
+//
+// When a file size limit is given, FileNetLogObserver will create temporary
+// directory containing chunks of events. This is used to drop older events in
+// favor of newer ones.
 class NET_EXPORT FileNetLogObserver : public NetLog::ThreadSafeObserver {
  public:
-  // Creates a FileNetLogObserver in bounded mode.
+  // Special value meaning "can use an unlimited number of bytes".
+  static const size_t kNoLimit;
+
+  // Creates an instance of FileNetLogObserver that writes observed netlog
+  // events to |log_path|.
   //
-  // |directory| is the directory where the log files will be written to. The
-  // directory must already exist.
+  // |log_path| is where the final log file will be written to. If a file
+  // already exists at this path it will be overwritten. While logging is in
+  // progress, events may be written to a like-named directory.
   //
-  // |max_total_size| is the approximate limit on the cumulative size of all
-  // netlog files.
-  //
-  // |total_num_files| sets the total number of event files that are used to
-  // write the events. It must be greater than 0.
+  // |max_total_size| is the limit on how many bytes logging may consume on
+  // disk. This is an approximate limit, and in practice FileNetLogObserver may
+  // (slightly) exceed it. This may be set to kNoLimit to remove any size
+  // restrictions.
   //
   // |constants| is an optional legend for decoding constant values used in
   // the log. It should generally be a modified version of GetNetConstants().
   // If not present, the output of GetNetConstants() will be used.
   static std::unique_ptr<FileNetLogObserver> CreateBounded(
-      const base::FilePath& directory,
+      const base::FilePath& log_path,
       size_t max_total_size,
-      size_t total_num_files,
       std::unique_ptr<base::Value> constants);
 
-  // Creates a FileNetLogObserver in unbounded mode.
-  //
-  // |log_path| is where the log file will be written to. If a file already
-  // exists at this path it will be overwritten.
-  //
-  // |constants| is an optional legend for decoding constant values used in
-  // the log. It should generally be a modified version of GetNetConstants().
-  // If not present, the output of GetNetConstants() will be used.
+  // Shortcut for calling CreateBounded() with kNoLimit.
   static std::unique_ptr<FileNetLogObserver> CreateUnbounded(
       const base::FilePath& log_path,
       std::unique_ptr<base::Value> constants);
@@ -101,11 +87,23 @@
   // NetLog::ThreadSafeObserver
   void OnAddEntry(const NetLogEntry& entry) override;
 
+  // Same as CreateBounded() but you can additionally specify
+  // |total_num_event_files|.
+  static std::unique_ptr<FileNetLogObserver> CreateBoundedForTests(
+      const base::FilePath& log_path,
+      size_t max_total_size,
+      size_t total_num_event_files,
+      std::unique_ptr<base::Value> constants);
+
  private:
   class WriteQueue;
   class FileWriter;
-  class BoundedFileWriter;
-  class UnboundedFileWriter;
+
+  static std::unique_ptr<FileNetLogObserver> CreateBoundedInternal(
+      const base::FilePath& log_path,
+      size_t max_total_size,
+      size_t total_num_event_files,
+      std::unique_ptr<base::Value> constants);
 
   FileNetLogObserver(scoped_refptr<base::SequencedTaskRunner> file_task_runner,
                      std::unique_ptr<FileWriter> file_writer,
diff --git a/net/log/file_net_log_observer_unittest.cc b/net/log/file_net_log_observer_unittest.cc
index af68ee8..908b54e1 100644
--- a/net/log/file_net_log_observer_unittest.cc
+++ b/net/log/file_net_log_observer_unittest.cc
@@ -4,11 +4,8 @@
 
 #include "net/log/file_net_log_observer.h"
 
-#include <math.h>
-
 #include <memory>
 #include <string>
-#include <utility>
 #include <vector>
 
 #include "base/files/file_enumerator.h"
@@ -52,9 +49,7 @@
 // where event size doesn't matter.
 const size_t kDummyEventSize = 150;
 
-const char kWinLineEnd[] = "\r\n";
-const char kLinuxLineEnd[] = "\n";
-
+// Adds |num_entries| to |logger|. The "inverse" of this is VerifyEventsInLog().
 void AddEntries(FileNetLogObserver* logger,
                 int num_entries,
                 size_t entry_size) {
@@ -103,74 +98,147 @@
   }
 }
 
-// Loads and concatenates the contents of bounded log files into a string
-void ReadBoundedLogFiles(const base::FilePath& log_dir, std::string* input) {
-  base::ReadFileToString(log_dir.AppendASCII("constants.json"), input);
-  size_t input_no_events = input->length();
-  std::string to_add;
-  for (int i = 0; base::ReadFileToString(
-           log_dir.AppendASCII("event_file_" + std::to_string(i) + ".json"),
-           &to_add);
-       ++i) {
-    *input += to_add;
-  }
+// ParsedNetLog holds the parsed contents of a NetLog file (constants, events,
+// and polled data).
+struct ParsedNetLog {
+  ::testing::AssertionResult InitFromFileContents(const std::string& input);
+  const base::DictionaryValue* GetEvent(size_t i) const;
 
-  // Delete the hanging comma and newline from the events array.
-  if (input->length() > input_no_events) {
-    // Remove carriage returns in case of Windows machine.
-    base::ReplaceSubstringsAfterOffset(input, 0, kWinLineEnd, kLinuxLineEnd);
-    ASSERT_GE(input->length() - input_no_events, 2u);
-    ASSERT_EQ(std::string(",\n"), std::string(*input, input->length() - 2));
-    input->erase(input->end() - 2, input->end() - 1);
-  }
+  // Initializes the ParsedNetLog by parsing a JSON file.
+  // Owner for the Value tree.
+  std::unique_ptr<base::Value> container;
 
-  base::ReadFileToString(log_dir.AppendASCII("end_netlog.json"), &to_add);
-  *input += to_add;
-}
+  // A dictionary for the entire netlog.
+  const base::DictionaryValue* root = nullptr;
 
-::testing::AssertionResult ParseNetLogString(const std::string& input,
-                                             std::unique_ptr<base::Value>* root,
-                                             base::ListValue** events) {
+  // The constants dictionary.
+  const base::DictionaryValue* constants = nullptr;
+
+  // The events list.
+  const base::ListValue* events = nullptr;
+
+  // The optional polled data (may be nullptr).
+  const base::DictionaryValue* polled_data = nullptr;
+};
+
+::testing::AssertionResult ParsedNetLog::InitFromFileContents(
+    const std::string& input) {
   if (input.empty()) {
     return ::testing::AssertionFailure() << "input is empty";
   }
 
   base::JSONReader reader;
-  *root = reader.ReadToValue(input);
-  if (!*root) {
+  container = reader.ReadToValue(input);
+  if (!container) {
     return ::testing::AssertionFailure() << reader.GetErrorMessage();
   }
 
-  base::DictionaryValue* dict;
-  if (!(*root)->GetAsDictionary(&dict)) {
+  if (!container->GetAsDictionary(&root)) {
     return ::testing::AssertionFailure() << "Not a dictionary";
   }
 
-  if (!dict->GetList("events", events)) {
+  if (!root->GetList("events", &events)) {
     return ::testing::AssertionFailure() << "No events list";
   }
 
+  if (!root->GetDictionary("constants", &constants)) {
+    return ::testing::AssertionFailure() << "No constants dictionary";
+  }
+
+  // Polled data is optional (ignore success).
+  root->GetDictionary("polledData", &polled_data);
+
   return ::testing::AssertionSuccess();
 }
 
+// Returns the event at index |i|, or nullptr if there is none.
+const base::DictionaryValue* ParsedNetLog::GetEvent(size_t i) const {
+  if (!events || i >= events->GetSize())
+    return nullptr;
+
+  const base::Value* value;
+  if (!events->Get(i, &value))
+    return nullptr;
+
+  const base::DictionaryValue* dict;
+  if (!value->GetAsDictionary(&dict))
+    return nullptr;
+
+  return dict;
+}
+
+// Creates a ParsedNetLog by reading a NetLog from a file. Returns nullptr on
+// failure.
+std::unique_ptr<ParsedNetLog> ReadNetLogFromDisk(
+    const base::FilePath& log_path) {
+  std::string input;
+  if (!base::ReadFileToString(log_path, &input)) {
+    ADD_FAILURE() << "Failed reading file: " << log_path.value();
+    return nullptr;
+  }
+
+  std::unique_ptr<ParsedNetLog> result = base::MakeUnique<ParsedNetLog>();
+
+  ::testing::AssertionResult init_result = result->InitFromFileContents(input);
+  EXPECT_TRUE(init_result);
+  if (!init_result)
+    return nullptr;
+
+  return result;
+}
+
+// Checks that |log| contains events as emitted by AddEntries() above.
+// |num_events_emitted| corresponds to |num_entries| of AddEntries(). Whereas
+// |num_events_saved| is the expected number of events that have actually been
+// written to the log (post-truncation).
+void VerifyEventsInLog(const ParsedNetLog* log,
+                       size_t num_events_emitted,
+                       size_t num_events_saved) {
+  ASSERT_TRUE(log);
+  ASSERT_LE(num_events_saved, num_events_emitted);
+  ASSERT_EQ(num_events_saved, log->events->GetSize());
+
+  // The last |num_events_saved| should all be sequential, with the last one
+  // being numbered |num_events_emitted - 1|.
+  for (size_t i = 0; i < num_events_saved; ++i) {
+    const base::DictionaryValue* event = log->GetEvent(i);
+    ASSERT_TRUE(event);
+
+    size_t expected_source_id = num_events_emitted - num_events_saved + i;
+
+    const base::Value* id_value = nullptr;
+    ASSERT_TRUE(event->Get("source.id", &id_value));
+    int actual_id;
+    ASSERT_TRUE(id_value->GetAsInteger(&actual_id));
+    ASSERT_EQ(static_cast<int>(expected_source_id), actual_id);
+  }
+}
+
+// Helper that checks whether |dict| has a string property at |key| having
+// |value|.
+void ExpectDictionaryContainsProperty(const base::DictionaryValue* dict,
+                                      const std::string& key,
+                                      const std::string& value) {
+  ASSERT_TRUE(dict);
+  std::string actual_value;
+  ASSERT_TRUE(dict->GetString(key, &actual_value));
+  ASSERT_EQ(value, actual_value);
+}
+
 // Used for tests that are common to both bounded and unbounded modes of the
 // the FileNetLogObserver. The param is true if bounded mode is used.
 class FileNetLogObserverTest : public ::testing::TestWithParam<bool> {
  public:
   void SetUp() override {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-    if (IsBounded()) {
-      log_path_ = temp_dir_.GetPath();
-    } else {
-      log_path_ = temp_dir_.GetPath().AppendASCII("net-log.json");
-    }
+    log_path_ = temp_dir_.GetPath().AppendASCII("net-log.json");
   }
 
   bool IsBounded() const { return GetParam(); }
 
   void CreateAndStartObserving(std::unique_ptr<base::Value> constants) {
     if (IsBounded()) {
-      logger_ = FileNetLogObserver::CreateBounded(
+      logger_ = FileNetLogObserver::CreateBoundedForTests(
           log_path_, kLargeFileSize, kTotalNumFiles, std::move(constants));
     } else {
       logger_ =
@@ -180,37 +248,12 @@
     logger_->StartObserving(&net_log_, NetLogCaptureMode::Default());
   }
 
-  ::testing::AssertionResult ReadNetLogFromDisk(
-      std::unique_ptr<base::Value>* root,
-      base::ListValue** events) {
-    std::string input;
-    if (IsBounded()) {
-      ReadBoundedLogFiles(log_path_, &input);
-    } else {
-      base::ReadFileToString(log_path_, &input);
-    }
-    return ParseNetLogString(input, root, events);
-  }
-
-  bool LogFilesExist() {
+  bool LogFileExists() {
     // The log files are written by a sequenced task runner. Drain all the
     // scheduled tasks to ensure that the file writing ones have run before
     // checking if they exist.
     base::TaskScheduler::GetInstance()->FlushForTesting();
-
-    if (IsBounded()) {
-      if (base::PathExists(log_path_.AppendASCII("constants.json")) ||
-          base::PathExists(log_path_.AppendASCII("end_netlog.json")))
-        return true;
-      for (int i = 0; i < kTotalNumFiles; i++) {
-        if (base::PathExists(log_path_.AppendASCII(
-                "event_file_" + std::to_string(i) + ".json")))
-          return true;
-      }
-      return false;
-    } else {
-      return base::PathExists(log_path_);
-    }
+    return base::PathExists(log_path_);
   }
 
  protected:
@@ -225,48 +268,41 @@
  public:
   void SetUp() override {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-    bounded_log_dir_ = temp_dir_.GetPath();
+    log_path_ = temp_dir_.GetPath().AppendASCII("net-log.json");
   }
 
   void CreateAndStartObserving(std::unique_ptr<base::Value> constants,
                                int total_file_size,
                                int num_files) {
-    logger_ = FileNetLogObserver::CreateBounded(
-        bounded_log_dir_, total_file_size, num_files, std::move(constants));
+    logger_ = FileNetLogObserver::CreateBoundedForTests(
+        log_path_, total_file_size, num_files, std::move(constants));
     logger_->StartObserving(&net_log_, NetLogCaptureMode::Default());
   }
 
-  ::testing::AssertionResult ReadNetLogFromDisk(
-      std::unique_ptr<base::Value>* root,
-      base::ListValue** events) {
-    std::string input;
-    ReadBoundedLogFiles(bounded_log_dir_, &input);
-    return ParseNetLogString(input, root, events);
+  // Returns the path for an internally directory created for bounded logs (this
+  // needs to be kept in sync with the implementation).
+  base::FilePath GetInprogressDirectory() const {
+    return log_path_.AddExtension(FILE_PATH_LITERAL(".inprogress"));
   }
 
   base::FilePath GetEventFilePath(int index) const {
-    return bounded_log_dir_.AppendASCII("event_file_" + std::to_string(index) +
-                                        ".json");
+    return GetInprogressDirectory().AppendASCII(
+        "event_file_" + std::to_string(index) + ".json");
   }
 
   base::FilePath GetEndNetlogPath() const {
-    return bounded_log_dir_.AppendASCII("end_netlog.json");
+    return GetInprogressDirectory().AppendASCII("end_netlog.json");
   }
 
   base::FilePath GetConstantsPath() const {
-    return bounded_log_dir_.AppendASCII("constants.json");
+    return GetInprogressDirectory().AppendASCII("constants.json");
   }
 
-  static int64_t GetFileSize(const base::FilePath& path) {
-    int64_t file_size;
-    EXPECT_TRUE(base::GetFileSize(path, &file_size));
-    return file_size;
-  }
 
  protected:
   NetLog net_log_;
   std::unique_ptr<FileNetLogObserver> logger_;
-  base::FilePath bounded_log_dir_;
+  base::FilePath log_path_;
 
  private:
   base::ScopedTempDir temp_dir_;
@@ -285,13 +321,13 @@
   AddEntries(logger_.get(), 1, kDummyEventSize);
 
   // The log files should have been started.
-  ASSERT_TRUE(LogFilesExist());
+  ASSERT_TRUE(LogFileExists());
 
   logger_.reset();
 
   // When the logger is re-set without having called StopObserving(), the
   // partially written log files are deleted.
-  ASSERT_FALSE(LogFilesExist());
+  ASSERT_FALSE(LogFileExists());
 }
 
 // Tests calling StopObserving() with a null closure.
@@ -302,14 +338,14 @@
   AddEntries(logger_.get(), 1, kDummyEventSize);
 
   // The log files should have been started.
-  ASSERT_TRUE(LogFilesExist());
+  ASSERT_TRUE(LogFileExists());
 
   logger_->StopObserving(nullptr, base::OnceClosure());
 
   logger_.reset();
 
   // Since the logger was explicitly stopped, its files should still exist.
-  ASSERT_TRUE(LogFilesExist());
+  ASSERT_TRUE(LogFileExists());
 }
 
 // Tests creating a FileNetLogObserver using an invalid (can't be written to)
@@ -325,14 +361,14 @@
 
   // No log files should have been written, as the log writer will not create
   // missing directories.
-  ASSERT_FALSE(LogFilesExist());
+  ASSERT_FALSE(LogFileExists());
 
   logger_->StopObserving(nullptr, base::OnceClosure());
 
   logger_.reset();
 
   // There should still be no files.
-  ASSERT_FALSE(LogFilesExist());
+  ASSERT_FALSE(LogFileExists());
 }
 
 TEST_P(FileNetLogObserverTest, GeneratesValidJSONWithNoEvents) {
@@ -344,18 +380,10 @@
 
   closure.WaitForResult();
 
-  std::unique_ptr<base::Value> root;
-  base::ListValue* events;
-  ASSERT_TRUE(ReadNetLogFromDisk(&root, &events));
-
-  // Check that there are no events
-  ASSERT_EQ(0u, events->GetSize());
-
-  // Check that constants are printed
-  base::DictionaryValue* dict;
-  ASSERT_TRUE(root->GetAsDictionary(&dict));
-  base::DictionaryValue* constants;
-  ASSERT_TRUE(dict->GetDictionary("constants", &constants));
+  // Verify the written log.
+  std::unique_ptr<ParsedNetLog> log = ReadNetLogFromDisk(log_path_);
+  ASSERT_TRUE(log);
+  ASSERT_EQ(0u, log->events->GetSize());
 }
 
 TEST_P(FileNetLogObserverTest, GeneratesValidJSONWithOneEvent) {
@@ -370,19 +398,19 @@
 
   closure.WaitForResult();
 
-  std::unique_ptr<base::Value> root;
-  base::ListValue* events;
-  ASSERT_TRUE(ReadNetLogFromDisk(&root, &events));
-
-  // Check that there is 1 event written.
-  ASSERT_EQ(1u, events->GetSize());
+  // Verify the written log.
+  std::unique_ptr<ParsedNetLog> log = ReadNetLogFromDisk(log_path_);
+  ASSERT_TRUE(log);
+  ASSERT_EQ(1u, log->events->GetSize());
 }
 
 TEST_P(FileNetLogObserverTest, CustomConstants) {
   TestClosure closure;
 
-  const char kConstantString[] = "awesome constant";
-  std::unique_ptr<base::Value> constants(new base::Value(kConstantString));
+  const char kConstantKey[] = "magic";
+  const char kConstantString[] = "poney";
+  std::unique_ptr<base::DictionaryValue> constants(new base::DictionaryValue());
+  constants->SetString(kConstantKey, kConstantString);
 
   CreateAndStartObserving(std::move(constants));
 
@@ -390,16 +418,13 @@
 
   closure.WaitForResult();
 
-  std::unique_ptr<base::Value> root;
-  base::ListValue* events;
-  ASSERT_TRUE(ReadNetLogFromDisk(&root, &events));
+  // Verify the written log.
+  std::unique_ptr<ParsedNetLog> log = ReadNetLogFromDisk(log_path_);
+  ASSERT_TRUE(log);
 
   // Check that custom constant was correctly printed.
-  base::DictionaryValue* dict;
-  ASSERT_TRUE(root->GetAsDictionary(&dict));
-  std::string constants_string;
-  ASSERT_TRUE(dict->GetString("constants", &constants_string));
-  ASSERT_EQ(kConstantString, constants_string);
+  ExpectDictionaryContainsProperty(log->constants, kConstantKey,
+                                   kConstantString);
 }
 
 TEST_P(FileNetLogObserverTest, GeneratesValidJSONWithPolledData) {
@@ -418,21 +443,15 @@
 
   closure.WaitForResult();
 
-  std::unique_ptr<base::Value> root;
-  base::ListValue* events;
-  ASSERT_TRUE(ReadNetLogFromDisk(&root, &events));
-
-  // Check that no events were written.
-  ASSERT_EQ(0u, events->GetSize());
+  // Verify the written log.
+  std::unique_ptr<ParsedNetLog> log = ReadNetLogFromDisk(log_path_);
+  ASSERT_TRUE(log);
+  ASSERT_EQ(0u, log->events->GetSize());
 
   // Make sure additional information is present and validate it.
-  base::DictionaryValue* dict;
-  ASSERT_TRUE(root->GetAsDictionary(&dict));
-  base::DictionaryValue* polled_data;
-  std::string dummy_string;
-  ASSERT_TRUE(dict->GetDictionary("polledData", &polled_data));
-  ASSERT_TRUE(polled_data->GetString(kDummyPolledDataPath, &dummy_string));
-  ASSERT_EQ(dummy_string, kDummyPolledDataString);
+  ASSERT_TRUE(log->polled_data);
+  ExpectDictionaryContainsProperty(log->polled_data, kDummyPolledDataPath,
+                                   kDummyPolledDataString);
 }
 
 // Adds events concurrently from several different threads. The exact order of
@@ -468,11 +487,11 @@
   logger_->StopObserving(nullptr, closure.closure());
   closure.WaitForResult();
 
+  // Verify the written log.
+  std::unique_ptr<ParsedNetLog> log = ReadNetLogFromDisk(log_path_);
+  ASSERT_TRUE(log);
   // Check that the expected number of events were written to disk.
-  std::unique_ptr<base::Value> root;
-  base::ListValue* events;
-  ASSERT_TRUE(ReadNetLogFromDisk(&root, &events));
-  ASSERT_EQ(kNumEventsAddedPerThread * kNumThreads, events->GetSize());
+  EXPECT_EQ(kNumEventsAddedPerThread * kNumThreads, log->events->GetSize());
 }
 
 // Sends enough events to the observer to completely fill one file, but not
@@ -492,31 +511,10 @@
 
   closure.WaitForResult();
 
-  std::unique_ptr<base::Value> root;
-  base::ListValue* events;
-  ASSERT_TRUE(ReadNetLogFromDisk(&root, &events));
-
-  // Check that the correct number of events were written.
-  ASSERT_EQ(static_cast<size_t>(kNumEvents), events->GetSize());
-
-  // Check that the last event in array is the last event written.
-  base::Value* last_event = nullptr;
-  ASSERT_TRUE(events->Get(events->GetSize() - 1, &last_event));
-  base::DictionaryValue* dict;
-  last_event->GetAsDictionary(&dict);
-  base::Value* id_value = nullptr;
-  ASSERT_TRUE(dict->Get("source.id", &id_value));
-  int id;
-  ASSERT_TRUE(id_value->GetAsInteger(&id));
-  ASSERT_EQ(kNumEvents - 1, id);
-
-  // Check that events have been written to the first file.
-  ASSERT_GT(GetFileSize(GetEventFilePath(0)), 0);
-
-  // Check that all event files except the first do not exist.
-  for (int i = 1; i < kTotalNumFiles; i++) {
-    ASSERT_FALSE(base::PathExists(GetEventFilePath(i)));
-  }
+  // Verify the written log.
+  std::unique_ptr<ParsedNetLog> log = ReadNetLogFromDisk(log_path_);
+  ASSERT_TRUE(log);
+  VerifyEventsInLog(log.get(), kNumEvents, kNumEvents);
 }
 
 // Sends enough events to fill one file, and partially fill a second file.
@@ -540,28 +538,10 @@
 
   closure.WaitForResult();
 
-  std::unique_ptr<base::Value> root;
-  base::ListValue* events;
-  ASSERT_TRUE(ReadNetLogFromDisk(&root, &events));
-
-  // Check that the correct number of events were written.
-  ASSERT_EQ(static_cast<size_t>(kNumEvents), events->GetSize());
-
-  // Check that the last event in array is the last event written.
-  base::Value* last_event = nullptr;
-  ASSERT_TRUE(events->Get(events->GetSize() - 1, &last_event));
-  base::DictionaryValue* dict;
-  last_event->GetAsDictionary(&dict);
-  base::Value* id_value = nullptr;
-  ASSERT_TRUE(dict->Get("source.id", &id_value));
-  int id;
-  ASSERT_TRUE(id_value->GetAsInteger(&id));
-  ASSERT_EQ(kNumEvents - 1, id);
-
-  // Check that all event files except the first two do not exist.
-  for (int i = 2; i < kTotalNumFiles; i++) {
-    ASSERT_FALSE(base::PathExists(GetEventFilePath(i)));
-  }
+  // Verify the written log.
+  std::unique_ptr<ParsedNetLog> log = ReadNetLogFromDisk(log_path_);
+  ASSERT_TRUE(log);
+  VerifyEventsInLog(log.get(), kNumEvents, kNumEvents);
 }
 
 // Sends enough events to the observer to completely fill two files.
@@ -581,36 +561,10 @@
 
   closure.WaitForResult();
 
-  std::unique_ptr<base::Value> root;
-  base::ListValue* events;
-  ASSERT_TRUE(ReadNetLogFromDisk(&root, &events));
-
-  // Check that the correct number of events were written.
-  ASSERT_EQ(static_cast<size_t>(kNumEvents), events->GetSize());
-
-  // Check that the last event in array is the last event written.
-  base::Value* last_event = nullptr;
-  ASSERT_TRUE(events->Get(events->GetSize() - 1, &last_event));
-  base::DictionaryValue* dict;
-  last_event->GetAsDictionary(&dict);
-  base::Value* id_value = nullptr;
-  ASSERT_TRUE(dict->Get("source.id", &id_value));
-  int id;
-  ASSERT_TRUE(id_value->GetAsInteger(&id));
-  ASSERT_EQ(kNumEvents - 1, id);
-
-  // Check that the first two event files are full.
-  for (int i = 0; i < (kNumEvents * kEventSize) /
-                          ((kTotalFileSize - 1) / kTotalNumFiles + 1);
-       i++) {
-    ASSERT_GE(GetFileSize(GetEventFilePath(i)),
-              static_cast<int64_t>(kTotalFileSize / kTotalNumFiles));
-  }
-
-  // Check that all event files except the first two do not exist.
-  for (int i = 2; i < kTotalNumFiles; i++) {
-    ASSERT_FALSE(base::PathExists(GetEventFilePath(i)));
-  }
+  // Verify the written log.
+  std::unique_ptr<ParsedNetLog> log = ReadNetLogFromDisk(log_path_);
+  ASSERT_TRUE(log);
+  VerifyEventsInLog(log.get(), kNumEvents, kNumEvents);
 }
 
 // Sends exactly enough events to the observer to completely fill all files,
@@ -633,29 +587,10 @@
 
   closure.WaitForResult();
 
-  std::unique_ptr<base::Value> root;
-  base::ListValue* events;
-  ASSERT_TRUE(ReadNetLogFromDisk(&root, &events));
-
-  // Check that the correct number of events were written.
-  ASSERT_EQ(static_cast<size_t>(kNumEvents), events->GetSize());
-
-  // Check that the last event in array is the last event written.
-  base::Value* last_event = nullptr;
-  ASSERT_TRUE(events->Get(events->GetSize() - 1, &last_event));
-  base::DictionaryValue* dict;
-  last_event->GetAsDictionary(&dict);
-  base::Value* id_value = nullptr;
-  ASSERT_TRUE(dict->Get("source.id", &id_value));
-  int id;
-  ASSERT_TRUE(id_value->GetAsInteger(&id));
-  ASSERT_EQ(kNumEvents - 1, id);
-
-  // Check that all the event files are full.
-  for (int i = 0; i < kTotalNumFiles; i++) {
-    ASSERT_GE(GetFileSize(GetEventFilePath(i)),
-              static_cast<int64_t>(kTotalFileSize / kTotalNumFiles));
-  }
+  // Verify the written log.
+  std::unique_ptr<ParsedNetLog> log = ReadNetLogFromDisk(log_path_);
+  ASSERT_TRUE(log);
+  VerifyEventsInLog(log.get(), kNumEvents, kNumEvents);
 }
 
 // Sends more events to the observer than will fill the WriteQueue, forcing the
@@ -679,33 +614,12 @@
 
   closure.WaitForResult();
 
-  std::unique_ptr<base::Value> root;
-  base::ListValue* events;
-  ASSERT_TRUE(ReadNetLogFromDisk(&root, &events));
-
-  // Check that the correct number of events were written.
-  ASSERT_EQ(
-      static_cast<size_t>(kTotalNumFiles * ((kFileSize - 1) / kEventSize + 1)),
-      events->GetSize());
-
-  // Check that the oldest event was dropped from the queue.
-  base::Value* event_to_check = nullptr;
-  ASSERT_TRUE(events->Get(0, &event_to_check));
-  base::DictionaryValue* dict;
-  event_to_check->GetAsDictionary(&dict);
-  base::Value* id_value = nullptr;
-  ASSERT_TRUE(dict->Get("source.id", &id_value));
-  int id;
-  ASSERT_TRUE(id_value->GetAsInteger(&id));
-  ASSERT_EQ(1, id);
-
-  // Check that the last event was written last.
-  event_to_check = nullptr;
-  ASSERT_TRUE(events->Get(events->GetSize() - 1, &event_to_check));
-  event_to_check->GetAsDictionary(&dict);
-  ASSERT_TRUE(dict->Get("source.id", &id_value));
-  ASSERT_TRUE(id_value->GetAsInteger(&id));
-  ASSERT_EQ(kNumEvents - 1, id);
+  // Verify the written log.
+  std::unique_ptr<ParsedNetLog> log = ReadNetLogFromDisk(log_path_);
+  ASSERT_TRUE(log);
+  VerifyEventsInLog(
+      log.get(), kNumEvents,
+      static_cast<size_t>(kTotalNumFiles * ((kFileSize - 1) / kEventSize + 1)));
 }
 
 // Sends twice as many events as will fill all files to the observer, so that
@@ -730,10 +644,6 @@
 
   closure.WaitForResult();
 
-  std::unique_ptr<base::Value> root;
-  base::ListValue* events;
-  ASSERT_TRUE(ReadNetLogFromDisk(&root, &events));
-
   // Check that the minimum number of events that should fit in event files
   // have been written to all files.
   int events_per_file = (kFileSize - 1) / kEventSize + 1;
@@ -743,39 +653,11 @@
   int num_events_in_files =
       (kTotalNumFiles - 1) * events_per_file + events_in_last_file;
 
-  // Tracks whether each of the events that should be written to all files
-  // actually appears in the |events| array. The bool at each index corresponds
-  // to the event with id = index + |kNumEvents| - |num_events_in_files|.
-  std::vector<bool> events_written(num_events_in_files, false);
-
-  base::Value* event = nullptr;
-  base::Value* id_value = nullptr;
-  int id;
-
-  // Iterate through each event in |events| and if it is supposed to appear in
-  // file, mark the corresponding bool in |events_written| as true.
-  for (size_t i = 0; i < events->GetSize(); i++) {
-    ASSERT_TRUE(events->Get(i, &event));
-    base::DictionaryValue* dict;
-    event->GetAsDictionary(&dict);
-    ASSERT_TRUE(dict->Get("source.id", &id_value));
-    ASSERT_TRUE(id_value->GetAsInteger(&id));
-    ASSERT_LT(id, kNumEvents);
-    if (id >= kNumEvents - num_events_in_files) {
-      events_written[id - (kNumEvents - num_events_in_files)] = true;
-    }
-  }
-
-  // Check that all events that are supposed to be written to all files
-  // appeared in the |events| array.
-  ASSERT_TRUE(std::all_of(std::begin(events_written), std::end(events_written),
-                          [](bool j) { return j; }));
-
-  // Check that there are events written to all files.
-  for (int i = 0; i < kTotalNumFiles; i++) {
-    ASSERT_GE(GetFileSize(GetEventFilePath(i)),
-              static_cast<int64_t>(kEventSize));
-  }
+  // Verify the written log.
+  std::unique_ptr<ParsedNetLog> log = ReadNetLogFromDisk(log_path_);
+  ASSERT_TRUE(log);
+  VerifyEventsInLog(log.get(), kNumEvents,
+                    static_cast<size_t>(num_events_in_files));
 }
 
 // Sends enough events to the observer to fill all event files, plus overwrite
@@ -802,10 +684,6 @@
 
   closure.WaitForResult();
 
-  std::unique_ptr<base::Value> root;
-  base::ListValue* events;
-  ASSERT_TRUE(ReadNetLogFromDisk(&root, &events));
-
   // Check that the minimum number of events that should fit in event files
   // have been written to a file.
   int events_per_file = (kFileSize - 1) / kEventSize + 1;
@@ -814,29 +692,12 @@
     events_in_last_file = events_per_file;
   int num_events_in_files =
       (kTotalNumFiles - 1) * events_per_file + events_in_last_file;
-  std::vector<bool> events_written(num_events_in_files, false);
-  base::Value* event = nullptr;
-  base::Value* id_value = nullptr;
-  int id;
-  for (size_t i = 0; i < events->GetSize(); i++) {
-    ASSERT_TRUE(events->Get(i, &event));
-    base::DictionaryValue* dict;
-    event->GetAsDictionary(&dict);
-    ASSERT_TRUE(dict->Get("source.id", &id_value));
-    ASSERT_TRUE(id_value->GetAsInteger(&id));
-    ASSERT_LT(id, kNumEvents);
-    if (id >= kNumEvents - num_events_in_files) {
-      events_written[id - (kNumEvents - num_events_in_files)] = true;
-    }
-  }
-  ASSERT_TRUE(std::all_of(std::begin(events_written), std::end(events_written),
-                          [](bool j) { return j; }));
 
-  // Check that there are events written to all files.
-  for (int i = 0; i < kTotalNumFiles; i++) {
-    ASSERT_GE(GetFileSize(GetEventFilePath(i)),
-              static_cast<int64_t>(kEventSize));
-  }
+  // Verify the written log.
+  std::unique_ptr<ParsedNetLog> log = ReadNetLogFromDisk(log_path_);
+  ASSERT_TRUE(log);
+  VerifyEventsInLog(log.get(), kNumEvents,
+                    static_cast<size_t>(num_events_in_files));
 }
 
 // Start logging in bounded mode. Create directories in places where the logger
@@ -866,40 +727,81 @@
 
   closure.WaitForResult();
 
-  // Verify that the log directory only contains 3 files -- the
-  // original directories we created to block file creation, plus events.json.
-  base::FileEnumerator log_files(
-      bounded_log_dir_, /*recursive=*/true,
-      base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
+  // The written log is invalid (and hence can't be parsed). It is just the
+  // constants.
+  std::string log_contents;
+  ASSERT_TRUE(base::ReadFileToString(log_path_, &log_contents));
+  // TODO(eroman): Verify the partially written log file?
 
-  int matched_files = 0;
-  for (base::FilePath name = log_files.Next(); !name.empty();
-       name = log_files.Next()) {
-    // Either constants.json
-    if (name == GetConstantsPath()) {
-      matched_files++;
-      EXPECT_FALSE(log_files.GetInfo().IsDirectory());
-      continue;
-    }
+  // Even though FileNetLogObserver didn't create the directory itself, it will
+  // unconditionally delete it. The name should be uncommon enough for this be
+  // to reasonable.
+  EXPECT_FALSE(base::PathExists(GetInprogressDirectory()));
+}
 
-    // Or event_file_0.json
-    if (name == GetEventFilePath(0)) {
-      matched_files++;
-      EXPECT_TRUE(log_files.GetInfo().IsDirectory());
-      continue;
-    }
+// Start logging in bounded mode. Create a file at the path where the logger
+// expects to create its inprogress directory to store event files. This will
+// cause logging to completely break. open it.
+TEST_F(FileNetLogObserverBoundedTest, InprogressDirectoryBlocked) {
+  // The total size of events is equal to the total size of all files.
+  // |kEventSize| * |kNumEvents| = |kTotalFileSize|
+  const int kTotalFileSize = 10000;
+  const int kEventSize = 200;
+  const int kFileSize = kTotalFileSize / kTotalNumFiles;
+  const int kNumEvents = kTotalNumFiles * ((kFileSize - 1) / kEventSize + 1);
+  TestClosure closure;
 
-    // Or end_netlog.json
-    if (name == GetEndNetlogPath()) {
-      matched_files++;
-      EXPECT_TRUE(log_files.GetInfo().IsDirectory());
-      continue;
-    }
+  // By creating a file where a directory should be, it will not be possible to
+  // write any event files.
+  EXPECT_TRUE(base::WriteFile(GetInprogressDirectory(), "x", 1));
 
-    ADD_FAILURE() << "Unexpected file: " << name.value();
-  }
+  CreateAndStartObserving(nullptr, kTotalFileSize, kTotalNumFiles);
 
-  EXPECT_EQ(3, matched_files);
+  AddEntries(logger_.get(), kNumEvents, kEventSize);
+
+  logger_->StopObserving(nullptr, closure.closure());
+
+  closure.WaitForResult();
+
+  // There will be a log file at the final output, however it will be empty
+  // since nothing was written to the .inprogress directory.
+  std::string log_contents;
+  ASSERT_TRUE(base::ReadFileToString(log_path_, &log_contents));
+  EXPECT_EQ("", log_contents);
+
+  // FileNetLogObserver unconditionally deletes the inprogress path (even though
+  // it didn't actually create this file and it was a file instead of a
+  // directory).
+  // TODO(eroman): Should it only delete if it is a file?
+  EXPECT_FALSE(base::PathExists(GetInprogressDirectory()));
+}
+
+// Start logging in bounded mode. Create a file with the same name as the 0th
+// events file. This will prevent any events from being written.
+TEST_F(FileNetLogObserverBoundedTest, BlockEventsFile0) {
+  // The total size of events is equal to the total size of all files.
+  // |kEventSize| * |kNumEvents| = |kTotalFileSize|
+  const int kTotalFileSize = 10000;
+  const int kEventSize = 200;
+  const int kFileSize = kTotalFileSize / kTotalNumFiles;
+  const int kNumEvents = kTotalNumFiles * ((kFileSize - 1) / kEventSize + 1);
+  TestClosure closure;
+
+  // Block the 0th events file.
+  EXPECT_TRUE(base::CreateDirectory(GetEventFilePath(0)));
+
+  CreateAndStartObserving(nullptr, kTotalFileSize, kTotalNumFiles);
+
+  AddEntries(logger_.get(), kNumEvents, kEventSize);
+
+  logger_->StopObserving(nullptr, closure.closure());
+
+  closure.WaitForResult();
+
+  // Verify the written log.
+  std::unique_ptr<ParsedNetLog> log = ReadNetLogFromDisk(log_path_);
+  ASSERT_TRUE(log);
+  ASSERT_EQ(0u, log->events->GetSize());
 }
 
 void AddEntriesViaNetLog(NetLog* net_log, int num_entries) {
@@ -939,7 +841,7 @@
   // Join all the threads.
   threads.clear();
 
-  ASSERT_TRUE(LogFilesExist());
+  ASSERT_TRUE(LogFileExists());
 }
 
 TEST_P(FileNetLogObserverTest,
@@ -973,7 +875,7 @@
   threads.clear();
 
   // The log file doesn't exist since StopObserving() was not called.
-  ASSERT_FALSE(LogFilesExist());
+  ASSERT_FALSE(LogFileExists());
 }
 
 }  // namespace
diff --git a/net/log/net_log_event_type_list.h b/net/log/net_log_event_type_list.h
index 4570eaa..aeb7fce 100644
--- a/net/log/net_log_event_type_list.h
+++ b/net/log/net_log_event_type_list.h
@@ -1378,18 +1378,17 @@
 //   }
 EVENT_TYPE(HTTP2_SESSION_RECV_HEADERS)
 
-// On sending an HTTP/2 SETTINGS frame.
+// On sending an HTTP/2 SETTINGS frame without ACK flag.
 // The following parameters are attached:
 //   {
-//     "settings": <The list of setting id, flags and value>,
+//     "settings": <The list of setting ids and values>,
 //   }
 EVENT_TYPE(HTTP2_SESSION_SEND_SETTINGS)
 
-// Receipt of an HTTP/2 SETTINGS frame.
-// The following parameters are attached:
-//   {
-//     "host": <The host-port string>,
-//   }
+// On sending an HTTP/2 SETTINGS frame with ACK flag.
+EVENT_TYPE(HTTP2_SESSION_SEND_SETTINGS_ACK)
+
+// Receipt of an HTTP/2 SETTINGS frame without ACK flag.
 EVENT_TYPE(HTTP2_SESSION_RECV_SETTINGS)
 
 // Receipt of an individual HTTP/2 setting.
@@ -1400,6 +1399,9 @@
 //   }
 EVENT_TYPE(HTTP2_SESSION_RECV_SETTING)
 
+// Receipt of an HTTP/2 SETTINGS frame with ACK flag.
+EVENT_TYPE(HTTP2_SESSION_RECV_SETTINGS_ACK)
+
 // The receipt of a RST_STREAM frame.
 // The following parameters are attached:
 //   {
@@ -1468,6 +1470,7 @@
 //   {
 //     "header_name": <The header name>,
 //     "header_value": <The header value>,
+//     "error": <Error message>,
 //   }
 EVENT_TYPE(HTTP2_SESSION_RECV_INVALID_HEADER)
 
diff --git a/net/quic/chromium/bidirectional_stream_quic_impl.cc b/net/quic/chromium/bidirectional_stream_quic_impl.cc
index c10720d5..648056a 100644
--- a/net/quic/chromium/bidirectional_stream_quic_impl.cc
+++ b/net/quic/chromium/bidirectional_stream_quic_impl.cc
@@ -17,6 +17,7 @@
 #include "net/socket/next_proto.h"
 #include "net/spdy/chromium/spdy_http_utils.h"
 #include "net/spdy/core/spdy_header_block.h"
+#include "quic_http_stream.h"
 
 namespace net {
 namespace {
@@ -226,6 +227,16 @@
   return true;
 }
 
+void BidirectionalStreamQuicImpl::PopulateNetErrorDetails(
+    NetErrorDetails* details) {
+  DCHECK(details);
+  details->connection_info =
+      QuicHttpStream::ConnectionInfoFromQuicVersion(session_->GetQuicVersion());
+  session_->PopulateNetErrorDetails(details);
+  if (session_->IsCryptoHandshakeConfirmed() && stream_)
+    details->quic_connection_error = stream_->connection_error();
+}
+
 void BidirectionalStreamQuicImpl::OnStreamReady(int rv) {
   DCHECK_NE(ERR_IO_PENDING, rv);
   DCHECK(!stream_);
diff --git a/net/quic/chromium/bidirectional_stream_quic_impl.h b/net/quic/chromium/bidirectional_stream_quic_impl.h
index 8ec93aee..8b63600bd 100644
--- a/net/quic/chromium/bidirectional_stream_quic_impl.h
+++ b/net/quic/chromium/bidirectional_stream_quic_impl.h
@@ -51,6 +51,7 @@
   int64_t GetTotalReceivedBytes() const override;
   int64_t GetTotalSentBytes() const override;
   bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override;
+  void PopulateNetErrorDetails(NetErrorDetails* details) override;
 
  private:
   int WriteHeaders();
diff --git a/net/quic/core/frames/quic_ack_frame.cc b/net/quic/core/frames/quic_ack_frame.cc
index 6c75614..77016b9d 100644
--- a/net/quic/core/frames/quic_ack_frame.cc
+++ b/net/quic/core/frames/quic_ack_frame.cc
@@ -6,9 +6,40 @@
 
 #include "net/quic/core/quic_constants.h"
 #include "net/quic/platform/api/quic_bug_tracker.h"
+#include "net/quic/platform/api/quic_flag_utils.h"
 
 namespace net {
 
+PacketNumberQueue::const_iterator::const_iterator(const const_iterator& other) =
+    default;
+PacketNumberQueue::const_iterator::const_iterator(const_iterator&& other) =
+    default;
+PacketNumberQueue::const_iterator::~const_iterator() {}
+
+PacketNumberQueue::const_iterator::const_iterator(
+    typename QuicIntervalSet<QuicPacketNumber>::const_iterator it)
+    : vector_it_(it), use_deque_it_(false) {}
+
+PacketNumberQueue::const_reverse_iterator::const_reverse_iterator(
+    const const_reverse_iterator& other) = default;
+PacketNumberQueue::const_reverse_iterator::const_reverse_iterator(
+    const_reverse_iterator&& other) = default;
+PacketNumberQueue::const_reverse_iterator::~const_reverse_iterator() {}
+
+PacketNumberQueue::const_iterator::const_iterator(
+    typename std::deque<Interval<QuicPacketNumber>>::const_iterator it)
+    : deque_it_(it), use_deque_it_(true) {}
+
+PacketNumberQueue::const_reverse_iterator::const_reverse_iterator(
+    const typename QuicIntervalSet<QuicPacketNumber>::const_reverse_iterator&
+        it)
+    : vector_it_(it), use_deque_it_(false) {}
+
+PacketNumberQueue::const_reverse_iterator::const_reverse_iterator(
+    const typename std::deque<
+        Interval<QuicPacketNumber>>::const_reverse_iterator& it)
+    : deque_it_(it), use_deque_it_(true) {}
+
 bool IsAwaitingPacket(const QuicAckFrame& ack_frame,
                       QuicPacketNumber packet_number,
                       QuicPacketNumber peer_least_packet_awaiting_ack) {
@@ -35,8 +66,13 @@
   os << " ] }\n";
   return os;
 }
+PacketNumberQueue::PacketNumberQueue()
+    : use_deque_(FLAGS_quic_reloadable_flag_quic_frames_deque) {
+  if (use_deque_) {
+    QUIC_FLAG_COUNT(quic_reloadable_flag_quic_frames_deque);
+  }
+}
 
-PacketNumberQueue::PacketNumberQueue() = default;
 PacketNumberQueue::PacketNumberQueue(const PacketNumberQueue& other) = default;
 PacketNumberQueue::PacketNumberQueue(PacketNumberQueue&& other) = default;
 PacketNumberQueue::~PacketNumberQueue() {}
@@ -47,80 +83,270 @@
     default;
 
 void PacketNumberQueue::Add(QuicPacketNumber packet_number) {
-  packet_number_intervals_.Add(packet_number, packet_number + 1);
+  if (use_deque_) {
+    // Check if the deque is empty
+    if (packet_number_deque_.empty()) {
+      packet_number_deque_.push_front(
+          Interval<QuicPacketNumber>(packet_number, packet_number + 1));
+      return;
+    }
+
+    // Check for the typical case,
+    // when the next packet in order is acked
+    if ((packet_number_deque_.back()).max() == packet_number) {
+      (packet_number_deque_.back()).SetMax(packet_number + 1);
+      return;
+    }
+    // Check if the next packet in order is skipped
+    if ((packet_number_deque_.back()).max() < packet_number) {
+      packet_number_deque_.push_back(
+          Interval<QuicPacketNumber>(packet_number, packet_number + 1));
+      return;
+    }
+    // Check if the packet can be  popped on the front
+    if ((packet_number_deque_.front()).min() > packet_number + 1) {
+      packet_number_deque_.push_front(
+          Interval<QuicPacketNumber>(packet_number, packet_number + 1));
+      return;
+    }
+    if ((packet_number_deque_.front()).min() == packet_number + 1) {
+      (packet_number_deque_.front()).SetMin(packet_number);
+      return;
+    }
+
+    int i = packet_number_deque_.size() - 1;
+    // Iterating through the queue backwards
+    // to find a proper place for the packet
+    while (i >= 0) {
+      // Check if the packet is contained in an interval already
+      if (packet_number_deque_[i].max() > packet_number &&
+          packet_number_deque_[i].min() <= packet_number) {
+        return;
+      }
+
+      // Check if the packet can extend an interval
+      // and merges two intervals if needed
+      if (packet_number_deque_[i].max() == packet_number) {
+        packet_number_deque_[i].SetMax(packet_number + 1);
+        if (static_cast<size_t>(i) < packet_number_deque_.size() - 1 &&
+            packet_number_deque_[i].max() ==
+                packet_number_deque_[i + 1].min()) {
+          packet_number_deque_[i].SetMax(packet_number_deque_[i + 1].max());
+          packet_number_deque_.erase(packet_number_deque_.begin() + i + 1);
+        }
+        return;
+      }
+      if (packet_number_deque_[i].min() == packet_number + 1) {
+        packet_number_deque_[i].SetMin(packet_number);
+        if (i > 0 && packet_number_deque_[i].min() ==
+                         packet_number_deque_[i - 1].max()) {
+          packet_number_deque_[i - 1].SetMax(packet_number_deque_[i].max());
+          packet_number_deque_.erase(packet_number_deque_.begin() + i);
+        }
+        return;
+      }
+
+      // Check if we need to make a new interval for the packet
+      if (packet_number_deque_[i].max() < packet_number + 1) {
+        packet_number_deque_.insert(
+            packet_number_deque_.begin() + i + 1,
+            Interval<QuicPacketNumber>(packet_number, packet_number + 1));
+        return;
+      }
+      i--;
+    }
+  } else {
+    packet_number_intervals_.Add(packet_number, packet_number + 1);
+  }
 }
 
 void PacketNumberQueue::Add(QuicPacketNumber lower, QuicPacketNumber higher) {
-  packet_number_intervals_.Add(lower, higher);
-}
+  if (lower >= higher) {
+    return;
+  }
+  if (use_deque_) {
+    if (packet_number_deque_.empty()) {
+      packet_number_deque_.push_front(
+          Interval<QuicPacketNumber>(lower, higher));
 
+    } else if ((packet_number_deque_.back()).max() == lower) {
+      // Check for the typical case,
+      // when the next packet in order is acked
+      (packet_number_deque_.back()).SetMax(higher);
+
+    } else if ((packet_number_deque_.back()).max() < lower) {
+      // Check if the next packet in order is skipped
+      packet_number_deque_.push_back(Interval<QuicPacketNumber>(lower, higher));
+
+      // Check if the packets are being added in reverse order
+    } else if ((packet_number_deque_.front()).min() == higher) {
+      (packet_number_deque_.front()).SetMax(lower);
+    } else if ((packet_number_deque_.front()).min() > higher) {
+      packet_number_deque_.push_front(
+          Interval<QuicPacketNumber>(lower, higher));
+
+    } else {
+      // Iterating through the interval and adding packets one by one
+      for (size_t i = lower; i != higher; i++) {
+        PacketNumberQueue::Add(i);
+      }
+    }
+  } else {
+    packet_number_intervals_.Add(lower, higher);
+  }
+}
 
 bool PacketNumberQueue::RemoveUpTo(QuicPacketNumber higher) {
   if (Empty()) {
     return false;
   }
   const QuicPacketNumber old_min = Min();
-  packet_number_intervals_.Difference(0, higher);
+  if (use_deque_) {
+    while (!packet_number_deque_.empty()) {
+      if (packet_number_deque_[0].max() < higher) {
+        packet_number_deque_.pop_front();
+      } else if (packet_number_deque_[0].min() < higher &&
+                 packet_number_deque_[0].max() >= higher) {
+        packet_number_deque_[0].SetMin(higher);
+        if (packet_number_deque_[0].max() == packet_number_deque_[0].min()) {
+          packet_number_deque_.pop_front();
+        }
+        break;
+      } else {
+        break;
+      }
+    }
+  } else {
+    packet_number_intervals_.Difference(0, higher);
+  }
+
   return Empty() || old_min != Min();
 }
 
 void PacketNumberQueue::RemoveSmallestInterval() {
-  QUIC_BUG_IF(packet_number_intervals_.Size() < 2)
-      << (Empty() ? "No intervals to remove."
-                  : "Can't remove the last interval.");
-
-  packet_number_intervals_.Difference(*packet_number_intervals_.begin());
+  if (use_deque_) {
+    QUIC_BUG_IF(packet_number_deque_.size() < 2)
+        << (Empty() ? "No intervals to remove."
+                    : "Can't remove the last interval.");
+    packet_number_deque_.pop_front();
+  } else {
+    QUIC_BUG_IF(packet_number_intervals_.Size() < 2)
+        << (Empty() ? "No intervals to remove."
+                    : "Can't remove the last interval.");
+    packet_number_intervals_.Difference(*packet_number_intervals_.begin());
+  }
 }
 
 bool PacketNumberQueue::Contains(QuicPacketNumber packet_number) const {
-  return packet_number_intervals_.Contains(packet_number);
+  if (use_deque_) {
+    // TODO(lilika): Consider using std::binary_search based on profiles
+    // http://www.cplusplus.com/reference/algorithm/binary_search/
+    if (packet_number_deque_.empty()) {
+      return false;
+    }
+    for (Interval<QuicPacketNumber> interval : packet_number_deque_) {
+      if (packet_number < interval.min()) {
+        return false;
+      }
+      if (interval.min() <= packet_number && interval.max() > packet_number) {
+        return true;
+      }
+    }
+    return false;
+  } else {
+    return packet_number_intervals_.Contains(packet_number);
+  }
 }
 
 bool PacketNumberQueue::Empty() const {
-  return packet_number_intervals_.Empty();
+  if (use_deque_) {
+    return packet_number_deque_.empty();
+  } else {
+    return packet_number_intervals_.Empty();
+  }
 }
 
 QuicPacketNumber PacketNumberQueue::Min() const {
   DCHECK(!Empty());
-  return packet_number_intervals_.begin()->min();
+  if (use_deque_) {
+    return packet_number_deque_[0].min();
+  } else {
+    return packet_number_intervals_.begin()->min();
+  }
 }
 
 QuicPacketNumber PacketNumberQueue::Max() const {
   DCHECK(!Empty());
-  return packet_number_intervals_.rbegin()->max() - 1;
+  if (use_deque_) {
+    return packet_number_deque_[packet_number_deque_.size() - 1].max() - 1;
+  } else {
+    return packet_number_intervals_.rbegin()->max() - 1;
+  }
 }
 
 size_t PacketNumberQueue::NumPacketsSlow() const {
-  size_t num_packets = 0;
-  for (const auto& interval : packet_number_intervals_) {
-    num_packets += interval.Length();
+  if (use_deque_) {
+    size_t n_packets = 0;
+    for (size_t i = 0; i < packet_number_deque_.size(); i++) {
+      n_packets += packet_number_deque_[i].Length();
+    }
+    return n_packets;
+  } else {
+    size_t num_packets = 0;
+    for (const auto& interval : packet_number_intervals_) {
+      num_packets += interval.Length();
+    }
+    return num_packets;
   }
-  return num_packets;
 }
 
 size_t PacketNumberQueue::NumIntervals() const {
-  return packet_number_intervals_.Size();
+  if (use_deque_) {
+    return packet_number_deque_.size();
+  } else {
+    return packet_number_intervals_.Size();
+  }
+}
+
+PacketNumberQueue::const_iterator PacketNumberQueue::begin() const {
+  if (use_deque_) {
+    return PacketNumberQueue::const_iterator(packet_number_deque_.begin());
+  } else {
+    return PacketNumberQueue::const_iterator(packet_number_intervals_.begin());
+  }
+}
+
+PacketNumberQueue::const_iterator PacketNumberQueue::end() const {
+  if (use_deque_) {
+    return const_iterator(packet_number_deque_.end());
+  } else {
+    return const_iterator(packet_number_intervals_.end());
+  }
+}
+
+PacketNumberQueue::const_reverse_iterator PacketNumberQueue::rbegin() const {
+  if (use_deque_) {
+    return const_reverse_iterator(packet_number_deque_.rbegin());
+  } else {
+    return const_reverse_iterator(packet_number_intervals_.rbegin());
+  }
+}
+
+PacketNumberQueue::const_reverse_iterator PacketNumberQueue::rend() const {
+  if (use_deque_) {
+    return const_reverse_iterator(packet_number_deque_.rend());
+  } else {
+    return const_reverse_iterator(packet_number_intervals_.rend());
+  }
 }
 
 QuicPacketNumber PacketNumberQueue::LastIntervalLength() const {
   DCHECK(!Empty());
-  return packet_number_intervals_.rbegin()->Length();
-}
-
-PacketNumberQueue::const_iterator PacketNumberQueue::begin() const {
-  return packet_number_intervals_.begin();
-}
-
-PacketNumberQueue::const_iterator PacketNumberQueue::end() const {
-  return packet_number_intervals_.end();
-}
-
-PacketNumberQueue::const_reverse_iterator PacketNumberQueue::rbegin() const {
-  return packet_number_intervals_.rbegin();
-}
-
-PacketNumberQueue::const_reverse_iterator PacketNumberQueue::rend() const {
-  return packet_number_intervals_.rend();
+  if (use_deque_) {
+    return packet_number_deque_[packet_number_deque_.size() - 1].Length();
+  } else {
+    return packet_number_intervals_.rbegin()->Length();
+  }
 }
 
 std::ostream& operator<<(std::ostream& os, const PacketNumberQueue& q) {
diff --git a/net/quic/core/frames/quic_ack_frame.h b/net/quic/core/frames/quic_ack_frame.h
index a4dc93d..c7584c1 100644
--- a/net/quic/core/frames/quic_ack_frame.h
+++ b/net/quic/core/frames/quic_ack_frame.h
@@ -5,12 +5,14 @@
 #ifndef NET_QUIC_CORE_FRAMES_QUIC_ACK_FRAME_H_
 #define NET_QUIC_CORE_FRAMES_QUIC_ACK_FRAME_H_
 
+#include <deque>
 #include <ostream>
 #include <string>
 
 #include "net/quic/core/quic_types.h"
 #include "net/quic/platform/api/quic_containers.h"
 #include "net/quic/platform/api/quic_export.h"
+#include "net/quic/platform/api/quic_flags.h"
 
 namespace net {
 
@@ -19,10 +21,6 @@
 // larger new packet numbers are added, with the occasional random access.
 class QUIC_EXPORT_PRIVATE PacketNumberQueue {
  public:
-  using const_iterator = QuicIntervalSet<QuicPacketNumber>::const_iterator;
-  using const_reverse_iterator =
-      QuicIntervalSet<QuicPacketNumber>::const_reverse_iterator;
-
   PacketNumberQueue();
   PacketNumberQueue(const PacketNumberQueue& other);
   PacketNumberQueue(PacketNumberQueue&& other);
@@ -31,6 +29,170 @@
   PacketNumberQueue& operator=(const PacketNumberQueue& other);
   PacketNumberQueue& operator=(PacketNumberQueue&& other);
 
+  class QUIC_EXPORT_PRIVATE const_iterator {
+   public:
+    const_iterator(const const_iterator& other);
+    const_iterator(const_iterator&& other);
+    ~const_iterator();
+
+    explicit const_iterator(
+        typename QuicIntervalSet<QuicPacketNumber>::const_iterator it);
+
+    explicit const_iterator(
+        typename std::deque<Interval<QuicPacketNumber>>::const_iterator it);
+
+    typedef std::input_iterator_tag iterator_category;
+    typedef Interval<QuicPacketNumber> value_type;
+    typedef value_type& reference;
+    typedef value_type* pointer;
+    typedef typename std::vector<value_type>::iterator::difference_type
+        difference_type;
+
+    inline const Interval<QuicPacketNumber>& operator*() {
+      if (use_deque_it_) {
+        return *deque_it_;
+      } else {
+        return *vector_it_;
+      }
+    }
+
+    inline const_iterator& operator++() {
+      if (use_deque_it_) {
+        deque_it_++;
+      } else {
+        vector_it_++;
+      }
+      return *this;
+    }
+
+    inline const_iterator& operator--() {
+      if (use_deque_it_) {
+        deque_it_--;
+      } else {
+        vector_it_--;
+      }
+      return *this;
+    }
+
+    inline const_iterator& operator++(int) {
+      if (use_deque_it_) {
+        ++deque_it_;
+      } else {
+        ++vector_it_;
+      }
+      return *this;
+    }
+
+    inline bool operator==(const const_iterator& other) {
+      if (use_deque_it_ != other.use_deque_it_) {
+        return false;
+      }
+
+      if (use_deque_it_) {
+        return deque_it_ == other.deque_it_;
+      } else {
+        return vector_it_ == other.vector_it_;
+      }
+    }
+
+    inline bool operator!=(const const_iterator& other) {
+      return !(*this == other);
+    }
+
+   private:
+    typename QuicIntervalSet<QuicPacketNumber>::const_iterator vector_it_;
+    typename std::deque<Interval<QuicPacketNumber>>::const_iterator deque_it_;
+    const bool use_deque_it_;
+  };
+
+  class QUIC_EXPORT_PRIVATE const_reverse_iterator {
+   public:
+    const_reverse_iterator(const const_reverse_iterator& other);
+    const_reverse_iterator(const_reverse_iterator&& other);
+    ~const_reverse_iterator();
+
+    explicit const_reverse_iterator(
+        const typename QuicIntervalSet<
+            QuicPacketNumber>::const_reverse_iterator& it);
+
+    explicit const_reverse_iterator(
+        const typename std::deque<
+            Interval<QuicPacketNumber>>::const_reverse_iterator& it);
+
+    typedef std::input_iterator_tag iterator_category;
+    typedef Interval<QuicPacketNumber> value_type;
+    typedef value_type& reference;
+    typedef value_type* pointer;
+    typedef typename std::vector<value_type>::iterator::difference_type
+        difference_type;
+
+    inline const Interval<QuicPacketNumber>& operator*() {
+      if (use_deque_it_) {
+        return *deque_it_;
+      } else {
+        return *vector_it_;
+      }
+    }
+
+    inline const Interval<QuicPacketNumber>* operator->() {
+      if (use_deque_it_) {
+        return &*deque_it_;
+      } else {
+        return &*vector_it_;
+      }
+    }
+
+    inline const_reverse_iterator& operator++() {
+      if (use_deque_it_) {
+        deque_it_++;
+      } else {
+        vector_it_++;
+      }
+      return *this;
+    }
+
+    inline const_reverse_iterator& operator--() {
+      if (use_deque_it_) {
+        deque_it_--;
+      } else {
+        vector_it_--;
+      }
+      return *this;
+    }
+
+    inline const_reverse_iterator& operator++(int) {
+      if (use_deque_it_) {
+        ++deque_it_;
+      } else {
+        ++vector_it_;
+      }
+      return *this;
+    }
+
+    inline bool operator==(const const_reverse_iterator& other) {
+      if (use_deque_it_ != other.use_deque_it_) {
+        return false;
+      }
+
+      if (use_deque_it_) {
+        return deque_it_ == other.deque_it_;
+      } else {
+        return vector_it_ == other.vector_it_;
+      }
+    }
+
+    inline bool operator!=(const const_reverse_iterator& other) {
+      return !(*this == other);
+    }
+
+   private:
+    typename QuicIntervalSet<QuicPacketNumber>::const_reverse_iterator
+        vector_it_;
+    typename std::deque<Interval<QuicPacketNumber>>::const_reverse_iterator
+        deque_it_;
+    const bool use_deque_it_;
+  };
+
   // Adds |packet_number| to the set of packets in the queue.
   void Add(QuicPacketNumber packet_number);
 
@@ -81,7 +243,11 @@
       const PacketNumberQueue& q);
 
  private:
+  // TODO(lilika): Remove QuicIntervalSet<QuicPacketNumber>
+  // once FLAGS_quic_reloadable_flag_quic_frames_deque is removed
   QuicIntervalSet<QuicPacketNumber> packet_number_intervals_;
+  std::deque<Interval<QuicPacketNumber>> packet_number_deque_;
+  bool use_deque_;
 };
 
 struct QUIC_EXPORT_PRIVATE QuicAckFrame {
@@ -89,8 +255,9 @@
   QuicAckFrame(const QuicAckFrame& other);
   ~QuicAckFrame();
 
-  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
-                                                      const QuicAckFrame& s);
+  friend QUIC_EXPORT_PRIVATE std::ostream& operator<<(
+      std::ostream& os,
+      const QuicAckFrame& ack_frame);
 
   // The highest packet number we've observed from the peer.
   QuicPacketNumber largest_observed;
diff --git a/net/quic/core/frames/quic_frames_test.cc b/net/quic/core/frames/quic_frames_test.cc
index 6402cf0..70cbfcb3 100644
--- a/net/quic/core/frames/quic_frames_test.cc
+++ b/net/quic/core/frames/quic_frames_test.cc
@@ -20,8 +20,6 @@
 namespace test {
 namespace {
 
-using testing::_;
-
 class QuicFramesTest : public QuicTest {};
 
 TEST_F(QuicFramesTest, AckFrameToString) {
@@ -137,6 +135,179 @@
   EXPECT_TRUE(IsAwaitingPacket(ack_frame2, 101u, 20u));
 }
 
+TEST_F(QuicFramesTest, AddPacket) {
+  QuicAckFrame ack_frame1;
+  ack_frame1.packets.Add(1);
+  ack_frame1.packets.Add(99);
+
+  EXPECT_EQ(2u, ack_frame1.packets.NumIntervals());
+  EXPECT_EQ(1u, ack_frame1.packets.Min());
+  EXPECT_EQ(99u, ack_frame1.packets.Max());
+
+  std::vector<Interval<QuicPacketNumber>> expected_intervals;
+  expected_intervals.push_back(Interval<QuicPacketNumber>(1, 2));
+  expected_intervals.push_back(Interval<QuicPacketNumber>(99, 100));
+
+  const std::vector<Interval<QuicPacketNumber>> actual_intervals(
+      ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+  EXPECT_EQ(expected_intervals, actual_intervals);
+
+  ack_frame1.packets.Add(20);
+  const std::vector<Interval<QuicPacketNumber>> actual_intervals2(
+      ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+  std::vector<Interval<QuicPacketNumber>> expected_intervals2;
+  expected_intervals2.push_back(Interval<QuicPacketNumber>(1, 2));
+  expected_intervals2.push_back(Interval<QuicPacketNumber>(20, 21));
+  expected_intervals2.push_back(Interval<QuicPacketNumber>(99, 100));
+
+  EXPECT_EQ(3u, ack_frame1.packets.NumIntervals());
+  EXPECT_EQ(expected_intervals2, actual_intervals2);
+
+  ack_frame1.packets.Add(19);
+  ack_frame1.packets.Add(21);
+
+  const std::vector<Interval<QuicPacketNumber>> actual_intervals3(
+      ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+  std::vector<Interval<QuicPacketNumber>> expected_intervals3;
+  expected_intervals3.push_back(Interval<QuicPacketNumber>(1, 2));
+  expected_intervals3.push_back(Interval<QuicPacketNumber>(19, 22));
+  expected_intervals3.push_back(Interval<QuicPacketNumber>(99, 100));
+
+  EXPECT_EQ(expected_intervals3, actual_intervals3);
+
+  ack_frame1.packets.Add(20);
+
+  const std::vector<Interval<QuicPacketNumber>> actual_intervals4(
+      ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+  EXPECT_EQ(expected_intervals3, actual_intervals4);
+
+  QuicAckFrame ack_frame2;
+  ack_frame2.packets.Add(20);
+  ack_frame2.packets.Add(40);
+  ack_frame2.packets.Add(60);
+  ack_frame2.packets.Add(10);
+  ack_frame2.packets.Add(80);
+
+  const std::vector<Interval<QuicPacketNumber>> actual_intervals5(
+      ack_frame2.packets.begin(), ack_frame2.packets.end());
+
+  std::vector<Interval<QuicPacketNumber>> expected_intervals5;
+  expected_intervals5.push_back(Interval<QuicPacketNumber>(10, 11));
+  expected_intervals5.push_back(Interval<QuicPacketNumber>(20, 21));
+  expected_intervals5.push_back(Interval<QuicPacketNumber>(40, 41));
+  expected_intervals5.push_back(Interval<QuicPacketNumber>(60, 61));
+  expected_intervals5.push_back(Interval<QuicPacketNumber>(80, 81));
+
+  EXPECT_EQ(expected_intervals5, actual_intervals5);
+}
+
+TEST_F(QuicFramesTest, AddInterval) {
+  QuicAckFrame ack_frame1;
+  ack_frame1.packets.Add(1, 10);
+  ack_frame1.packets.Add(50, 100);
+
+  EXPECT_EQ(2u, ack_frame1.packets.NumIntervals());
+  EXPECT_EQ(1u, ack_frame1.packets.Min());
+  EXPECT_EQ(99u, ack_frame1.packets.Max());
+
+  std::vector<Interval<QuicPacketNumber>> expected_intervals;
+  expected_intervals.push_back(Interval<QuicPacketNumber>(1, 10));
+  expected_intervals.push_back(Interval<QuicPacketNumber>(50, 100));
+
+  const std::vector<Interval<QuicPacketNumber>> actual_intervals(
+      ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+  EXPECT_EQ(expected_intervals, actual_intervals);
+
+  ack_frame1.packets.Add(20, 30);
+  const std::vector<Interval<QuicPacketNumber>> actual_intervals2(
+      ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+  std::vector<Interval<QuicPacketNumber>> expected_intervals2;
+  expected_intervals2.push_back(Interval<QuicPacketNumber>(1, 10));
+  expected_intervals2.push_back(Interval<QuicPacketNumber>(20, 30));
+  expected_intervals2.push_back(Interval<QuicPacketNumber>(50, 100));
+
+  EXPECT_EQ(3u, ack_frame1.packets.NumIntervals());
+  EXPECT_EQ(expected_intervals2, actual_intervals2);
+
+  ack_frame1.packets.Add(15, 20);
+  ack_frame1.packets.Add(30, 35);
+
+  const std::vector<Interval<QuicPacketNumber>> actual_intervals3(
+      ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+  std::vector<Interval<QuicPacketNumber>> expected_intervals3;
+  expected_intervals3.push_back(Interval<QuicPacketNumber>(1, 10));
+  expected_intervals3.push_back(Interval<QuicPacketNumber>(15, 35));
+  expected_intervals3.push_back(Interval<QuicPacketNumber>(50, 100));
+
+  EXPECT_EQ(expected_intervals3, actual_intervals3);
+
+  ack_frame1.packets.Add(20, 35);
+
+  const std::vector<Interval<QuicPacketNumber>> actual_intervals4(
+      ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+  EXPECT_EQ(expected_intervals3, actual_intervals4);
+
+  ack_frame1.packets.Add(12, 20);
+  ack_frame1.packets.Add(30, 38);
+
+  const std::vector<Interval<QuicPacketNumber>> actual_intervals5(
+      ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+  std::vector<Interval<QuicPacketNumber>> expected_intervals5;
+  expected_intervals5.push_back(Interval<QuicPacketNumber>(1, 10));
+  expected_intervals5.push_back(Interval<QuicPacketNumber>(12, 38));
+  expected_intervals5.push_back(Interval<QuicPacketNumber>(50, 100));
+
+  EXPECT_EQ(expected_intervals5, actual_intervals5);
+
+  ack_frame1.packets.Add(8, 55);
+
+  const std::vector<Interval<QuicPacketNumber>> actual_intervals6(
+      ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+  std::vector<Interval<QuicPacketNumber>> expected_intervals6;
+  expected_intervals6.push_back(Interval<QuicPacketNumber>(1, 100));
+
+  EXPECT_EQ(expected_intervals6, actual_intervals6);
+
+  ack_frame1.packets.Add(0, 200);
+
+  const std::vector<Interval<QuicPacketNumber>> actual_intervals7(
+      ack_frame1.packets.begin(), ack_frame1.packets.end());
+
+  std::vector<Interval<QuicPacketNumber>> expected_intervals7;
+  expected_intervals7.push_back(Interval<QuicPacketNumber>(0, 200));
+
+  EXPECT_EQ(expected_intervals7, actual_intervals7);
+
+  QuicAckFrame ack_frame2;
+  ack_frame2.packets.Add(20, 25);
+  ack_frame2.packets.Add(40, 45);
+  ack_frame2.packets.Add(60, 65);
+  ack_frame2.packets.Add(10, 15);
+  ack_frame2.packets.Add(80, 85);
+
+  const std::vector<Interval<QuicPacketNumber>> actual_intervals8(
+      ack_frame2.packets.begin(), ack_frame2.packets.end());
+
+  std::vector<Interval<QuicPacketNumber>> expected_intervals8;
+  expected_intervals8.push_back(Interval<QuicPacketNumber>(10, 15));
+  expected_intervals8.push_back(Interval<QuicPacketNumber>(20, 25));
+  expected_intervals8.push_back(Interval<QuicPacketNumber>(40, 45));
+  expected_intervals8.push_back(Interval<QuicPacketNumber>(60, 65));
+  expected_intervals8.push_back(Interval<QuicPacketNumber>(80, 85));
+
+  EXPECT_EQ(expected_intervals8, actual_intervals8);
+}
+
 TEST_F(QuicFramesTest, RemoveSmallestInterval) {
   QuicAckFrame ack_frame1;
   ack_frame1.largest_observed = 100u;
@@ -178,9 +349,46 @@
   EXPECT_EQ(70u, queue.Max());
 }
 
+// Tests Contains function
+TEST_F(PacketNumberQueueTest, Contains) {
+  PacketNumberQueue queue;
+  EXPECT_FALSE(queue.Contains(0));
+  queue.Add(5, 10);
+  queue.Add(20);
+
+  for (int i = 1; i < 5; ++i) {
+    EXPECT_FALSE(queue.Contains(i));
+  }
+
+  for (int i = 5; i < 10; ++i) {
+    EXPECT_TRUE(queue.Contains(i));
+  }
+  for (int i = 10; i < 20; ++i) {
+    EXPECT_FALSE(queue.Contains(i));
+  }
+  EXPECT_TRUE(queue.Contains(20));
+  EXPECT_FALSE(queue.Contains(21));
+
+  PacketNumberQueue queue2;
+  EXPECT_FALSE(queue2.Contains(1));
+  for (int i = 1; i < 51; ++i) {
+    queue2.Add(2 * i);
+  }
+  EXPECT_FALSE(queue2.Contains(0));
+  for (int i = 1; i < 51; ++i) {
+    if (i % 2 == 0) {
+      EXPECT_TRUE(queue2.Contains(i));
+    } else {
+      EXPECT_FALSE(queue2.Contains(i));
+    }
+  }
+  EXPECT_FALSE(queue2.Contains(101));
+}
+
 // Tests that a queue contains the expected data after calls to RemoveUpTo().
 TEST_F(PacketNumberQueueTest, Removal) {
   PacketNumberQueue queue;
+  EXPECT_FALSE(queue.Contains(51));
   queue.Add(0, 100);
 
   EXPECT_TRUE(queue.RemoveUpTo(51));
@@ -196,6 +404,12 @@
   EXPECT_EQ(49u, queue.NumPacketsSlow());
   EXPECT_EQ(51u, queue.Min());
   EXPECT_EQ(99u, queue.Max());
+
+  PacketNumberQueue queue2;
+  queue2.Add(0, 5);
+  EXPECT_TRUE(queue2.RemoveUpTo(3));
+  EXPECT_TRUE(queue2.RemoveUpTo(50));
+  EXPECT_TRUE(queue2.Empty());
 }
 
 // Tests that a queue is empty when all of its elements are removed.
@@ -229,10 +443,54 @@
   const std::vector<Interval<QuicPacketNumber>> actual_intervals(queue.begin(),
                                                                  queue.end());
 
+  PacketNumberQueue queue2;
+  for (int i = 1; i < 100; i++) {
+    queue2.Add(i, i + 1);
+  }
+
+  const std::vector<Interval<QuicPacketNumber>> actual_intervals2(
+      queue2.begin(), queue2.end());
+
+  std::vector<Interval<QuicPacketNumber>> expected_intervals;
+  expected_intervals.push_back(Interval<QuicPacketNumber>(1, 100));
+  EXPECT_EQ(expected_intervals, actual_intervals);
+  EXPECT_EQ(expected_intervals, actual_intervals2);
+  EXPECT_EQ(actual_intervals, actual_intervals2);
+}
+
+TEST_F(PacketNumberQueueTest, ReversedIterators) {
+  PacketNumberQueue queue;
+  queue.Add(1, 100);
+  PacketNumberQueue queue2;
+  for (int i = 1; i < 100; i++) {
+    queue2.Add(i, i + 1);
+  }
+  const std::vector<Interval<QuicPacketNumber>> actual_intervals(queue.rbegin(),
+                                                                 queue.rend());
+  const std::vector<Interval<QuicPacketNumber>> actual_intervals2(
+      queue2.rbegin(), queue2.rend());
+
   std::vector<Interval<QuicPacketNumber>> expected_intervals;
   expected_intervals.push_back(Interval<QuicPacketNumber>(1, 100));
 
   EXPECT_EQ(expected_intervals, actual_intervals);
+  EXPECT_EQ(expected_intervals, actual_intervals2);
+  EXPECT_EQ(actual_intervals, actual_intervals2);
+
+  PacketNumberQueue queue3;
+  for (int i = 1; i < 20; i++) {
+    queue3.Add(2 * i);
+  }
+
+  auto begin = queue3.begin();
+  auto end = queue3.end();
+  --end;
+  auto rbegin = queue3.rbegin();
+  auto rend = queue3.rend();
+  --rend;
+
+  EXPECT_EQ(*begin, *rend);
+  EXPECT_EQ(*rbegin, *end);
 }
 
 TEST_F(PacketNumberQueueTest, IntervalLengthAndRemoveInterval) {
diff --git a/net/quic/core/quic_flags_list.h b/net/quic/core/quic_flags_list.h
index 9d58326..a5617f3 100644
--- a/net/quic/core/quic_flags_list.h
+++ b/net/quic/core/quic_flags_list.h
@@ -193,3 +193,6 @@
 QUIC_FLAG(bool,
           FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes3,
           false)
+
+// When enabled, ack frame uses a deque internally instead of a set.
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_frames_deque, false)
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc
index e9248ba..40c7727 100644
--- a/net/socket/ssl_client_socket_impl.cc
+++ b/net/socket/ssl_client_socket_impl.cc
@@ -319,7 +319,8 @@
     SSL_CTX_set_cert_cb(ssl_ctx_.get(), ClientCertRequestCallback, NULL);
 
     // The server certificate is verified after the handshake in DoVerifyCert.
-    SSL_CTX_i_promise_to_verify_certs_after_the_handshake(ssl_ctx_.get());
+    SSL_CTX_set_custom_verify(ssl_ctx_.get(), SSL_VERIFY_PEER,
+                              CertVerifyCallback);
 
     // Disable the internal session cache. Session caching is handled
     // externally (i.e. by SSLClientSessionCache).
@@ -383,6 +384,11 @@
     return socket->ClientCertRequestCallback(ssl);
   }
 
+  static ssl_verify_result_t CertVerifyCallback(SSL* ssl, uint8_t* out_alert) {
+    // The certificate is verified after the handshake in DoVerifyCert.
+    return ssl_verify_ok;
+  }
+
   static int NewSessionCallback(SSL* ssl, SSL_SESSION* session) {
     SSLClientSocketImpl* socket = GetInstance()->GetClientSocketFromSSL(ssl);
     return socket->NewSessionCallback(session);
diff --git a/net/spdy/chromium/bidirectional_stream_spdy_impl.cc b/net/spdy/chromium/bidirectional_stream_spdy_impl.cc
index fa223bb4..616f1673 100644
--- a/net/spdy/chromium/bidirectional_stream_spdy_impl.cc
+++ b/net/spdy/chromium/bidirectional_stream_spdy_impl.cc
@@ -193,6 +193,9 @@
   return stream_->GetLoadTimingInfo(load_timing_info);
 }
 
+void BidirectionalStreamSpdyImpl::PopulateNetErrorDetails(
+    NetErrorDetails* details) {}
+
 void BidirectionalStreamSpdyImpl::OnHeadersSent() {
   DCHECK(stream_);
 
diff --git a/net/spdy/chromium/bidirectional_stream_spdy_impl.h b/net/spdy/chromium/bidirectional_stream_spdy_impl.h
index 61e00e0..c4c11ed 100644
--- a/net/spdy/chromium/bidirectional_stream_spdy_impl.h
+++ b/net/spdy/chromium/bidirectional_stream_spdy_impl.h
@@ -57,6 +57,7 @@
   int64_t GetTotalReceivedBytes() const override;
   int64_t GetTotalSentBytes() const override;
   bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override;
+  void PopulateNetErrorDetails(NetErrorDetails* details) override;
 
   // SpdyStream::Delegate implementation:
   void OnHeadersSent() override;
diff --git a/net/spdy/chromium/buffered_spdy_framer.h b/net/spdy/chromium/buffered_spdy_framer.h
index 87c17a06..287faa2 100644
--- a/net/spdy/chromium/buffered_spdy_framer.h
+++ b/net/spdy/chromium/buffered_spdy_framer.h
@@ -73,10 +73,10 @@
   virtual void OnSetting(SpdySettingsIds id, uint32_t value) = 0;
 
   // Called when a SETTINGS frame is received with the ACK flag set.
-  virtual void OnSettingsAck() {}
+  virtual void OnSettingsAck() = 0;
 
   // Called at the completion of parsing SETTINGS id and value tuples.
-  virtual void OnSettingsEnd() {}
+  virtual void OnSettingsEnd() = 0;
 
   // Called when a PING frame has been parsed.
   virtual void OnPing(SpdyPingId unique_id, bool is_ack) = 0;
diff --git a/net/spdy/chromium/buffered_spdy_framer_unittest.cc b/net/spdy/chromium/buffered_spdy_framer_unittest.cc
index 62169061..dd0c4490 100644
--- a/net/spdy/chromium/buffered_spdy_framer_unittest.cc
+++ b/net/spdy/chromium/buffered_spdy_framer_unittest.cc
@@ -76,6 +76,10 @@
 
   void OnSettings() override {}
 
+  void OnSettingsAck() override {}
+
+  void OnSettingsEnd() override {}
+
   void OnSetting(SpdySettingsIds id, uint32_t value) override {
     setting_count_++;
   }
diff --git a/net/spdy/chromium/header_coalescer.cc b/net/spdy/chromium/header_coalescer.cc
index 019f8062..f19f3d29 100644
--- a/net/spdy/chromium/header_coalescer.cc
+++ b/net/spdy/chromium/header_coalescer.cc
@@ -8,8 +8,8 @@
 
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
-#include "base/strings/string_util.h"
 #include "base/values.h"
+#include "net/base/escape.h"
 #include "net/http/http_log_util.h"
 #include "net/http/http_util.h"
 #include "net/spdy/platform/api/spdy_estimate_memory_usage.h"
@@ -20,12 +20,15 @@
 std::unique_ptr<base::Value> ElideNetLogHeaderCallback(
     SpdyStringPiece header_name,
     SpdyStringPiece header_value,
+    SpdyStringPiece error_message,
     NetLogCaptureMode capture_mode) {
   auto dict = base::MakeUnique<base::DictionaryValue>();
-  dict->SetString("header_name", header_name);
-  dict->SetString("header_value", ElideHeaderValueForNetLog(
-                                      capture_mode, header_name.as_string(),
-                                      header_value.as_string()));
+  dict->SetString("header_name", EscapeExternalHandlerValue(header_name));
+  dict->SetString(
+      "header_value",
+      EscapeExternalHandlerValue(ElideHeaderValueForNetLog(
+          capture_mode, header_name.as_string(), header_value.as_string())));
+  dict->SetString("error", error_message);
   return std::move(dict);
 }
 
@@ -37,13 +40,8 @@
 void HeaderCoalescer::OnHeader(SpdyStringPiece key, SpdyStringPiece value) {
   if (error_seen_)
     return;
-  if (!AddHeader(key, value)) {
+  if (!AddHeader(key, value))
     error_seen_ = true;
-    if (net_log_.IsCapturing()) {
-      net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_INVALID_HEADER,
-                        base::Bind(&ElideNetLogHeaderCallback, key, value));
-    }
-  }
 }
 
 SpdyHeaderBlock HeaderCoalescer::release_headers() {
@@ -58,13 +56,19 @@
 
 bool HeaderCoalescer::AddHeader(SpdyStringPiece key, SpdyStringPiece value) {
   if (key.empty()) {
-    DVLOG(1) << "Header name must not be empty.";
+    net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_INVALID_HEADER,
+                      base::Bind(&ElideNetLogHeaderCallback, key, value,
+                                 "Header name must not be empty."));
     return false;
   }
 
   SpdyStringPiece key_name = key;
   if (key[0] == ':') {
     if (regular_header_seen_) {
+      net_log_.AddEvent(
+          NetLogEventType::HTTP2_SESSION_RECV_INVALID_HEADER,
+          base::Bind(&ElideNetLogHeaderCallback, key, value,
+                     "Pseudo header must not follow regular headers."));
       return false;
     }
     key_name.remove_prefix(1);
@@ -73,18 +77,29 @@
   }
 
   if (!HttpUtil::IsValidHeaderName(key_name)) {
+    net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_INVALID_HEADER,
+                      base::Bind(&ElideNetLogHeaderCallback, key, value,
+                                 "Invalid character in header name."));
     return false;
   }
 
   // 32 byte overhead according to RFC 7540 Section 6.5.2.
   header_list_size_ += key.size() + value.size() + 32;
-  if (header_list_size_ > kMaxHeaderListSize)
+  if (header_list_size_ > kMaxHeaderListSize) {
+    net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_INVALID_HEADER,
+                      base::Bind(&ElideNetLogHeaderCallback, key, value,
+                                 "Header list too large."));
     return false;
+  }
 
   // End of line delimiter is forbidden according to RFC 7230 Section 3.2.
   // Line folding, RFC 7230 Section 3.2.4., is a special case of this.
-  if (value.find("\r\n") != SpdyStringPiece::npos)
+  if (value.find("\r\n") != SpdyStringPiece::npos) {
+    net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_INVALID_HEADER,
+                      base::Bind(&ElideNetLogHeaderCallback, key, value,
+                                 "Header value must not contain CR+LF."));
     return false;
+  }
 
   auto iter = headers_.find(key);
   if (iter == headers_.end()) {
diff --git a/net/spdy/chromium/header_coalescer_test.cc b/net/spdy/chromium/header_coalescer_test.cc
index 58b3047..2137d224 100644
--- a/net/spdy/chromium/header_coalescer_test.cc
+++ b/net/spdy/chromium/header_coalescer_test.cc
@@ -6,7 +6,7 @@
 
 #include <vector>
 
-#include "net/log/net_log_with_source.h"
+#include "net/log/test_net_log.h"
 #include "net/spdy/platform/api/spdy_string.h"
 #include "net/spdy/platform/api/spdy_string_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -20,9 +20,28 @@
 
 class HeaderCoalescerTest : public ::testing::Test {
  public:
-  HeaderCoalescerTest() : header_coalescer_(NetLogWithSource()) {}
+  HeaderCoalescerTest() : header_coalescer_(net_log_.bound()) {}
+
+  void ExpectEntry(SpdyStringPiece expected_header_name,
+                   SpdyStringPiece expected_header_value,
+                   SpdyStringPiece expected_error_message) {
+    TestNetLogEntry::List entry_list;
+    net_log_.GetEntries(&entry_list);
+    ASSERT_EQ(1u, entry_list.size());
+    EXPECT_EQ(entry_list[0].type,
+              NetLogEventType::HTTP2_SESSION_RECV_INVALID_HEADER);
+    EXPECT_EQ(entry_list[0].source.id, net_log_.bound().source().id);
+    std::string value;
+    EXPECT_TRUE(entry_list[0].GetStringValue("header_name", &value));
+    EXPECT_EQ(expected_header_name, value);
+    EXPECT_TRUE(entry_list[0].GetStringValue("header_value", &value));
+    EXPECT_EQ(expected_header_value, value);
+    EXPECT_TRUE(entry_list[0].GetStringValue("error", &value));
+    EXPECT_EQ(expected_error_message, value);
+  }
 
  protected:
+  BoundTestNetLog net_log_;
   HeaderCoalescer header_coalescer_;
 };
 
@@ -37,9 +56,9 @@
 }
 
 TEST_F(HeaderCoalescerTest, EmptyHeaderKey) {
-  EXPECT_FALSE(header_coalescer_.error_seen());
   header_coalescer_.OnHeader("", "foo");
   EXPECT_TRUE(header_coalescer_.error_seen());
+  ExpectEntry("", "foo", "Header name must not be empty.");
 }
 
 TEST_F(HeaderCoalescerTest, HeaderBlockTooLarge) {
@@ -49,9 +68,11 @@
   header_coalescer_.OnHeader("foo", data);
   EXPECT_FALSE(header_coalescer_.error_seen());
 
-  // Another 3 + 3 + 32 bytes: too large.
-  header_coalescer_.OnHeader("bar", "baz");
+  // Another 3 + 4 + 32 bytes: too large.
+  SpdyStringPiece header_value("\x1\x7F\x80\xFF");
+  header_coalescer_.OnHeader("bar", header_value);
   EXPECT_TRUE(header_coalescer_.error_seen());
+  ExpectEntry("bar", "%01%7F%80%FF", "Header list too large.");
 }
 
 TEST_F(HeaderCoalescerTest, PseudoHeadersMustNotFollowRegularHeaders) {
@@ -59,6 +80,7 @@
   EXPECT_FALSE(header_coalescer_.error_seen());
   header_coalescer_.OnHeader(":baz", "qux");
   EXPECT_TRUE(header_coalescer_.error_seen());
+  ExpectEntry(":baz", "qux", "Pseudo header must not follow regular headers.");
 }
 
 TEST_F(HeaderCoalescerTest, Append) {
@@ -75,15 +97,16 @@
 }
 
 TEST_F(HeaderCoalescerTest, CRLFInHeaderValue) {
-  EXPECT_FALSE(header_coalescer_.error_seen());
   header_coalescer_.OnHeader("foo", "bar\r\nbaz");
   EXPECT_TRUE(header_coalescer_.error_seen());
+  ExpectEntry("foo", "bar%0D%0Abaz", "Header value must not contain CR+LF.");
 }
 
 TEST_F(HeaderCoalescerTest, HeaderNameNotValid) {
-  SpdyStringPiece header_name("\x01\x7F\x80\xff");
+  SpdyStringPiece header_name("\x1\x7F\x80\xFF");
   header_coalescer_.OnHeader(header_name, "foo");
   EXPECT_TRUE(header_coalescer_.error_seen());
+  ExpectEntry("%01%7F%80%FF", "foo", "Invalid character in header name.");
 }
 
 // RFC 7230 Section 3.2. Valid header name is defined as:
diff --git a/net/spdy/chromium/spdy_session.cc b/net/spdy/chromium/spdy_session.cc
index 47dd11e..665cc54e 100644
--- a/net/spdy/chromium/spdy_session.cc
+++ b/net/spdy/chromium/spdy_session.cc
@@ -185,14 +185,6 @@
   return std::move(dict);
 }
 
-std::unique_ptr<base::Value> NetLogSpdyRecvSettingsCallback(
-    const HostPortPair& host_port_pair,
-    NetLogCaptureMode /* capture_mode */) {
-  auto dict = base::MakeUnique<base::DictionaryValue>();
-  dict->SetString("host", host_port_pair.ToString());
-  return std::move(dict);
-}
-
 std::unique_ptr<base::Value> NetLogSpdyRecvSettingCallback(
     SpdySettingsIds id,
     uint32_t value,
@@ -2831,9 +2823,8 @@
   CHECK(in_io_loop_);
 
   if (net_log_.IsCapturing()) {
-    net_log_.AddEvent(
-        NetLogEventType::HTTP2_SESSION_RECV_SETTINGS,
-        base::Bind(&NetLogSpdyRecvSettingsCallback, host_port_pair()));
+    net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_SETTINGS);
+    net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_SEND_SETTINGS_ACK);
   }
 
   // Send an acknowledgment of the setting.
@@ -2844,6 +2835,13 @@
   EnqueueSessionWrite(HIGHEST, SpdyFrameType::SETTINGS, std::move(frame));
 }
 
+void SpdySession::OnSettingsAck() {
+  CHECK(in_io_loop_);
+
+  if (net_log_.IsCapturing())
+    net_log_.AddEvent(NetLogEventType::HTTP2_SESSION_RECV_SETTINGS_ACK);
+}
+
 void SpdySession::OnSetting(SpdySettingsIds id, uint32_t value) {
   CHECK(in_io_loop_);
 
diff --git a/net/spdy/chromium/spdy_session.h b/net/spdy/chromium/spdy_session.h
index 67eb00e..3c4b3fc 100644
--- a/net/spdy/chromium/spdy_session.h
+++ b/net/spdy/chromium/spdy_session.h
@@ -879,7 +879,9 @@
   void OnStreamEnd(SpdyStreamId stream_id) override;
   void OnStreamPadding(SpdyStreamId stream_id, size_t len) override;
   void OnSettings() override;
+  void OnSettingsAck() override;
   void OnSetting(SpdySettingsIds id, uint32_t value) override;
+  void OnSettingsEnd() override {}
   void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override;
   void OnPushPromise(SpdyStreamId stream_id,
                      SpdyStreamId promised_stream_id,
diff --git a/net/spdy/chromium/spdy_test_util_common.cc b/net/spdy/chromium/spdy_test_util_common.cc
index 1024f3e5d..0a799fe 100644
--- a/net/spdy/chromium/spdy_test_util_common.cc
+++ b/net/spdy/chromium/spdy_test_util_common.cc
@@ -212,7 +212,9 @@
   void OnStreamEnd(SpdyStreamId stream_id) override {}
   void OnStreamPadding(SpdyStreamId stream_id, size_t len) override {}
   void OnSettings() override {}
+  void OnSettingsAck() override {}
   void OnSetting(SpdySettingsIds id, uint32_t value) override {}
+  void OnSettingsEnd() override {}
   void OnPing(SpdyPingId unique_id, bool is_ack) override {}
   void OnRstStream(SpdyStreamId stream_id, SpdyErrorCode error_code) override {}
   void OnGoAway(SpdyStreamId last_accepted_stream_id,
diff --git a/net/log/stitch_net_log_files.py b/net/tools/stitch_net_log_files.py
similarity index 100%
rename from net/log/stitch_net_log_files.py
rename to net/tools/stitch_net_log_files.py
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc
index 4955f6b..30972ab42 100644
--- a/net/url_request/url_request_context_builder.cc
+++ b/net/url_request/url_request_context_builder.cc
@@ -192,6 +192,7 @@
     : name_(nullptr),
       enable_brotli_(false),
       network_quality_estimator_(nullptr),
+      shared_http_user_agent_settings_(nullptr),
       data_enabled_(false),
 #if !BUILDFLAG(DISABLE_FILE_SUPPORT)
       file_enabled_(false),
@@ -203,9 +204,14 @@
       throttling_enabled_(false),
       sdch_enabled_(false),
       cookie_store_set_by_client_(false),
+      transport_security_persister_readonly_(false),
       net_log_(nullptr),
+      shared_host_resolver_(nullptr),
       pac_quick_check_enabled_(true),
-      pac_sanitize_url_policy_(ProxyService::SanitizeUrlPolicy::SAFE) {
+      pac_sanitize_url_policy_(ProxyService::SanitizeUrlPolicy::SAFE),
+      shared_proxy_delegate_(nullptr),
+      shared_http_auth_handler_factory_(nullptr),
+      shared_cert_verifier_(nullptr) {
 }
 
 URLRequestContextBuilder::~URLRequestContextBuilder() {}
@@ -237,6 +243,22 @@
   }
 }
 
+void URLRequestContextBuilder::set_accept_language(
+    const std::string& accept_language) {
+  DCHECK(!shared_http_user_agent_settings_);
+  accept_language_ = accept_language;
+}
+void URLRequestContextBuilder::set_user_agent(const std::string& user_agent) {
+  DCHECK(!shared_http_user_agent_settings_);
+  user_agent_ = user_agent;
+}
+void URLRequestContextBuilder::set_shared_http_user_agent_settings(
+    HttpUserAgentSettings* shared_http_user_agent_settings) {
+  DCHECK(accept_language_.empty());
+  DCHECK(user_agent_.empty());
+  shared_http_user_agent_settings_ = shared_http_user_agent_settings;
+}
+
 void URLRequestContextBuilder::EnableHttpCache(const HttpCacheParams& params) {
   http_cache_enabled_ = true;
   http_cache_params_ = params;
@@ -265,9 +287,16 @@
 
 void URLRequestContextBuilder::SetCertVerifier(
     std::unique_ptr<CertVerifier> cert_verifier) {
+  DCHECK(!shared_cert_verifier_);
   cert_verifier_ = std::move(cert_verifier);
 }
 
+void URLRequestContextBuilder::set_shared_cert_verifier(
+    CertVerifier* shared_cert_verifier) {
+  DCHECK(!cert_verifier_);
+  shared_cert_verifier_ = shared_cert_verifier;
+}
+
 #if BUILDFLAG(ENABLE_REPORTING)
 void URLRequestContextBuilder::set_reporting_policy(
     std::unique_ptr<net::ReportingPolicy> reporting_policy) {
@@ -281,6 +310,12 @@
   url_request_interceptors_ = std::move(url_request_interceptors);
 }
 
+void URLRequestContextBuilder::set_create_intercepting_job_factory(
+    CreateInterceptingJobFactory create_intercepting_job_factory) {
+  DCHECK(!create_intercepting_job_factory_);
+  create_intercepting_job_factory_ = std::move(create_intercepting_job_factory);
+}
+
 void URLRequestContextBuilder::SetCookieAndChannelIdStores(
     std::unique_ptr<CookieStore> cookie_store,
     std::unique_ptr<ChannelIDService> channel_id_service) {
@@ -300,14 +335,48 @@
     const std::string& scheme,
     std::unique_ptr<URLRequestJobFactory::ProtocolHandler> protocol_handler) {
   DCHECK(protocol_handler);
+  // If a consumer sets a ProtocolHandler and then overwrites it with another,
+  // it's probably a bug.
+  DCHECK_EQ(0u, protocol_handlers_.count(scheme));
   protocol_handlers_[scheme] = std::move(protocol_handler);
 }
 
+void URLRequestContextBuilder::set_host_resolver(
+    std::unique_ptr<HostResolver> host_resolver) {
+  DCHECK(!shared_host_resolver_);
+  host_resolver_ = std::move(host_resolver);
+}
+
+void URLRequestContextBuilder::set_shared_host_resolver(
+    HostResolver* shared_host_resolver) {
+  DCHECK(!host_resolver_);
+  shared_host_resolver_ = shared_host_resolver;
+}
+
+void URLRequestContextBuilder::set_proxy_delegate(
+    std::unique_ptr<ProxyDelegate> proxy_delegate) {
+  DCHECK(!shared_proxy_delegate_);
+  proxy_delegate_ = std::move(proxy_delegate);
+}
+
+void URLRequestContextBuilder::set_shared_proxy_delegate(
+    ProxyDelegate* shared_proxy_delegate) {
+  DCHECK(!proxy_delegate_);
+  shared_proxy_delegate_ = shared_proxy_delegate;
+}
+
 void URLRequestContextBuilder::SetHttpAuthHandlerFactory(
     std::unique_ptr<HttpAuthHandlerFactory> factory) {
+  DCHECK(!shared_http_auth_handler_factory_);
   http_auth_handler_factory_ = std::move(factory);
 }
 
+void URLRequestContextBuilder::set_shared_http_auth_handler_factory(
+    HttpAuthHandlerFactory* shared_http_auth_handler_factory) {
+  DCHECK(!http_auth_handler_factory_);
+  shared_http_auth_handler_factory_ = shared_http_auth_handler_factory;
+}
+
 void URLRequestContextBuilder::SetHttpServerProperties(
     std::unique_ptr<HttpServerProperties> http_server_properties) {
   http_server_properties_ = std::move(http_server_properties);
@@ -322,9 +391,13 @@
   context->set_enable_brotli(enable_brotli_);
   context->set_network_quality_estimator(network_quality_estimator_);
 
-  storage->set_http_user_agent_settings(
-      base::MakeUnique<StaticHttpUserAgentSettings>(accept_language_,
-                                                    user_agent_));
+  if (shared_http_user_agent_settings_) {
+    context->set_http_user_agent_settings(shared_http_user_agent_settings_);
+  } else {
+    storage->set_http_user_agent_settings(
+        base::MakeUnique<StaticHttpUserAgentSettings>(accept_language_,
+                                                      user_agent_));
+  }
 
   if (!network_delegate_)
     network_delegate_.reset(new BasicNetworkDelegate);
@@ -338,10 +411,15 @@
     storage->set_net_log(base::WrapUnique(new NetLog));
   }
 
-  if (!host_resolver_) {
-    host_resolver_ = HostResolver::CreateDefaultResolver(context->net_log());
+  if (host_resolver_) {
+    DCHECK(!shared_host_resolver_);
+    storage->set_host_resolver(std::move(host_resolver_));
+  } else if (shared_host_resolver_) {
+    context->set_host_resolver(shared_host_resolver_);
+  } else {
+    storage->set_host_resolver(
+        HostResolver::CreateDefaultResolver(context->net_log()));
   }
-  storage->set_host_resolver(std::move(host_resolver_));
 
   if (ssl_config_service_) {
     // This takes a raw pointer, but |storage| will hold onto a reference to the
@@ -351,13 +429,18 @@
     storage->set_ssl_config_service(new SSLConfigServiceDefaults);
   }
 
-  if (!http_auth_handler_factory_) {
-    http_auth_handler_factory_ =
-        HttpAuthHandlerRegistryFactory::CreateDefault(context->host_resolver());
+  if (http_auth_handler_factory_) {
+    DCHECK(!shared_http_auth_handler_factory_);
+    storage->set_http_auth_handler_factory(
+        std::move(http_auth_handler_factory_));
+  } else if (shared_http_auth_handler_factory_) {
+    context->set_http_auth_handler_factory(shared_http_auth_handler_factory_);
+  } else {
+    storage->set_http_auth_handler_factory(
+        HttpAuthHandlerRegistryFactory::CreateDefault(
+            context->host_resolver()));
   }
 
-  storage->set_http_auth_handler_factory(std::move(http_auth_handler_factory_));
-
   if (cookie_store_set_by_client_) {
     storage->set_cookie_store(std::move(cookie_store_));
     storage->set_channel_id_service(std::move(channel_id_service_));
@@ -389,9 +472,10 @@
 
     context->set_transport_security_persister(
         base::WrapUnique<TransportSecurityPersister>(
-            new TransportSecurityPersister(context->transport_security_state(),
-                                           transport_security_persister_path_,
-                                           task_runner, false)));
+            new TransportSecurityPersister(
+                context->transport_security_state(),
+                transport_security_persister_path_, task_runner,
+                transport_security_persister_readonly_)));
   }
 
   if (http_server_properties_) {
@@ -402,7 +486,10 @@
   }
 
   if (cert_verifier_) {
+    DCHECK(!shared_cert_verifier_);
     storage->set_cert_verifier(std::move(cert_verifier_));
+  } else if (shared_cert_verifier_) {
+    context->set_cert_verifier(shared_cert_verifier_);
   } else {
     storage->set_cert_verifier(CertVerifier::CreateDefault());
   }
@@ -448,8 +535,11 @@
   SetHttpNetworkSessionComponents(context.get(), &network_session_context);
 
   if (proxy_delegate_) {
+    DCHECK(!shared_proxy_delegate_);
     network_session_context.proxy_delegate = proxy_delegate_.get();
     storage->set_proxy_delegate(std::move(proxy_delegate_));
+  } else if (shared_proxy_delegate_) {
+    network_session_context.proxy_delegate = shared_proxy_delegate_;
   }
 
   storage->set_http_network_session(base::MakeUnique<HttpNetworkSession>(
@@ -465,10 +555,23 @@
                 {base::MayBlock(), base::TaskPriority::USER_BLOCKING,
                  base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
       }
-      BackendType backend_type =
-          http_cache_params_.type == HttpCacheParams::DISK
-              ? CACHE_BACKEND_DEFAULT
-              : CACHE_BACKEND_SIMPLE;
+      // TODO(mmenke): Maybe merge BackendType and HttpCacheParams::Type? The
+      // first doesn't include in memory, so may require some work.
+      BackendType backend_type = CACHE_BACKEND_DEFAULT;
+      switch (http_cache_params_.type) {
+        case HttpCacheParams::DISK:
+          backend_type = CACHE_BACKEND_DEFAULT;
+          break;
+        case HttpCacheParams::DISK_BLOCKFILE:
+          backend_type = CACHE_BACKEND_BLOCKFILE;
+          break;
+        case HttpCacheParams::DISK_SIMPLE:
+          backend_type = CACHE_BACKEND_SIMPLE;
+          break;
+        case HttpCacheParams::IN_MEMORY:
+          NOTREACHED();
+          break;
+      }
       http_cache_backend.reset(new HttpCache::DefaultBackend(
           DISK_CACHE, backend_type, http_cache_params_.path,
           http_cache_params_.max_size, cache_thread_task_runner_));
@@ -526,6 +629,10 @@
     }
     url_request_interceptors_.clear();
   }
+  if (create_intercepting_job_factory_) {
+    top_job_factory = std::move(create_intercepting_job_factory_)
+                          .Run(std::move(top_job_factory));
+  }
   storage->set_job_factory(std::move(top_job_factory));
 
 #if BUILDFLAG(ENABLE_REPORTING)
diff --git a/net/url_request/url_request_context_builder.h b/net/url_request/url_request_context_builder.h
index 9f695c3..ce19ca3 100644
--- a/net/url_request/url_request_context_builder.h
+++ b/net/url_request/url_request_context_builder.h
@@ -23,6 +23,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/callback.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -54,6 +55,7 @@
 class CTPolicyEnforcer;
 class CTVerifier;
 class HttpAuthHandlerFactory;
+class HttpUserAgentSettings;
 class HttpServerProperties;
 class NetworkQualityEstimator;
 class ProxyConfigService;
@@ -79,12 +81,18 @@
 // Builder may be used to create only a single URLRequestContext.
 class NET_EXPORT URLRequestContextBuilder {
  public:
+  using CreateInterceptingJobFactory =
+      base::OnceCallback<std::unique_ptr<net::URLRequestJobFactory>(
+          std::unique_ptr<net::URLRequestJobFactory> inner_job_factory)>;
+
   struct NET_EXPORT HttpCacheParams {
     enum Type {
       // In-memory cache.
       IN_MEMORY,
       // Disk cache using "default" backend.
       DISK,
+      // Disk cache using "blockfile" backend (BackendImpl).
+      DISK_BLOCKFILE,
       // Disk cache using "simple" backend (SimpleBackendImpl).
       DISK_SIMPLE,
     };
@@ -166,12 +174,17 @@
   // Call these functions to specify hard-coded Accept-Language
   // or User-Agent header values for all requests that don't
   // have the headers already set.
-  void set_accept_language(const std::string& accept_language) {
-    accept_language_ = accept_language;
-  }
-  void set_user_agent(const std::string& user_agent) {
-    user_agent_ = user_agent;
-  }
+  void set_accept_language(const std::string& accept_language);
+  void set_user_agent(const std::string& user_agent);
+  // Makes the created URLRequestContext use a shared HttpUserAgentSettings
+  // object. Not compatible with set_accept_language() / set_user_agent(). The
+  // consumer must ensure the HttpUserAgentSettings outlives the
+  // URLRequestContext returned by the builder.
+  //
+  // TODO(mmenke): Take ownership of the object instead. See:
+  // https://crbug.com/743251
+  void set_shared_http_user_agent_settings(
+      HttpUserAgentSettings* shared_http_user_agent_settings);
 
   // Control support for data:// requests. By default it's disabled.
   void set_data_enabled(bool enable) {
@@ -205,9 +218,14 @@
   void set_net_log(NetLog* net_log) { net_log_ = net_log; }
 
   // By default host_resolver is constructed with CreateDefaultResolver.
-  void set_host_resolver(std::unique_ptr<HostResolver> host_resolver) {
-    host_resolver_ = std::move(host_resolver);
-  }
+  void set_host_resolver(std::unique_ptr<HostResolver> host_resolver);
+  // Allows sharing the HostResolver with other URLRequestContexts. Should not
+  // be used if set_host_resolver() is used. The consumer must ensure the
+  // HostResolver outlives the URLRequestContext returned by the builder.
+  //
+  // TODO(mmenke): Figure out the cost/benefits of not supporting sharing
+  // HostResolvers between URLRequestContexts. See: https://crbug.com/743251.
+  void set_shared_host_resolver(HostResolver* host_resolver);
 
   // Uses BasicNetworkDelegate by default. Note that calling Build will unset
   // any custom delegate in builder, so this must be called each time before
@@ -216,20 +234,31 @@
     network_delegate_ = std::move(delegate);
   }
 
-  // Temporarily stores a ProxyDelegate. Ownership is transferred to
-  // UrlRequestContextStorage during Build.
-  void set_proxy_delegate(std::unique_ptr<ProxyDelegate> delegate) {
-    proxy_delegate_ = std::move(delegate);
-  }
+  // Sets the ProxyDelegate.
+  void set_proxy_delegate(std::unique_ptr<ProxyDelegate> proxy_delegate);
+  // Allows sharing the PreoxyDelegates with other URLRequestContexts. Should
+  // not be used if set_proxy_delegate() is used. The consumer must ensure the
+  // ProxyDelegate outlives the URLRequestContext returned by the builder.
+  //
+  // TODO(mmenke): Remove this (And update consumers). See:
+  // https://crbug.com/743251.
+  void set_shared_proxy_delegate(ProxyDelegate* shared_proxy_delegate);
 
   // Sets a specific HttpAuthHandlerFactory to be used by the URLRequestContext
   // rather than the default |HttpAuthHandlerRegistryFactory|. The builder
   // takes ownership of the factory and will eventually transfer it to the new
-  // URLRequestContext. Note that since Build will transfer ownership, the
-  // custom factory will be unset and this must be called before the next Build
-  // to set another custom one.
+  // URLRequestContext.
   void SetHttpAuthHandlerFactory(
       std::unique_ptr<HttpAuthHandlerFactory> factory);
+  // Makes the created URLRequestContext use a shared HttpAuthHandlerFactory
+  // object. Not compatible with SetHttpAuthHandlerFactory(). The consumer must
+  // ensure the HttpAuthHandlerFactory outlives the URLRequestContext returned
+  // by the builder.
+  //
+  // TODO(mmenke): Evaluate if sharing is really needed. See:
+  // https://crbug.com/743251.
+  void set_shared_http_auth_handler_factory(
+      HttpAuthHandlerFactory* shared_http_auth_handler_factory);
 
   // By default HttpCache is enabled with a default constructed HttpCacheParams.
   void EnableHttpCache(const HttpCacheParams& params);
@@ -246,6 +275,17 @@
     transport_security_persister_path_ = transport_security_persister_path;
   }
 
+  // Sets whether the TransportSecurityPersister only reads persisted
+  // information, or also writes it. By default, it both reads and writes.
+  //
+  // TODO(mmenke): Consider removing this in favor of the above method. See:
+  // https://crbug.com/743251.
+  void set_transport_security_persister_readonly(
+      bool transport_security_persister_readonly) {
+    transport_security_persister_readonly_ =
+        transport_security_persister_readonly;
+  }
+
   void SetSpdyAndQuicEnabled(bool spdy_enabled,
                              bool quic_enabled);
 
@@ -259,6 +299,14 @@
 
   void SetCertVerifier(std::unique_ptr<CertVerifier> cert_verifier);
 
+  // Makes the created URLRequestContext use a shared CertVerifier object.
+  // Should not be used it SetCertVerifier() is used. The consumer must ensure
+  // the CertVerifier outlives the URLRequestContext returned by the builder.
+  //
+  // TODO(mmenke): Figure out if consumers can use SetCertVerifier instead. See:
+  // https://crbug.com/743251.
+  void set_shared_cert_verifier(CertVerifier* shared_cert_verifier);
+
 #if BUILDFLAG(ENABLE_REPORTING)
   void set_reporting_policy(
       std::unique_ptr<net::ReportingPolicy> reporting_policy);
@@ -267,6 +315,13 @@
   void SetInterceptors(std::vector<std::unique_ptr<URLRequestInterceptor>>
                            url_request_interceptors);
 
+  // Sets a callback that is passed ownership of the URLRequestJobFactory, and
+  // can wrap it in another URLRequestJobFactory. URLRequestInterceptors can't
+  // handle intercepting unsupported protocols, while this case.
+  // TODO(mmenke): Remove this, once it's no longer needed.
+  void set_create_intercepting_job_factory(
+      CreateInterceptingJobFactory create_intercepting_job_factory);
+
   // Override the default in-memory cookie store and channel id service.
   // If both |cookie_store| and |channel_id_service| are NULL, CookieStore and
   // ChannelIDService will be disabled for this context.
@@ -322,6 +377,8 @@
 
   std::string accept_language_;
   std::string user_agent_;
+  HttpUserAgentSettings* shared_http_user_agent_settings_;
+
   // Include support for data:// requests.
   bool data_enabled_;
 #if !BUILDFLAG(DISABLE_FILE_SUPPORT)
@@ -341,8 +398,10 @@
   HttpCacheParams http_cache_params_;
   HttpNetworkSession::Params http_network_session_params_;
   base::FilePath transport_security_persister_path_;
+  bool transport_security_persister_readonly_;
   NetLog* net_log_;
   std::unique_ptr<HostResolver> host_resolver_;
+  net::HostResolver* shared_host_resolver_;
   std::unique_ptr<ChannelIDService> channel_id_service_;
   std::unique_ptr<ProxyConfigService> proxy_config_service_;
   bool pac_quick_check_enabled_;
@@ -351,15 +410,19 @@
   scoped_refptr<net::SSLConfigService> ssl_config_service_;
   std::unique_ptr<NetworkDelegate> network_delegate_;
   std::unique_ptr<ProxyDelegate> proxy_delegate_;
+  ProxyDelegate* shared_proxy_delegate_;
   std::unique_ptr<CookieStore> cookie_store_;
   std::unique_ptr<HttpAuthHandlerFactory> http_auth_handler_factory_;
+  HttpAuthHandlerFactory* shared_http_auth_handler_factory_;
   std::unique_ptr<CertVerifier> cert_verifier_;
+  CertVerifier* shared_cert_verifier_;
   std::unique_ptr<CTVerifier> ct_verifier_;
   std::unique_ptr<CTPolicyEnforcer> ct_policy_enforcer_;
 #if BUILDFLAG(ENABLE_REPORTING)
   std::unique_ptr<net::ReportingPolicy> reporting_policy_;
 #endif  // BUILDFLAG(ENABLE_REPORTING)
   std::vector<std::unique_ptr<URLRequestInterceptor>> url_request_interceptors_;
+  CreateInterceptingJobFactory create_intercepting_job_factory_;
   std::unique_ptr<HttpServerProperties> http_server_properties_;
   std::map<std::string, std::unique_ptr<URLRequestJobFactory::ProtocolHandler>>
       protocol_handlers_;
diff --git a/ppapi/generators/OWNERS b/ppapi/generators/OWNERS
index 18a9061..48148d6 100644
--- a/ppapi/generators/OWNERS
+++ b/ppapi/generators/OWNERS
@@ -1,8 +1,4 @@
 bradnelson@chromium.org
-noelallen@chromium.org
-noelallen@google.com
-sehr@chromium.org
-sehr@google.com
 yzshen@chromium.org
 
 # COMPONENT: Internals>Plugins>Pepper
diff --git a/ppapi/native_client/OWNERS b/ppapi/native_client/OWNERS
index 4021feb..0f846bf 100644
--- a/ppapi/native_client/OWNERS
+++ b/ppapi/native_client/OWNERS
@@ -1,6 +1,5 @@
 bbudge@chromium.org
 bradnelson@chromium.org
 mseaborn@chromium.org
-sehr@chromium.org
 
-# COMPONENT: Internals>Plugins>Pepper
\ No newline at end of file
+# COMPONENT: Internals>Plugins>Pepper
diff --git a/ppapi/native_client/tools/browser_tester/browserdata/nacltest.js b/ppapi/native_client/tools/browser_tester/browserdata/nacltest.js
index f5e7c97..0378563 100644
--- a/ppapi/native_client/tools/browser_tester/browserdata/nacltest.js
+++ b/ppapi/native_client/tools/browser_tester/browserdata/nacltest.js
@@ -123,7 +123,6 @@
       for (var pname in params) {
         msg[pname] = params[pname];
       }
-      domAutomationController.setAutomationId(0);
       domAutomationController.send(JSON.stringify(msg));
     } else if (this_.rpc_available) {
       // Construct the URL for the RPC request.
diff --git a/remoting/host/BUILD.gn b/remoting/host/BUILD.gn
index af21a8c..887d1ad 100644
--- a/remoting/host/BUILD.gn
+++ b/remoting/host/BUILD.gn
@@ -234,8 +234,6 @@
     "process_stats_agent.h",
     "process_stats_sender.cc",
     "process_stats_sender.h",
-    "process_stats_util.cc",
-    "process_stats_util.h",
     "register_support_host_request.cc",
     "register_support_host_request.h",
     "remote_input_filter.cc",
diff --git a/remoting/host/chromeos/aura_desktop_capturer.cc b/remoting/host/chromeos/aura_desktop_capturer.cc
index 08fda205..133923c 100644
--- a/remoting/host/chromeos/aura_desktop_capturer.cc
+++ b/remoting/host/chromeos/aura_desktop_capturer.cc
@@ -41,7 +41,7 @@
 
 void AuraDesktopCapturer::CaptureFrame() {
   std::unique_ptr<cc::CopyOutputRequest> request =
-      cc::CopyOutputRequest::CreateBitmapRequest(base::Bind(
+      cc::CopyOutputRequest::CreateBitmapRequest(base::BindOnce(
           &AuraDesktopCapturer::OnFrameCaptured, weak_factory_.GetWeakPtr()));
 
   gfx::Rect window_rect(desktop_window_->bounds().size());
diff --git a/remoting/host/chromoting_param_traits.cc b/remoting/host/chromoting_param_traits.cc
index 0a5f26b3..3c00ef37 100644
--- a/remoting/host/chromoting_param_traits.cc
+++ b/remoting/host/chromoting_param_traits.cc
@@ -7,6 +7,7 @@
 #include <stdint.h>
 
 #include "base/strings/stringprintf.h"
+#include "ipc/ipc_message_protobuf_utils.h"
 #include "ipc/ipc_message_utils.h"
 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
 
@@ -281,32 +282,41 @@
 }
 
 // static
-void ParamTraits<remoting::protocol::AggregatedProcessResourceUsage>::Write(
+void ParamTraits<remoting::protocol::ProcessResourceUsage>::GetSize(
+    base::PickleSizer* s, const param_type& p) {
+  GetParamSize(s, p.process_name());
+  GetParamSize(s, p.processor_usage());
+  GetParamSize(s, p.working_set_size());
+  GetParamSize(s, p.pagefile_size());
+}
+
+// static
+void ParamTraits<remoting::protocol::ProcessResourceUsage>::Write(
     base::Pickle* m,
-    const remoting::protocol::AggregatedProcessResourceUsage& p) {
-  m->WriteString(p.name());
+    const param_type& p) {
+  m->WriteString(p.process_name());
   m->WriteDouble(p.processor_usage());
   m->WriteUInt64(p.working_set_size());
   m->WriteUInt64(p.pagefile_size());
 }
 
 // static
-bool ParamTraits<remoting::protocol::AggregatedProcessResourceUsage>::Read(
+bool ParamTraits<remoting::protocol::ProcessResourceUsage>::Read(
     const base::Pickle* m,
     base::PickleIterator* iter,
-    remoting::protocol::AggregatedProcessResourceUsage* p) {
-  std::string name;
+    param_type* p) {
+  std::string process_name;
   double processor_usage;
   uint64_t working_set_size;
   uint64_t pagefile_size;
-  if (!iter->ReadString(&name) ||
+  if (!iter->ReadString(&process_name) ||
       !iter->ReadDouble(&processor_usage) ||
       !iter->ReadUInt64(&working_set_size) ||
       !iter->ReadUInt64(&pagefile_size)) {
     return false;
   }
 
-  p->set_name(name);
+  p->set_process_name(process_name);
   p->set_processor_usage(processor_usage);
   p->set_working_set_size(working_set_size);
   p->set_pagefile_size(pagefile_size);
@@ -314,10 +324,40 @@
 }
 
 // static
-void ParamTraits<remoting::protocol::AggregatedProcessResourceUsage>::Log(
-    const remoting::protocol::AggregatedProcessResourceUsage& p,
+void ParamTraits<remoting::protocol::ProcessResourceUsage>::Log(
+    const param_type& p,
     std::string* l) {
-  l->append("AggregatedProcessResourceUsage()");
+  l->append("ProcessResourceUsage(").append(p.process_name()).append(")");
+}
+
+// static
+void ParamTraits<remoting::protocol::AggregatedProcessResourceUsage>::GetSize(
+    base::PickleSizer* s, const param_type& p) {
+  GetParamSize(s, p.usages());
+}
+
+// static
+void ParamTraits<remoting::protocol::AggregatedProcessResourceUsage>::Write(
+    base::Pickle* m,
+    const param_type& p) {
+  WriteParam(m, p.usages());
+}
+
+// static
+bool ParamTraits<remoting::protocol::AggregatedProcessResourceUsage>::Read(
+    const base::Pickle* m,
+    base::PickleIterator* iter,
+    param_type* p) {
+  return ReadParam(m, iter, p->mutable_usages());
+}
+
+// static
+void ParamTraits<remoting::protocol::AggregatedProcessResourceUsage>::Log(
+    const param_type& p,
+    std::string* l) {
+  l->append("AggregatedProcessResourceUsage(");
+  LogParam(p.usages(), l);
+  l->append(")");
 }
 
 }  // namespace IPC
diff --git a/remoting/host/chromoting_param_traits.h b/remoting/host/chromoting_param_traits.h
index 7be70d1..3a1c59d4 100644
--- a/remoting/host/chromoting_param_traits.h
+++ b/remoting/host/chromoting_param_traits.h
@@ -92,11 +92,21 @@
   static void Log(const param_type& p, std::string* l);
 };
 
-// Serializes and deserializes AggregatedProcessResourceUsage. This ParamTraits
-// specialization does not handle AggregatedProcessResourceUsage::usages().
+template <>
+struct ParamTraits<remoting::protocol::ProcessResourceUsage> {
+  typedef remoting::protocol::ProcessResourceUsage param_type;
+  static void GetSize(base::PickleSizer* s, const param_type& p);
+  static void Write(base::Pickle* m, const param_type& p);
+  static bool Read(const base::Pickle* m,
+                   base::PickleIterator* iter,
+                   param_type* p);
+  static void Log(const param_type& p, std::string* l);
+};
+
 template <>
 struct ParamTraits<remoting::protocol::AggregatedProcessResourceUsage> {
   typedef remoting::protocol::AggregatedProcessResourceUsage param_type;
+  static void GetSize(base::PickleSizer* s, const param_type& p);
   static void Write(base::Pickle* m, const param_type& p);
   static bool Read(const base::Pickle* m,
                    base::PickleIterator* iter,
diff --git a/remoting/host/desktop_session_agent_unittest.cc b/remoting/host/desktop_session_agent_unittest.cc
index fca3e95..a74db60 100644
--- a/remoting/host/desktop_session_agent_unittest.cc
+++ b/remoting/host/desktop_session_agent_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "ipc/ipc_channel_proxy.h"
 #include "ipc/ipc_listener.h"
 #include "remoting/base/auto_thread_task_runner.h"
@@ -196,4 +197,72 @@
   run_loop_.Run();
 }
 
+TEST_F(DesktopSessionAgentTest, SendAggregatedProcessResourceUsage) {
+  std::unique_ptr<IPC::Channel> receiver;
+  std::unique_ptr<IPC::Channel> sender;
+  ProcessStatsListener listener(base::Bind([](
+          DesktopSessionAgentTest* test,
+          std::unique_ptr<IPC::Channel>* receiver,
+          std::unique_ptr<IPC::Channel>* sender) {
+        test->Shutdown();
+        base::ThreadTaskRunnerHandle::Get()->DeleteSoon(
+            FROM_HERE, receiver->release());
+        base::ThreadTaskRunnerHandle::Get()->DeleteSoon(
+            FROM_HERE, sender->release());
+      },
+      base::Unretained(this),
+      base::Unretained(&receiver),
+      base::Unretained(&sender)));
+  mojo::MessagePipe pipe;
+  receiver = IPC::Channel::CreateServer(
+      pipe.handle1.release(),
+      &listener,
+      task_runner_);
+  ASSERT_TRUE(receiver->Connect());
+  sender = IPC::Channel::CreateClient(
+      pipe.handle0.release(),
+      &listener,
+      task_runner_);
+  ASSERT_TRUE(sender->Connect());
+  protocol::AggregatedProcessResourceUsage aggregated;
+  for (int i = 0; i < 2; i++) {
+    *aggregated.add_usages() = protocol::ProcessResourceUsage();
+  }
+  ASSERT_TRUE(sender->Send(
+      new ChromotingAnyToNetworkMsg_ReportProcessStats(aggregated)));
+  run_loop_.Run();
+}
+
+TEST_F(DesktopSessionAgentTest, SendEmptyAggregatedProcessResourceUsage) {
+  std::unique_ptr<IPC::Channel> receiver;
+  std::unique_ptr<IPC::Channel> sender;
+  ProcessStatsListener listener(base::Bind([](
+          DesktopSessionAgentTest* test,
+          std::unique_ptr<IPC::Channel>* receiver,
+          std::unique_ptr<IPC::Channel>* sender) {
+        test->Shutdown();
+        base::ThreadTaskRunnerHandle::Get()->DeleteSoon(
+            FROM_HERE, receiver->release());
+        base::ThreadTaskRunnerHandle::Get()->DeleteSoon(
+            FROM_HERE, sender->release());
+      },
+      base::Unretained(this),
+      base::Unretained(&receiver),
+      base::Unretained(&sender)));
+  mojo::MessagePipe pipe;
+  receiver = IPC::Channel::CreateServer(
+      pipe.handle1.release(),
+      &listener,
+      task_runner_);
+  ASSERT_TRUE(receiver->Connect());
+  sender = IPC::Channel::CreateClient(
+      pipe.handle0.release(),
+      &listener,
+      task_runner_);
+  ASSERT_TRUE(sender->Connect());
+  ASSERT_TRUE(sender->Send(new ChromotingAnyToNetworkMsg_ReportProcessStats(
+      protocol::AggregatedProcessResourceUsage())));
+  run_loop_.Run();
+}
+
 }  // namespace remoting
diff --git a/remoting/host/process_stats_sender.cc b/remoting/host/process_stats_sender.cc
index 7a2f7f8..3ec1e2d3 100644
--- a/remoting/host/process_stats_sender.cc
+++ b/remoting/host/process_stats_sender.cc
@@ -9,10 +9,18 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "remoting/host/process_stats_agent.h"
-#include "remoting/host/process_stats_util.h"
 
 namespace remoting {
 
+namespace {
+
+bool IsProcessResourceUsageValid(const protocol::ProcessResourceUsage& usage) {
+  return usage.has_process_name() && usage.has_processor_usage() &&
+         usage.has_working_set_size() && usage.has_pagefile_size();
+}
+
+}  // namespace
+
 ProcessStatsSender::ProcessStatsSender(
     protocol::ProcessStatsStub* host_stats_stub,
     base::TimeDelta interval,
@@ -41,16 +49,20 @@
 void ProcessStatsSender::ReportUsage() {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  std::vector<protocol::ProcessResourceUsage> usages;
+  protocol::AggregatedProcessResourceUsage aggregated;
   for (auto* const agent : agents_) {
     DCHECK(agent);
     protocol::ProcessResourceUsage usage = agent->GetResourceUsage();
-    if (!IsEmptyProcessResourceUsage(usage)) {
-      usages.push_back(std::move(usage));
+    if (IsProcessResourceUsageValid(usage)) {
+      *aggregated.add_usages() = usage;
+    } else {
+      LOG(ERROR) << "Invalid ProcessResourceUsage "
+                 << usage.process_name()
+                 << " received.";
     }
   }
 
-  host_stats_stub_->OnProcessStats(AggregateProcessResourceUsage(usages));
+  host_stats_stub_->OnProcessStats(aggregated);
 }
 
 }  // namespace remoting
diff --git a/remoting/host/process_stats_sender_unittest.cc b/remoting/host/process_stats_sender_unittest.cc
index 6d08818c..1a445f9 100644
--- a/remoting/host/process_stats_sender_unittest.cc
+++ b/remoting/host/process_stats_sender_unittest.cc
@@ -73,19 +73,19 @@
   }
 
   // Checks the expected usage based on index.
-  static void AssertExpected(
-      const protocol::AggregatedProcessResourceUsage& usage,
-      size_t index) {
+  static void AssertExpected(const protocol::ProcessResourceUsage& usage,
+                             size_t index) {
+    ASSERT_EQ(usage.process_name(), "FakeProcessStatsAgent");
     ASSERT_EQ(usage.processor_usage(), index);
     ASSERT_EQ(usage.working_set_size(), index);
     ASSERT_EQ(usage.pagefile_size(), index);
   }
 
-  static void AssertExpected(const protocol::ProcessResourceUsage& usage,
-                             size_t index) {
-    ASSERT_EQ(usage.processor_usage(), index);
-    ASSERT_EQ(usage.working_set_size(), index);
-    ASSERT_EQ(usage.pagefile_size(), index);
+  static void AssertExpected(
+      const protocol::AggregatedProcessResourceUsage& usage,
+      size_t index) {
+    ASSERT_EQ(usage.usages_size(), 1);
+    AssertExpected(usage.usages().Get(0), index);
   }
 
   size_t issued_times() const { return index_; }
@@ -169,7 +169,7 @@
 
   ASSERT_EQ(stub.received().size(), 10U);
   for (size_t i = 0; i < stub.received().size(); i++) {
-    FakeProcessStatsAgent::AssertExpected(stub.received()[i], i * 2);
+    ASSERT_EQ(stub.received()[i].usages_size(), 2);
     for (int j = 0; j < stub.received()[i].usages_size(); j++) {
       FakeProcessStatsAgent::AssertExpected(
           stub.received()[i].usages().Get(j), i);
diff --git a/remoting/host/process_stats_util.cc b/remoting/host/process_stats_util.cc
deleted file mode 100644
index b87402f..0000000
--- a/remoting/host/process_stats_util.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2017 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/process_stats_util.h"
-
-#include <stdint.h>
-
-#include <string>
-#include <utility>
-
-namespace remoting {
-
-bool IsEmptyProcessResourceUsage(const protocol::ProcessResourceUsage& usage) {
-  return !usage.has_process_name() && !usage.has_processor_usage() &&
-         !usage.has_working_set_size() && !usage.has_pagefile_size();
-}
-
-protocol::AggregatedProcessResourceUsage AggregateProcessResourceUsage(
-    const std::vector<protocol::ProcessResourceUsage>& usages) {
-  if (usages.empty()) {
-    return protocol::AggregatedProcessResourceUsage();
-  }
-
-  if (usages.size() == 1) {
-    const protocol::ProcessResourceUsage& usage = usages[0];
-    protocol::AggregatedProcessResourceUsage aggregated;
-    aggregated.set_name(usage.process_name());
-    aggregated.set_processor_usage(usage.processor_usage());
-    aggregated.set_working_set_size(usage.working_set_size());
-    aggregated.set_pagefile_size(usage.pagefile_size());
-    return aggregated;
-  }
-
-  std::string name = "aggregate { ";
-  double processor_usage = 0;
-  uint64_t working_set_size = 0;
-  uint64_t pagefile_size = 0;
-  protocol::AggregatedProcessResourceUsage aggregated;
-  for (const auto& usage : usages) {
-    name.append(usage.process_name()).append(", ");
-    processor_usage += usage.processor_usage();
-    working_set_size += usage.working_set_size();
-    pagefile_size += usage.pagefile_size();
-    *aggregated.add_usages() = usage;
-  }
-  name += " }";
-  aggregated.set_name(std::move(name));
-  aggregated.set_processor_usage(processor_usage);
-  aggregated.set_working_set_size(working_set_size);
-  aggregated.set_pagefile_size(pagefile_size);
-
-  return aggregated;
-}
-
-}  // namespace remoting
diff --git a/remoting/host/process_stats_util.h b/remoting/host/process_stats_util.h
deleted file mode 100644
index 6ad9739..0000000
--- a/remoting/host/process_stats_util.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2017 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_PROCESS_STATS_UTIL_H_
-#define REMOTING_HOST_PROCESS_STATS_UTIL_H_
-
-#include <vector>
-
-#include "remoting/proto/process_stats.pb.h"
-
-namespace remoting {
-
-// Whether the |usage| is empty, i.e. all fields hold initial values.
-bool IsEmptyProcessResourceUsage(const protocol::ProcessResourceUsage& usage);
-
-// Merges several ProcessResourceUsage instances into one
-// AggregatedProcessResourceUsage.
-protocol::AggregatedProcessResourceUsage AggregateProcessResourceUsage(
-    const std::vector<protocol::ProcessResourceUsage>& usages);
-
-}  // namespace remoting
-
-#endif  // REMOTING_HOST_PROCESS_STATS_UTIL_H_
diff --git a/remoting/ios/app/BUILD.gn b/remoting/ios/app/BUILD.gn
index 2bee702c..f784476a 100644
--- a/remoting/ios/app/BUILD.gn
+++ b/remoting/ios/app/BUILD.gn
@@ -26,6 +26,8 @@
     "first_launch_view_presenter.mm",
     "help_and_feedback.h",
     "help_and_feedback.mm",
+    "help_view_controller.h",
+    "help_view_controller.mm",
     "host_collection_header_view.h",
     "host_collection_header_view.mm",
     "host_collection_view_cell.h",
diff --git a/remoting/ios/app/app_delegate.mm b/remoting/ios/app/app_delegate.mm
index 5907963..320d97f2 100644
--- a/remoting/ios/app/app_delegate.mm
+++ b/remoting/ios/app/app_delegate.mm
@@ -15,6 +15,7 @@
 #import "remoting/ios/app/app_view_controller.h"
 #import "remoting/ios/app/first_launch_view_presenter.h"
 #import "remoting/ios/app/help_and_feedback.h"
+#import "remoting/ios/app/help_view_controller.h"
 #import "remoting/ios/app/remoting_view_controller.h"
 #import "remoting/ios/app/user_status_presenter.h"
 #import "remoting/ios/app/web_view_controller.h"
@@ -26,9 +27,6 @@
 }
 @end
 
-// TODO(nicholss): These urls should come from a global config.
-static NSString* const kHelpCenterUrl =
-    @"https://support.google.com/chrome/answer/1649523?co=GENIE.Platform%3DiOS";
 // TODO(nicholss): There is no FAQ page at the moment.
 static NSString* const kFAQsUrl =
     @"https://support.google.com/chrome/answer/1649523?co=GENIE.Platform%3DiOS";
@@ -123,13 +121,13 @@
 }
 
 - (void)navigateToHelpCenter:(UINavigationController*)navigationController {
-  [navigationController pushViewController:[self createHelpViewController]
+  [navigationController pushViewController:[[HelpViewController alloc] init]
                                   animated:YES];
 }
 
 - (void)presentHelpCenter {
   UINavigationController* navController = [[UINavigationController alloc]
-      initWithRootViewController:[self createHelpViewController]];
+      initWithRootViewController:[[HelpViewController alloc] init]];
   [AppDelegate.topPresentingVC presentViewController:navController
                                             animated:YES
                                           completion:nil];
@@ -152,22 +150,6 @@
 
 #pragma mark - Private
 
-- (WebViewController*)createHelpViewController {
-  WebViewController* viewController =
-      [[WebViewController alloc] initWithUrl:kHelpCenterUrl
-                                       title:@"Help Center"];
-  viewController.navigationItem.rightBarButtonItem =
-      [[UIBarButtonItem alloc] initWithTitle:@"Credits"
-                                       style:UIBarButtonItemStylePlain
-                                      target:self
-                                      action:@selector(onTapCredits:)];
-  return viewController;
-}
-
-- (void)onTapCredits:(id)button {
-  NSLog(@"tap credits");
-}
-
 + (UIViewController*)topPresentingVC {
   UIViewController* topController =
       UIApplication.sharedApplication.keyWindow.rootViewController;
diff --git a/remoting/ios/app/help_view_controller.h b/remoting/ios/app/help_view_controller.h
new file mode 100644
index 0000000..bd081fd
--- /dev/null
+++ b/remoting/ios/app/help_view_controller.h
@@ -0,0 +1,19 @@
+// Copyright 2017 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_IOS_APP_HELP_VIEW_CONTROLLER_H_
+#define REMOTING_IOS_APP_HELP_VIEW_CONTROLLER_H_
+
+#import <UIKit/UIKit.h>
+
+#import "remoting/ios/app/web_view_controller.h"
+
+// A VC that shows the help center.
+@interface HelpViewController : WebViewController
+
+- (instancetype)init;
+
+@end
+
+#endif  // REMOTING_IOS_APP_HELP_VIEW_CONTROLLER_H_
diff --git a/remoting/ios/app/help_view_controller.mm b/remoting/ios/app/help_view_controller.mm
new file mode 100644
index 0000000..fbd8027
--- /dev/null
+++ b/remoting/ios/app/help_view_controller.mm
@@ -0,0 +1,41 @@
+// Copyright 2017 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.
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+#import "remoting/ios/app/help_view_controller.h"
+
+// TODO(nicholss): These urls should come from a global config.
+static NSString* const kHelpCenterUrl =
+    @"https://support.google.com/chrome/answer/1649523?co=GENIE.Platform%3DiOS";
+
+static NSString* const kCreditsUrlString =
+    [[NSBundle mainBundle] URLForResource:@"credits" withExtension:@"html"]
+        .absoluteString;
+
+@implementation HelpViewController
+
+- (instancetype)init {
+  if (self = [super initWithUrl:kHelpCenterUrl title:@"Help Center"]) {
+    self.navigationItem.rightBarButtonItem =
+        [[UIBarButtonItem alloc] initWithTitle:@"Credits"
+                                         style:UIBarButtonItemStylePlain
+                                        target:self
+                                        action:@selector(onTapCredits:)];
+  }
+  return self;
+}
+
+#pragma mark - Private
+
+- (void)onTapCredits:(id)button {
+  WebViewController* creditsVC =
+      [[WebViewController alloc] initWithUrl:kCreditsUrlString
+                                       title:@"Credits"];
+  [self.navigationController pushViewController:creditsVC animated:YES];
+}
+
+@end
diff --git a/remoting/ios/app/remoting_ios_tmpl.gni b/remoting/ios/app/remoting_ios_tmpl.gni
index 2711e01..da3d07b 100644
--- a/remoting/ios/app/remoting_ios_tmpl.gni
+++ b/remoting/ios/app/remoting_ios_tmpl.gni
@@ -7,8 +7,9 @@
 import("//build/mac/tweak_info_plist.gni")
 import("//build/util/process_version.gni")
 import("//remoting/build/config/remoting_build.gni")
+import("//remoting/credits/credits.gni")
 
-remoting_ios_app_source_dir = get_path_info("./", "abspath")
+_remoting_ios_app_source_dir = get_path_info("./", "abspath")
 
 # Arguments
 #
@@ -28,24 +29,47 @@
 #     (optional) string, the bundle_id. If this is not set, it will come from
 #     either branding_Chromium or branding_Chrome
 template("ios_remoting_app_tmpl") {
-  info_plist_target_name = "${target_name}_tweak_info_plist"
-  tweak_info_plist(info_plist_target_name) {
+  _app_target_name = target_name
+  _info_plist_target_name = "${target_name}_tweak_info_plist"
+  tweak_info_plist(_info_plist_target_name) {
     info_plist = invoker.info_plist_path
     args = [ "--platform=ios" ]
   }
 
-  launchscreen_storyboard_target_name = "${target_name}_launchscreen_storyboard"
-  bundle_data_ib_file(launchscreen_storyboard_target_name) {
+  _launchscreen_storyboard_target_name = "${target_name}_launchscreen_storyboard"
+  bundle_data_ib_file(_launchscreen_storyboard_target_name) {
     source = rebase_path("resources/LaunchScreen.storyboard",
                          ".",
-                         remoting_ios_app_source_dir)
+                         _remoting_ios_app_source_dir)
+  }
+
+  # Compiles the credits files into the gen directory.
+  _credits_resources_target_name = "${target_name}_credits_resources"
+  remoting_credits(_credits_resources_target_name) {
+    app_target_gen_dir = get_label_info(":$_app_target_name", "target_gen_dir")
+    credits_gen_dir =
+        "${app_target_gen_dir}/${_app_target_name}_credits_resources"
+    target_dir = get_path_info("./", "abspath")
+    gn_target = "${target_dir}:${_app_target_name}"
+  }
+
+  # Adds the compiled credits files into the bundle.
+  _credits_bundle_target_name = "${target_name}_credits_bundle"
+  bundle_data(_credits_bundle_target_name) {
+    sources = get_target_outputs(":$_credits_resources_target_name")
+    public_deps = [
+      ":$_credits_resources_target_name",
+    ]
+    outputs = [
+      "{{bundle_resources_dir}}/{{source_file_part}}",
+    ]
   }
 
   ios_app_bundle(target_name) {
     output_name = invoker.output_name
 
     entitlements_path = invoker.entitlements_path
-    info_plist_target = ":$info_plist_target_name"
+    info_plist_target = ":$_info_plist_target_name"
 
     if (defined(invoker.bundle_id)) {
       bundle_id = invoker.bundle_id
@@ -79,6 +103,11 @@
 
     deps = invoker.deps
 
-    bundle_deps = [ ":$launchscreen_storyboard_target_name" ]
+    bundle_deps = [
+      ":$_launchscreen_storyboard_target_name",
+      ":$_credits_bundle_target_name",
+    ]
+
+    assert_no_deps = [ "//third_party/ffmpeg:*" ]
   }
 }
diff --git a/remoting/proto/process_stats.proto b/remoting/proto/process_stats.proto
index 77d9c8f..c7f521d2 100644
--- a/remoting/proto/process_stats.proto
+++ b/remoting/proto/process_stats.proto
@@ -28,20 +28,8 @@
 }
 
 // The resource usage of several processes.
-// Next Id: 6
+// Next Id: 2
 message AggregatedProcessResourceUsage {
-  // A friendly name of the processes current instance aggregated from.
-  optional string name = 1;
-
-  // The total processor usage.
-  optional double processor_usage = 2;
-
-  // The total memory usage of working set.
-  optional uint64 working_set_size = 3;
-
-  // The total memory usage of page file.
-  optional uint64 pagefile_size = 4;
-
   // The process resource usage of each individual process.
-  repeated ProcessResourceUsage usages = 5;
+  repeated ProcessResourceUsage usages = 1;
 }
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index fa4c3fa..96b61b5 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -385,11 +385,12 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
           ],
+          "hard_timeout": 960,
           "output_links": [
             {
               "link": [
@@ -399,7 +400,8 @@
               ],
               "name": "shard #${SHARD_INDEX} logcats"
             }
-          ]
+          ],
+          "shards": 2
         },
         "test": "components_unittests"
       },
@@ -467,7 +469,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -482,7 +484,8 @@
               ],
               "name": "shard #${SHARD_INDEX} logcats"
             }
-          ]
+          ],
+          "shards": 3
         },
         "test": "content_shell_test_apk"
       },
@@ -507,11 +510,12 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
           ],
+          "hard_timeout": 960,
           "output_links": [
             {
               "link": [
@@ -1100,12 +1104,12 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
           ],
-          "hard_timeout": 120,
+          "hard_timeout": 300,
           "output_links": [
             {
               "link": [
@@ -1143,7 +1147,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -1183,11 +1187,12 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
           ],
+          "hard_timeout": 960,
           "output_links": [
             {
               "link": [
@@ -1197,7 +1202,8 @@
               ],
               "name": "shard #${SHARD_INDEX} logcats"
             }
-          ]
+          ],
+          "shards": 3
         },
         "test": "net_unittests"
       },
@@ -1252,12 +1258,12 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
           ],
-          "hard_timeout": 120,
+          "hard_timeout": 300,
           "output_links": [
             {
               "link": [
@@ -1487,11 +1493,12 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
           ],
+          "hard_timeout": 960,
           "output_links": [
             {
               "link": [
@@ -1501,7 +1508,8 @@
               ],
               "name": "shard #${SHARD_INDEX} logcats"
             }
-          ]
+          ],
+          "shards": 2
         },
         "test": "unit_tests"
       },
@@ -6152,7 +6160,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -6167,7 +6175,8 @@
               ],
               "name": "shard #${SHARD_INDEX} logcats"
             }
-          ]
+          ],
+          "shards": 2
         },
         "test": "components_unittests"
       },
@@ -6196,7 +6205,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -6211,7 +6220,8 @@
               ],
               "name": "shard #${SHARD_INDEX} logcats"
             }
-          ]
+          ],
+          "shards": 2
         },
         "test": "components_unittests"
       },
@@ -6323,12 +6333,12 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
           ],
-          "hard_timeout": 1920,
+          "hard_timeout": 960,
           "output_links": [
             {
               "link": [
@@ -6338,7 +6348,8 @@
               ],
               "name": "shard #${SHARD_INDEX} logcats"
             }
-          ]
+          ],
+          "shards": 3
         },
         "test": "content_shell_test_apk"
       },
@@ -6368,12 +6379,12 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
           ],
-          "hard_timeout": 1920,
+          "hard_timeout": 960,
           "output_links": [
             {
               "link": [
@@ -6383,7 +6394,8 @@
               ],
               "name": "shard #${SHARD_INDEX} logcats"
             }
-          ]
+          ],
+          "shards": 3
         },
         "test": "content_shell_test_apk"
       },
@@ -6408,7 +6420,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -6452,7 +6464,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -6892,7 +6904,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -6907,7 +6919,8 @@
               ],
               "name": "shard #${SHARD_INDEX} logcats"
             }
-          ]
+          ],
+          "shards": 3
         },
         "test": "net_unittests"
       },
@@ -7172,7 +7185,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -7187,7 +7200,8 @@
               ],
               "name": "shard #${SHARD_INDEX} logcats"
             }
-          ]
+          ],
+          "shards": 2
         },
         "test": "unit_tests"
       },
@@ -7216,7 +7230,7 @@
           ],
           "dimension_sets": [
             {
-              "android_devices": "4",
+              "android_devices": "1",
               "device_os": "MMB29Q",
               "device_type": "bullhead"
             }
@@ -7231,7 +7245,8 @@
               ],
               "name": "shard #${SHARD_INDEX} logcats"
             }
-          ]
+          ],
+          "shards": 2
         },
         "test": "unit_tests"
       },
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 1d02c49..d23fc91 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -10011,7 +10011,7 @@
     "additional_compile_targets": [
       "d8",
       "gl_unittests",
-      "net_unittests",
+      "media_unittests",
       "skia_unittests",
       "ui_base_unittests"
     ],
@@ -10069,6 +10069,15 @@
           "can_use_on_swarming_builders": false
         },
         "test": "mojo_system_unittests"
+      },
+      {
+        "args": [
+          "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.net_unittests.filter"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": false
+        },
+        "test": "net_unittests"
       }
     ]
   },
@@ -10076,7 +10085,7 @@
     "additional_compile_targets": [
       "d8",
       "gl_unittests",
-      "net_unittests",
+      "media_unittests",
       "skia_unittests",
       "ui_base_unittests"
     ],
@@ -10134,6 +10143,15 @@
           "can_use_on_swarming_builders": false
         },
         "test": "mojo_system_unittests"
+      },
+      {
+        "args": [
+          "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.net_unittests.filter"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": false
+        },
+        "test": "net_unittests"
       }
     ]
   },
diff --git a/testing/buildbot/filters/fuchsia.net_unittests.filter b/testing/buildbot/filters/fuchsia.net_unittests.filter
new file mode 100644
index 0000000..a83fef6
--- /dev/null
+++ b/testing/buildbot/filters/fuchsia.net_unittests.filter
@@ -0,0 +1,36 @@
+# TODO(fuchsia): Fix these tests and remove the filter. crbug.com/731302 .
+
+-*HTTPS*
+-*QuicEndToEndTest.Large*
+-*QuicEndToEndTest.TokenBinding*
+-*QuicEndToEndTest.Uber*
+-*QuicHttpStreamTest*
+-*RootCert*
+-*Socket*
+-BbrSenderTest.SimpleTransferAckDecimation2
+-CertNetFetcherImplTest*
+-CertVerifyProcInternalTest.*
+-CloseOnConnectHttpServerTest.ServerImmediatelyClosesConnection
+-DiskCache*
+-EffectiveConnectionTypeTest*
+-EmbeddedTestServer*
+-FilenameUtilTest.Generate*
+-FileStreamTest.*
+-HttpNetworkTransactionTest.UploadUnreadableFile
+-HttpServerTest.*
+-MimeUtilTest.*
+-NetworkInterfacesTest.GetNetworkList
+-NetworkQualitiesPrefManager*
+-NetworkQualityEstimatorTest*
+-Proxy*
+-PythonUtils*
+-QuicSimpleClientTest*
+-ReportingUploader*
+-SimpleIndexFileTest*
+-SpdyNetworkTransactionTest.UnreadableFilePost
+-SQLite*
+-SSL*
+-ThroughputAnalyzerTest*
+-TokenBindingURLRequest*
+-URLFetcher*
+-URLRequest*
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index dfc049c..2ca86cf4 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -46,7 +46,6 @@
 crbug.com/591099 accessibility/aria-text-role.html [ Failure ]
 crbug.com/591099 accessibility/aria-toggle-button-with-title.html [ Failure ]
 crbug.com/591099 accessibility/aria-used-on-image-maps.html [ Failure ]
-crbug.com/591099 accessibility/bounds-calc.html [ Crash Failure Pass ]
 crbug.com/591099 accessibility/br-element-has-correct-title.html [ Failure ]
 crbug.com/591099 accessibility/button-title-uses-inner-img-alt.html [ Failure ]
 crbug.com/591099 accessibility/calling-accessibility-methods-with-pending-layout-causes-crash.html [ Failure ]
@@ -212,7 +211,7 @@
 crbug.com/591099 animations/font-size-using-ems.html [ Failure Pass ]
 crbug.com/591099 animations/hit-testing/inline-element-animation-end-hit-test.html [ Failure ]
 crbug.com/591099 animations/interpolation/backdrop-filter-interpolation.html [ Crash Timeout ]
-crbug.com/591099 animations/interpolation/background-image-interpolation.html [ Crash Timeout ]
+crbug.com/591099 animations/interpolation/background-image-interpolation.html [ Crash Pass Timeout ]
 crbug.com/591099 animations/interpolation/border-image-width-interpolation.html [ Crash Timeout ]
 crbug.com/591099 animations/interpolation/filter-interpolation.html [ Crash Pass Timeout ]
 crbug.com/591099 animations/interpolation/line-height-interpolation.html [ Crash Pass Timeout ]
@@ -262,8 +261,8 @@
 crbug.com/591099 compositing/animation/busy-indicator.html [ Failure ]
 crbug.com/591099 compositing/animation/hidden-composited.html [ Failure ]
 crbug.com/591099 compositing/animation/state-at-end-event-transform-layer.html [ Failure Pass ]
-crbug.com/591099 compositing/backface-visibility/backface-visibility-image.html [ Failure ]
-crbug.com/591099 compositing/backface-visibility/backface-visibility-webgl.html [ Failure ]
+crbug.com/591099 compositing/backface-visibility/backface-visibility-image.html [ Failure Pass ]
+crbug.com/591099 compositing/backface-visibility/backface-visibility-webgl.html [ Failure Pass ]
 crbug.com/591099 compositing/backing/no-backing-foreground-layer.html [ Failure ]
 crbug.com/591099 compositing/checkerboard.html [ Failure ]
 crbug.com/591099 compositing/child-transform-layer-requires-box.html [ Failure ]
@@ -347,7 +346,6 @@
 crbug.com/591099 compositing/gestures/gesture-tapHighlight-img-and-text-2.html [ Failure ]
 crbug.com/591099 compositing/gestures/gesture-tapHighlight-img-transformed.html [ Failure ]
 crbug.com/591099 compositing/gestures/gesture-tapHighlight-overflowing-text-crash.html [ Failure ]
-crbug.com/591099 compositing/gestures/gesture-tapHighlight-pixel-rotated-link.html [ Failure Pass ]
 crbug.com/591099 compositing/gestures/gesture-tapHighlight-with-box-shadow.html [ Failure ]
 crbug.com/591099 compositing/iframes/become-composited-nested-iframes.html [ Failure ]
 crbug.com/591099 compositing/iframes/become-overlapped-iframe.html [ Failure ]
@@ -1508,7 +1506,7 @@
 crbug.com/591099 css3/filters/regions-expanding.html [ Crash Failure ]
 crbug.com/591099 css3/filters/remove-filter-rendering.html [ Failure ]
 crbug.com/591099 css3/filters/simple-filter-rendering.html [ Failure ]
-crbug.com/591099 css3/flexbox/alignContent-applies-with-flexWrap-wrap-with-single-line.html [ Failure ]
+crbug.com/591099 css3/flexbox/alignContent-applies-with-flexWrap-wrap-with-single-line.html [ Failure Pass ]
 crbug.com/591099 css3/flexbox/assert-generated-new-flexbox.html [ Failure ]
 crbug.com/591099 css3/flexbox/bug527039.html [ Failure ]
 crbug.com/591099 css3/flexbox/button.html [ Failure ]
@@ -1531,14 +1529,13 @@
 crbug.com/591099 css3/flexbox/flex-item-contains-strict.html [ Crash Failure ]
 crbug.com/591099 css3/flexbox/flex-longhand-parsing.html [ Failure ]
 crbug.com/591099 css3/flexbox/flex-one-sets-flex-basis-to-zero-px.html [ Failure ]
-crbug.com/591099 css3/flexbox/flex-percentage-height-in-table-standards-mode.html [ Failure ]
-crbug.com/591099 css3/flexbox/flex-percentage-height-in-table.html [ Failure ]
+crbug.com/591099 css3/flexbox/flex-percentage-height-in-table-standards-mode.html [ Failure Pass ]
+crbug.com/591099 css3/flexbox/flex-percentage-height-in-table.html [ Failure Pass ]
 crbug.com/591099 css3/flexbox/flex-property-parsing.html [ Failure ]
 crbug.com/591099 css3/flexbox/flexbox-baseline-margins.html [ Failure ]
 crbug.com/591099 css3/flexbox/flexbox-baseline.html [ Failure ]
 crbug.com/591099 css3/flexbox/flexbox-wordwrap.html [ Failure ]
 crbug.com/591099 css3/flexbox/floated-flexbox.html [ Failure ]
-crbug.com/591099 css3/flexbox/floated-flexitem.html [ Failure Pass ]
 crbug.com/591099 css3/flexbox/intrinsic-width-orthogonal-writing-mode.html [ Failure ]
 crbug.com/591099 css3/flexbox/large-flex-shrink-assert.html [ Failure ]
 crbug.com/591099 css3/flexbox/line-wrapping.html [ Failure ]
@@ -3230,25 +3227,39 @@
 crbug.com/591099 external/wpt/WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_empty.https.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_long.https.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/derive_bits_keys/test_pbkdf2_short_short.https.html [ Pass Timeout ]
+crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures.worker.html [ Timeout ]
+crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_AES-CBC.worker.html [ Timeout ]
+crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_AES-CTR.worker.html [ Timeout ]
+crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_AES-GCM.worker.html [ Timeout ]
+crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_AES-KW.worker.html [ Timeout ]
+crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_ECDH.worker.html [ Timeout ]
+crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_ECDSA.worker.html [ Timeout ]
+crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_HMAC.worker.html [ Timeout ]
+crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_RSA-OAEP.worker.html [ Timeout ]
+crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_RSA-PSS.worker.html [ Timeout ]
+crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_RSASSA-PKCS1-v1_5.worker.html [ Timeout ]
+crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/successes.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/test_failures.https.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/test_failures_AES-CBC.https.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/test_failures_AES-CTR.https.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/test_failures_AES-GCM.https.html [ Pass Timeout ]
+crbug.com/591099 external/wpt/WebCryptoAPI/import_export/rsa_importKey.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/import_export/test_rsa_importKey.https.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/import_export/test_symmetric_importKey.https.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/XMLHttpRequest/send-authentication-prompt-2-manual.htm [ Crash Failure ]
 crbug.com/591099 external/wpt/css/CSS2/abspos/abspos-containing-block-initial-001.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/abspos/abspos-containing-block-initial-009a.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/floats-clear/float-replaced-width-002.xht [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/floats-clear/floats-001.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/floats-clear/floats-001.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/CSS2/floats-clear/floats-009.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/floats-clear/floats-029.xht [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/floats-clear/floats-031.xht [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/floats-clear/floats-114.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/floats-clear/floats-031.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/CSS2/floats-clear/floats-114.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/CSS2/floats-clear/floats-125.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/CSS2/floats-clear/floats-132.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/CSS2/floats-clear/floats-143.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/floats-clear/floats-144.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/CSS2/floats-clear/floats-147.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/floats-clear/margin-collapse-018.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/floats-clear/margin-collapse-027.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/floats-clear/margin-collapse-033.xht [ Failure ]
@@ -3256,10 +3267,10 @@
 crbug.com/591099 external/wpt/css/CSS2/floats-clear/margin-collapse-035.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/floats-clear/margin-collapse-125.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/floats-clear/margin-collapse-157.xht [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/floats-clear/margin-collapse-clear-002.xht [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/floats-clear/margin-collapse-clear-003.xht [ Crash Failure ]
+crbug.com/591099 external/wpt/css/CSS2/floats-clear/margin-collapse-clear-002.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/CSS2/floats-clear/margin-collapse-clear-003.xht [ Crash Failure Pass ]
 crbug.com/591099 external/wpt/css/CSS2/floats-clear/margin-collapse-clear-008.xht [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/floats-clear/margin-collapse-clear-009.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/floats-clear/margin-collapse-clear-009.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/CSS2/floats-clear/margin-collapse-clear-012.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/floats-clear/margin-collapse-clear-013.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/floats-clear/margin-collapse-clear-014.xht [ Failure ]
@@ -3271,7 +3282,7 @@
 crbug.com/591099 external/wpt/css/CSS2/floats/floats-wrap-bfc-003-left-overflow.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/floats/floats-wrap-bfc-003-right-overflow.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/floats/floats-wrap-bfc-004.xht [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/floats/floats-wrap-bfc-005.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/floats/floats-wrap-bfc-005.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/CSS2/floats/floats-wrap-bfc-007.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/floats/floats-wrap-top-below-bfc-001l.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/floats/floats-wrap-top-below-bfc-001r.xht [ Failure ]
@@ -3289,12 +3300,10 @@
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-percents-001.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-replaced-width-006.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/blocks-025.xht [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/normal-flow/inline-block-valign-001.xht [ Failure Pass ]
-crbug.com/591099 external/wpt/css/CSS2/normal-flow/inline-block-valign-002.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/inline-replaced-width-012.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/inline-replaced-width-013.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/inline-replaced-width-015.xht [ Failure Pass ]
-crbug.com/591099 external/wpt/css/CSS2/normal-flow/inline-table-zorder-005.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/normal-flow/inline-table-zorder-005.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/inlines-013.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/max-height-percentage-002.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/root-box-001.xht [ Crash Failure ]
@@ -3373,28 +3382,28 @@
 crbug.com/591099 external/wpt/css/CSS2/text/text-decoration-applies-to-015.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/text/text-indent-012.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/text/text-transform-capitalize-003.xht [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/text/white-space-mixed-002.xht [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/text/white-space-normal-001.xht [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/text/white-space-normal-002.xht [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/text/white-space-normal-003.xht [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/text/white-space-normal-004.xht [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/text/white-space-normal-005.xht [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/text/white-space-normal-006.xht [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/text/white-space-nowrap-005.xht [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/text/white-space-nowrap-006.xht [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/text/white-space-pre-001.xht [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/text/white-space-pre-002.xht [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/text/white-space-pre-005.xht [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/text/white-space-pre-006.xht [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-mixed-002.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-normal-001.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-normal-002.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-normal-003.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-normal-004.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-normal-005.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-normal-006.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-nowrap-005.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-nowrap-006.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-pre-001.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-pre-002.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-pre-005.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/CSS2/text/white-space-pre-006.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-align-3/distribution-values/space-evenly-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-display-3/display-contents-dynamic-flex-002-inline.html [ Crash Failure ]
-crbug.com/591099 external/wpt/css/css-display-3/display-contents-dynamic-list-001-inline.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-display-3/display-contents-dynamic-list-001-none.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-display-3/display-contents-dynamic-multicol-001-inline.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-display-3/display-contents-dynamic-multicol-001-none.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-display-3/display-contents-dynamic-list-001-inline.html [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-display-3/display-contents-dynamic-list-001-none.html [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-display-3/display-contents-dynamic-multicol-001-inline.html [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-display-3/display-contents-dynamic-multicol-001-none.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-display-3/display-contents-dynamic-table-001-inline.html [ Crash Failure ]
-crbug.com/591099 external/wpt/css/css-display-3/display-contents-list-001.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-display-3/display-contents-multicol-001.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-display-3/display-contents-list-001.html [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-display-3/display-contents-multicol-001.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-display-3/display-flow-root-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-flexbox-1/Flexible-order.html [ Crash Failure Pass ]
 crbug.com/591099 external/wpt/css/css-flexbox-1/auto-margins-001.html [ Failure ]
@@ -3547,7 +3556,7 @@
 crbug.com/591099 external/wpt/css/css-flexbox-1/flexbox_margin-auto.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-flexbox-1/flexbox_margin-left-ex.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-flexbox-1/flexbox_margin.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-flexbox-1/flexbox_object.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-flexbox-1/flexbox_object.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-flexbox-1/flexbox_order-box.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-flexbox-1/flexbox_order.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-flexbox-1/flexbox_rtl-direction.html [ Failure ]
@@ -3562,7 +3571,7 @@
 crbug.com/591099 external/wpt/css/css-flexbox-1/order/order-with-row-reverse.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-flexbox-1/percentage-heights-000.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-flexbox-1/percentage-heights-001.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-flexbox-1/percentage-widths-001.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-flexbox-1/percentage-widths-001.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-flexbox-1/position-absolute-002.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-flexbox-1/position-absolute-004.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-flexbox-1/position-absolute-005.html [ Failure ]
@@ -3599,10 +3608,7 @@
 crbug.com/591099 external/wpt/css/css-grid-1/abspos/positioned-grid-items-015.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-grid-1/abspos/positioned-grid-items-016.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-grid-1/abspos/positioned-grid-items-017.html [ Failure ]
-crbug.com/591099 external/wpt/css/css-grid-1/alignment/grid-self-alignment-stretch-001.html [ Crash Failure Pass ]
 crbug.com/591099 external/wpt/css/css-grid-1/alignment/grid-self-alignment-stretch-002.html [ Crash Failure ]
-crbug.com/591099 external/wpt/css/css-grid-1/alignment/grid-self-alignment-stretch-003.html [ Crash Failure Pass ]
-crbug.com/591099 external/wpt/css/css-grid-1/alignment/grid-self-alignment-stretch-004.html [ Crash Failure Pass ]
 crbug.com/591099 external/wpt/css/css-grid-1/alignment/grid-self-alignment-stretch-005.html [ Crash Failure ]
 crbug.com/591099 external/wpt/css/css-grid-1/alignment/grid-self-alignment-stretch-006.html [ Crash Failure ]
 crbug.com/591099 external/wpt/css/css-grid-1/alignment/grid-self-alignment-stretch-007.html [ Crash Failure ]
@@ -3985,6 +3991,8 @@
 crbug.com/591099 external/wpt/css/css-writing-modes-3/box-offsets-rel-pos-vlr-003.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/box-offsets-rel-pos-vrl-002.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/central-baseline-alignment-002.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes-3/clearance-calculations-vrl-002.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes-3/clearance-calculations-vrl-004.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/clearance-calculations-vrl-006.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/clip-rect-vlr-011.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/clip-rect-vlr-013.xht [ Failure ]
@@ -4008,6 +4016,8 @@
 crbug.com/591099 external/wpt/css/css-writing-modes-3/float-contiguous-vlr-009.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/float-contiguous-vlr-011.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/float-contiguous-vlr-013.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes-3/float-contiguous-vrl-002.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes-3/float-contiguous-vrl-004.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/float-contiguous-vrl-006.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/float-contiguous-vrl-008.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/float-contiguous-vrl-010.xht [ Failure ]
@@ -4018,11 +4028,17 @@
 crbug.com/591099 external/wpt/css/css-writing-modes-3/float-lft-orthog-vrl-in-htb-002.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/float-rgt-orthog-htb-in-vlr-003.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/float-rgt-orthog-htb-in-vrl-003.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes-3/float-rgt-orthog-vlr-in-htb-003.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes-3/float-rgt-orthog-vrl-in-htb-003.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes-3/float-rgt-orthog-vlr-in-htb-003.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes-3/float-rgt-orthog-vrl-in-htb-003.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes-3/float-vlr-005.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/float-vlr-009.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes-3/float-vlr-011.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/float-vlr-013.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes-3/float-vrl-002.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes-3/float-vrl-004.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes-3/float-vrl-006.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/float-vrl-008.xht [ Failure Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes-3/float-vrl-010.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/float-vrl-012.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/horizontal-rule-vlr-003.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/horizontal-rule-vrl-002.xht [ Failure ]
@@ -4047,6 +4063,7 @@
 crbug.com/591099 external/wpt/css/css-writing-modes-3/line-box-direction-vrl-011.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/line-box-direction-vrl-012.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/line-box-direction-vrl-019.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes-3/margin-collapse-vrl-010.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/margin-vlr-003.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/margin-vrl-002.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/normal-flow-overconstrained-vlr-003.xht [ Failure ]
@@ -4173,6 +4190,7 @@
 crbug.com/591099 external/wpt/css/css-writing-modes-3/writing-mode-vertical-rl-002.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/writing-mode-vertical-rl-003.htm [ Failure ]
 crbug.com/591099 external/wpt/css/geometry-1/interfaces.html [ Timeout ]
+crbug.com/591099 external/wpt/css/geometry-1/interfaces.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-content-vert-001a.xhtml [ Crash Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-baseline-horiz-002.xhtml [ Failure Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-baseline-horiz-003.xhtml [ Failure Pass ]
@@ -4185,9 +4203,9 @@
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-vert-rtl-002.xhtml [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-vert-rtl-003.xhtml [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-vert-rtl-004.xhtml [ Failure ]
-crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-baseline-multi-line-horiz-003.html [ Failure ]
-crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-baseline-multi-line-horiz-004.html [ Failure ]
-crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-baseline-multi-line-vert-002.html [ Failure ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-baseline-multi-line-horiz-003.html [ Failure Pass ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-baseline-multi-line-horiz-004.html [ Failure Pass ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-baseline-multi-line-vert-002.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-baseline-single-item-001a.html [ Crash Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-baseline-single-item-001b.html [ Crash Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-break-request-horiz-002a.html [ Failure ]
@@ -4421,7 +4439,6 @@
 crbug.com/591099 external/wpt/pointerevents/pointerevent_lostpointercapture_for_disconnected_node-manual.html [ Crash Timeout ]
 crbug.com/591099 external/wpt/pointerevents/pointerevent_pointerleave_pen-manual.html [ Failure Timeout ]
 crbug.com/591099 external/wpt/pointerevents/pointerevent_touch-action-button-test_touch-manual.html [ Crash Failure Timeout ]
-crbug.com/591099 external/wpt/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html [ Crash Pass Timeout ]
 crbug.com/591099 external/wpt/pointerevents/pointerevent_touch-action-inherit_child-none_touch-manual.html [ Crash Pass Timeout ]
 crbug.com/591099 external/wpt/pointerevents/pointerevent_touch-action-span-test_touch-manual.html [ Crash Timeout ]
 crbug.com/591099 external/wpt/pointerevents/pointerevent_touch-action-svg-test_touch-manual.html [ Crash Failure Timeout ]
@@ -4608,7 +4625,7 @@
 crbug.com/591099 fast/block/float/018.html [ Failure ]
 crbug.com/591099 fast/block/float/019.html [ Failure Pass ]
 crbug.com/591099 fast/block/float/020.html [ Failure ]
-crbug.com/591099 fast/block/float/021.html [ Failure ]
+crbug.com/591099 fast/block/float/021.html [ Failure Pass ]
 crbug.com/591099 fast/block/float/022.html [ Failure ]
 crbug.com/591099 fast/block/float/023.html [ Failure ]
 crbug.com/591099 fast/block/float/024.html [ Failure ]
@@ -4630,7 +4647,7 @@
 crbug.com/591099 fast/block/float/avoid-floats-when-negative-margin-top-5.html [ Failure ]
 crbug.com/591099 fast/block/float/avoid-floats-when-negative-margin-top-6.html [ Failure ]
 crbug.com/591099 fast/block/float/avoid-floats-when-negative-margin-top.html [ Failure ]
-crbug.com/591099 fast/block/float/avoidance-rtl.html [ Crash Failure ]
+crbug.com/591099 fast/block/float/avoidance-rtl.html [ Crash Failure Pass ]
 crbug.com/591099 fast/block/float/avoiding-float-centered.html [ Failure ]
 crbug.com/591099 fast/block/float/block-with-negative-margin-clears-float.html [ Failure ]
 crbug.com/591099 fast/block/float/br-with-clear-2.html [ Failure ]
@@ -4677,8 +4694,7 @@
 crbug.com/591099 fast/block/float/intruding-painted-twice.html [ Failure ]
 crbug.com/591099 fast/block/float/logical-bottom-exceeds-layoutunit-max.html [ Failure ]
 crbug.com/591099 fast/block/float/marquee-shrink-to-avoid-floats.html [ Failure ]
-crbug.com/591099 fast/block/float/max-width-clear-float-with-overflow-hidden.html [ Failure Pass ]
-crbug.com/591099 fast/block/float/multiple-float-positioning.html [ Failure ]
+crbug.com/591099 fast/block/float/multiple-float-positioning.html [ Failure Pass ]
 crbug.com/591099 fast/block/float/negative-margin-on-element-avoiding-floats-with-margin-on-parent.html [ Failure ]
 crbug.com/591099 fast/block/float/negative-margin-on-element-avoiding-floats.html [ Failure ]
 crbug.com/591099 fast/block/float/nested-clearance.html [ Failure ]
@@ -4713,7 +4729,7 @@
 crbug.com/591099 fast/block/line-layout/negative-max-height.html [ Failure ]
 crbug.com/591099 fast/block/margin-collapse/001.html [ Failure ]
 crbug.com/591099 fast/block/margin-collapse/005.html [ Failure ]
-crbug.com/591099 fast/block/margin-collapse/006.html [ Failure ]
+crbug.com/591099 fast/block/margin-collapse/006.html [ Failure Pass ]
 crbug.com/591099 fast/block/margin-collapse/016.html [ Failure Pass ]
 crbug.com/591099 fast/block/margin-collapse/025.html [ Failure ]
 crbug.com/591099 fast/block/margin-collapse/032.html [ Failure ]
@@ -4725,9 +4741,6 @@
 crbug.com/591099 fast/block/margin-collapse/103.html [ Failure ]
 crbug.com/591099 fast/block/margin-collapse/bfc-beside-float-complex-margin-collapsing.html [ Failure ]
 crbug.com/591099 fast/block/margin-collapse/block-inside-inline/001.html [ Failure ]
-crbug.com/591099 fast/block/margin-collapse/block-inside-inline/002.html [ Failure Pass ]
-crbug.com/591099 fast/block/margin-collapse/block-inside-inline/003.html [ Failure Pass ]
-crbug.com/591099 fast/block/margin-collapse/block-inside-inline/004.html [ Failure Pass ]
 crbug.com/591099 fast/block/margin-collapse/block-inside-inline/005.html [ Failure ]
 crbug.com/591099 fast/block/margin-collapse/block-inside-inline/006.html [ Failure Pass ]
 crbug.com/591099 fast/block/margin-collapse/block-inside-inline/010.html [ Failure Pass ]
@@ -4789,7 +4802,6 @@
 crbug.com/591099 fast/block/positioning/auto/004.html [ Failure ]
 crbug.com/591099 fast/block/positioning/auto/005.html [ Failure ]
 crbug.com/591099 fast/block/positioning/auto/006.html [ Failure ]
-crbug.com/591099 fast/block/positioning/auto/007.html [ Failure Pass ]
 crbug.com/591099 fast/block/positioning/auto/vertical-lr/001.html [ Failure ]
 crbug.com/591099 fast/block/positioning/auto/vertical-lr/002.html [ Failure ]
 crbug.com/591099 fast/block/positioning/auto/vertical-lr/003.html [ Failure ]
@@ -5403,9 +5415,7 @@
 crbug.com/591099 fast/css-grid-layout/should-not-collapse-anonymous-blocks.html [ Failure ]
 crbug.com/591099 fast/css-grid-layout/stale-grid-layout.html [ Failure Pass ]
 crbug.com/591099 fast/css-grid-layout/tracks-wider-min-track-breadth-crash.html [ Failure ]
-crbug.com/591099 fast/css-intrinsic-dimensions/fill-available-with-zero-width.html [ Crash Failure Pass ]
 crbug.com/591099 fast/css-intrinsic-dimensions/fillavailable-minmax-content-inlinesize-contribution-nonreplaced-blocks.html [ Crash Failure ]
-crbug.com/591099 fast/css-intrinsic-dimensions/fit-content-container-with-replaced-child.html [ Crash Failure Pass ]
 crbug.com/591099 fast/css-intrinsic-dimensions/fitcontent-minmax-content-inlinesize-contribution-nonreplaced-blocks.html [ Crash Failure ]
 crbug.com/591099 fast/css-intrinsic-dimensions/fixed-height-stf-img-block-child-percent-height.html [ Failure ]
 crbug.com/591099 fast/css-intrinsic-dimensions/fixed-height-stf-img-inline-child-percent-height.html [ Crash Failure ]
@@ -5415,14 +5425,8 @@
 crbug.com/591099 fast/css-intrinsic-dimensions/height-property-value.html [ Failure ]
 crbug.com/591099 fast/css-intrinsic-dimensions/height.html [ Failure ]
 crbug.com/591099 fast/css-intrinsic-dimensions/indefinite-percent-minmax-content-inlinesize-contribution-nonreplaced-blocks.html [ Failure ]
-crbug.com/591099 fast/css-intrinsic-dimensions/intrinsic-sized-blocks.html [ Crash Failure Pass ]
-crbug.com/591099 fast/css-intrinsic-dimensions/max-width-constrained.html [ Crash Failure Pass ]
-crbug.com/591099 fast/css-intrinsic-dimensions/max-width-unconstrained.html [ Crash Failure Pass ]
-crbug.com/591099 fast/css-intrinsic-dimensions/maxcontent-minmax-content-inlinesize-contribution-nonreplaced-blocks.html [ Crash Failure Pass ]
 crbug.com/591099 fast/css-intrinsic-dimensions/min-width.html [ Crash Failure ]
-crbug.com/591099 fast/css-intrinsic-dimensions/mincontent-minmax-content-inlinesize-contribution-nonreplaced-blocks.html [ Crash Failure Pass ]
 crbug.com/591099 fast/css-intrinsic-dimensions/resize-inside-percent-width-overflow-hidden.html [ Failure ]
-crbug.com/591099 fast/css-intrinsic-dimensions/width-avoid-floats.html [ Crash Failure Pass ]
 crbug.com/591099 fast/css-intrinsic-dimensions/width-property-value.html [ Failure ]
 crbug.com/591099 fast/css-intrinsic-dimensions/width.html [ Crash Failure ]
 crbug.com/591099 fast/css/001.html [ Crash Failure ]
@@ -5444,7 +5448,7 @@
 crbug.com/591099 fast/css/acid2-pixel.html [ Crash Failure ]
 crbug.com/591099 fast/css/acid2.html [ Crash Failure ]
 crbug.com/591099 fast/css/all-shorthand-css-text.html [ Failure ]
-crbug.com/591099 fast/css/all-shorthand-first-letter.html [ Failure ]
+crbug.com/591099 fast/css/all-shorthand-first-letter.html [ Failure Pass ]
 crbug.com/591099 fast/css/annotated-regions.html [ Failure ]
 crbug.com/591099 fast/css/anonymous-block-continuation-outline.html [ Failure ]
 crbug.com/591099 fast/css/appearance-caps-lock-indicator.html [ Failure ]
@@ -6173,10 +6177,10 @@
 crbug.com/591099 fast/css/unused-data-url-fontface.html [ Failure ]
 crbug.com/591099 fast/css/uri-token-parsing.html [ Failure ]
 crbug.com/591099 fast/css/url-with-multi-byte-unicode-escape.html [ Failure ]
-crbug.com/591099 fast/css/vertical-align-baseline-rowspan-003.htm [ Failure ]
-crbug.com/591099 fast/css/vertical-align-baseline-rowspan-004.htm [ Failure ]
-crbug.com/591099 fast/css/vertical-align-baseline-rowspan-005.htm [ Failure ]
-crbug.com/591099 fast/css/vertical-align-baseline-rowspan-006.htm [ Failure ]
+crbug.com/591099 fast/css/vertical-align-baseline-rowspan-003.htm [ Failure Pass ]
+crbug.com/591099 fast/css/vertical-align-baseline-rowspan-004.htm [ Failure Pass ]
+crbug.com/591099 fast/css/vertical-align-baseline-rowspan-005.htm [ Failure Pass ]
+crbug.com/591099 fast/css/vertical-align-baseline-rowspan-006.htm [ Failure Pass ]
 crbug.com/591099 fast/css/vertical-align-length-copy-bug.html [ Failure ]
 crbug.com/591099 fast/css/vertical-align-lengths.html [ Failure ]
 crbug.com/591099 fast/css/vertical-lr-bfc-auto-margins-beside-float.html [ Crash Failure ]
@@ -8622,25 +8626,25 @@
 crbug.com/591099 fast/forms/search/searchfield-heights.html [ Crash Failure ]
 crbug.com/591099 fast/forms/select-popup/popup-menu-appearance-coarse.html [ Failure ]
 crbug.com/591099 fast/forms/select-popup/popup-menu-appearance-fractional-width.html [ Failure ]
-crbug.com/591099 fast/forms/select-popup/popup-menu-appearance-long.html [ Failure ]
-crbug.com/591099 fast/forms/select-popup/popup-menu-appearance-many.html [ Failure ]
-crbug.com/591099 fast/forms/select-popup/popup-menu-appearance-minimum-font.html [ Failure ]
+crbug.com/591099 fast/forms/select-popup/popup-menu-appearance-long.html [ Failure Pass ]
+crbug.com/591099 fast/forms/select-popup/popup-menu-appearance-many.html [ Failure Pass ]
+crbug.com/591099 fast/forms/select-popup/popup-menu-appearance-minimum-font.html [ Failure Pass ]
 crbug.com/591099 fast/forms/select-popup/popup-menu-appearance-rtl-default.html [ Failure ]
 crbug.com/591099 fast/forms/select-popup/popup-menu-appearance-rtl.html [ Failure ]
 crbug.com/591099 fast/forms/select-popup/popup-menu-appearance-styled.html [ Failure ]
-crbug.com/591099 fast/forms/select-popup/popup-menu-appearance-texttransform.html [ Failure ]
+crbug.com/591099 fast/forms/select-popup/popup-menu-appearance-texttransform.html [ Failure Pass ]
 crbug.com/591099 fast/forms/select-popup/popup-menu-appearance-zoom.html [ Failure ]
 crbug.com/591099 fast/forms/select-popup/popup-menu-appearance-zoom090.html [ Failure ]
 crbug.com/591099 fast/forms/select-popup/popup-menu-appearance-zoom110.html [ Failure ]
-crbug.com/591099 fast/forms/select-popup/popup-menu-appearance.html [ Failure ]
+crbug.com/591099 fast/forms/select-popup/popup-menu-appearance.html [ Failure Pass ]
 crbug.com/591099 fast/forms/select-popup/popup-menu-ax.html [ Crash Failure ]
 crbug.com/591099 fast/forms/select-popup/popup-menu-crash-on-cancel.html [ Crash Failure ]
 crbug.com/591099 fast/forms/select-popup/popup-menu-crash-on-close.html [ Failure ]
 crbug.com/591099 fast/forms/select-popup/popup-menu-crash-on-select.html [ Failure ]
-crbug.com/591099 fast/forms/select-popup/popup-menu-mouse-operations.html [ Failure ]
+crbug.com/591099 fast/forms/select-popup/popup-menu-mouse-operations.html [ Failure Pass ]
 crbug.com/591099 fast/forms/select-popup/popup-menu-nested-style.html [ Failure ]
-crbug.com/591099 fast/forms/select-popup/popup-menu-touch-operations.html [ Failure Timeout ]
-crbug.com/591099 fast/forms/select-popup/popup-menu-update-from-element.html [ Failure ]
+crbug.com/591099 fast/forms/select-popup/popup-menu-touch-operations.html [ Failure Pass Timeout ]
+crbug.com/591099 fast/forms/select-popup/popup-menu-update-from-element.html [ Failure Pass ]
 crbug.com/591099 fast/forms/select/003.html [ Crash Failure ]
 crbug.com/591099 fast/forms/select/004.html [ Failure ]
 crbug.com/591099 fast/forms/select/HTMLOptionElement_label01.html [ Failure ]
@@ -8781,7 +8785,7 @@
 crbug.com/591099 fast/forms/select/select-option-accesskey-crash.html [ Failure ]
 crbug.com/591099 fast/forms/select/select-overflow-scroll-inherited.html [ Failure ]
 crbug.com/591099 fast/forms/select/select-overflow-scroll.html [ Failure ]
-crbug.com/591099 fast/forms/select/select-percent-width.html [ Failure ]
+crbug.com/591099 fast/forms/select/select-percent-width.html [ Failure Pass ]
 crbug.com/591099 fast/forms/select/select-popup-close-no-crash.html [ Failure ]
 crbug.com/591099 fast/forms/select/select-popup-pagekeys.html [ Failure ]
 crbug.com/591099 fast/forms/select/select-replace-option.html [ Failure ]
@@ -8999,7 +9003,7 @@
 crbug.com/591099 fast/forms/textarea/textarea-resize-below-min-intrinsic-size.html [ Crash Pass Timeout ]
 crbug.com/591099 fast/forms/textarea/textarea-resize-below-min-size-zoomed.html [ Crash Pass Timeout ]
 crbug.com/591099 fast/forms/textarea/textarea-resize-below-min-size.html [ Crash Pass Timeout ]
-crbug.com/591099 fast/forms/textarea/textarea-resize-orthogonal-containing-block.html [ Crash Failure ]
+crbug.com/591099 fast/forms/textarea/textarea-resize-orthogonal-containing-block.html [ Crash Failure Timeout ]
 crbug.com/591099 fast/forms/textarea/textarea-rows-cols.html [ Crash Failure ]
 crbug.com/591099 fast/forms/textarea/textarea-scroll-height.html [ Crash Failure ]
 crbug.com/591099 fast/forms/textarea/textarea-scrollbar-height.html [ Crash Failure ]
@@ -9351,15 +9355,17 @@
 crbug.com/591099 fast/html/set-text-direction.html [ Crash Failure ]
 crbug.com/591099 fast/html/tab-order.html [ Crash Failure ]
 crbug.com/591099 fast/html/unknown-tag.html [ Crash Failure ]
-crbug.com/591099 fast/inline-block/001.html [ Failure Pass ]
 crbug.com/591099 fast/inline-block/002.html [ Failure ]
 crbug.com/591099 fast/inline-block/003.html [ Failure ]
 crbug.com/591099 fast/inline-block/004.html [ Failure ]
 crbug.com/591099 fast/inline-block/005.html [ Failure ]
-crbug.com/591099 fast/inline-block/006.html [ Failure Pass ]
 crbug.com/591099 fast/inline-block/14498-positionForCoordinates.html [ Failure ]
 crbug.com/591099 fast/inline-block/baseline-vertical.html [ Failure ]
 crbug.com/591099 fast/inline-block/contenteditable-baseline.html [ Failure ]
+crbug.com/591099 fast/inline-block/float-both-whitespace.html [ Failure ]
+crbug.com/591099 fast/inline-block/float-leading-whitespace.html [ Failure ]
+crbug.com/591099 fast/inline-block/float-no-whitespace.html [ Failure ]
+crbug.com/591099 fast/inline-block/float-trailing-whitespace.html [ Failure ]
 crbug.com/591099 fast/inline-block/inline-block-vertical-align-2.html [ Failure ]
 crbug.com/591099 fast/inline-block/inline-block-vertical-align.html [ Failure ]
 crbug.com/591099 fast/inline-block/overflow-clip.html [ Failure ]
@@ -9931,11 +9937,11 @@
 crbug.com/591099 fast/multicol/balance-breakafter-before-table-section-crash.html [ Failure ]
 crbug.com/591099 fast/multicol/balance-float-after-forced-break.html [ Failure ]
 crbug.com/591099 fast/multicol/balance-float-with-margin-top-and-line-after-break-2.html [ Failure ]
-crbug.com/591099 fast/multicol/balance-float-with-margin-top-and-line-after-break-3.html [ Failure ]
+crbug.com/591099 fast/multicol/balance-float-with-margin-top-and-line-after-break-3.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/balance-float-with-margin-top-and-line-after-break.html [ Failure ]
 crbug.com/591099 fast/multicol/balance-float-with-margin-top-and-line-before-break.html [ Failure ]
 crbug.com/591099 fast/multicol/balance-floats.html [ Failure ]
-crbug.com/591099 fast/multicol/balance-repeating-table-headers.html [ Crash Failure ]
+crbug.com/591099 fast/multicol/balance-repeating-table-headers.html [ Crash Failure Pass ]
 crbug.com/591099 fast/multicol/balance-short-trailing-empty-block.html [ Failure ]
 crbug.com/591099 fast/multicol/balance-trailing-border-after-break.html [ Failure ]
 crbug.com/591099 fast/multicol/balance-trailing-border.html [ Failure ]
@@ -9952,9 +9958,9 @@
 crbug.com/591099 fast/multicol/client-rect-nested.html [ Failure ]
 crbug.com/591099 fast/multicol/client-rect-overflowing-multicol-2-columns.html [ Failure ]
 crbug.com/591099 fast/multicol/client-rect-overflowing-multicol.html [ Failure ]
-crbug.com/591099 fast/multicol/client-rects-rtl.html [ Failure ]
+crbug.com/591099 fast/multicol/client-rects-rtl.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/client-rects-sole-empty-block.html [ Failure ]
-crbug.com/591099 fast/multicol/client-rects.html [ Failure ]
+crbug.com/591099 fast/multicol/client-rects.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/column-break-with-balancing.html [ Failure ]
 crbug.com/591099 fast/multicol/column-count-with-rules.html [ Failure ]
 crbug.com/591099 fast/multicol/column-width-zero.html [ Failure ]
@@ -9980,17 +9986,18 @@
 crbug.com/591099 fast/multicol/dynamic/change-block-with-inline-to-multicol-assert.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/change-second-row-height.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/change-spanner-display.html [ Crash Failure ]
+crbug.com/591099 fast/multicol/dynamic/change-spanner-parent-display.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/insert-before-sole-abspos.html [ Failure ]
-crbug.com/591099 fast/multicol/dynamic/insert-block-among-text-in-anonymous-wrapper.html [ Failure ]
-crbug.com/591099 fast/multicol/dynamic/insert-block-before-spanner-before-content.html [ Failure ]
-crbug.com/591099 fast/multicol/dynamic/insert-block-into-content.html [ Failure ]
+crbug.com/591099 fast/multicol/dynamic/insert-block-among-text-in-anonymous-wrapper.html [ Failure Pass ]
+crbug.com/591099 fast/multicol/dynamic/insert-block-before-spanner-before-content.html [ Failure Pass ]
+crbug.com/591099 fast/multicol/dynamic/insert-block-into-content.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/dynamic/insert-block-into-inline-beside-ex-spanner-table-column.html [ Crash Failure ]
 crbug.com/591099 fast/multicol/dynamic/insert-spanner-after-abspos-subtree-crash.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/insert-spanner-after-inner-multicol-crash.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/insert-spanner-after-spanner-before-content.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/dynamic/insert-spanner-after-spanner-with-inner-multicol-with-spanner-crash.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/insert-spanner-between-out-of-flow-crash.html [ Failure ]
-crbug.com/591099 fast/multicol/dynamic/insert-spanner-into-content.html [ Failure ]
+crbug.com/591099 fast/multicol/dynamic/insert-spanner-into-content.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/dynamic/insert-spanner-into-stf-constrained-width.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/insert-spanner-into-stf-unconstrained-width.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/insert-spanner-pseudo-after-then-content.html [ Crash Failure ]
@@ -10007,7 +10014,7 @@
 crbug.com/591099 fast/multicol/dynamic/remove-inline-and-spanner-after-spanner-foreignObject.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/remove-spanner-in-content.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/sole-spanner-becomes-abspos-crash.html [ Failure ]
-crbug.com/591099 fast/multicol/dynamic/spanner-after-content-becomes-regular-block.html [ Failure ]
+crbug.com/591099 fast/multicol/dynamic/spanner-after-content-becomes-regular-block.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/dynamic/spanner-ancestor-becomes-spanner.html [ Failure ]
 crbug.com/591099 fast/multicol/dynamic/spanner-becomes-abspos-crash.html [ Crash Failure ]
 crbug.com/591099 fast/multicol/dynamic/spanner-becomes-regular-block.html [ Failure ]
@@ -10038,13 +10045,13 @@
 crbug.com/591099 fast/multicol/float-big-line.html [ Failure ]
 crbug.com/591099 fast/multicol/float-break.html [ Failure ]
 crbug.com/591099 fast/multicol/float-content-break.html [ Failure ]
-crbug.com/591099 fast/multicol/float-edge.html [ Failure ]
+crbug.com/591099 fast/multicol/float-edge.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/float-margin-at-row-boundary-fixed-multicol-height.html [ Failure ]
 crbug.com/591099 fast/multicol/float-margin-at-row-boundary.html [ Failure ]
 crbug.com/591099 fast/multicol/float-moved-by-child-line-and-unbreakable.html [ Failure ]
 crbug.com/591099 fast/multicol/float-paginate-empty-lines.html [ Failure ]
 crbug.com/591099 fast/multicol/float-paginate.html [ Failure ]
-crbug.com/591099 fast/multicol/float-truncation.html [ Failure ]
+crbug.com/591099 fast/multicol/float-truncation.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/float-with-margin-moved-by-child-block-and-unbreakable.html [ Failure ]
 crbug.com/591099 fast/multicol/float-with-margin-moved-by-child-block.html [ Failure ]
 crbug.com/591099 fast/multicol/float-with-margin-moved-by-child-line-and-unbreakable.html [ Failure ]
@@ -10078,7 +10085,7 @@
 crbug.com/591099 fast/multicol/mixed-positioning-stacking-order.html [ Failure ]
 crbug.com/591099 fast/multicol/multicol-with-spanner-becomes-paged.html [ Crash Failure Pass ]
 crbug.com/591099 fast/multicol/negative-margins-crash.html [ Failure ]
-crbug.com/591099 fast/multicol/nested-3-multicols-fixed-height.html [ Failure ]
+crbug.com/591099 fast/multicol/nested-3-multicols-fixed-height.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/nested-after-composited-layer-crash.html [ Failure ]
 crbug.com/591099 fast/multicol/nested-auto-height-short-first-row.html [ Failure ]
 crbug.com/591099 fast/multicol/nested-balanced-inner-column-count-1-with-forced-break.html [ Failure ]
@@ -10117,7 +10124,7 @@
 crbug.com/591099 fast/multicol/newmulticol/breaks-3-columns-3.html [ Failure ]
 crbug.com/591099 fast/multicol/newmulticol/clipping-overflow-hidden.html [ Crash Failure ]
 crbug.com/591099 fast/multicol/newmulticol/clipping.html [ Failure ]
-crbug.com/591099 fast/multicol/newmulticol/fixed-height-fill-auto.html [ Failure ]
+crbug.com/591099 fast/multicol/newmulticol/fixed-height-fill-auto.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/newmulticol/fixed-height-fill-balance.html [ Failure ]
 crbug.com/591099 fast/multicol/newmulticol/hide-box-vertical-lr.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/newmulticol/hide-box-vertical-rl.html [ Failure Pass ]
@@ -10130,7 +10137,7 @@
 crbug.com/591099 fast/multicol/out-of-flow/abspos-auto-position-small-on-line-at-boundary.html [ Failure ]
 crbug.com/591099 fast/multicol/out-of-flow/nested-multicol.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/out-of-flow/offset-properties.html [ Failure ]
-crbug.com/591099 fast/multicol/overflow-unsplittable.html [ Failure ]
+crbug.com/591099 fast/multicol/overflow-unsplittable.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/overflowing-columns-large-gaps.html [ Failure ]
 crbug.com/591099 fast/multicol/pageLogicalOffset-vertical.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/paged-becomes-multicol-with-spanner.html [ Failure ]
@@ -10138,12 +10145,11 @@
 crbug.com/591099 fast/multicol/paginated-layer-crash.html [ Failure ]
 crbug.com/591099 fast/multicol/percent-height.html [ Failure ]
 crbug.com/591099 fast/multicol/positioned-split.html [ Failure ]
-crbug.com/591099 fast/multicol/positive-leading.html [ Crash Failure Pass ]
 crbug.com/591099 fast/multicol/relayout-and-push-float.html [ Failure ]
 crbug.com/591099 fast/multicol/remove-all-children.html [ Failure ]
 crbug.com/591099 fast/multicol/remove-style-multicol-with-nested-layers.html [ Failure ]
 crbug.com/591099 fast/multicol/ruby-crash.html [ Failure ]
-crbug.com/591099 fast/multicol/scrolling-overflow.html [ Failure ]
+crbug.com/591099 fast/multicol/scrolling-overflow.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/shadow-breaking.html [ Failure ]
 crbug.com/591099 fast/multicol/short-columns-insane-unbreakable-content-height-crash.html [ Failure ]
 crbug.com/591099 fast/multicol/shrink-to-column-height-for-pagination.html [ Crash Failure ]
@@ -10154,7 +10160,7 @@
 crbug.com/591099 fast/multicol/span/anonymous-before-child-parent-crash.html [ Crash Failure ]
 crbug.com/591099 fast/multicol/span/anonymous-split-block-crash.html [ Crash Failure ]
 crbug.com/591099 fast/multicol/span/as-inner-multicol-after-composited-layer-crash.html [ Failure ]
-crbug.com/591099 fast/multicol/span/as-inner-multicol.html [ Failure ]
+crbug.com/591099 fast/multicol/span/as-inner-multicol.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/span/autofill-after-spanner.html [ Failure ]
 crbug.com/591099 fast/multicol/span/balance-after-spanner-exact-fit.html [ Failure ]
 crbug.com/591099 fast/multicol/span/balance-after-spanner-extra-height.html [ Failure ]
@@ -10182,7 +10188,7 @@
 crbug.com/591099 fast/multicol/span/inside-overflow-hidden-crash.html [ Failure ]
 crbug.com/591099 fast/multicol/span/invalid-span-1.html [ Failure ]
 crbug.com/591099 fast/multicol/span/margin-on-multicol.html [ Failure ]
-crbug.com/591099 fast/multicol/span/nested-multicol.html [ Failure ]
+crbug.com/591099 fast/multicol/span/nested-multicol.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/span/offset-properties.html [ Failure ]
 crbug.com/591099 fast/multicol/span/outer-column-break-after-inner-spanner-2.html [ Crash Failure ]
 crbug.com/591099 fast/multicol/span/outer-column-break-after-inner-spanner-and-float.html [ Failure ]
@@ -10207,8 +10213,8 @@
 crbug.com/591099 fast/multicol/span/spanner-img.html [ Crash Failure ]
 crbug.com/591099 fast/multicol/span/spanner-in-flexbox-in-multicol-in-flexbox-crash.html [ Failure ]
 crbug.com/591099 fast/multicol/span/spanner-with-margin.html [ Crash Failure ]
-crbug.com/591099 fast/multicol/span/summary-split.html [ Failure ]
-crbug.com/591099 fast/multicol/span/two-rows-then-spanner-then-two-rows.html [ Failure ]
+crbug.com/591099 fast/multicol/span/summary-split.html [ Failure Pass ]
+crbug.com/591099 fast/multicol/span/two-rows-then-spanner-then-two-rows.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/span/underflow-after-spanner.html [ Crash Failure ]
 crbug.com/591099 fast/multicol/span/vertical-lr.html [ Failure ]
 crbug.com/591099 fast/multicol/span/vertical-rl.html [ Failure ]
@@ -10243,7 +10249,7 @@
 crbug.com/591099 fast/multicol/vertical-lr/float-content-break.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/float-edge.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/float-paginate.html [ Failure ]
-crbug.com/591099 fast/multicol/vertical-lr/float-truncation.html [ Failure ]
+crbug.com/591099 fast/multicol/vertical-lr/float-truncation.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/vertical-lr/gap-non-negative.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/image-inside-nested-blocks-with-border.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/nested-columns.html [ Crash Failure ]
@@ -10269,7 +10275,7 @@
 crbug.com/591099 fast/multicol/vertical-rl/float-content-break.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-rl/float-edge.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-rl/float-paginate.html [ Failure ]
-crbug.com/591099 fast/multicol/vertical-rl/float-truncation.html [ Failure ]
+crbug.com/591099 fast/multicol/vertical-rl/float-truncation.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/vertical-rl/gap-non-negative.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-rl/image-inside-nested-blocks-with-border.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-rl/unsplittable-inline-block.html [ Failure ]
@@ -10305,7 +10311,7 @@
 crbug.com/591099 fast/overflow/line-clamp.html [ Failure ]
 crbug.com/591099 fast/overflow/onscroll-layer-self-destruct.html [ Timeout ]
 crbug.com/591099 fast/overflow/overflow-auto-position-absolute.html [ Failure ]
-crbug.com/591099 fast/overflow/overflow-auto-table.html [ Failure ]
+crbug.com/591099 fast/overflow/overflow-auto-table.html [ Failure Pass ]
 crbug.com/591099 fast/overflow/overflow-clamp-after-visible-rect-resize.html [ Failure ]
 crbug.com/591099 fast/overflow/overflow-float-stacking.html [ Failure ]
 crbug.com/591099 fast/overflow/overflow-rtl-inline-scrollbar.html [ Failure ]
@@ -10314,7 +10320,6 @@
 crbug.com/591099 fast/overflow/overflow-rtl.html [ Crash Failure ]
 crbug.com/591099 fast/overflow/overflow-stacking.html [ Failure ]
 crbug.com/591099 fast/overflow/overflow-update-transform.html [ Failure ]
-crbug.com/591099 fast/overflow/overflow-visible-should-ignore-scroll.html [ Failure Pass ]
 crbug.com/591099 fast/overflow/overflow-with-local-background-attachment.html [ Crash Failure ]
 crbug.com/591099 fast/overflow/overflow-x-y.html [ Crash Failure ]
 crbug.com/591099 fast/overflow/overflow-y-scroll.html [ Failure ]
@@ -10644,7 +10649,7 @@
 crbug.com/591099 fast/scrolling/hover-during-scroll.html [ Failure Timeout ]
 crbug.com/591099 fast/scrolling/html-element-client-rect-excludes-scrollbars.html [ Failure ]
 crbug.com/591099 fast/scrolling/keyboard-scroll-page-scale.html [ Failure Timeout ]
-crbug.com/591099 fast/scrolling/listbox-wheel-event.html [ Failure ]
+crbug.com/591099 fast/scrolling/listbox-wheel-event.html [ Failure Pass ]
 crbug.com/591099 fast/scrolling/overflow-auto-ltr.html [ Failure ]
 crbug.com/591099 fast/scrolling/overflow-scrollability.html [ Failure ]
 crbug.com/591099 fast/scrolling/scroll-clears-fragment-anchor.html [ Failure ]
@@ -10831,7 +10836,6 @@
 crbug.com/591099 fast/spatial-navigation/snav-clipped-overflowed-content.html [ Failure ]
 crbug.com/591099 fast/spatial-navigation/snav-container-white-space.html [ Failure ]
 crbug.com/591099 fast/spatial-navigation/snav-date.html [ Failure ]
-crbug.com/591099 fast/spatial-navigation/snav-div-scrollable-but-without-focusable-content.html [ Failure Pass ]
 crbug.com/591099 fast/spatial-navigation/snav-fully-aligned-vertically.html [ Failure ]
 crbug.com/591099 fast/spatial-navigation/snav-hidden-focusable-element.html [ Failure ]
 crbug.com/591099 fast/spatial-navigation/snav-hidden-iframe-zero-size.html [ Failure ]
@@ -10880,7 +10884,7 @@
 crbug.com/591099 fast/sub-pixel/float-with-right-margin-zoom.html [ Failure ]
 crbug.com/591099 fast/sub-pixel/inline-block-with-padding.html [ Failure ]
 crbug.com/591099 fast/sub-pixel/repaint-subpixel-layer-in-subpixel-composited-layer.html [ Failure Pass ]
-crbug.com/591099 fast/sub-pixel/selection/selection-rect-in-sub-pixel-table.html [ Failure ]
+crbug.com/591099 fast/sub-pixel/selection/selection-rect-in-sub-pixel-table.html [ Failure Pass ]
 crbug.com/591099 fast/sub-pixel/shadows-computed-style.html [ Failure ]
 crbug.com/591099 fast/sub-pixel/should-not-repaint-subpixel-composited-layer.html [ Failure Pass ]
 crbug.com/591099 fast/sub-pixel/size-of-box-with-zoom.html [ Failure ]
@@ -10888,16 +10892,16 @@
 crbug.com/591099 fast/sub-pixel/sub-pixel-border-2.html [ Failure ]
 crbug.com/591099 fast/sub-pixel/sub-pixel-precision-on-height-of-replaced-element.html [ Failure ]
 crbug.com/591099 fast/sub-pixel/table-rows-have-stable-height.html [ Failure ]
-crbug.com/591099 fast/table/003.html [ Failure ]
-crbug.com/591099 fast/table/007.html [ Failure ]
+crbug.com/591099 fast/table/003.html [ Failure Pass ]
+crbug.com/591099 fast/table/007.html [ Failure Pass ]
 crbug.com/591099 fast/table/009.html [ Failure ]
 crbug.com/591099 fast/table/014.html [ Failure Pass ]
 crbug.com/591099 fast/table/018.html [ Failure ]
 crbug.com/591099 fast/table/032.html [ Failure ]
-crbug.com/591099 fast/table/034.html [ Failure ]
+crbug.com/591099 fast/table/034.html [ Failure Pass ]
 crbug.com/591099 fast/table/035-vertical.html [ Failure ]
 crbug.com/591099 fast/table/035.html [ Failure ]
-crbug.com/591099 fast/table/036.html [ Failure ]
+crbug.com/591099 fast/table/036.html [ Failure Pass ]
 crbug.com/591099 fast/table/040-vertical.html [ Failure ]
 crbug.com/591099 fast/table/040.html [ Failure ]
 crbug.com/591099 fast/table/100-percent-cell-width.html [ Failure ]
@@ -10939,7 +10943,7 @@
 crbug.com/591099 fast/table/caption-orthogonal-writing-mode-sizing.html [ Failure ]
 crbug.com/591099 fast/table/cell-absolute-child.html [ Failure ]
 crbug.com/591099 fast/table/cell-height-min-intrinsic.html [ Failure ]
-crbug.com/591099 fast/table/cell-pref-width-invalidation.html [ Failure ]
+crbug.com/591099 fast/table/cell-pref-width-invalidation.html [ Failure Pass ]
 crbug.com/591099 fast/table/cellIndex-of-cell-with-different-parents.html [ Failure ]
 crbug.com/591099 fast/table/change-cell-border-width.html [ Failure ]
 crbug.com/591099 fast/table/change-col-border-width.html [ Crash Failure ]
@@ -10955,7 +10959,6 @@
 crbug.com/591099 fast/table/columngroup-inside-columngroup.html [ Failure ]
 crbug.com/591099 fast/table/containment-crash.html [ Failure ]
 crbug.com/591099 fast/table/containment.html [ Failure ]
-crbug.com/591099 fast/table/convert-inline-anonoymous-wrapper-to-block.html [ Failure Pass ]
 crbug.com/591099 fast/table/convert-inline-to-table-cell.html [ Failure ]
 crbug.com/591099 fast/table/crash-bad-child-table-continuation.html [ Failure ]
 crbug.com/591099 fast/table/crash-empty-section-calcBorder.html [ Failure ]
@@ -11033,10 +11036,10 @@
 crbug.com/591099 fast/table/percent-widths-total-less-than-one.html [ Failure ]
 crbug.com/591099 fast/table/prepend-in-anonymous-table.html [ Failure ]
 crbug.com/591099 fast/table/recalc-section-first-body-crash-main.html [ Failure ]
-crbug.com/591099 fast/table/remove-anonymous-cell.html [ Failure ]
+crbug.com/591099 fast/table/remove-anonymous-cell.html [ Failure Pass ]
 crbug.com/591099 fast/table/remove-cell-with-large-border-width.html [ Failure ]
 crbug.com/591099 fast/table/remove-td-display-none.html [ Failure ]
-crbug.com/591099 fast/table/replaced-percent-height.html [ Failure ]
+crbug.com/591099 fast/table/replaced-percent-height.html [ Failure Pass ]
 crbug.com/591099 fast/table/resize-table-binding-cell.html [ Failure ]
 crbug.com/591099 fast/table/resize-table-cell.html [ Failure ]
 crbug.com/591099 fast/table/resize-table-row.html [ Failure ]
@@ -11254,7 +11257,7 @@
 crbug.com/591099 fast/text/international/bidi-european-terminators.html [ Failure ]
 crbug.com/591099 fast/text/international/bidi-ignored-for-first-child-inline.html [ Failure ]
 crbug.com/591099 fast/text/international/bidi-innertext.html [ Failure ]
-crbug.com/591099 fast/text/international/bidi-layout-across-linebreak.html [ Failure ]
+crbug.com/591099 fast/text/international/bidi-layout-across-linebreak.html [ Failure Pass ]
 crbug.com/591099 fast/text/international/bidi-linebreak-001.html [ Failure ]
 crbug.com/591099 fast/text/international/bidi-linebreak-002.html [ Failure ]
 crbug.com/591099 fast/text/international/bidi-linebreak-003.html [ Failure ]
@@ -11263,7 +11266,7 @@
 crbug.com/591099 fast/text/international/bidi-mirror-he-ar.html [ Failure ]
 crbug.com/591099 fast/text/international/bidi-neutral-directionality-paragraph-start.html [ Failure ]
 crbug.com/591099 fast/text/international/bidi-neutral-run.html [ Failure ]
-crbug.com/591099 fast/text/international/bidi-override.html [ Failure ]
+crbug.com/591099 fast/text/international/bidi-override.html [ Failure Pass ]
 crbug.com/591099 fast/text/international/block-flow-parser-test.html [ Crash Failure ]
 crbug.com/591099 fast/text/international/bold-bengali.html [ Failure ]
 crbug.com/591099 fast/text/international/cjk-segmentation.html [ Crash Failure ]
@@ -11379,7 +11382,7 @@
 crbug.com/591099 fast/text/textIteratorNilRenderer.html [ Failure ]
 crbug.com/591099 fast/text/trailing-white-space-2.html [ Failure ]
 crbug.com/591099 fast/text/trailing-white-space.html [ Failure ]
-crbug.com/591099 fast/text/updateNewFont.html [ Failure ]
+crbug.com/591099 fast/text/updateNewFont.html [ Failure Pass ]
 crbug.com/591099 fast/text/vertical-rl-rtl-linebreak.html [ Failure ]
 crbug.com/591099 fast/text/vertical-surrogate-pair.html [ Failure ]
 crbug.com/591099 fast/text/wbr-in-pre-crash.html [ Failure ]
@@ -11388,23 +11391,23 @@
 crbug.com/591099 fast/text/wbr.html [ Failure ]
 crbug.com/591099 fast/text/webfont-synthetic-bold.html [ Failure ]
 crbug.com/591099 fast/text/whitespace/001.html [ Failure ]
-crbug.com/591099 fast/text/whitespace/002.html [ Failure ]
-crbug.com/591099 fast/text/whitespace/003.html [ Failure ]
-crbug.com/591099 fast/text/whitespace/004.html [ Failure ]
-crbug.com/591099 fast/text/whitespace/005.html [ Failure ]
-crbug.com/591099 fast/text/whitespace/010.html [ Failure ]
-crbug.com/591099 fast/text/whitespace/011.html [ Failure ]
-crbug.com/591099 fast/text/whitespace/013.html [ Failure ]
-crbug.com/591099 fast/text/whitespace/014.html [ Failure ]
-crbug.com/591099 fast/text/whitespace/015.html [ Failure ]
-crbug.com/591099 fast/text/whitespace/016.html [ Failure ]
+crbug.com/591099 fast/text/whitespace/002.html [ Failure Pass ]
+crbug.com/591099 fast/text/whitespace/003.html [ Failure Pass ]
+crbug.com/591099 fast/text/whitespace/004.html [ Failure Pass ]
+crbug.com/591099 fast/text/whitespace/005.html [ Failure Pass ]
+crbug.com/591099 fast/text/whitespace/010.html [ Failure Pass ]
+crbug.com/591099 fast/text/whitespace/011.html [ Failure Pass ]
+crbug.com/591099 fast/text/whitespace/013.html [ Failure Pass ]
+crbug.com/591099 fast/text/whitespace/014.html [ Failure Pass ]
+crbug.com/591099 fast/text/whitespace/015.html [ Failure Pass ]
+crbug.com/591099 fast/text/whitespace/016.html [ Failure Pass ]
 crbug.com/591099 fast/text/whitespace/018.html [ Failure ]
 crbug.com/591099 fast/text/whitespace/019.html [ Failure ]
 crbug.com/591099 fast/text/whitespace/020.html [ Failure ]
 crbug.com/591099 fast/text/whitespace/022.html [ Failure ]
 crbug.com/591099 fast/text/whitespace/023.html [ Failure ]
 crbug.com/591099 fast/text/whitespace/024.html [ Failure ]
-crbug.com/591099 fast/text/whitespace/025.html [ Failure ]
+crbug.com/591099 fast/text/whitespace/025.html [ Failure Pass ]
 crbug.com/591099 fast/text/whitespace/028.html [ Failure ]
 crbug.com/591099 fast/text/whitespace/029.html [ Failure ]
 crbug.com/591099 fast/text/whitespace/inline-whitespace-wrapping-2.html [ Failure Pass ]
@@ -11594,7 +11597,7 @@
 crbug.com/591099 fast/writing-mode/percentage-margins-absolute.html [ Failure ]
 crbug.com/591099 fast/writing-mode/table-hit-test.html [ Failure ]
 crbug.com/591099 fast/writing-mode/table-percent-width-quirk.html [ Crash Failure ]
-crbug.com/591099 fast/writing-mode/table-vertical-child-width.html [ Failure ]
+crbug.com/591099 fast/writing-mode/table-vertical-child-width.html [ Failure Pass ]
 crbug.com/591099 fast/writing-mode/text-combine-compress.html [ Crash Failure ]
 crbug.com/591099 fast/writing-mode/text-combine-justify.html [ Failure ]
 crbug.com/591099 fast/writing-mode/text-combine-line-break.html [ Failure ]
@@ -11733,8 +11736,8 @@
 crbug.com/591099 fragmentation/relayout-abspos.html [ Failure ]
 crbug.com/591099 fragmentation/remove-unbreakable-block-in-line-float.html [ Failure ]
 crbug.com/591099 fragmentation/repeating-thead-exceeds-page-size.html [ Failure ]
-crbug.com/591099 fragmentation/repeating-thead-multiple-tables-page-border.html [ Failure ]
-crbug.com/591099 fragmentation/repeating-thead-multiple-tables.html [ Failure ]
+crbug.com/591099 fragmentation/repeating-thead-multiple-tables-page-border.html [ Failure Pass ]
+crbug.com/591099 fragmentation/repeating-thead-multiple-tables.html [ Failure Pass ]
 crbug.com/591099 fragmentation/repeating-thead-no-room-for-content-row-on-first-page.html [ Failure ]
 crbug.com/591099 fragmentation/single-cell-repeating-thead-break-inside-avoid-content.html [ Failure ]
 crbug.com/591099 fragmentation/single-cell-repeating-thead-break-inside-content-first-line.html [ Failure ]
@@ -11749,9 +11752,9 @@
 crbug.com/591099 fragmentation/table-disable-fragmentation.html [ Failure ]
 crbug.com/591099 fragmentation/table-in-subpixel-fragmentainer.html [ Failure ]
 crbug.com/591099 fragmentation/table-overlapping-rowspan.html [ Failure ]
-crbug.com/591099 fragmentation/table-with-border-spacing.html [ Failure ]
+crbug.com/591099 fragmentation/table-with-border-spacing.html [ Failure Pass ]
 crbug.com/591099 fragmentation/tbody-before-thead.html [ Failure ]
-crbug.com/591099 fragmentation/unbreakable-tall-float-before-block.html [ Failure ]
+crbug.com/591099 fragmentation/unbreakable-tall-float-before-block.html [ Failure Pass ]
 crbug.com/591099 fragmentation/unbreakable-tall-float-before-line.html [ Failure Pass ]
 crbug.com/591099 fullscreen/compositor-touch-hit-rects-fullscreen-video-controls.html [ Failure ]
 crbug.com/591099 fullscreen/exit-full-screen-iframe.html [ Crash Failure ]
@@ -12273,7 +12276,7 @@
 crbug.com/591099 http/tests/inspector/console-xhr-logging.html [ Crash Failure ]
 crbug.com/591099 http/tests/inspector/console/console-links-in-errors-with-trace.html [ Crash Failure ]
 crbug.com/591099 http/tests/inspector/console/console-links-on-messages-before-inspection.html [ Failure ]
-crbug.com/591099 http/tests/inspector/console/console-on-paint-worklet.html [ Failure ]
+crbug.com/591099 http/tests/inspector/console/console-on-paint-worklet.html [ Failure Timeout ]
 crbug.com/591099 http/tests/inspector/debugger/fetch-breakpoints.html [ Crash Failure Timeout ]
 crbug.com/591099 http/tests/inspector/elements/elements-linkify-attributes.html [ Crash Failure Timeout ]
 crbug.com/591099 http/tests/inspector/elements/event-listeners-framework-with-service-worker.html [ Crash Failure ]
@@ -12339,6 +12342,7 @@
 crbug.com/591099 http/tests/inspector/network/network-content-replacement-xhr.html [ Crash Failure ]
 crbug.com/591099 http/tests/inspector/network/network-cyrillic-xhr.html [ Failure ]
 crbug.com/591099 http/tests/inspector/network/network-datareceived.html [ Crash Failure Timeout ]
+crbug.com/591099 http/tests/inspector/network/network-datasaver-warning.html [ Failure ]
 crbug.com/591099 http/tests/inspector/network/network-disable-cache-cors.html [ Crash Failure ]
 crbug.com/591099 http/tests/inspector/network/network-disable-cache-memory.html [ Crash Failure ]
 crbug.com/591099 http/tests/inspector/network/network-disable-cache-preloads.php [ Crash Failure ]
@@ -12350,7 +12354,7 @@
 crbug.com/591099 http/tests/inspector/network/network-fetch-post-payload.html [ Crash Failure ]
 crbug.com/591099 http/tests/inspector/network/network-fetch.html [ Crash Failure ]
 crbug.com/591099 http/tests/inspector/network/network-filters-internals.html [ Crash Failure ]
-crbug.com/591099 http/tests/inspector/network/network-filters.html [ Crash Failure ]
+crbug.com/591099 http/tests/inspector/network/network-filters.html [ Crash Failure Timeout ]
 crbug.com/591099 http/tests/inspector/network/network-iframe-load-and-delete.html [ Crash Failure ]
 crbug.com/591099 http/tests/inspector/network/network-image-404.html [ Failure ]
 crbug.com/591099 http/tests/inspector/network/network-imported-resource-content.html [ Crash Failure ]
@@ -12538,7 +12542,6 @@
 crbug.com/591099 http/tests/media/media-source/mediasource-duration.html [ Crash Failure Pass ]
 crbug.com/591099 http/tests/media/progress-events-generated-correctly.html [ Crash Failure Pass ]
 crbug.com/591099 http/tests/media/video-buffered-range-contains-currentTime.html [ Failure Pass ]
-crbug.com/591099 http/tests/media/video-buffered.html [ Crash Failure Pass ]
 crbug.com/591099 http/tests/media/video-play-stall.html [ Crash Pass Timeout ]
 crbug.com/591099 http/tests/mime/quoted-charset.php [ Failure ]
 crbug.com/591099 http/tests/misc/BOM-override-script.html [ Failure ]
@@ -13271,14 +13274,13 @@
 crbug.com/591099 http/tests/xmlhttprequest/getAllResponseHeaders.html [ Failure ]
 crbug.com/591099 http/tests/xmlhttprequest/getResponseHeader.html [ Failure ]
 crbug.com/591099 http/tests/xmlhttprequest/infoOnProgressEvent-response-type-blob.html [ Failure ]
-crbug.com/591099 http/tests/xmlhttprequest/infoOnProgressEvent.html [ Failure ]
+crbug.com/591099 http/tests/xmlhttprequest/infoOnProgressEvent.html [ Failure Timeout ]
 crbug.com/591099 http/tests/xmlhttprequest/inject-header.html [ Failure ]
 crbug.com/591099 http/tests/xmlhttprequest/interactive-state.html [ Crash Failure ]
 crbug.com/591099 http/tests/xmlhttprequest/logout.html [ Failure ]
 crbug.com/591099 http/tests/xmlhttprequest/methods-async.html [ Crash Failure ]
 crbug.com/591099 http/tests/xmlhttprequest/methods-lower-case.html [ Crash Failure ]
 crbug.com/591099 http/tests/xmlhttprequest/methods.html [ Crash Failure ]
-crbug.com/591099 http/tests/xmlhttprequest/navigation-abort-detaches-frame.html [ Crash Pass Timeout ]
 crbug.com/591099 http/tests/xmlhttprequest/newline-in-request-uri.html [ Failure ]
 crbug.com/591099 http/tests/xmlhttprequest/null-auth.php [ Failure ]
 crbug.com/591099 http/tests/xmlhttprequest/onabort-event.html [ Failure ]
@@ -13526,7 +13528,7 @@
 crbug.com/591099 ietestcenter/css3/bordersbackgrounds/order-of-images.htm [ Failure Pass ]
 crbug.com/591099 ietestcenter/css3/flexbox/flexbox-direction-001.htm [ Failure ]
 crbug.com/591099 ietestcenter/css3/flexbox/flexbox-ordinal-group-001.htm [ Failure ]
-crbug.com/591099 ietestcenter/css3/multicolumn/column-containing-block-003.htm [ Failure ]
+crbug.com/591099 ietestcenter/css3/multicolumn/column-containing-block-003.htm [ Failure Pass ]
 crbug.com/591099 ietestcenter/css3/multicolumn/column-width-negative-001.htm [ Failure ]
 crbug.com/591099 ietestcenter/css3/multicolumn/column-width-percentage-001.htm [ Failure ]
 crbug.com/591099 ietestcenter/css3/text/textshadow-002.htm [ Failure ]
@@ -13668,13 +13670,6 @@
 crbug.com/591099 inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot.js [ Crash Failure Timeout ]
 crbug.com/591099 inspector-protocol/emulation/device-emulation-small-dw.js [ Failure ]
 crbug.com/591099 inspector-protocol/emulation/device-emulation-small.js [ Failure ]
-crbug.com/591099 inspector-protocol/heap-profiler/heap-objects-tracking.js [ Failure ]
-crbug.com/591099 inspector-protocol/heap-profiler/heap-samples-in-snapshot.js [ Failure ]
-crbug.com/591099 inspector-protocol/heap-profiler/heap-snapshot-with-active-dom-object.js [ Failure ]
-crbug.com/591099 inspector-protocol/heap-profiler/heap-snapshot-with-detached-dom-tree.js [ Failure ]
-crbug.com/591099 inspector-protocol/heap-profiler/heap-snapshot-with-event-listener.js [ Failure ]
-crbug.com/591099 inspector-protocol/heap-profiler/sampling-heap-profiler.js [ Failure ]
-crbug.com/591099 inspector-protocol/heap-profiler/take-heap-snapshot.js [ Failure ]
 crbug.com/591099 inspector-protocol/layers/paint-profiler.js [ Failure ]
 crbug.com/591099 inspector-protocol/layout-fonts/languages-emoji-rare-glyphs.html [ Failure ]
 crbug.com/591099 inspector/agents-enable-disable.html [ Failure ]
@@ -13717,7 +13712,6 @@
 crbug.com/591099 inspector/console-document-write-from-external-script-logging.html [ Failure ]
 crbug.com/591099 inspector/console/alert-toString-exception.html [ Crash Failure ]
 crbug.com/591099 inspector/console/command-line-api-getEventListeners.html [ Crash Failure ]
-crbug.com/591099 http/tests/devtools/console/command-line-api.js [ Crash Failure ]
 crbug.com/591099 inspector/console/console-Object-overwritten.html [ Failure ]
 crbug.com/591099 inspector/console/console-api-on-call-frame.html [ Crash Failure ]
 crbug.com/591099 inspector/console/console-assert.html [ Failure ]
@@ -13725,7 +13719,6 @@
 crbug.com/591099 inspector/console/console-bind-fake.html [ Failure ]
 crbug.com/591099 inspector/console/console-call-getter-on-proto.html [ Failure ]
 crbug.com/591099 inspector/console/console-clear-function.html [ Failure ]
-crbug.com/591099 http/tests/devtools/console/console-clear.js [ Failure ]
 crbug.com/591099 inspector/console/console-command-clear.html [ Failure ]
 crbug.com/591099 inspector/console/console-command-copy.html [ Failure ]
 crbug.com/591099 inspector/console/console-context-selector.html [ Crash Failure ]
@@ -13803,7 +13796,7 @@
 crbug.com/591099 inspector/console/console-revoke-error.html [ Crash Failure ]
 crbug.com/591099 inspector/console/console-save-to-temp-var.html [ Failure ]
 crbug.com/591099 inspector/console/console-search-reveals-messages.html [ Failure ]
-crbug.com/591099 inspector/console/console-search.html [ Crash Failure ]
+crbug.com/591099 inspector/console/console-search.html [ Crash Failure Timeout ]
 crbug.com/591099 inspector/console/console-smart-enter.html [ Failure ]
 crbug.com/591099 inspector/console/console-stack-overflow.html [ Failure ]
 crbug.com/591099 inspector/console/console-string-format.html [ Failure ]
@@ -15017,7 +15010,7 @@
 crbug.com/591099 paint/invalidation/multi-subsequence-composited.html [ Failure ]
 crbug.com/591099 paint/invalidation/multi-subsequence-scrolled.html [ Failure ]
 crbug.com/591099 paint/invalidation/multicol-as-paint-container.html [ Failure Pass ]
-crbug.com/591099 paint/invalidation/multicol-nested.html [ Failure ]
+crbug.com/591099 paint/invalidation/multicol-nested.html [ Failure Pass ]
 crbug.com/591099 paint/invalidation/multicol-relpos-with-abspos.html [ Failure Pass ]
 crbug.com/591099 paint/invalidation/multicol-with-abspos-in-relpos.html [ Failure ]
 crbug.com/591099 paint/invalidation/multicol-with-abspos.html [ Failure Pass ]
@@ -15216,7 +15209,7 @@
 crbug.com/591099 paint/invalidation/svg/transform-foreign-object.html [ Failure Pass ]
 crbug.com/591099 paint/invalidation/svg/use-instanceRoot-event-bubbling.xhtml [ Timeout ]
 crbug.com/591099 paint/invalidation/svg/use-setAttribute-crash.svg [ Failure Pass ]
-crbug.com/591099 paint/invalidation/svg/zoom-foreignObject.svg [ Failure ]
+crbug.com/591099 paint/invalidation/svg/zoom-foreignObject.svg [ Failure Pass ]
 crbug.com/591099 paint/invalidation/table-cell-collapsed-border.html [ Failure ]
 crbug.com/591099 paint/invalidation/table-cell-move.html [ Failure ]
 crbug.com/591099 paint/invalidation/table-cell-overflow.html [ Failure Pass ]
@@ -15380,7 +15373,6 @@
 crbug.com/591099 presentation/presentation-controller-connection-closed-by-receiver.html [ Crash Pass Timeout ]
 crbug.com/591099 presentation/presentation-controller-terminate-connection.html [ Crash Pass Timeout ]
 crbug.com/591099 presentation/presentation-receiver-terminate-connection.html [ Crash Pass Timeout ]
-crbug.com/591099 presentation/presentation-reconnect.html [ Crash Pass Timeout ]
 crbug.com/591099 presentation/presentation-start-error.html [ Crash Failure Pass Timeout ]
 crbug.com/591099 presentation/presentation-start.html [ Crash Pass Timeout ]
 crbug.com/591099 presentation/presentationconnectionavailableevent-ctor-mock.html [ Crash Pass Timeout ]
@@ -15447,7 +15439,7 @@
 crbug.com/591099 scrollbars/disabled-scrollbar.html [ Failure ]
 crbug.com/591099 scrollbars/hidden-iframe-scrollbar-crash.html [ Crash Failure ]
 crbug.com/591099 scrollbars/hidden-scrollbar-prevents-layout.html [ Failure ]
-crbug.com/591099 scrollbars/listbox-scrollbar-combinations.html [ Failure ]
+crbug.com/591099 scrollbars/listbox-scrollbar-combinations.html [ Failure Pass ]
 crbug.com/591099 scrollbars/scrollbar-added-during-drag.html [ Timeout ]
 crbug.com/591099 scrollbars/scrollbar-buttons.html [ Failure ]
 crbug.com/591099 scrollbars/scrollbar-click-does-not-blur-content.html [ Crash Failure ]
@@ -16477,7 +16469,7 @@
 crbug.com/591099 svg/foreignObject/multiple-foreign-objects.html [ Failure ]
 crbug.com/591099 svg/foreignObject/no-crash-with-svg-content-in-html-document.svg [ Failure Pass ]
 crbug.com/591099 svg/foreignObject/svg-document-in-html-document.svg [ Failure Pass ]
-crbug.com/591099 svg/foreignObject/vertical-foreignObject.html [ Failure ]
+crbug.com/591099 svg/foreignObject/vertical-foreignObject.html [ Failure Pass ]
 crbug.com/591099 svg/hittest/clip-path-shape.html [ Crash Failure ]
 crbug.com/591099 svg/hittest/ellipse-hittest.html [ Failure ]
 crbug.com/591099 svg/hittest/empty-container.html [ Crash Failure ]
@@ -16607,7 +16599,7 @@
 crbug.com/591099 tables/hittesting/filltable-stress.html [ Pass Timeout ]
 crbug.com/591099 tables/layering/paint-test-layering-1.html [ Failure ]
 crbug.com/591099 tables/layering/paint-test-layering-2.html [ Failure ]
-crbug.com/591099 tables/mozilla/bugs/bug1055-1.html [ Failure ]
+crbug.com/591099 tables/mozilla/bugs/bug1055-1.html [ Failure Pass ]
 crbug.com/591099 tables/mozilla/bugs/bug10565.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug10633.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug1067-1.html [ Failure Pass ]
@@ -16626,11 +16618,11 @@
 crbug.com/591099 tables/mozilla/bugs/bug131020_iframe.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug13105.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug13118.html [ Failure ]
-crbug.com/591099 tables/mozilla/bugs/bug133756-1.html [ Failure ]
+crbug.com/591099 tables/mozilla/bugs/bug133756-1.html [ Failure Pass ]
 crbug.com/591099 tables/mozilla/bugs/bug133948.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug137388-3.html [ Failure ]
-crbug.com/591099 tables/mozilla/bugs/bug138725.html [ Failure ]
-crbug.com/591099 tables/mozilla/bugs/bug14159-1.html [ Failure ]
+crbug.com/591099 tables/mozilla/bugs/bug138725.html [ Failure Pass ]
+crbug.com/591099 tables/mozilla/bugs/bug14159-1.html [ Failure Pass ]
 crbug.com/591099 tables/mozilla/bugs/bug149275-1.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug149275-2.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug15247.html [ Failure Pass ]
@@ -16641,7 +16633,7 @@
 crbug.com/591099 tables/mozilla/bugs/bug17130-1.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug17130-2.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug17138.html [ Failure ]
-crbug.com/591099 tables/mozilla/bugs/bug1828.html [ Failure ]
+crbug.com/591099 tables/mozilla/bugs/bug1828.html [ Failure Pass ]
 crbug.com/591099 tables/mozilla/bugs/bug18359.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug18440.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug18664.html [ Failure ]
@@ -16668,9 +16660,9 @@
 crbug.com/591099 tables/mozilla/bugs/bug269566.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug27038-1.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug27038-2.html [ Failure ]
-crbug.com/591099 tables/mozilla/bugs/bug27038-3.html [ Failure ]
+crbug.com/591099 tables/mozilla/bugs/bug27038-3.html [ Failure Pass ]
 crbug.com/591099 tables/mozilla/bugs/bug2773.html [ Failure ]
-crbug.com/591099 tables/mozilla/bugs/bug278385.html [ Failure ]
+crbug.com/591099 tables/mozilla/bugs/bug278385.html [ Failure Pass ]
 crbug.com/591099 tables/mozilla/bugs/bug2886-2.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug2886.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug28928.html [ Failure ]
@@ -16691,20 +16683,20 @@
 crbug.com/591099 tables/mozilla/bugs/bug3454.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug3718.html [ Failure Pass ]
 crbug.com/591099 tables/mozilla/bugs/bug38916.html [ Failure ]
-crbug.com/591099 tables/mozilla/bugs/bug39209.html [ Failure ]
+crbug.com/591099 tables/mozilla/bugs/bug39209.html [ Failure Pass ]
 crbug.com/591099 tables/mozilla/bugs/bug3977.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug4093.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug42187.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug4284.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug43204.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug43854-1.html [ Failure ]
-crbug.com/591099 tables/mozilla/bugs/bug43854-2.html [ Failure ]
-crbug.com/591099 tables/mozilla/bugs/bug44505.html [ Failure ]
+crbug.com/591099 tables/mozilla/bugs/bug43854-2.html [ Failure Pass ]
+crbug.com/591099 tables/mozilla/bugs/bug44505.html [ Failure Pass ]
 crbug.com/591099 tables/mozilla/bugs/bug44523.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug4527.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug4576.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug46480-1.html [ Failure ]
-crbug.com/591099 tables/mozilla/bugs/bug46924.html [ Failure ]
+crbug.com/591099 tables/mozilla/bugs/bug46924.html [ Failure Pass ]
 crbug.com/591099 tables/mozilla/bugs/bug4849-2.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug48827.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug50695-1.html [ Failure ]
@@ -16725,14 +16717,14 @@
 crbug.com/591099 tables/mozilla/bugs/bug63785.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug641-2.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug647.html [ Failure ]
-crbug.com/591099 tables/mozilla/bugs/bug6674.html [ Failure ]
+crbug.com/591099 tables/mozilla/bugs/bug6674.html [ Failure Pass ]
 crbug.com/591099 tables/mozilla/bugs/bug68912.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug69187.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug7112-1.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug7112-2.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug7121-1.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug727.html [ Failure ]
-crbug.com/591099 tables/mozilla/bugs/bug73321.html [ Failure ]
+crbug.com/591099 tables/mozilla/bugs/bug73321.html [ Failure Pass ]
 crbug.com/591099 tables/mozilla/bugs/bug7342.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug7471.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug7714.html [ Failure ]
@@ -16749,7 +16741,7 @@
 crbug.com/591099 tables/mozilla/bugs/bug8950.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug9123-1.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug9123-2.html [ Failure ]
-crbug.com/591099 tables/mozilla/bugs/bug93363.html [ Failure ]
+crbug.com/591099 tables/mozilla/bugs/bug93363.html [ Failure Pass ]
 crbug.com/591099 tables/mozilla/bugs/bug97383.html [ Failure Pass ]
 crbug.com/591099 tables/mozilla/bugs/bug98196.html [ Failure ]
 crbug.com/591099 tables/mozilla/collapsing_borders/bug41262-3.html [ Crash Failure ]
@@ -16883,7 +16875,7 @@
 crbug.com/591099 tables/mozilla_expected_failures/bugs/bug33784.html [ Failure ]
 crbug.com/591099 tables/mozilla_expected_failures/bugs/bug42043.html [ Failure ]
 crbug.com/591099 tables/mozilla_expected_failures/bugs/bug4294.html [ Failure ]
-crbug.com/591099 tables/mozilla_expected_failures/bugs/bug47163.html [ Failure ]
+crbug.com/591099 tables/mozilla_expected_failures/bugs/bug47163.html [ Failure Pass ]
 crbug.com/591099 tables/mozilla_expected_failures/bugs/bug51000.html [ Failure ]
 crbug.com/591099 tables/mozilla_expected_failures/bugs/bug61042-1.html [ Failure ]
 crbug.com/591099 tables/mozilla_expected_failures/bugs/bug61042-2.html [ Failure ]
@@ -17302,7 +17294,7 @@
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-layer-filter.html [ Crash Failure ]
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-layer.html [ Crash Failure Timeout ]
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-mask-image-svg.html [ Crash Failure ]
-crbug.com/591099 virtual/gpu-rasterization/images/color-profile-reflection.html [ Crash Failure ]
+crbug.com/591099 virtual/gpu-rasterization/images/color-profile-reflection.html [ Crash Failure Timeout ]
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-svg-foreign-object.html [ Crash Failure ]
 crbug.com/591099 virtual/gpu-rasterization/images/cross-fade-background-size.html [ Failure ]
 crbug.com/591099 virtual/gpu-rasterization/images/cross-fade-blending.html [ Failure ]
@@ -17472,13 +17464,13 @@
 crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-applies-to-008.xht [ Crash Failure ]
 crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/float-replaced-width-002.xht [ Crash Failure ]
 crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-005.xht [ Crash Failure ]
-crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-031.xht [ Crash Failure ]
+crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-031.xht [ Crash Failure Pass ]
 crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-036.xht [ Crash Failure ]
 crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-143.xht [ Crash Failure ]
 crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-144.xht [ Crash Failure Pass ]
 crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/margin-collapse-018.xht [ Crash Failure ]
 crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/margin-collapse-035.xht [ Crash Failure ]
-crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/margin-collapse-clear-003.xht [ Crash Failure ]
+crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/margin-collapse-clear-003.xht [ Crash Failure Pass ]
 crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-placement-vertical-001a.xht [ Crash Failure ]
 crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-placement-vertical-001b.xht [ Crash Failure ]
 crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-placement-vertical-001c.xht [ Crash Failure ]
@@ -17486,7 +17478,7 @@
 crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-rule3-outside-right-002.xht [ Crash Failure ]
 crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-wrap-bfc-003-right-overflow.xht [ Crash Failure ]
 crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-wrap-bfc-004.xht [ Crash Failure ]
-crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-wrap-bfc-005.xht [ Crash Failure ]
+crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-wrap-bfc-005.xht [ Crash Failure Pass ]
 crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-wrap-bfc-006.xht [ Crash Failure ]
 crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-wrap-top-below-bfc-001l.xht [ Crash Failure ]
 crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-wrap-top-below-bfc-001r.xht [ Crash Failure ]
@@ -17786,7 +17778,7 @@
 crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/hover-during-scroll.html [ Failure Timeout ]
 crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/html-element-client-rect-excludes-scrollbars.html [ Failure ]
 crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/keyboard-scroll-page-scale.html [ Failure Timeout ]
-crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/listbox-wheel-event.html [ Failure ]
+crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/listbox-wheel-event.html [ Failure Pass ]
 crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/overflow-auto-ltr.html [ Failure ]
 crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/overflow-scrollability.html [ Failure ]
 crbug.com/591099 virtual/rootlayerscrolls/fast/scrolling/scroll-clears-fragment-anchor.html [ Failure ]
@@ -17867,7 +17859,6 @@
 crbug.com/591099 virtual/service-worker-navigation-preload-disabled/webexposed/global-interface-listing.html [ Timeout ]
 crbug.com/591099 virtual/service-worker-navigation-preload-disabled/webexposed/nonstable-css-properties.html [ Failure ]
 crbug.com/591099 virtual/service-worker-navigation-preload-disabled/webexposed/permissions-attribute.html [ Failure ]
-crbug.com/591099 virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/extendable-message-event.https.html [ Crash Pass Timeout ]
 crbug.com/591099 virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/fetch-frame-resource.https.html [ Crash Timeout ]
 crbug.com/591099 virtual/service-worker-script-streaming/external/wpt/service-workers/service-worker/fetch-response-taint.https.html [ Crash Timeout ]
 crbug.com/591099 virtual/service-worker-script-streaming/http/tests/serviceworker/chromium/frame-detached-by-navigation.html [ Crash Failure ]
@@ -17968,7 +17959,7 @@
 crbug.com/591099 virtual/threaded/animations/interpolation/background-size-interpolation.html [ Crash Pass Timeout ]
 crbug.com/591099 virtual/threaded/animations/interpolation/border-image-slice-interpolation.html [ Crash Pass Timeout ]
 crbug.com/591099 virtual/threaded/animations/interpolation/border-image-width-interpolation.html [ Crash Timeout ]
-crbug.com/591099 virtual/threaded/animations/interpolation/line-height-interpolation.html [ Crash Timeout ]
+crbug.com/591099 virtual/threaded/animations/interpolation/line-height-interpolation.html [ Crash Pass Timeout ]
 crbug.com/591099 virtual/threaded/animations/interpolation/svg-d-interpolation.html [ Crash Timeout ]
 crbug.com/591099 virtual/threaded/animations/interpolation/svg-stroke-dasharray-interpolation.html [ Crash Timeout ]
 crbug.com/591099 virtual/threaded/animations/interpolation/transform-interpolation.html [ Crash Timeout ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
index 91c9d6d..25fef2d8 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
@@ -181,6 +181,9 @@
 crbug.com/650348 http/tests/webaudio/autoplay-crossorigin.html [ Timeout ]
 crbug.com/650348 virtual/mojo-loading/http/tests/webaudio/autoplay-crossorigin.html [ Timeout ]
 
+# https://crbug.com/745881: Image diff in test due to font rendering issues.
+crbug.com/745881 [ Win ] fast/text/ellipsis-in-relative-inline.html [ Failure ]
+
 # TODO(lukasza, alexmos): Triage these failures.
 Bug(none) fast/frames/cached-frame-counter.html [ Timeout ]
 Bug(none) fast/frames/frame-limit.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index b26ee07..6986dd1 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1859,6 +1859,7 @@
 crbug.com/626703 virtual/threaded/transitions/transition-end-event-multiple-03.html [ Pass Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Win10 ] external/wpt/preload/delaying-onload-link-preload-after-discovery.html [ Timeout ]
 crbug.com/626703 external/wpt/2dcontext/building-paths/canvas_complexshapes_arcto_001.htm [ Failure ]
 crbug.com/626703 external/wpt/2dcontext/building-paths/canvas_complexshapes_beziercurveto_001.htm [ Failure ]
 crbug.com/626703 external/wpt/2dcontext/drawing-images-to-the-canvas/drawimage_canvas_11.html [ Failure ]
@@ -3103,3 +3104,8 @@
 crbug.com/626703 [ Win7 ] external/wpt/html/semantics/tabular-data/processing-model-1/span-limits.html [ Timeout ]
 
 crbug.com/745887 [ Mac Win ] fast/frames/sandboxed-iframe-plugins.html [ Failure Pass ]
+crbug.com/745899 [ Linux ] vr/getFrameData_samewithinframe.html [ Failure Pass ]
+
+crbug.com/626703 [ Win7 ] external/wpt/domxpath/xml_xpath_runner.html [ Timeout Pass ]
+crbug.com/626703 [ Win7 ] external/wpt/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/parsing.html [ Failure Pass ]
+crbug.com/626703 [ Win7 ] external/wpt/html/syntax/parsing/html5lib_tests16.html?run_type=uri [ Timeout Pass ]
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index cbc1417..7b062925 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -66704,11 +66704,6 @@
      {}
     ]
    ],
-   "XMLHttpRequest/overridemimetype-blob-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "XMLHttpRequest/resources/accept-language.py": [
     [
      {}
@@ -66719,6 +66714,11 @@
      {}
     ]
    ],
+   "XMLHttpRequest/resources/access-control-allow-lists.py": [
+    [
+     {}
+    ]
+   ],
    "XMLHttpRequest/resources/auth1/auth.py": [
     [
      {}
@@ -95684,6 +95684,11 @@
      {}
     ]
    ],
+   "html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/parsing-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/support/;url=foo": [
     [
      {}
@@ -99764,6 +99769,21 @@
      {}
     ]
    ],
+   "mediacapture-fromelement/webm/test-a-128k-44100Hz-1ch.webm": [
+    [
+     {}
+    ]
+   ],
+   "mediacapture-fromelement/webm/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.webm": [
+    [
+     {}
+    ]
+   ],
+   "mediacapture-fromelement/webm/test-v-128k-320x240-24fps-8kfr.webm": [
+    [
+     {}
+    ]
+   ],
    "mediacapture-image/idlharness-expected.txt": [
     [
      {}
@@ -101159,11 +101179,6 @@
      {}
     ]
    ],
-   "payment-request/payment-request-update-event-constructor.http-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "payment-request/payment-request-update-event-constructor.https-expected.txt": [
     [
      {}
@@ -118283,6 +118298,12 @@
      {}
     ]
    ],
+   "XMLHttpRequest/allow-lists-starting-with-comma.htm": [
+    [
+     "/XMLHttpRequest/allow-lists-starting-with-comma.htm",
+     {}
+    ]
+   ],
    "XMLHttpRequest/anonymous-mode-unsupported.htm": [
     [
      "/XMLHttpRequest/anonymous-mode-unsupported.htm",
@@ -139805,6 +139826,24 @@
      {}
     ]
    ],
+   "mediacapture-fromelement/capture.html": [
+    [
+     "/mediacapture-fromelement/capture.html",
+     {}
+    ]
+   ],
+   "mediacapture-fromelement/creation.html": [
+    [
+     "/mediacapture-fromelement/creation.html",
+     {}
+    ]
+   ],
+   "mediacapture-fromelement/ended.html": [
+    [
+     "/mediacapture-fromelement/ended.html",
+     {}
+    ]
+   ],
    "mediacapture-fromelement/idlharness.html": [
     [
      "/mediacapture-fromelement/idlharness.html",
@@ -163209,9 +163248,9 @@
      {}
     ]
    ],
-   "wasm/wasm_service_worker_test.html": [
+   "wasm/wasm_service_worker_test.https.html": [
     [
-     "/wasm/wasm_service_worker_test.html",
+     "/wasm/wasm_service_worker_test.https.html",
      {}
     ]
    ],
@@ -179182,6 +179221,10 @@
    "07fc81c4d96ced6791efde32982fe3edff515cfe",
    "testharness"
   ],
+  "XMLHttpRequest/allow-lists-starting-with-comma.htm": [
+   "5e7870a6d66c475c2f96fd64a146ea751b08f4b1",
+   "testharness"
+  ],
   "XMLHttpRequest/anonymous-mode-unsupported.htm": [
    "54a03fefabfad02e09baa4e9d37e19b6403dad9b",
    "testharness"
@@ -179522,10 +179565,6 @@
    "9e28bf35af12bb962fdfd2213d7e20e031a29703",
    "testharness"
   ],
-  "XMLHttpRequest/overridemimetype-blob-expected.txt": [
-   "f6a7104f61e4b2f44f21c37ff7bac3a36204fadf",
-   "support"
-  ],
   "XMLHttpRequest/overridemimetype-blob.html": [
    "e1b9cd224a563b32715a7d738e0070adca360be4",
    "testharness"
@@ -179574,6 +179613,10 @@
    "4769a0c31c00777fb37e1af76209e68040918b64",
    "support"
   ],
+  "XMLHttpRequest/resources/access-control-allow-lists.py": [
+   "72914699c33449255e47adb9668983e1bef8da14",
+   "support"
+  ],
   "XMLHttpRequest/resources/auth1/auth.py": [
    "cbe9305740f7e0a9e8c7be9dbfcb606f8abb2758",
    "support"
@@ -230411,7 +230454,7 @@
    "testharness"
   ],
   "html/dom/reflection-tabular-expected.txt": [
-   "c709bb136d8ca3acb99f363c89ec6ccb50922c60",
+   "620a0a046c7669b4954476bd78c8c4608c3ed3c7",
    "support"
   ],
   "html/dom/reflection-tabular.html": [
@@ -235798,6 +235841,10 @@
    "0d5f568af3b295b36e390156caf5ce523fd83d93",
    "testharness"
   ],
+  "html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/parsing-expected.txt": [
+   "ea69b05b31089656f7feb265a89ab18f2766887f",
+   "support"
+  ],
   "html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/parsing.html": [
    "709457936084abefd847c1557748df61551bd920",
    "testharness"
@@ -242726,6 +242773,18 @@
    "c3f2ab0ca87e837a5ffc6dfc1e757e1357c49d1f",
    "support"
   ],
+  "mediacapture-fromelement/capture.html": [
+   "645f6b8f31cb98d79a6a1f54c15bd15cd5e16a25",
+   "testharness"
+  ],
+  "mediacapture-fromelement/creation.html": [
+   "d6a0385016f2c8adc3035961a7d6240c1bd41770",
+   "testharness"
+  ],
+  "mediacapture-fromelement/ended.html": [
+   "6ae885eaa92de57609faea1dd5b9c9244c4b899a",
+   "testharness"
+  ],
   "mediacapture-fromelement/idlharness-expected.txt": [
    "8a4cd1bf27e02170c3dace68de4bd1723a2f25fa",
    "support"
@@ -242734,6 +242793,18 @@
    "ceeb48e7982eb88561f4c1630cb0fcf15d9cf73c",
    "testharness"
   ],
+  "mediacapture-fromelement/webm/test-a-128k-44100Hz-1ch.webm": [
+   "eeaba4c92c956b9b97c0241b10a54c32557b9e37",
+   "support"
+  ],
+  "mediacapture-fromelement/webm/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.webm": [
+   "e7c89345ef8085498f642f2eac75ac9b867d5814",
+   "support"
+  ],
+  "mediacapture-fromelement/webm/test-v-128k-320x240-24fps-8kfr.webm": [
+   "30080b0409424f065a1b286709c87c04c29fbb22",
+   "support"
+  ],
   "mediacapture-image/idlharness-expected.txt": [
    "7eaa5e273426a8d9b3472cb228091ed90f11a77e",
    "support"
@@ -251378,10 +251449,6 @@
    "7f58fa01b008be011158cbb834ef1ef1bec2bce5",
    "testharness"
   ],
-  "payment-request/payment-request-update-event-constructor.http-expected.txt": [
-   "b755f601bf4b9b5319008818eaf901e5c5d00077",
-   "support"
-  ],
   "payment-request/payment-request-update-event-constructor.http.html": [
    "017f1f1aca43171083833ddb27ff66e39902e85d",
    "testharness"
@@ -264830,8 +264897,8 @@
    "d70aecce9f01ae39589bf339588d3a3002bed258",
    "support"
   ],
-  "wasm/wasm_service_worker_test.html": [
-   "894981ab7cb20e72dd683c8063868311ea226838",
+  "wasm/wasm_service_worker_test.https.html": [
+   "254d9b7074c89c57e15613e6efe9674eba95b74d",
    "testharness"
   ],
   "web-animations/README.md": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/allow-lists-starting-with-comma.htm b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/allow-lists-starting-with-comma.htm
new file mode 100644
index 0000000..03cc7cb8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/allow-lists-starting-with-comma.htm
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Allow lists starting with a comma should be parsed correctly</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+  <body>
+  <script type="text/javascript">
+    var test = async_test();
+
+    test.step(function() {
+      var xhr = new XMLHttpRequest();
+      var url = "resources/access-control-allow-lists.py?headers=,y-lol,x-print,%20,,,y-print&origin=http://127.0.0.1:8000";
+      xhr.open("GET", url, false);
+      xhr.setRequestHeader('x-print', 'unicorn')
+      xhr.setRequestHeader('y-print', 'narwhal')
+      // Sending GET request with custom headers
+      assert_equals(xhr.send(null), undefined);
+      var response = JSON.parse(xhr.response);
+      assert_equals(response['x-print'], "unicorn");
+      assert_equals(response['y-print'], "narwhal");
+
+      url = "resources/access-control-allow-lists.py?methods=,,PUT,GET&origin=http://127.0.0.1:8000";
+      xhr.open("PUT", url, false);
+      // Sending PUT request
+      assert_equals(xhr.send(null), undefined);
+      test.done();
+    });
+  </script>
+  </body>
+  </html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/resources/access-control-allow-lists.py b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/resources/access-control-allow-lists.py
new file mode 100644
index 0000000..c020cd2d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/resources/access-control-allow-lists.py
@@ -0,0 +1,22 @@
+import json
+
+def main(request, response):
+    if "origin" in request.GET:
+        response.headers.set("Access-Control-Allow-Origin", request.GET["origin"])
+    elif "origins" in request.GET:
+        for origin in request.GET["origins"].split(','):
+            response.headers.set("Access-Control-Allow-Origin", request.GET["origin"])
+
+    if "headers" in request.GET:
+        response.headers.set("Access-Control-Allow-Headers", '{'+request.GET["headers"]+'}')
+    if "methods" in request.GET:
+        response.headers.set("Access-Control-Allow-Methods", '{'+request.GET["methods"]+'}')
+
+    headers = dict(request.headers)
+
+    for header in headers:
+        headers[header] = headers[header][0]
+
+    headers["get_value"] = "" if "get_value" not in request.GET else request.GET["get_value"]
+
+    return json.dumps(headers)
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/capture.html b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/capture.html
new file mode 100644
index 0000000..3a99e5c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/capture.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+</head>
+<body>
+<script>
+
+// Run captureStream() on different videos, and assert data is flowing.
+
+var makeAsyncTest = function(filename) {
+  async_test(function(test) {
+    var video = document.createElement('video');
+    video.src = "webm/" + filename;
+    video.onerror = this.unreached_func("<video> error");
+    video.play();
+
+    var stream = video.captureStream();
+
+    // onactive event is marked for deprecation (https://crbug.com/649328)
+    stream.onactive = this.step_func_done(function() {
+      var recorder = new MediaRecorder(stream);
+        recorder.ondataavailable = test.step_func_done(function(event) {
+            assert_true(event.data.size > 0, 'Recorded data size should be > 0');
+      });
+      recorder.start(0);
+    });
+ }), "<video>.captureStream() and assert data flows.";
+};
+
+generate_tests(makeAsyncTest, [
+  [ "video-only", "test-v-128k-320x240-24fps-8kfr.webm" ],
+  [ "audio-only", "test-a-128k-44100Hz-1ch.webm" ],
+  [ "video+audio", "test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.webm" ]
+]);
+
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/creation.html b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/creation.html
new file mode 100644
index 0000000..7355e3b3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/creation.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+</head>
+<body>
+<script>
+
+// Run captureStream() on <video>/<audio>s and inspect the generated Stream.
+
+var makeAsyncTest = function(filename, numTracks) {
+  async_test(function() {
+    var video = document.createElement('video');
+    video.src = "webm/" + filename;
+    video.onerror = this.unreached_func("<video> error");
+    video.play();
+
+    assert_true('captureStream' in video);
+
+    var stream = video.captureStream();
+    assert_not_equals(stream, null, "error generating stream");
+
+    // onactive event is marked for deprecation (https://crbug.com/649328)
+    stream.onactive = this.step_func_done(function() {
+      // The stream got a (number of) MediaStreamTracks added.
+      assert_equals(stream.getVideoTracks().length, numTracks['vid'], 'video');
+      assert_equals(stream.getAudioTracks().length, numTracks['aud'], 'audio');
+    });
+  }), "<video>.captureStream()";
+};
+
+generate_tests(makeAsyncTest, [
+  [ "video-only", "test-v-128k-320x240-24fps-8kfr.webm", {vid : 1, aud : 0} ],
+  [ "audio-only", "test-a-128k-44100Hz-1ch.webm", {vid : 0, aud : 1} ],
+  [ "video+audio", "test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.webm", {vid : 1, aud : 1} ]
+]);
+
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/ended.html b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/ended.html
new file mode 100644
index 0000000..4c0ef40
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/ended.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+</head>
+<body>
+<script>
+
+// Run captureStream() on different videos, and assert the mediastream is
+// ended when the source HTMLMediaElement finishes
+
+var makeAsyncTest = function(filename) {
+  async_test(function(test) {
+    var video = document.createElement('video');
+    video.src = "webm/" + filename;
+    video.onerror = this.unreached_func("<video> error");
+    video.play();
+
+    assert_true('captureStream' in video);
+
+    var stream = video.captureStream();
+
+    stream.onremovetrack = this.step_func_done(function() {
+      assert_true(video.ended, 'video must be ended');
+      assert_equals(stream.getTracks().length, 0, 'stream must have no tracks');
+      assert_false(stream.active, 'stream must be inactive');
+    });
+
+ }), "<video>.captureStream() and assert ended event.";
+};
+
+generate_tests(makeAsyncTest, [
+  [ "video-only", "test-v-128k-320x240-24fps-8kfr.webm" ],
+  [ "audio-only", "test-a-128k-44100Hz-1ch.webm" ],
+  [ "video+audio", "test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.webm" ]
+]);
+
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/webm/test-a-128k-44100Hz-1ch.webm b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/webm/test-a-128k-44100Hz-1ch.webm
new file mode 100644
index 0000000..c5b064de
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/webm/test-a-128k-44100Hz-1ch.webm
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/webm/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.webm b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/webm/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.webm
new file mode 100644
index 0000000..8b705db
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/webm/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.webm
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/webm/test-v-128k-320x240-24fps-8kfr.webm b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/webm/test-v-128k-320x240-24fps-8kfr.webm
new file mode 100644
index 0000000..189c472
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/webm/test-v-128k-320x240-24fps-8kfr.webm
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Window/open-as-popup-vs-tab.html b/third_party/WebKit/LayoutTests/fast/dom/Window/open-as-popup-vs-tab.html
deleted file mode 100644
index ba9c77a..0000000
--- a/third_party/WebKit/LayoutTests/fast/dom/Window/open-as-popup-vs-tab.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<!doctype html>
-<html>
-<head>
-  <meta charset="utf-8">
-  <title>window.open: popup vs tab</title>
-  <script src="../../../resources/testharness.js"></script>
-  <script src="../../../resources/testharnessreport.js"></script>
-</head>
-<body>
-  <script>
-    function openToolbarOnWindow() {
-      return window.open("", "", "toolbar=1");
-    };
-    function openToolbarOffWindow() {
-      return window.open("", "", "toolbar=0");
-    }
-    function openDefaultFeaturesWindow() {
-      return window.open();
-    }
-    test(function() {
-      var w = openToolbarOnWindow();
-      assert_equals(w.toolbar.visible, true);
-      w.close();
-    }, "window.open with toolbar=1 creates a new tab");
-    test(function() {
-      var w = openToolbarOffWindow();
-      assert_equals(w.toolbar.visible, false);
-      w.close();
-    }, "window.open with toolbar=0 creates a new popup");
-    test(function() {
-      var w = openDefaultFeaturesWindow();
-      assert_equals(w.toolbar.visible, true);
-      w.close();
-    }, "window.open defaults to creating a new tab");
-  </script>
-  <button onclick="openToolbarOnWindow()">Window Features: toolbar=1</button>
-  <button onclick="openToolbarOffWindow()">Window Features: toolbar=0</button>
-  <button onclick="openDefaultFeaturesWindow()">Window Features: default</button>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/ellipsis-in-absolute-block-expected.txt b/third_party/WebKit/LayoutTests/fast/text/ellipsis-in-absolute-block-expected.txt
new file mode 100644
index 0000000..2c1ada0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/text/ellipsis-in-absolute-block-expected.txt
@@ -0,0 +1,24 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x52
+  LayoutBlockFlow {HTML} at (0,0) size 800x52
+    LayoutBlockFlow {BODY} at (8,16) size 784x20
+      LayoutBlockFlow {P} at (0,0) size 784x20
+        LayoutText {#text} at (0,0) size 478x19
+          text run at (0,0) width 478: "crbug.com/737837: Place ellipsis correctly when inline has relative position."
+layer at (31,50) size 100x14 scrollWidth 114 scrollHeight 16
+  LayoutBlockFlow (positioned) {DIV} at (31,50) size 100x14
+    LayoutText {#text} at (0,-3) size 114x19
+      text run at (0,-3) width 114: "abcdefghijklmnop"
+layer at (31,70) size 100x14 scrollX 14.00 scrollWidth 114 scrollHeight 16
+  LayoutBlockFlow (positioned) {DIV} at (31,70) size 100x14
+    LayoutText {#text} at (-14,-3) size 114x19
+      text run at (-14,-3) width 114: "abcdefghijklmnop"
+layer at (31,90) size 100x14 scrollWidth 134 scrollHeight 16
+  LayoutBlockFlow (positioned) {DIV} at (31,90) size 100x14
+    LayoutText {#text} at (0,-3) size 134x19
+      text run at (0,-3) width 134 RTL: "\x{5D0}\x{5D1}\x{5D2}\x{5D3}\x{5D4}\x{5D5}\x{5D6}\x{5D7}\x{5D8}\x{5D9}\x{5DB}\x{5DA}\x{5DC}\x{5DC}\x{5DB}\x{5DA}\x{5DC}\x{5DB}\x{5DA}\x{5DC}"
+layer at (31,110) size 100x14 scrollX 34.00 scrollWidth 134 scrollHeight 16
+  LayoutBlockFlow (positioned) {DIV} at (31,110) size 100x14
+    LayoutText {#text} at (-34,-3) size 134x19
+      text run at (-34,-3) width 134 RTL: "\x{5D0}\x{5D1}\x{5D2}\x{5D3}\x{5D4}\x{5D5}\x{5D6}\x{5D7}\x{5D8}\x{5D9}\x{5DB}\x{5DA}\x{5DC}\x{5DC}\x{5DB}\x{5DA}\x{5DC}\x{5DB}\x{5DA}\x{5DC}"
diff --git a/third_party/WebKit/LayoutTests/fast/text/ellipsis-in-absolute-block.html b/third_party/WebKit/LayoutTests/fast/text/ellipsis-in-absolute-block.html
new file mode 100644
index 0000000..efb3069
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/text/ellipsis-in-absolute-block.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<style>
+div {
+left: 31px;
+ line-height: 14px;
+ overflow: hidden;
+ position: absolute;
+ right: 3px;
+ text-overflow: ellipsis;
+ top: 9px;
+ white-space: nowrap;
+ width: 100px;
+ 
+}
+.rtl {
+  direction: rtl;
+}
+</style>
+<p>crbug.com/737837: Place ellipsis correctly when inline has relative position.</p>
+<div style="top: 50px;">abcdefghijklmnop</div>
+<div class="rtl" style="top: 70px;">abcdefghijklmnop</div>
+<div style="top: 90px;">אבגדהוזחטיכךללכךלכךל</div>
+<div class="rtl" style="top: 110px;">אבגדהוזחטיכךללכךלכךל</div>
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-2-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-2-expected.txt
index 695a637..df8feeb 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/line-flow-with-floats-2-expected.txt
@@ -510,6 +510,10 @@
       "reason": "scroll control"
     },
     {
+      "object": "LayoutView #document",
+      "reason": "incremental"
+    },
+    {
       "object": "LayoutBlockFlow P",
       "reason": "geometry"
     },
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
index 48f2d3f..9b3ef92 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
@@ -2,13 +2,13 @@
   "layers": [
     {
       "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
+      "bounds": [2011, 2081],
+      "contentsOpaque": false,
       "drawsContent": true,
       "paintInvalidations": [
         {
           "object": "LayoutView #document",
-          "rect": [3, 65, 235, 235],
+          "rect": [3, 65, 2008, 2016],
           "reason": "subtree"
         },
         {
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/resize-scrollable-iframe-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/resize-scrollable-iframe-expected.txt
index 8a6e599..83d9bce 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/resize-scrollable-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/resize-scrollable-iframe-expected.txt
@@ -2,14 +2,14 @@
   "layers": [
     {
       "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
+      "bounds": [1016, 1124],
+      "contentsOpaque": false,
       "drawsContent": true,
       "paintInvalidations": [
         {
           "object": "LayoutView #document",
-          "rect": [8, 193, 285, 200],
-          "reason": "incremental"
+          "rect": [8, 108, 1008, 1016],
+          "reason": "geometry"
         },
         {
           "object": "HorizontalScrollbar",
@@ -17,11 +17,6 @@
           "reason": "scroll control"
         },
         {
-          "object": "LayoutView #document",
-          "rect": [93, 108, 200, 285],
-          "reason": "incremental"
-        },
-        {
           "object": "HorizontalScrollbar",
           "rect": [8, 193, 85, 15],
           "reason": "scroll control"
@@ -67,10 +62,6 @@
     {
       "object": "VerticalScrollbar",
       "reason": "scroll control"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "incremental"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
index 2338aedd..20d8b3de 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
@@ -13,7 +13,7 @@
         },
         {
           "object": "LayoutView #document",
-          "rect": [0, 0, 300, 150],
+          "rect": [0, 0, 400, 200],
           "reason": "disappeared"
         },
         {
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
index 2338aedd..20d8b3de 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
@@ -13,7 +13,7 @@
         },
         {
           "object": "LayoutView #document",
-          "rect": [0, 0, 300, 150],
+          "rect": [0, 0, 400, 200],
           "reason": "disappeared"
         },
         {
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/text-match-document-change-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/text-match-document-change-expected.txt
index c14d6b7..205fd07 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/text-match-document-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/text-match-document-change-expected.txt
@@ -35,6 +35,10 @@
       "reason": "scroll control"
     },
     {
+      "object": "LayoutView #document",
+      "reason": "incremental"
+    },
+    {
       "object": "LayoutBlockFlow DIV id='to-be-changed'",
       "reason": "full"
     },
diff --git a/third_party/WebKit/LayoutTests/paint/filters/clip-under-filter-expected.png b/third_party/WebKit/LayoutTests/paint/filters/clip-under-filter-expected.png
index e2a35b5..f78122df 100644
--- a/third_party/WebKit/LayoutTests/paint/filters/clip-under-filter-expected.png
+++ b/third_party/WebKit/LayoutTests/paint/filters/clip-under-filter-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/svg/paintorder-filtered-expected.png b/third_party/WebKit/LayoutTests/paint/invalidation/svg/paintorder-filtered-expected.png
index 711e7f7..68097c13 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/svg/paintorder-filtered-expected.png
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/svg/paintorder-filtered-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/rootlayerscrolls/scrollbars/custom-scrollbar-appearance-property-expected.png b/third_party/WebKit/LayoutTests/paint/subpixel/transform-inside-clip-expected.png
similarity index 70%
rename from third_party/WebKit/LayoutTests/platform/win/virtual/rootlayerscrolls/scrollbars/custom-scrollbar-appearance-property-expected.png
rename to third_party/WebKit/LayoutTests/paint/subpixel/transform-inside-clip-expected.png
index b32d484..e77502f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/rootlayerscrolls/scrollbars/custom-scrollbar-appearance-property-expected.png
+++ b/third_party/WebKit/LayoutTests/paint/subpixel/transform-inside-clip-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/paint/subpixel/transform-inside-clip-expected.txt b/third_party/WebKit/LayoutTests/paint/subpixel/transform-inside-clip-expected.txt
new file mode 100644
index 0000000..8bb8872c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/subpixel/transform-inside-clip-expected.txt
@@ -0,0 +1,11 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x116
+  LayoutBlockFlow {HTML} at (0,0) size 800x116
+    LayoutBlockFlow {BODY} at (8,8) size 784x100
+layer at (9,8) size 100x100
+  LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 100x100
+layer at (9,8) size 52x52 clip at (10,9) size 50x50 scrollWidth 200 scrollHeight 200
+  LayoutBlockFlow (relative positioned) {DIV} at (0,0) size 52x52 [border: (1px solid #808080)]
+layer at (10,9) size 200x200 backgroundClip at (10,9) size 50x50 clip at (10,9) size 50x50
+  LayoutBlockFlow {DIV} at (1,1) size 200x200 [bgcolor=#ADD8E6]
diff --git a/third_party/WebKit/LayoutTests/paint/subpixel/transform-inside-clip.html b/third_party/WebKit/LayoutTests/paint/subpixel/transform-inside-clip.html
new file mode 100644
index 0000000..5cc6cf28
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/subpixel/transform-inside-clip.html
@@ -0,0 +1,7 @@
+<!doctype HTML>
+<!-- Passes if you see a 1px black border with blue contents -->
+<div style="width: 100px; height: 100px; left: 0.5px; will-change: transform; position: relative;">
+  <div style="width: 50px; height: 50px; border: 1px solid gray; left: 0.5px; position: relative; overflow: hidden">
+    <div style="width: 200px; height: 200px; transform: scale(1); background: lightblue"></div>
+  </div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/css3/filters/filter-repaint-turbulence-expected.png b/third_party/WebKit/LayoutTests/platform/linux/css3/filters/filter-repaint-turbulence-expected.png
index 38c363cb..6033dde 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/css3/filters/filter-repaint-turbulence-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/css3/filters/filter-repaint-turbulence-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-in-absolute-block-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-in-absolute-block-expected.png
new file mode 100644
index 0000000..d5a8e0c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/text/ellipsis-in-absolute-block-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/filter-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/filter-repaint-expected.png
index 74ef382..125d3f8 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/filter-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/filter-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/filter-width-update-expected.png b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/filter-width-update-expected.png
index 512499e..f7c0e8d5 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/filter-width-update-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/svg/filter-width-update-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-color-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-color-01-b-expected.png
index 7e4f407..6e02e4cb 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-color-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-color-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-composite-02-b-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-composite-02-b-expected.png
index a1d5db4..8c57efa 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-composite-02-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-composite-02-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-comptran-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-comptran-01-b-expected.png
index 893b50e0..6d859b7d 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-comptran-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-comptran-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-conv-01-f-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-conv-01-f-expected.png
index af9856f..a59b4378 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-conv-01-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-conv-01-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-diffuse-01-f-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-diffuse-01-f-expected.png
index bb5f03d..4c08e51 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-diffuse-01-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-diffuse-01-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-displace-01-f-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-displace-01-f-expected.png
index 045dded..5e5003f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-displace-01-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-displace-01-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-example-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-example-01-b-expected.png
index 355812145..b81de46 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-example-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-example-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-gauss-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-gauss-01-b-expected.png
index 00b0891..32068f68 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-gauss-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-gauss-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-light-01-f-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-light-01-f-expected.png
index c58f020..fb63f2333 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-light-01-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-light-01-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-light-04-f-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-light-04-f-expected.png
index e8d25e2a..73abe3f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-light-04-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-light-04-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png
index 009b4ee..0a80bb6 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-offset-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-offset-01-b-expected.png
index 348f76a..04bd8d32 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-offset-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-offset-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-turb-01-f-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-turb-01-f-expected.png
index e5be983..13993ac 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-turb-01-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-turb-01-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-turb-02-f-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-turb-02-f-expected.png
index eaa4f87..200b67a 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-turb-02-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.1/filters-turb-02-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/batik/filters/feTile-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/batik/filters/feTile-expected.png
index 8914ae2e..28a45a3 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/batik/filters/feTile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/batik/filters/feTile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/feComponentTransfer-Discrete-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/feComponentTransfer-Discrete-expected.png
index 76a7195..c4194ad9 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/feComponentTransfer-Discrete-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/feComponentTransfer-Discrete-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/feComponentTransfer-Gamma-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/feComponentTransfer-Gamma-expected.png
index 2d12e50..8f0745a 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/feComponentTransfer-Gamma-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/feComponentTransfer-Gamma-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/feComponentTransfer-Linear-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/feComponentTransfer-Linear-expected.png
index 431934a..680e6cb4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/feComponentTransfer-Linear-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/feComponentTransfer-Linear-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/feComponentTransfer-Table-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/feComponentTransfer-Table-expected.png
index e575a76..218ec16 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/feComponentTransfer-Table-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/feComponentTransfer-Table-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/image-with-transform-clip-filter-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/image-with-transform-clip-filter-expected.png
index 42f0fee..4af5ac58 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/image-with-transform-clip-filter-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/image-with-transform-clip-filter-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/text-filter-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/text-filter-expected.png
index e7c87fe..7608a326 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/text-filter-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/text-filter-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/dynamic-updates/SVGFEMorphologyElement-dom-in-attr-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/dynamic-updates/SVGFEMorphologyElement-dom-in-attr-expected.png
index 04daf71..3e19b16 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/dynamic-updates/SVGFEMorphologyElement-dom-in-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/dynamic-updates/SVGFEMorphologyElement-dom-in-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/dynamic-updates/SVGFEMorphologyElement-svgdom-in-prop-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/dynamic-updates/SVGFEMorphologyElement-svgdom-in-prop-expected.png
index 04daf71..3e19b16 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/dynamic-updates/SVGFEMorphologyElement-svgdom-in-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/dynamic-updates/SVGFEMorphologyElement-svgdom-in-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/filters/feComposite-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/filters/feComposite-expected.png
index ba80705..a684c63 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/filters/feComposite-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/filters/feComposite-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/basic-scrollbar-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/basic-scrollbar-expected.png
deleted file mode 100644
index 7145a28..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/basic-scrollbar-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/border-box-rect-clips-scrollbars-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/border-box-rect-clips-scrollbars-expected.png
deleted file mode 100644
index 6674039..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/border-box-rect-clips-scrollbars-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/custom-scrollbar-appearance-property-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/custom-scrollbar-appearance-property-expected.png
deleted file mode 100644
index 157ee435a..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/custom-scrollbar-appearance-property-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/disabled-scrollbar-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/disabled-scrollbar-expected.png
deleted file mode 100644
index 9d1dad9c..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/disabled-scrollbar-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/resize-scales-with-dpi-150-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/resize-scales-with-dpi-150-expected.png
deleted file mode 100644
index 20a4550..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/resize-scales-with-dpi-150-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/scrollbar-buttons-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/scrollbar-buttons-expected.png
deleted file mode 100644
index 7d1f4e3..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/scrollbar-buttons-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/scrollbar-orientation-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/scrollbar-orientation-expected.png
deleted file mode 100644
index 805e6f4..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/scrollbar-orientation-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/scrollbars-on-positioned-content-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/scrollbars-on-positioned-content-expected.png
deleted file mode 100644
index 942946d..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/rootlayerscrolls/scrollbars/scrollbars-on-positioned-content-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-in-absolute-block-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-in-absolute-block-expected.png
new file mode 100644
index 0000000..e00b4cb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-in-absolute-block-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-in-absolute-block-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-in-absolute-block-expected.png
new file mode 100644
index 0000000..3baf6373
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-in-absolute-block-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/rootlayerscrolls/scrollbars/border-box-rect-clips-scrollbars-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/rootlayerscrolls/scrollbars/border-box-rect-clips-scrollbars-expected.png
deleted file mode 100644
index cb4dce0..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/rootlayerscrolls/scrollbars/border-box-rect-clips-scrollbars-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/rootlayerscrolls/scrollbars/resize-scales-with-dpi-150-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/rootlayerscrolls/scrollbars/resize-scales-with-dpi-150-expected.png
deleted file mode 100644
index 0f908f9..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/rootlayerscrolls/scrollbars/resize-scales-with-dpi-150-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/rootlayerscrolls/scrollbars/scrollbars-on-positioned-content-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/rootlayerscrolls/scrollbars/scrollbars-on-positioned-content-expected.png
deleted file mode 100644
index af62165..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/rootlayerscrolls/scrollbars/scrollbars-on-positioned-content-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/filters/filter-repaint-turbulence-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/filters/filter-repaint-turbulence-expected.png
index c91ec41..f561ed21 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/filters/filter-repaint-turbulence-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/filters/filter-repaint-turbulence-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-in-absolute-block-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-in-absolute-block-expected.png
new file mode 100644
index 0000000..24d1728f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-in-absolute-block-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/filter-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/filter-repaint-expected.png
index 093b8d6d..7b2c0ee 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/filter-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/filter-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/filter-width-update-expected.png b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/filter-width-update-expected.png
index 84390d60..79076502a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/filter-width-update-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/svg/filter-width-update-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-color-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-color-01-b-expected.png
index 2b8bbf2b1..d13b60a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-color-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-color-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-composite-02-b-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-composite-02-b-expected.png
index 4de3348..a244f6e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-composite-02-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-composite-02-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-comptran-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-comptran-01-b-expected.png
index 95cba144..fea77b8f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-comptran-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-comptran-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-conv-01-f-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-conv-01-f-expected.png
index 9ca93ae..a874493 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-conv-01-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-conv-01-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-diffuse-01-f-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-diffuse-01-f-expected.png
index d474443..2d942ef3 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-diffuse-01-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-diffuse-01-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-displace-01-f-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-displace-01-f-expected.png
index efd3283..7d5e97b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-displace-01-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-displace-01-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-example-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-example-01-b-expected.png
index 92be1620..4fa6c7a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-example-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-example-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-gauss-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-gauss-01-b-expected.png
index 10c4604..5e51376 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-gauss-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-gauss-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-light-01-f-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-light-01-f-expected.png
index bde6e6f..ed9d284 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-light-01-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-light-01-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-light-04-f-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-light-04-f-expected.png
index 57d8320..0945c4f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-light-04-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-light-04-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png
index 434d18f..7664fac6 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-offset-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-offset-01-b-expected.png
index 05fa92c..f421c0c9 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-offset-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-offset-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-turb-01-f-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-turb-01-f-expected.png
index 34307a51..1f6da5a8 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-turb-01-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-turb-01-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-turb-02-f-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-turb-02-f-expected.png
index 5d251c6b..3c184ae0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-turb-02-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-turb-02-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/batik/filters/feTile-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/batik/filters/feTile-expected.png
index 7950b9d..5364dc6 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/batik/filters/feTile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/batik/filters/feTile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/convolution-crash-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/convolution-crash-expected.png
index 7367bcc..49a5138 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/convolution-crash-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/convolution-crash-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/feComponentTransfer-Discrete-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/feComponentTransfer-Discrete-expected.png
index 413e1b2..d9ad37e1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/feComponentTransfer-Discrete-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/feComponentTransfer-Discrete-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/feComponentTransfer-Gamma-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/feComponentTransfer-Gamma-expected.png
index a1a72ac..bd01e53 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/feComponentTransfer-Gamma-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/feComponentTransfer-Gamma-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/feComponentTransfer-Linear-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/feComponentTransfer-Linear-expected.png
index da29bc7..8edb4721 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/feComponentTransfer-Linear-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/feComponentTransfer-Linear-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/feComponentTransfer-Table-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/feComponentTransfer-Table-expected.png
index 9113dd3..ff853b62 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/feComponentTransfer-Table-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/feComponentTransfer-Table-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/image-with-transform-clip-filter-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/image-with-transform-clip-filter-expected.png
index a305ce7..5541ca8e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/image-with-transform-clip-filter-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/image-with-transform-clip-filter-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/text-filter-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/text-filter-expected.png
index 9b34a847..06f1157 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/text-filter-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/text-filter-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-color-attr-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-color-attr-expected.png
index 360e308..0c349376 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-color-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-color-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-opacity-attr-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-opacity-attr-expected.png
index 61c5d8ab..96cedec3 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-opacity-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-opacity-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-color-prop-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-color-prop-expected.png
index 360e308..0c349376 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-color-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-color-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-opacity-prop-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-opacity-prop-expected.png
index 61c5d8ab..96cedec3 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-opacity-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-opacity-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEMorphologyElement-dom-in-attr-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEMorphologyElement-dom-in-attr-expected.png
index f2ba96b..622c26a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEMorphologyElement-dom-in-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEMorphologyElement-dom-in-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEMorphologyElement-svgdom-in-prop-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEMorphologyElement-svgdom-in-prop-expected.png
index f2ba96b..622c26a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEMorphologyElement-svgdom-in-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/dynamic-updates/SVGFEMorphologyElement-svgdom-in-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/filters/feBlend-all-modes-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/filters/feBlend-all-modes-expected.png
index 3b8b1eb..c076b51 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/filters/feBlend-all-modes-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/filters/feBlend-all-modes-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/filters/feComposite-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/filters/feComposite-expected.png
index 40e664f2f..1b169cf 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/filters/feComposite-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/filters/feComposite-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/filters/feDropShadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/filters/feDropShadow-expected.png
index c0cbaa7..141abcc 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/filters/feDropShadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/filters/feDropShadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/filters/feGaussianBlur-zero-deviation-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/filters/feGaussianBlur-zero-deviation-expected.png
deleted file mode 100644
index 353c61a7..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/filters/feGaussianBlur-zero-deviation-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/filters/innershadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/filters/innershadow-expected.png
deleted file mode 100644
index 3b65770..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/filters/innershadow-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/rootlayerscrolls/scrollbars/border-box-rect-clips-scrollbars-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/rootlayerscrolls/scrollbars/border-box-rect-clips-scrollbars-expected.png
deleted file mode 100644
index fa48bc9e..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/rootlayerscrolls/scrollbars/border-box-rect-clips-scrollbars-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/rootlayerscrolls/scrollbars/resize-scales-with-dpi-150-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/rootlayerscrolls/scrollbars/resize-scales-with-dpi-150-expected.png
deleted file mode 100644
index 89fd005..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/rootlayerscrolls/scrollbars/resize-scales-with-dpi-150-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/rootlayerscrolls/scrollbars/scrollbars-on-positioned-content-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/rootlayerscrolls/scrollbars/scrollbars-on-positioned-content-expected.png
deleted file mode 100644
index b27e7bb..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/rootlayerscrolls/scrollbars/scrollbars-on-positioned-content-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/filters/filter-repaint-turbulence-expected.png b/third_party/WebKit/LayoutTests/platform/win/css3/filters/filter-repaint-turbulence-expected.png
index 1810381..b32f4f68 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/filters/filter-repaint-turbulence-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css3/filters/filter-repaint-turbulence-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-in-absolute-block-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-in-absolute-block-expected.png
new file mode 100644
index 0000000..5c1a84c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-in-absolute-block-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/filter-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/filter-repaint-expected.png
index 46e74865..73bfff1 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/filter-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/filter-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/filter-width-update-expected.png b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/filter-width-update-expected.png
index ee99f64..7548748 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/filter-width-update-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/svg/filter-width-update-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-color-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-color-01-b-expected.png
index e6b6ed2..d7653c39 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-color-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-color-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-composite-02-b-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-composite-02-b-expected.png
index 271efe2..0f5965ef 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-composite-02-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-composite-02-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-comptran-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-comptran-01-b-expected.png
index 3e517131..001611e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-comptran-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-comptran-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-conv-01-f-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-conv-01-f-expected.png
index 19c669b..4e6d2ec 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-conv-01-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-conv-01-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-diffuse-01-f-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-diffuse-01-f-expected.png
index 32fa1ee..6e7d1d0 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-diffuse-01-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-diffuse-01-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-displace-01-f-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-displace-01-f-expected.png
index 853bdda..c074308 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-displace-01-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-displace-01-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-example-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-example-01-b-expected.png
index 78ec3512c..9eb47a05 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-example-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-example-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-gauss-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-gauss-01-b-expected.png
index 2ae160f1..93f62bc2 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-gauss-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-gauss-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-light-01-f-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-light-01-f-expected.png
index f1c876e..5a66863f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-light-01-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-light-01-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-light-04-f-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-light-04-f-expected.png
index ac85e6b4..f3ac271 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-light-04-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-light-04-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png
index a25b15e..f258313a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-morph-01-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-offset-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-offset-01-b-expected.png
index d7a8742..447ca39 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-offset-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-offset-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-turb-01-f-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-turb-01-f-expected.png
index 76938d0..357fa80f5 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-turb-01-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-turb-01-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-turb-02-f-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-turb-02-f-expected.png
index 7e6ca86..159efb3 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-turb-02-f-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.1/filters-turb-02-f-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/batik/filters/feTile-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/batik/filters/feTile-expected.png
index bfca85a..bfc9e2c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/batik/filters/feTile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/batik/filters/feTile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/convolution-crash-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/convolution-crash-expected.png
index 85ccba2..56fcea3 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/convolution-crash-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/convolution-crash-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/feComponentTransfer-Discrete-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/feComponentTransfer-Discrete-expected.png
index 926cfd3..9d63e625 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/feComponentTransfer-Discrete-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/feComponentTransfer-Discrete-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/feComponentTransfer-Gamma-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/feComponentTransfer-Gamma-expected.png
index 19e7bb8..a4e98b7 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/feComponentTransfer-Gamma-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/feComponentTransfer-Gamma-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/feComponentTransfer-Linear-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/feComponentTransfer-Linear-expected.png
index 795cc4eb..53151c8 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/feComponentTransfer-Linear-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/feComponentTransfer-Linear-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/feComponentTransfer-Table-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/feComponentTransfer-Table-expected.png
index b06c6250..d15e729 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/feComponentTransfer-Table-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/feComponentTransfer-Table-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/image-with-transform-clip-filter-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/image-with-transform-clip-filter-expected.png
index 83073bcb..92becb28 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/image-with-transform-clip-filter-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/image-with-transform-clip-filter-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/text-filter-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/text-filter-expected.png
index ff80f287..4cea4bf 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/text-filter-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/text-filter-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-color-attr-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-color-attr-expected.png
new file mode 100644
index 0000000..d6e03f3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-color-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-opacity-attr-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-opacity-attr-expected.png
new file mode 100644
index 0000000..2a87d59
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-opacity-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-color-prop-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-color-prop-expected.png
new file mode 100644
index 0000000..d6e03f3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-color-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-opacity-prop-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-opacity-prop-expected.png
new file mode 100644
index 0000000..2a87d59
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-opacity-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEMorphologyElement-dom-in-attr-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEMorphologyElement-dom-in-attr-expected.png
index dedbfa4..d586d74f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEMorphologyElement-dom-in-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEMorphologyElement-dom-in-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEMorphologyElement-svgdom-in-prop-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEMorphologyElement-svgdom-in-prop-expected.png
index dedbfa4..d586d74f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEMorphologyElement-svgdom-in-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/dynamic-updates/SVGFEMorphologyElement-svgdom-in-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/filters/feBlend-all-modes-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/filters/feBlend-all-modes-expected.png
index 1be1491..231b65e4 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/filters/feBlend-all-modes-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/filters/feBlend-all-modes-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/filters/feComposite-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/filters/feComposite-expected.png
index 8d5b31c..b247163 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/filters/feComposite-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/filters/feComposite-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/filters/feDropShadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/filters/feDropShadow-expected.png
index ba0a4b6..85355b0 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/filters/feDropShadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/filters/feDropShadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/filters/feGaussianBlur-zero-deviation-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/filters/feGaussianBlur-zero-deviation-expected.png
deleted file mode 100644
index 438cd107..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/svg/filters/feGaussianBlur-zero-deviation-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/filters/innershadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/filters/innershadow-expected.png
deleted file mode 100644
index 9f71d25..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/svg/filters/innershadow-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/rootlayerscrolls/scrollbars/border-box-rect-clips-scrollbars-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/rootlayerscrolls/scrollbars/border-box-rect-clips-scrollbars-expected.png
deleted file mode 100644
index 4532ab5..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/rootlayerscrolls/scrollbars/border-box-rect-clips-scrollbars-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/rootlayerscrolls/scrollbars/scrollbars-on-positioned-content-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/rootlayerscrolls/scrollbars/scrollbars-on-positioned-content-expected.png
deleted file mode 100644
index 455109a..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/rootlayerscrolls/scrollbars/scrollbars-on-positioned-content-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/text/ellipsis-in-absolute-block-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/text/ellipsis-in-absolute-block-expected.png
new file mode 100644
index 0000000..ec004d624
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/text/ellipsis-in-absolute-block-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-SVG-1.1/filters-color-01-b-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-SVG-1.1/filters-color-01-b-expected.png
index 2b83f40..c0d9d396 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-SVG-1.1/filters-color-01-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-SVG-1.1/filters-color-01-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-SVG-1.1/filters-composite-02-b-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-SVG-1.1/filters-composite-02-b-expected.png
index fe4fa8f..9311e70 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-SVG-1.1/filters-composite-02-b-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/W3C-SVG-1.1/filters-composite-02-b-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/custom/feComponentTransfer-Discrete-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/custom/feComponentTransfer-Discrete-expected.png
index a759c783..bce8383 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/custom/feComponentTransfer-Discrete-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/custom/feComponentTransfer-Discrete-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/custom/feComponentTransfer-Gamma-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/custom/feComponentTransfer-Gamma-expected.png
index aaaa07c..f9ccfa33 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/custom/feComponentTransfer-Gamma-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/custom/feComponentTransfer-Gamma-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/custom/feComponentTransfer-Linear-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/custom/feComponentTransfer-Linear-expected.png
index 041498d0..e0bc0db6 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/custom/feComponentTransfer-Linear-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/custom/feComponentTransfer-Linear-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/custom/feComponentTransfer-Table-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/custom/feComponentTransfer-Table-expected.png
index ba747a1..e92eb75 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/custom/feComponentTransfer-Table-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/custom/feComponentTransfer-Table-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/dynamic-updates/SVGFEMorphologyElement-dom-in-attr-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/dynamic-updates/SVGFEMorphologyElement-dom-in-attr-expected.png
index 519c78a..2871e6d 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/dynamic-updates/SVGFEMorphologyElement-dom-in-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/dynamic-updates/SVGFEMorphologyElement-dom-in-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/svg/dynamic-updates/SVGFEMorphologyElement-svgdom-in-prop-expected.png b/third_party/WebKit/LayoutTests/platform/win7/svg/dynamic-updates/SVGFEMorphologyElement-svgdom-in-prop-expected.png
index 519c78a..2871e6d 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/svg/dynamic-updates/SVGFEMorphologyElement-svgdom-in-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/svg/dynamic-updates/SVGFEMorphologyElement-svgdom-in-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/css/path-gradient-stroke-shadow-expected.png b/third_party/WebKit/LayoutTests/svg/css/path-gradient-stroke-shadow-expected.png
index 858cb44..05e1c41 100644
--- a/third_party/WebKit/LayoutTests/svg/css/path-gradient-stroke-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/css/path-gradient-stroke-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/css/rect-gradient-stroke-shadow-expected.png b/third_party/WebKit/LayoutTests/svg/css/rect-gradient-stroke-shadow-expected.png
index 858cb44..05e1c41 100644
--- a/third_party/WebKit/LayoutTests/svg/css/rect-gradient-stroke-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/css/rect-gradient-stroke-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/custom/filter-css-transform-resolution-expected.png b/third_party/WebKit/LayoutTests/svg/custom/filter-css-transform-resolution-expected.png
index 288e0ff5..b0536cca 100644
--- a/third_party/WebKit/LayoutTests/svg/custom/filter-css-transform-resolution-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/custom/filter-css-transform-resolution-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/custom/grayscale-gradient-mask-2-expected.png b/third_party/WebKit/LayoutTests/svg/custom/grayscale-gradient-mask-2-expected.png
index df57de60..f4b4594 100644
--- a/third_party/WebKit/LayoutTests/svg/custom/grayscale-gradient-mask-2-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/custom/grayscale-gradient-mask-2-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEColorMatrixElement-dom-in-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEColorMatrixElement-dom-in-attr-expected.png
index 2dc5313..d2c50b9 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEColorMatrixElement-dom-in-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEColorMatrixElement-dom-in-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEColorMatrixElement-dom-type-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEColorMatrixElement-dom-type-attr-expected.png
index 2dc5313..d2c50b9 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEColorMatrixElement-dom-type-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEColorMatrixElement-dom-type-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEColorMatrixElement-dom-values-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEColorMatrixElement-dom-values-attr-expected.png
index 2dc5313..d2c50b9 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEColorMatrixElement-dom-values-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEColorMatrixElement-dom-values-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEColorMatrixElement-svgdom-in-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEColorMatrixElement-svgdom-in-prop-expected.png
index 2dc5313..d2c50b9 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEColorMatrixElement-svgdom-in-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEColorMatrixElement-svgdom-in-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEColorMatrixElement-svgdom-type-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEColorMatrixElement-svgdom-type-prop-expected.png
index 2dc5313..d2c50b9 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEColorMatrixElement-svgdom-type-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEColorMatrixElement-svgdom-type-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEColorMatrixElement-svgdom-values-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEColorMatrixElement-svgdom-values-prop-expected.png
index 2dc5313..d2c50b9 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEColorMatrixElement-svgdom-values-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEColorMatrixElement-svgdom-values-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-amplitude-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-amplitude-attr-expected.png
index 751bc7d..1fd92f3b 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-amplitude-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-amplitude-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-exponent-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-exponent-attr-expected.png
index 751bc7d..1fd92f3b 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-exponent-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-exponent-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-intercept-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-intercept-attr-expected.png
index 2c930145..f8a1725 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-intercept-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-intercept-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-offset-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-offset-attr-expected.png
index 2c930145..f8a1725 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-offset-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-offset-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-slope-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-slope-attr-expected.png
index 6c23abd..620627b 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-slope-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-slope-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-tableValues-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-tableValues-attr-expected.png
index 2698a91..98c6f9b 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-tableValues-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-tableValues-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-type-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-type-attr-expected.png
index 751bc7d..1fd92f3b 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-type-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-dom-type-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-amplitude-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-amplitude-prop-expected.png
index 751bc7d..1fd92f3b 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-amplitude-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-amplitude-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-exponent-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-exponent-prop-expected.png
index 751bc7d..1fd92f3b 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-exponent-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-exponent-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-intercept-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-intercept-prop-expected.png
index 2c930145..f8a1725 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-intercept-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-intercept-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-offset-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-offset-prop-expected.png
index 2c930145..f8a1725 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-offset-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-offset-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-slope-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-slope-prop-expected.png
index 6c23abd..620627b 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-slope-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-slope-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-tableValues-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-tableValues-prop-expected.png
index 10934c3..c913a17 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-tableValues-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-tableValues-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-type-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-type-prop-expected.png
index 751bc7d..1fd92f3b 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-type-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEComponentTransferElement-svgdom-type-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-in-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-in-attr-expected.png
index 7a1b7fd..6fcedd0b0 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-in-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-in-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-in2-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-in2-attr-expected.png
index fc0573d5..f5e25d1 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-in2-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-in2-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-k1-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-k1-attr-expected.png
index fc0573d5..f5e25d1 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-k1-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-k1-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-k2-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-k2-attr-expected.png
index fc0573d5..f5e25d1 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-k2-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-k2-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-k3-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-k3-attr-expected.png
index 68d08bc1..3e57811 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-k3-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-k3-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-k4-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-k4-attr-expected.png
index fc0573d5..f5e25d1 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-k4-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-k4-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-operator-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-operator-attr-expected.png
index fc0573d5..f5e25d1 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-operator-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-dom-operator-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-in-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-in-prop-expected.png
index 7a1b7fd..6fcedd0b0 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-in-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-in-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-in2-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-in2-prop-expected.png
index fc0573d5..f5e25d1 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-in2-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-in2-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-k1-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-k1-prop-expected.png
index fc0573d5..f5e25d1 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-k1-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-k1-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-k2-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-k2-prop-expected.png
index fc0573d5..f5e25d1 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-k2-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-k2-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-k3-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-k3-prop-expected.png
index 68d08bc1..3e57811 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-k3-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-k3-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-k4-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-k4-prop-expected.png
index fc0573d5..f5e25d1 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-k4-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-k4-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-operator-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-operator-prop-expected.png
index fc0573d5..f5e25d1 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-operator-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFECompositeElement-svgdom-operator-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-bias-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-bias-attr-expected.png
index 801c1f1d8..909c6d3 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-bias-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-bias-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-divisor-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-divisor-attr-expected.png
index 801c1f1d8..909c6d3 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-divisor-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-divisor-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-edgeMode-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-edgeMode-attr-expected.png
index 18837c9..14c8ba0 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-edgeMode-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-edgeMode-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-in-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-in-attr-expected.png
index 801c1f1d8..909c6d3 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-in-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-in-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-kernelMatrix-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-kernelMatrix-attr-expected.png
index 801c1f1d8..909c6d3 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-kernelMatrix-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-kernelMatrix-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-kernelUnitLength-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-kernelUnitLength-attr-expected.png
index 2daabd7..28b8dab 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-kernelUnitLength-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-kernelUnitLength-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-order-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-order-attr-expected.png
index 801c1f1d8..909c6d3 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-order-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-order-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-preserveAlpha-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-preserveAlpha-attr-expected.png
index a1c7aca8..ea726d1 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-preserveAlpha-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-preserveAlpha-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-targetX-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-targetX-attr-expected.png
index 18837c9..14c8ba0 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-targetX-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-targetX-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-targetY-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-targetY-attr-expected.png
index 5f1ea11..6c30dffa 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-targetY-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-dom-targetY-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-bias-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-bias-prop-expected.png
index 801c1f1d8..909c6d3 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-bias-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-bias-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-divisor-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-divisor-prop-expected.png
index 801c1f1d8..909c6d3 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-divisor-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-divisor-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-edgeMode-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-edgeMode-prop-expected.png
index 801c1f1d8..909c6d3 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-edgeMode-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-edgeMode-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-in-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-in-prop-expected.png
index 801c1f1d8..909c6d3 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-in-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-in-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-kernelMatrix-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-kernelMatrix-prop-expected.png
index 6a5711a..7b9a0b4b 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-kernelMatrix-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-kernelMatrix-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-kernelUnitLength-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-kernelUnitLength-prop-expected.png
index 2daabd7..28b8dab 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-kernelUnitLength-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-kernelUnitLength-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-order-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-order-prop-expected.png
index 801c1f1d8..909c6d3 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-order-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-order-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-preserveAlpha-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-preserveAlpha-prop-expected.png
index a1c7aca8..ea726d1 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-preserveAlpha-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-preserveAlpha-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-targetX-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-targetX-prop-expected.png
index 18837c9..14c8ba0 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-targetX-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-targetX-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-targetY-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-targetY-prop-expected.png
index 5f1ea11..6c30dffa 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-targetY-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEConvolveMatrixElement-svgdom-targetY-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-dom-diffuseConstant-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-dom-diffuseConstant-attr-expected.png
index d10057d..e1ef031 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-dom-diffuseConstant-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-dom-diffuseConstant-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-dom-in-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-dom-in-attr-expected.png
index d10057d..e1ef031 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-dom-in-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-dom-in-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-dom-kernelUnitLength-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-dom-kernelUnitLength-attr-expected.png
index ad8e391b1..7f23ff5 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-dom-kernelUnitLength-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-dom-kernelUnitLength-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-dom-lighting-color-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-dom-lighting-color-attr-expected.png
index d10057d..e1ef031 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-dom-lighting-color-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-dom-lighting-color-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-dom-surfaceScale-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-dom-surfaceScale-attr-expected.png
index d10057d..e1ef031 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-dom-surfaceScale-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-dom-surfaceScale-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-inherit-lighting-color-css-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-inherit-lighting-color-css-prop-expected.png
index d10057d..e1ef031 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-inherit-lighting-color-css-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-inherit-lighting-color-css-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-lighting-color-css-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-lighting-color-css-prop-expected.png
index d10057d..e1ef031 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-lighting-color-css-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-lighting-color-css-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-svgdom-diffuseConstant-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-svgdom-diffuseConstant-prop-expected.png
index d10057d..e1ef031 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-svgdom-diffuseConstant-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-svgdom-diffuseConstant-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-svgdom-in-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-svgdom-in-prop-expected.png
index d10057d..e1ef031 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-svgdom-in-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-svgdom-in-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-svgdom-surfaceScale-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-svgdom-surfaceScale-prop-expected.png
index d10057d..e1ef031 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-svgdom-surfaceScale-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDiffuseLightingElement-svgdom-surfaceScale-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-dom-in-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-dom-in-attr-expected.png
index 850fa68..c217472 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-dom-in-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-dom-in-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-dom-in2-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-dom-in2-attr-expected.png
index 850fa68..c217472 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-dom-in2-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-dom-in2-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-dom-scale-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-dom-scale-attr-expected.png
index 850fa68..c217472 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-dom-scale-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-dom-scale-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-dom-xChannelSelector-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-dom-xChannelSelector-attr-expected.png
index 850fa68..c217472 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-dom-xChannelSelector-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-dom-xChannelSelector-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-dom-yChannelSelector-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-dom-yChannelSelector-attr-expected.png
index 850fa68..c217472 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-dom-yChannelSelector-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-dom-yChannelSelector-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-svgdom-in-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-svgdom-in-prop-expected.png
index 850fa68..c217472 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-svgdom-in-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-svgdom-in-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-svgdom-in2-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-svgdom-in2-prop-expected.png
index 850fa68..c217472 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-svgdom-in2-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-svgdom-in2-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-svgdom-scale-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-svgdom-scale-prop-expected.png
index 850fa68..c217472 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-svgdom-scale-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-svgdom-scale-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-svgdom-xChannelSelector-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-svgdom-xChannelSelector-prop-expected.png
index 850fa68..c217472 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-svgdom-xChannelSelector-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-svgdom-xChannelSelector-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-svgdom-yChannelSelector-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-svgdom-yChannelSelector-prop-expected.png
index 850fa68..c217472 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-svgdom-yChannelSelector-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDisplacementMapElement-svgdom-yChannelSelector-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDistantLightElement-dom-azimuth-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDistantLightElement-dom-azimuth-attr-expected.png
index d540771..f4d4eb6c 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDistantLightElement-dom-azimuth-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDistantLightElement-dom-azimuth-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDistantLightElement-dom-elevation-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDistantLightElement-dom-elevation-attr-expected.png
index d540771..f4d4eb6c 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDistantLightElement-dom-elevation-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDistantLightElement-dom-elevation-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDistantLightElement-svgdom-azimuth-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDistantLightElement-svgdom-azimuth-prop-expected.png
index d540771..f4d4eb6c 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDistantLightElement-svgdom-azimuth-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDistantLightElement-svgdom-azimuth-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDistantLightElement-svgdom-elevation-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDistantLightElement-svgdom-elevation-prop-expected.png
index d540771..f4d4eb6c 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDistantLightElement-svgdom-elevation-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDistantLightElement-svgdom-elevation-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-dom-dx-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-dom-dx-attr-expected.png
index 58ce457..7d8b733a 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-dom-dx-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-dom-dx-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-dom-dy-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-dom-dy-attr-expected.png
index 58ce457..7d8b733a 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-dom-dy-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-dom-dy-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-dom-in-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-dom-in-attr-expected.png
index 58ce457..7d8b733a 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-dom-in-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-dom-in-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-color-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-color-attr-expected.png
deleted file mode 100644
index 777a12c..0000000
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-color-attr-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-opacity-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-opacity-attr-expected.png
deleted file mode 100644
index 3dc437f..0000000
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-dom-shadow-opacity-attr-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr-expected.png
index 9db3054f..7dddcae9a 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-dx-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-dx-prop-expected.png
index 58ce457..7d8b733a 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-dx-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-dx-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-dy-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-dy-prop-expected.png
index 58ce457..7d8b733a 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-dy-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-dy-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-in-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-in-prop-expected.png
index 58ce457..7d8b733a 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-in-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-in-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-color-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-color-prop-expected.png
deleted file mode 100644
index 777a12c..0000000
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-color-prop-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-opacity-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-opacity-prop-expected.png
deleted file mode 100644
index 3dc437f..0000000
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-shadow-opacity-prop-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-stdDeviation-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-stdDeviation-prop-expected.png
index 9db3054f..7dddcae9a 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-stdDeviation-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEDropShadowElement-svgdom-stdDeviation-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEGaussianBlurElement-dom-in-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEGaussianBlurElement-dom-in-attr-expected.png
index 0a42fb0..57ea65b 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEGaussianBlurElement-dom-in-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEGaussianBlurElement-dom-in-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEGaussianBlurElement-dom-stdDeviation-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEGaussianBlurElement-dom-stdDeviation-attr-expected.png
index 0a42fb0..57ea65b 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEGaussianBlurElement-dom-stdDeviation-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEGaussianBlurElement-dom-stdDeviation-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEGaussianBlurElement-dom-stdDeviation-call-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEGaussianBlurElement-dom-stdDeviation-call-expected.png
index 0a42fb0..57ea65b 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEGaussianBlurElement-dom-stdDeviation-call-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEGaussianBlurElement-dom-stdDeviation-call-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEGaussianBlurElement-svgdom-in-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEGaussianBlurElement-svgdom-in-prop-expected.png
index 0a42fb0..57ea65b 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEGaussianBlurElement-svgdom-in-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEGaussianBlurElement-svgdom-in-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEMergeNodeElement-dom-in-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEMergeNodeElement-dom-in-attr-expected.png
index 69940a9..45fb730 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEMergeNodeElement-dom-in-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEMergeNodeElement-dom-in-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEMergeNodeElement-svgdom-in-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEMergeNodeElement-svgdom-in-prop-expected.png
index 69940a9..45fb730 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEMergeNodeElement-svgdom-in-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEMergeNodeElement-svgdom-in-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEOffsetElement-dom-dx-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEOffsetElement-dom-dx-attr-expected.png
index 332820e..1248d2b 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEOffsetElement-dom-dx-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEOffsetElement-dom-dx-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEOffsetElement-dom-dy-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEOffsetElement-dom-dy-attr-expected.png
index 332820e..1248d2b 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEOffsetElement-dom-dy-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEOffsetElement-dom-dy-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEOffsetElement-dom-in-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEOffsetElement-dom-in-attr-expected.png
index 332820e..1248d2b 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEOffsetElement-dom-in-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEOffsetElement-dom-in-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEOffsetElement-svgdom-dx-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEOffsetElement-svgdom-dx-prop-expected.png
index 332820e..1248d2b 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEOffsetElement-svgdom-dx-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEOffsetElement-svgdom-dx-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEOffsetElement-svgdom-dy-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEOffsetElement-svgdom-dy-prop-expected.png
index 332820e..1248d2b 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEOffsetElement-svgdom-dy-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEOffsetElement-svgdom-dy-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEOffsetElement-svgdom-in-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEOffsetElement-svgdom-in-prop-expected.png
index 332820e..1248d2b 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEOffsetElement-svgdom-in-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEOffsetElement-svgdom-in-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEPointLightElement-dom-x-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEPointLightElement-dom-x-attr-expected.png
index d10057d..e1ef031 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEPointLightElement-dom-x-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEPointLightElement-dom-x-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEPointLightElement-dom-y-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEPointLightElement-dom-y-attr-expected.png
index d10057d..e1ef031 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEPointLightElement-dom-y-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEPointLightElement-dom-y-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEPointLightElement-dom-z-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEPointLightElement-dom-z-attr-expected.png
index d10057d..e1ef031 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEPointLightElement-dom-z-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEPointLightElement-dom-z-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEPointLightElement-svgdom-x-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEPointLightElement-svgdom-x-prop-expected.png
index d10057d..e1ef031 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEPointLightElement-svgdom-x-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEPointLightElement-svgdom-x-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEPointLightElement-svgdom-y-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEPointLightElement-svgdom-y-prop-expected.png
index d10057d..e1ef031 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEPointLightElement-svgdom-y-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEPointLightElement-svgdom-y-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEPointLightElement-svgdom-z-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEPointLightElement-svgdom-z-prop-expected.png
index d10057d..e1ef031 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEPointLightElement-svgdom-z-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFEPointLightElement-svgdom-z-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-dom-in-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-dom-in-attr-expected.png
index eab1ad8..279254f3 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-dom-in-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-dom-in-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-dom-kernelUnitLength-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-dom-kernelUnitLength-attr-expected.png
index 76e701b..397ec17 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-dom-kernelUnitLength-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-dom-kernelUnitLength-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-dom-specularConstant-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-dom-specularConstant-attr-expected.png
index eab1ad8..279254f3 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-dom-specularConstant-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-dom-specularConstant-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-dom-specularExponent-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-dom-specularExponent-attr-expected.png
index eab1ad8..279254f3 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-dom-specularExponent-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-dom-specularExponent-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-dom-suraceScale-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-dom-suraceScale-attr-expected.png
index eab1ad8..279254f3 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-dom-suraceScale-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-dom-suraceScale-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-inherit-lighting-color-css-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-inherit-lighting-color-css-prop-expected.png
index e828b3f..b5702bc 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-inherit-lighting-color-css-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-inherit-lighting-color-css-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-lighting-color-css-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-lighting-color-css-prop-expected.png
index e828b3f..b5702bc 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-lighting-color-css-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-lighting-color-css-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-svgdom-in-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-svgdom-in-prop-expected.png
index eab1ad8..279254f3 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-svgdom-in-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-svgdom-in-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-svgdom-specularConstant-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-svgdom-specularConstant-prop-expected.png
index eab1ad8..279254f3 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-svgdom-specularConstant-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-svgdom-specularConstant-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-svgdom-specularExponent-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-svgdom-specularExponent-prop-expected.png
index eab1ad8..279254f3 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-svgdom-specularExponent-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-svgdom-specularExponent-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-svgdom-suraceScale-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-svgdom-suraceScale-prop-expected.png
index eab1ad8..279254f3 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-svgdom-suraceScale-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpecularLightingElement-svgdom-suraceScale-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-limitingConeAngle-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-limitingConeAngle-attr-expected.png
index ada4290..0222a16 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-limitingConeAngle-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-limitingConeAngle-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-pointsAtX-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-pointsAtX-attr-expected.png
index ada4290..0222a16 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-pointsAtX-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-pointsAtX-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-pointsAtY-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-pointsAtY-attr-expected.png
index ada4290..0222a16 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-pointsAtY-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-pointsAtY-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-pointsAtZ-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-pointsAtZ-attr-expected.png
index ada4290..0222a16 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-pointsAtZ-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-pointsAtZ-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-specularExponent-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-specularExponent-attr-expected.png
index ada4290..0222a16 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-specularExponent-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-specularExponent-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-x-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-x-attr-expected.png
index ada4290..0222a16 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-x-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-x-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-y-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-y-attr-expected.png
index ada4290..0222a16 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-y-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-y-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-z-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-z-attr-expected.png
index ada4290..0222a16 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-z-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-dom-z-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-limitingConeAngle-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-limitingConeAngle-prop-expected.png
index ada4290..0222a16 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-limitingConeAngle-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-limitingConeAngle-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-pointsAtX-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-pointsAtX-prop-expected.png
index ada4290..0222a16 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-pointsAtX-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-pointsAtX-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-pointsAtY-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-pointsAtY-prop-expected.png
index ada4290..0222a16 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-pointsAtY-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-pointsAtY-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-pointsAtZ-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-pointsAtZ-prop-expected.png
index ada4290..0222a16 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-pointsAtZ-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-pointsAtZ-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-specularExponent-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-specularExponent-prop-expected.png
index ada4290..0222a16 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-specularExponent-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-specularExponent-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-x-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-x-prop-expected.png
index ada4290..0222a16 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-x-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-x-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-y-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-y-prop-expected.png
index ada4290..0222a16 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-y-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-y-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-z-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-z-prop-expected.png
index ada4290..0222a16 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-z-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFESpotLightElement-svgdom-z-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-dom-baseFrequency-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-dom-baseFrequency-attr-expected.png
index 2e60925..fff2431 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-dom-baseFrequency-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-dom-baseFrequency-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-dom-numOctaves-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-dom-numOctaves-attr-expected.png
index 2e60925..fff2431 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-dom-numOctaves-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-dom-numOctaves-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-dom-seed-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-dom-seed-attr-expected.png
index 2e60925..fff2431 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-dom-seed-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-dom-seed-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-dom-stitchTiles-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-dom-stitchTiles-attr-expected.png
index f93fa40..44f0fa4c13 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-dom-stitchTiles-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-dom-stitchTiles-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-dom-type-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-dom-type-attr-expected.png
index 2e60925..fff2431 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-dom-type-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-dom-type-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-svgdom-baseFrequency-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-svgdom-baseFrequency-prop-expected.png
index 2e60925..fff2431 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-svgdom-baseFrequency-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-svgdom-baseFrequency-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-svgdom-numOctaves-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-svgdom-numOctaves-prop-expected.png
index 2e60925..fff2431 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-svgdom-numOctaves-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-svgdom-numOctaves-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-svgdom-seed-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-svgdom-seed-prop-expected.png
index 85fb788..9950243 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-svgdom-seed-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-svgdom-seed-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-svgdom-stitchTiles-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-svgdom-stitchTiles-prop-expected.png
index 2e60925..fff2431 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-svgdom-stitchTiles-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-svgdom-stitchTiles-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-svgdom-type-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-svgdom-type-prop-expected.png
index 2e60925..fff2431 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-svgdom-type-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFETurbulenceElement-svgdom-type-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-dom-filterUnits-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-dom-filterUnits-attr-expected.png
index abad1f343..a334295 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-dom-filterUnits-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-dom-filterUnits-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-dom-height-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-dom-height-attr-expected.png
index abad1f343..a334295 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-dom-height-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-dom-height-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-dom-primitiveUnits-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-dom-primitiveUnits-attr-expected.png
index 7a5e4cce..45a9dc2d 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-dom-primitiveUnits-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-dom-primitiveUnits-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-dom-width-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-dom-width-attr-expected.png
index abad1f343..a334295 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-dom-width-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-dom-width-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-dom-x-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-dom-x-attr-expected.png
index abad1f343..a334295 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-dom-x-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-dom-x-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-dom-y-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-dom-y-attr-expected.png
index abad1f343..a334295 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-dom-y-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-dom-y-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-svgdom-filterUnits-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-svgdom-filterUnits-prop-expected.png
index abad1f343..a334295 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-svgdom-filterUnits-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-svgdom-filterUnits-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-svgdom-height-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-svgdom-height-prop-expected.png
index abad1f343..a334295 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-svgdom-height-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-svgdom-height-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-svgdom-primitiveUnits-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-svgdom-primitiveUnits-prop-expected.png
index 7a5e4cce..45a9dc2d 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-svgdom-primitiveUnits-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-svgdom-primitiveUnits-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-svgdom-width-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-svgdom-width-prop-expected.png
index abad1f343..a334295 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-svgdom-width-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-svgdom-width-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-svgdom-x-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-svgdom-x-prop-expected.png
index abad1f343..a334295 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-svgdom-x-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-svgdom-x-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-svgdom-y-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-svgdom-y-prop-expected.png
index abad1f343..a334295 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-svgdom-y-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterElement-svgdom-y-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-dom-height-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-dom-height-attr-expected.png
index abad1f343..a334295 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-dom-height-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-dom-height-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-dom-result-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-dom-result-attr-expected.png
index abad1f343..a334295 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-dom-result-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-dom-result-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-dom-width-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-dom-width-attr-expected.png
index abad1f343..a334295 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-dom-width-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-dom-width-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-dom-x-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-dom-x-attr-expected.png
index abad1f343..a334295 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-dom-x-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-dom-x-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-dom-y-attr-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-dom-y-attr-expected.png
index abad1f343..a334295 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-dom-y-attr-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-dom-y-attr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-svgdom-height-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-svgdom-height-prop-expected.png
index abad1f343..a334295 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-svgdom-height-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-svgdom-height-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-svgdom-result-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-svgdom-result-prop-expected.png
index abad1f343..a334295 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-svgdom-result-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-svgdom-result-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-svgdom-width-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-svgdom-width-prop-expected.png
index abad1f343..a334295 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-svgdom-width-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-svgdom-width-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-svgdom-x-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-svgdom-x-prop-expected.png
index abad1f343..a334295 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-svgdom-x-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-svgdom-x-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-svgdom-y-prop-expected.png b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-svgdom-y-prop-expected.png
index abad1f343..a334295 100644
--- a/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-svgdom-y-prop-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/dynamic-updates/SVGFilterPrimitiveStandardAttributes-svgdom-y-prop-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/filters/big-sized-filter-expected.png b/third_party/WebKit/LayoutTests/svg/filters/big-sized-filter-expected.png
index 316dea2..d06b45c 100644
--- a/third_party/WebKit/LayoutTests/svg/filters/big-sized-filter-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/filters/big-sized-filter-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/filters/feColorMatrix-offset-expected.png b/third_party/WebKit/LayoutTests/svg/filters/feColorMatrix-offset-expected.png
index ea21e78..95f5cd5 100644
--- a/third_party/WebKit/LayoutTests/svg/filters/feColorMatrix-offset-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/filters/feColorMatrix-offset-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/filters/feColorMatrix-saturate-expected.png b/third_party/WebKit/LayoutTests/svg/filters/feColorMatrix-saturate-expected.png
index 96c7500c..36e5fd11 100644
--- a/third_party/WebKit/LayoutTests/svg/filters/feColorMatrix-saturate-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/filters/feColorMatrix-saturate-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/filters/feDisplacementMap-expected.png b/third_party/WebKit/LayoutTests/svg/filters/feDisplacementMap-expected.png
index 1e89df6..ed2ee42 100644
--- a/third_party/WebKit/LayoutTests/svg/filters/feDisplacementMap-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/filters/feDisplacementMap-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/filters/feGaussianBlur-expected.png b/third_party/WebKit/LayoutTests/svg/filters/feGaussianBlur-expected.png
index e3bf080..85d216a 100644
--- a/third_party/WebKit/LayoutTests/svg/filters/feGaussianBlur-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/filters/feGaussianBlur-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/rootlayerscrolls/scrollbars/custom-scrollbar-appearance-property-expected.png b/third_party/WebKit/LayoutTests/svg/filters/feGaussianBlur-zero-deviation-expected.png
similarity index 70%
rename from third_party/WebKit/LayoutTests/platform/mac/virtual/rootlayerscrolls/scrollbars/custom-scrollbar-appearance-property-expected.png
rename to third_party/WebKit/LayoutTests/svg/filters/feGaussianBlur-zero-deviation-expected.png
index 5b0bf80..68dd751 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/rootlayerscrolls/scrollbars/custom-scrollbar-appearance-property-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/filters/feGaussianBlur-zero-deviation-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/filters/feTile-expected.png b/third_party/WebKit/LayoutTests/svg/filters/feTile-expected.png
index 2d1ebf9..d6d8a2c 100644
--- a/third_party/WebKit/LayoutTests/svg/filters/feTile-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/filters/feTile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/filters/feTurbulence-scale-expected.png b/third_party/WebKit/LayoutTests/svg/filters/feTurbulence-scale-expected.png
index 98ad363..7223dcc4 100644
--- a/third_party/WebKit/LayoutTests/svg/filters/feTurbulence-scale-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/filters/feTurbulence-scale-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/filters/feTurbulence-tiled-expected.png b/third_party/WebKit/LayoutTests/svg/filters/feTurbulence-tiled-expected.png
index b233f51f..38b8109 100644
--- a/third_party/WebKit/LayoutTests/svg/filters/feTurbulence-tiled-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/filters/feTurbulence-tiled-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/filters/filter-clip-expected.png b/third_party/WebKit/LayoutTests/svg/filters/filter-clip-expected.png
index 060e848..8d66f12 100644
--- a/third_party/WebKit/LayoutTests/svg/filters/filter-clip-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/filters/filter-clip-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/filters/filter-source-position-expected.png b/third_party/WebKit/LayoutTests/svg/filters/filter-source-position-expected.png
index 6586a47..15b5d1c5 100644
--- a/third_party/WebKit/LayoutTests/svg/filters/filter-source-position-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/filters/filter-source-position-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/filters/filteredImage-expected.png b/third_party/WebKit/LayoutTests/svg/filters/filteredImage-expected.png
index 00d2f04..ade998f 100644
--- a/third_party/WebKit/LayoutTests/svg/filters/filteredImage-expected.png
+++ b/third_party/WebKit/LayoutTests/svg/filters/filteredImage-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/filters/innershadow-expected.png b/third_party/WebKit/LayoutTests/svg/filters/innershadow-expected.png
new file mode 100644
index 0000000..428b6cd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/svg/filters/innershadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8EventListenerHelper.h b/third_party/WebKit/Source/bindings/core/v8/V8EventListenerHelper.h
index 12fdbf7..fde7266 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8EventListenerHelper.h
+++ b/third_party/WebKit/Source/bindings/core/v8/V8EventListenerHelper.h
@@ -89,9 +89,9 @@
 
   static V8PrivateProperty::Symbol ListenerProperty(v8::Isolate* isolate,
                                                     bool is_attribute) {
-    return V8PrivateProperty::GetSymbol(
-        isolate, is_attribute ? "EventListenerList::attributeListener"
-                              : "EventListenerList::listener");
+    return is_attribute
+               ? V8PrivateProperty::GetV8EventListenerAttributeListener(isolate)
+               : V8PrivateProperty::GetV8EventListenerListener(isolate);
   }
 };
 
diff --git a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
index 176fd8cb1..03394ef 100644
--- a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
@@ -171,7 +171,7 @@
 static void UpdateSuddenTerminationStatus(
     LocalDOMWindow* dom_window,
     bool added_listener,
-    LocalFrameClient::SuddenTerminationDisablerType disabler_type) {
+    WebSuddenTerminationDisablerType disabler_type) {
   Platform::Current()->SuddenTerminationChanged(!added_listener);
   if (dom_window->GetFrame() && dom_window->GetFrame()->Client())
     dom_window->GetFrame()->Client()->SuddenTerminationDisablerChanged(
@@ -191,80 +191,60 @@
   return windows_with_before_unload_event_listeners;
 }
 
-static void AddUnloadEventListener(LocalDOMWindow* dom_window) {
+static void TrackUnloadEventListener(LocalDOMWindow* dom_window) {
   DOMWindowSet& set = WindowsWithUnloadEventListeners();
-  if (set.IsEmpty()) {
-    UpdateSuddenTerminationStatus(dom_window, true,
-                                  LocalFrameClient::kUnloadHandler);
+  if (set.insert(dom_window).is_new_entry) {
+    // The first unload handler was added.
+    UpdateSuddenTerminationStatus(dom_window, true, kUnloadHandler);
   }
-
-  set.insert(dom_window);
 }
 
-static void RemoveUnloadEventListener(LocalDOMWindow* dom_window) {
+static void UntrackUnloadEventListener(LocalDOMWindow* dom_window) {
   DOMWindowSet& set = WindowsWithUnloadEventListeners();
   DOMWindowSet::iterator it = set.find(dom_window);
   if (it == set.end())
     return;
-  set.erase(it);
-  if (set.IsEmpty()) {
-    UpdateSuddenTerminationStatus(dom_window, false,
-                                  LocalFrameClient::kUnloadHandler);
+  if (set.erase(it)) {
+    // The last unload handler was removed.
+    UpdateSuddenTerminationStatus(dom_window, false, kUnloadHandler);
   }
 }
 
-static void RemoveAllUnloadEventListeners(LocalDOMWindow* dom_window) {
+static void UntrackAllUnloadEventListeners(LocalDOMWindow* dom_window) {
   DOMWindowSet& set = WindowsWithUnloadEventListeners();
   DOMWindowSet::iterator it = set.find(dom_window);
   if (it == set.end())
     return;
   set.RemoveAll(it);
-  if (set.IsEmpty()) {
-    UpdateSuddenTerminationStatus(dom_window, false,
-                                  LocalFrameClient::kUnloadHandler);
-  }
+  UpdateSuddenTerminationStatus(dom_window, false, kUnloadHandler);
 }
 
-static void AddBeforeUnloadEventListener(LocalDOMWindow* dom_window) {
+static void TrackBeforeUnloadEventListener(LocalDOMWindow* dom_window) {
   DOMWindowSet& set = WindowsWithBeforeUnloadEventListeners();
-  if (set.IsEmpty()) {
-    UpdateSuddenTerminationStatus(dom_window, true,
-                                  LocalFrameClient::kBeforeUnloadHandler);
+  if (set.insert(dom_window).is_new_entry) {
+    // The first beforeunload handler was added.
+    UpdateSuddenTerminationStatus(dom_window, true, kBeforeUnloadHandler);
   }
-
-  set.insert(dom_window);
 }
 
-static void RemoveBeforeUnloadEventListener(LocalDOMWindow* dom_window) {
+static void UntrackBeforeUnloadEventListener(LocalDOMWindow* dom_window) {
   DOMWindowSet& set = WindowsWithBeforeUnloadEventListeners();
   DOMWindowSet::iterator it = set.find(dom_window);
   if (it == set.end())
     return;
-  set.erase(it);
-  if (set.IsEmpty()) {
-    UpdateSuddenTerminationStatus(dom_window, false,
-                                  LocalFrameClient::kBeforeUnloadHandler);
+  if (set.erase(it)) {
+    // The last beforeunload handler was removed.
+    UpdateSuddenTerminationStatus(dom_window, false, kBeforeUnloadHandler);
   }
 }
 
-static void RemoveAllBeforeUnloadEventListeners(LocalDOMWindow* dom_window) {
+static void UntrackAllBeforeUnloadEventListeners(LocalDOMWindow* dom_window) {
   DOMWindowSet& set = WindowsWithBeforeUnloadEventListeners();
   DOMWindowSet::iterator it = set.find(dom_window);
   if (it == set.end())
     return;
   set.RemoveAll(it);
-  if (set.IsEmpty()) {
-    UpdateSuddenTerminationStatus(dom_window, false,
-                                  LocalFrameClient::kBeforeUnloadHandler);
-  }
-}
-
-static bool AllowsBeforeUnloadListeners(LocalDOMWindow* window) {
-  DCHECK(window);
-  LocalFrame* frame = window->GetFrame();
-  if (!frame)
-    return false;
-  return frame->IsMainFrame();
+  UpdateSuddenTerminationStatus(dom_window, false, kBeforeUnloadHandler);
 }
 
 LocalDOMWindow::LocalDOMWindow(LocalFrame& frame)
@@ -1438,17 +1418,11 @@
 
   if (event_type == EventTypeNames::unload) {
     UseCounter::Count(document(), WebFeature::kDocumentUnloadRegistered);
-    AddUnloadEventListener(this);
+    TrackUnloadEventListener(this);
   } else if (event_type == EventTypeNames::beforeunload) {
     UseCounter::Count(document(), WebFeature::kDocumentBeforeUnloadRegistered);
-    if (AllowsBeforeUnloadListeners(this)) {
-      // This is confusingly named. It doesn't actually add the listener. It
-      // just increments a count so that we know we have listeners registered
-      // for the purposes of determining if we can fast terminate the renderer
-      // process.
-      AddBeforeUnloadEventListener(this);
-    } else {
-      // Subframes return false from allowsBeforeUnloadListeners.
+    TrackBeforeUnloadEventListener(this);
+    if (GetFrame() && !GetFrame()->IsMainFrame()) {
       UseCounter::Count(document(),
                         WebFeature::kSubFrameBeforeUnloadRegistered);
     }
@@ -1468,10 +1442,9 @@
   }
 
   if (event_type == EventTypeNames::unload) {
-    RemoveUnloadEventListener(this);
-  } else if (event_type == EventTypeNames::beforeunload &&
-             AllowsBeforeUnloadListeners(this)) {
-    RemoveBeforeUnloadEventListener(this);
+    UntrackUnloadEventListener(this);
+  } else if (event_type == EventTypeNames::beforeunload) {
+    UntrackBeforeUnloadEventListener(this);
   }
 }
 
@@ -1562,8 +1535,8 @@
     GetFrame()->GetPage()->GetEventHandlerRegistry().DidRemoveAllEventHandlers(
         *this);
 
-  RemoveAllUnloadEventListeners(this);
-  RemoveAllBeforeUnloadEventListeners(this);
+  UntrackAllUnloadEventListeners(this);
+  UntrackAllBeforeUnloadEventListeners(this);
 }
 
 void LocalDOMWindow::FinishedLoading() {
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameClient.h b/third_party/WebKit/Source/core/frame/LocalFrameClient.h
index 02967c9..402eac4 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameClient.h
+++ b/third_party/WebKit/Source/core/frame/LocalFrameClient.h
@@ -54,6 +54,7 @@
 #include "public/platform/WebFeaturePolicy.h"
 #include "public/platform/WebInsecureRequestPolicy.h"
 #include "public/platform/WebLoadingBehaviorFlag.h"
+#include "public/platform/WebSuddenTerminationDisablerType.h"
 #include "public/platform/WebURLRequest.h"
 #include "public/web/WebTriggeringEventInfo.h"
 #include "v8/include/v8.h"
@@ -302,16 +303,9 @@
 
   virtual bool IsLocalFrameClientImpl() const { return false; }
 
-  // Called when elements preventing the sudden termination of the frame become
-  // present or stop being present. |type| is the type of element (BeforeUnload
-  // handler, Unload handler).
-  enum SuddenTerminationDisablerType {
-    kBeforeUnloadHandler,
-    kUnloadHandler,
-  };
-  virtual void SuddenTerminationDisablerChanged(bool present,
-                                                SuddenTerminationDisablerType) {
-  }
+  virtual void SuddenTerminationDisablerChanged(
+      bool present,
+      WebSuddenTerminationDisablerType) {}
 
   virtual LinkResource* CreateServiceWorkerLinkResource(HTMLLinkElement*) {
     return nullptr;
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
index 00e48ba..457f705a 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
@@ -215,6 +215,7 @@
       suppress_adjust_view_size_(false),
       allows_layout_invalidation_after_layout_clean_(true),
       forcing_layout_parent_view_(false),
+      needs_intersection_observation_(false),
       main_thread_scrolling_reasons_(0) {
   Init();
 }
@@ -4965,6 +4966,7 @@
        child = child->Tree().NextSibling()) {
     child->View()->UpdateViewportIntersectionsForSubtree(target_state);
   }
+  needs_intersection_observation_ = false;
 }
 
 void LocalFrameView::UpdateRenderThrottlingStatusForTesting() {
@@ -5125,9 +5127,15 @@
                                    total_screens_away));
 }
 
+void LocalFrameView::SetNeedsIntersectionObservation() {
+  needs_intersection_observation_ = true;
+  if (LocalFrameView* parent = ParentFrameView())
+    parent->SetNeedsIntersectionObservation();
+}
+
 bool LocalFrameView::ShouldThrottleRendering() const {
-  return CanThrottleRendering() && frame_->GetDocument() &&
-         Lifecycle().ThrottlingAllowed();
+  return CanThrottleRendering() && !needs_intersection_observation_ &&
+         frame_->GetDocument() && Lifecycle().ThrottlingAllowed();
 }
 
 bool LocalFrameView::CanThrottleRendering() const {
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.h b/third_party/WebKit/Source/core/frame/LocalFrameView.h
index 8a767dc..5e4af9bc 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameView.h
+++ b/third_party/WebKit/Source/core/frame/LocalFrameView.h
@@ -182,6 +182,10 @@
   void SetNeedsUpdateGeometries() { needs_update_geometries_ = true; }
   void UpdateGeometry() override;
 
+  // Marks this frame, and ancestor frames, as needing one intersection
+  // observervation. This overrides throttling for one frame.
+  void SetNeedsIntersectionObservation();
+
   // Methods for getting/setting the size Blink should use to layout the
   // contents.
   // NOTE: Scrollbar exclusion is based on the LocalFrameView's scrollbars. To
@@ -1191,6 +1195,7 @@
   bool suppress_adjust_view_size_;
   bool allows_layout_invalidation_after_layout_clean_;
   bool forcing_layout_parent_view_;
+  bool needs_intersection_observation_;
 
   Member<ElementVisibilityObserver> visibility_observer_;
 
diff --git a/third_party/WebKit/Source/core/input/MouseEventManager.cpp b/third_party/WebKit/Source/core/input/MouseEventManager.cpp
index 2cf0b38..ea6347d 100644
--- a/third_party/WebKit/Source/core/input/MouseEventManager.cpp
+++ b/third_party/WebKit/Source/core/input/MouseEventManager.cpp
@@ -782,12 +782,12 @@
   if (!mouse_pressed_)
     return WebInputEventResult::kNotHandled;
 
-  if (event.Event().pointer_type ==
-      blink::WebPointerProperties::PointerType::kPen)
-    return WebInputEventResult::kNotHandled;
-
-  if (HandleDrag(event, DragInitiator::kMouse))
+  // We disable the drag and drop actions on pen input.
+  if (event.Event().pointer_type !=
+          blink::WebPointerProperties::PointerType::kPen &&
+      HandleDrag(event, DragInitiator::kMouse)) {
     return WebInputEventResult::kHandledSystem;
+  }
 
   Node* target_node = event.InnerNode();
   if (!target_node)
diff --git a/third_party/WebKit/Source/core/intersection_observer/IntersectionObserver.cpp b/third_party/WebKit/Source/core/intersection_observer/IntersectionObserver.cpp
index a71ce862..978d6f2 100644
--- a/third_party/WebKit/Source/core/intersection_observer/IntersectionObserver.cpp
+++ b/third_party/WebKit/Source/core/intersection_observer/IntersectionObserver.cpp
@@ -246,8 +246,12 @@
       new IntersectionObservation(*this, *target);
   target->EnsureIntersectionObserverData().AddObservation(*observation);
   observations_.insert(observation);
-  if (LocalFrameView* frame_view = target_frame->View())
+  if (LocalFrameView* frame_view = target_frame->View()) {
+    // The IntersectionObsever spec requires that at least one observation
+    // be recorded afer observe() is called, even if the frame is throttled.
+    frame_view->SetNeedsIntersectionObservation();
     frame_view->ScheduleAnimation();
+  }
 }
 
 void IntersectionObserver::unobserve(Element* target,
diff --git a/third_party/WebKit/Source/core/layout/LayoutView.cpp b/third_party/WebKit/Source/core/layout/LayoutView.cpp
index d82ad0d2..5d544c2 100644
--- a/third_party/WebKit/Source/core/layout/LayoutView.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutView.cpp
@@ -327,10 +327,6 @@
   if (RuntimeEnabledFeatures::RootLayerScrollingEnabled())
     return LayoutBlockFlow::VisualOverflowRect();
 
-  // Ditto when not in compositing mode.
-  if (!UsesCompositing())
-    return LayoutBlockFlow::VisualOverflowRect();
-
   // In normal compositing mode, LayoutView doesn't actually apply clipping
   // on its descendants. Instead their visual overflow is propagated to
   // compositor()->m_rootContentLayer for accelerated scrolling.
diff --git a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp
index ff6f1f4..67790f5c 100644
--- a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp
+++ b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp
@@ -1466,7 +1466,9 @@
   // otherwise iterate from right to left. Varying the order allows us to
   // correctly hide the boxes following the ellipsis.
   LayoutUnit relative_offset =
-      BoxModelObject().RelativePositionLogicalOffset().Width();
+      BoxModelObject().IsInline()
+          ? BoxModelObject().RelativePositionLogicalOffset().Width()
+          : LayoutUnit();
   logical_left_offset += relative_offset;
   InlineBox* box = ltr ? FirstChild() : LastChild();
 
diff --git a/third_party/WebKit/Source/core/page/CreateWindow.cpp b/third_party/WebKit/Source/core/page/CreateWindow.cpp
index d6f9e19..931d01c 100644
--- a/third_party/WebKit/Source/core/page/CreateWindow.cpp
+++ b/third_party/WebKit/Source/core/page/CreateWindow.cpp
@@ -111,21 +111,15 @@
 }
 
 NavigationPolicy GetNavigationPolicy(const WebInputEvent* current_event,
-                                     bool toolbar_visible) {
-  // If the window features didn't enable the toolbar, or this window wasn't
-  // created by a user gesture, show as a popup instead of a new tab.
-  //
-  // Note: this previously also checked that menubar, resizable, scrollbar, and
-  // statusbar are enabled too. When no feature string is specified, these
-  // features default to enabled (and the window opens as a new tab). However,
-  // when a feature string is specified, any *unspecified* features default to
-  // disabled, often causing the window to open as a popup instead.
-  //
-  // As specifying menubar, resizable, scrollbar, and statusbar have no effect
-  // on the UI, just ignore them and only consider whether or not the toolbar is
-  // enabled, which matches Firefox's behavior.
-  NavigationPolicy policy = toolbar_visible ? kNavigationPolicyNewForegroundTab
-                                            : kNavigationPolicyNewPopup;
+                                     const WebWindowFeatures& features) {
+  // If our default configuration was modified by a script or wasn't
+  // created by a user gesture, then show as a popup. Else, let this
+  // new window be opened as a toplevel window.
+  bool as_popup = !features.tool_bar_visible || !features.status_bar_visible ||
+                  !features.scrollbars_visible || !features.menu_bar_visible ||
+                  !features.resizable;
+  NavigationPolicy policy =
+      as_popup ? kNavigationPolicyNewPopup : kNavigationPolicyNewForegroundTab;
   UpdatePolicyForEvent(current_event, &policy);
   return policy;
 }
@@ -134,11 +128,11 @@
 
 NavigationPolicy EffectiveNavigationPolicy(NavigationPolicy policy,
                                            const WebInputEvent* current_event,
-                                           bool toolbar_visible) {
+                                           const WebWindowFeatures& features) {
   if (policy == kNavigationPolicyIgnore)
-    return GetNavigationPolicy(current_event, toolbar_visible);
+    return GetNavigationPolicy(current_event, features);
   if (policy == kNavigationPolicyNewBackgroundTab &&
-      GetNavigationPolicy(current_event, toolbar_visible) !=
+      GetNavigationPolicy(current_event, features) !=
           kNavigationPolicyNewBackgroundTab &&
       !UIEventWithKeyState::NewTabModifierSetFromIsolatedWorld()) {
     return kNavigationPolicyNewForegroundTab;
@@ -245,6 +239,8 @@
       window_features.status_bar_visible = value;
     } else if (key_string == "scrollbars") {
       window_features.scrollbars_visible = value;
+    } else if (key_string == "resizable") {
+      window_features.resizable = value;
     } else if (key_string == "noopener") {
       window_features.noopener = true;
     } else if (key_string == "background") {
@@ -289,8 +285,7 @@
     return nullptr;
 
   policy = EffectiveNavigationPolicy(
-      policy, old_page->GetChromeClient().GetCurrentInputEvent(),
-      features.tool_bar_visible);
+      policy, old_page->GetChromeClient().GetCurrentInputEvent(), features);
 
   const SandboxFlags sandbox_flags =
       opener_frame.GetDocument()->IsSandboxed(
diff --git a/third_party/WebKit/Source/core/page/CreateWindow.h b/third_party/WebKit/Source/core/page/CreateWindow.h
index 557f25b..be82a71 100644
--- a/third_party/WebKit/Source/core/page/CreateWindow.h
+++ b/third_party/WebKit/Source/core/page/CreateWindow.h
@@ -57,7 +57,7 @@
 CORE_EXPORT NavigationPolicy
 EffectiveNavigationPolicy(NavigationPolicy,
                           const WebInputEvent* current_event,
-                          bool toolbar_visible);
+                          const WebWindowFeatures&);
 
 // Exposed for testing
 CORE_EXPORT WebWindowFeatures GetWindowFeaturesFromString(const String&);
diff --git a/third_party/WebKit/Source/core/page/EffectiveNavigationPolicyTest.cpp b/third_party/WebKit/Source/core/page/EffectiveNavigationPolicyTest.cpp
index 595b6b4..a622934 100644
--- a/third_party/WebKit/Source/core/page/EffectiveNavigationPolicyTest.cpp
+++ b/third_party/WebKit/Source/core/page/EffectiveNavigationPolicyTest.cpp
@@ -32,6 +32,7 @@
 #include "core/page/CreateWindow.h"
 #include "public/platform/WebInputEvent.h"
 #include "public/platform/WebMouseEvent.h"
+#include "public/web/WebWindowFeatures.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace blink {
@@ -45,9 +46,12 @@
     WebMouseEvent event(WebInputEvent::kMouseUp, modifiers,
                         WebInputEvent::kTimeStampForTesting);
     event.button = button;
-    return EffectiveNavigationPolicy(kNavigationPolicyIgnore, &event,
-                                     !as_popup);
+    if (as_popup)
+      features.tool_bar_visible = false;
+    return EffectiveNavigationPolicy(kNavigationPolicyIgnore, &event, features);
   }
+
+  WebWindowFeatures features;
 };
 
 TEST_F(EffectiveNavigationPolicyTest, LeftClick) {
@@ -149,10 +153,47 @@
 }
 
 TEST_F(EffectiveNavigationPolicyTest, NoToolbarsForcesPopup) {
-  EXPECT_EQ(kNavigationPolicyNewPopup,
-            EffectiveNavigationPolicy(kNavigationPolicyIgnore, nullptr, false));
-  EXPECT_EQ(kNavigationPolicyNewForegroundTab,
-            EffectiveNavigationPolicy(kNavigationPolicyIgnore, nullptr, true));
+  features.tool_bar_visible = false;
+  EXPECT_EQ(
+      kNavigationPolicyNewPopup,
+      EffectiveNavigationPolicy(kNavigationPolicyIgnore, nullptr, features));
+  features.tool_bar_visible = true;
+  EXPECT_EQ(
+      kNavigationPolicyNewForegroundTab,
+      EffectiveNavigationPolicy(kNavigationPolicyIgnore, nullptr, features));
+}
+
+TEST_F(EffectiveNavigationPolicyTest, NoStatusBarForcesPopup) {
+  features.status_bar_visible = false;
+  EXPECT_EQ(
+      kNavigationPolicyNewPopup,
+      EffectiveNavigationPolicy(kNavigationPolicyIgnore, nullptr, features));
+  features.status_bar_visible = true;
+  EXPECT_EQ(
+      kNavigationPolicyNewForegroundTab,
+      EffectiveNavigationPolicy(kNavigationPolicyIgnore, nullptr, features));
+}
+
+TEST_F(EffectiveNavigationPolicyTest, NoMenuBarForcesPopup) {
+  features.menu_bar_visible = false;
+  EXPECT_EQ(
+      kNavigationPolicyNewPopup,
+      EffectiveNavigationPolicy(kNavigationPolicyIgnore, nullptr, features));
+  features.menu_bar_visible = true;
+  EXPECT_EQ(
+      kNavigationPolicyNewForegroundTab,
+      EffectiveNavigationPolicy(kNavigationPolicyIgnore, nullptr, features));
+}
+
+TEST_F(EffectiveNavigationPolicyTest, NotResizableForcesPopup) {
+  features.resizable = false;
+  EXPECT_EQ(
+      kNavigationPolicyNewPopup,
+      EffectiveNavigationPolicy(kNavigationPolicyIgnore, nullptr, features));
+  features.resizable = true;
+  EXPECT_EQ(
+      kNavigationPolicyNewForegroundTab,
+      EffectiveNavigationPolicy(kNavigationPolicyIgnore, nullptr, features));
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp
index d12c091..d6011c0 100644
--- a/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp
+++ b/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp
@@ -81,7 +81,8 @@
   if (reason != PaintInvalidationReason::kIncremental)
     return reason;
 
-  if (box_.IsLayoutView()) {
+  if (!RuntimeEnabledFeatures::RootLayerScrollingEnabled() &&
+      box_.IsLayoutView()) {
     const LayoutView& layout_view = ToLayoutView(box_);
     // In normal compositing mode, root background doesn't need to be
     // invalidated for box changes, because the background always covers the
@@ -89,8 +90,8 @@
     // compositor()->m_containerLayer. Also the scrollbars are always
     // composited. There are no other box decoration on the LayoutView thus we
     // can safely exit here.
-    if (layout_view.UsesCompositing() &&
-        !RuntimeEnabledFeatures::RootLayerScrollingEnabled())
+    if (layout_view.UsesCompositing() ||
+        RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
       return reason;
   }
 
diff --git a/third_party/WebKit/Source/core/paint/BoxPainterBase.cpp b/third_party/WebKit/Source/core/paint/BoxPainterBase.cpp
index 5d3820d..a1ea9ddd 100644
--- a/third_party/WebKit/Source/core/paint/BoxPainterBase.cpp
+++ b/third_party/WebKit/Source/core/paint/BoxPainterBase.cpp
@@ -137,20 +137,8 @@
     return;
   FloatRoundedRect bounds = style.GetRoundedInnerBorderFor(
       paint_rect, include_logical_left_edge, include_logical_right_edge);
-  PaintInsetBoxShadowInBounds(info, bounds, style, include_logical_left_edge,
-                              include_logical_right_edge);
-}
 
-void BoxPainterBase::PaintInsetBoxShadowInBounds(
-    const PaintInfo& info,
-    const FloatRoundedRect& bounds,
-    const ComputedStyle& style,
-    bool include_logical_left_edge,
-    bool include_logical_right_edge) {
-  // The caller should have checked style.boxShadow() when computing bounds.
-  DCHECK(style.BoxShadow());
   GraphicsContext& context = info.context;
-
   bool is_horizontal = style.IsHorizontalWritingMode();
   GraphicsContextStateSaver state_saver(context, false);
 
diff --git a/third_party/WebKit/Source/core/paint/BoxPainterBase.h b/third_party/WebKit/Source/core/paint/BoxPainterBase.h
index 6e54429..c8a790d 100644
--- a/third_party/WebKit/Source/core/paint/BoxPainterBase.h
+++ b/third_party/WebKit/Source/core/paint/BoxPainterBase.h
@@ -47,16 +47,6 @@
                                   bool include_logical_left_edge = true,
                                   bool include_logical_right_edge = true);
 
-  // This form is used by callers requiring special computation of the outer
-  // bounds of the shadow. For example, TableCellPainter insets the bounds by
-  // half widths of collapsed borders instead of the default whole widths.
-  static void PaintInsetBoxShadowInBounds(
-      const PaintInfo&,
-      const FloatRoundedRect& bounds,
-      const ComputedStyle&,
-      bool include_logical_left_edge = true,
-      bool include_logical_right_edge = true);
-
   static void PaintBorder(const ImageResourceObserver&,
                           const Document&,
                           Node*,
diff --git a/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp
index fcb2592..3aca967 100644
--- a/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintInvalidator.cpp
@@ -250,11 +250,10 @@
 
 namespace {
 
-// This is temporary to workaround paint invalidation issues in
-// non-rootLayerScrolls mode.
+// This is a helper to handle paint invalidation for frames in
+// non-RootLayerScrolling mode.
 // It undoes LocalFrameView's content clip and scroll for paint invalidation of
-// frame scroll controls and the LayoutView to which the content clip and scroll
-// don't apply.
+// frame scroll controls to which the content clip and scroll don't apply.
 class ScopedUndoFrameViewContentClipAndScroll {
  public:
   ScopedUndoFrameViewContentClipAndScroll(
@@ -266,18 +265,18 @@
         saved_context_(tree_builder_context_.current) {
     DCHECK(!RuntimeEnabledFeatures::RootLayerScrollingEnabled());
 
-    if (frame_view.ContentClip() == saved_context_.clip) {
-      tree_builder_context_.current.clip = saved_context_.clip->Parent();
-    }
     if (const auto* scroll_translation = frame_view.ScrollTranslation()) {
-      if (scroll_translation->ScrollNode() == saved_context_.scroll) {
-        tree_builder_context_.current.scroll = saved_context_.scroll->Parent();
-      }
-      if (scroll_translation == saved_context_.transform) {
-        tree_builder_context_.current.transform =
-            saved_context_.transform->Parent();
-      }
+      DCHECK_EQ(scroll_translation, saved_context_.transform);
+      DCHECK_EQ(scroll_translation->ScrollNode(), saved_context_.scroll);
+      tree_builder_context_.current.transform =
+          saved_context_.transform->Parent();
+      tree_builder_context_.current.scroll = saved_context_.scroll->Parent();
     }
+    DCHECK_EQ(frame_view.PreTranslation(),
+              tree_builder_context_.current.transform);
+
+    DCHECK_EQ(frame_view.ContentClip(), saved_context_.clip);
+    tree_builder_context_.current.clip = saved_context_.clip->Parent();
   }
 
   ~ScopedUndoFrameViewContentClipAndScroll() {
@@ -389,15 +388,6 @@
   DCHECK(context.tree_builder_context_->current.paint_offset ==
          object.PaintOffset());
 
-  Optional<ScopedUndoFrameViewContentClipAndScroll>
-      undo_frame_view_content_clip_and_scroll;
-
-  if (!RuntimeEnabledFeatures::RootLayerScrollingEnabled() &&
-      object.IsLayoutView() && !object.IsPaintInvalidationContainer()) {
-    undo_frame_view_content_clip_and_scroll.emplace(
-        *ToLayoutView(object).GetFrameView(), *context.tree_builder_context_);
-  }
-
   LayoutRect new_visual_rect = ComputeVisualRectInBacking(object, context);
   if (object.IsBoxModelObject()) {
     context.new_location = ComputeLocationInBacking(object, context);
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
index 3cd46107..c4b7f552 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -2709,7 +2709,9 @@
 BackgroundPaintLocation PaintLayer::GetBackgroundPaintLocation(
     uint32_t* reasons) const {
   BackgroundPaintLocation location;
-  if (!ScrollsOverflow()) {
+  bool has_scrolling_layers =
+      scrollable_area_ && scrollable_area_->NeedsCompositedScrolling();
+  if (!ScrollsOverflow() && !has_scrolling_layers) {
     location = kBackgroundPaintInGraphicsLayer;
   } else if (RuntimeEnabledFeatures::RootLayerScrollingEnabled()) {
     location = GetLayoutObject().GetBackgroundPaintLocation(reasons);
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp b/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp
index 55ae99c7..0753940 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp
@@ -285,7 +285,6 @@
     foreground_rect = ClipRect(LayoutRect(LayoutRect::InfiniteIntRect()));
   } else {
     CalculateBackgroundClipRectWithGeometryMapper(context, background_rect);
-    background_rect.Move(context.sub_pixel_accumulation);
     background_rect.Intersect(paint_dirty_rect);
 
     foreground_rect = background_rect;
@@ -469,6 +468,7 @@
   }
 
   output.MoveBy(-context.root_layer->GetLayoutObject().PaintOffset());
+  output.Move(context.sub_pixel_accumulation);
 }
 
 void PaintLayerClipper::InitializeCommonClipRectState(
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerClipperTest.cpp b/third_party/WebKit/Source/core/paint/PaintLayerClipperTest.cpp
index 8a730190..2575108 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerClipperTest.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerClipperTest.cpp
@@ -30,6 +30,32 @@
   }
 };
 
+TEST_F(PaintLayerClipperTest, BackgroundClipRectSubpixelAccumulation) {
+  SetBodyInnerHTML(
+      "<!DOCTYPE html>"
+      "<svg id=target width=200 height=300 style='position: relative'>"
+      "  <rect width=400 height=500 fill='blue'/>"
+      "</svg>");
+
+  Element* target = GetDocument().getElementById("target");
+  PaintLayer* target_paint_layer =
+      ToLayoutBoxModelObject(target->GetLayoutObject())->Layer();
+  ClipRectsContext context(
+      GetDocument().GetLayoutView()->Layer(), kUncachedClipRects,
+      kIgnorePlatformOverlayScrollbarSize, LayoutSize(FloatSize(0.25, 0.35)));
+  // When RLS is enabled, the LayoutView will have a composited scrolling layer,
+  // so don't apply an overflow clip.
+  if (RuntimeEnabledFeatures::RootLayerScrollingEnabled())
+    context.SetIgnoreOverflowClip();
+  ClipRect background_rect;
+
+  target_paint_layer->Clipper(PaintLayer::kUseGeometryMapper)
+      .CalculateBackgroundClipRect(context, background_rect);
+
+  EXPECT_EQ(LayoutRect(FloatRect(8.25, 8.35, 200, 300)),
+            background_rect.Rect());
+}
+
 TEST_F(PaintLayerClipperTest, LayoutSVGRoot) {
   SetBodyInnerHTML(
       "<!DOCTYPE html>"
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
index f95250b..aa7f398 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
@@ -801,7 +801,8 @@
           painting_info.root_layer,
           (paint_flags & kPaintLayerUncachedClipRects) ? kUncachedClipRects
                                                        : kPaintingClipRects,
-          kIgnorePlatformOverlayScrollbarSize);
+          kIgnorePlatformOverlayScrollbarSize,
+          painting_info.sub_pixel_accumulation);
       if (ShouldRespectOverflowClip(paint_flags,
                                     paint_layer_.GetLayoutObject()) ==
           kIgnoreOverflowClip)
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerPainterTest.cpp b/third_party/WebKit/Source/core/paint/PaintLayerPainterTest.cpp
index 3fab1f0..77d48d9 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerPainterTest.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerPainterTest.cpp
@@ -101,33 +101,28 @@
   auto& content2 = *GetLayoutObjectByElementId("content2");
   auto& filler2 = *GetLayoutObjectByElementId("filler2");
 
+  DisplayItemClient* background_display_item_client = nullptr;
+
   if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
       RuntimeEnabledFeatures::RootLayerScrollingEnabled()) {
-    // With SPv1 and RLS, the LayoutView gets painted into the
-    // MainGraphicsLayer while the rest into the ScrollingContentsLayer
-    EXPECT_DISPLAY_LIST(
-        MainGraphicsLayerPaintController().GetDisplayItemList(), 1,
-        TestDisplayItem(GetLayoutView(), kDocumentBackgroundType));
-
-    EXPECT_DISPLAY_LIST(RootPaintController().GetDisplayItemList(), 6,
-                        TestDisplayItem(container1, kBackgroundType),
-                        TestDisplayItem(content1, kBackgroundType),
-                        TestDisplayItem(filler1, kBackgroundType),
-                        TestDisplayItem(container2, kBackgroundType),
-                        TestDisplayItem(content2, kBackgroundType),
-                        TestDisplayItem(filler2, kBackgroundType));
+    // With SPv1 and RLS, the document background uses the scrolling contents
+    // layer as its DisplayItemClient.
+    background_display_item_client =
+        GetLayoutView().Layer()->GraphicsLayerBacking();
   } else {
-    EXPECT_DISPLAY_LIST(
-        RootPaintController().GetDisplayItemList(), 7,
-        TestDisplayItem(GetLayoutView(), kDocumentBackgroundType),
-        TestDisplayItem(container1, kBackgroundType),
-        TestDisplayItem(content1, kBackgroundType),
-        TestDisplayItem(filler1, kBackgroundType),
-        TestDisplayItem(container2, kBackgroundType),
-        TestDisplayItem(content2, kBackgroundType),
-        TestDisplayItem(filler2, kBackgroundType));
+    background_display_item_client = &GetLayoutView();
   }
 
+  EXPECT_DISPLAY_LIST(
+      RootPaintController().GetDisplayItemList(), 7,
+      TestDisplayItem(*background_display_item_client, kDocumentBackgroundType),
+      TestDisplayItem(container1, kBackgroundType),
+      TestDisplayItem(content1, kBackgroundType),
+      TestDisplayItem(filler1, kBackgroundType),
+      TestDisplayItem(container2, kBackgroundType),
+      TestDisplayItem(content2, kBackgroundType),
+      TestDisplayItem(filler2, kBackgroundType));
+
   auto* root_layer = GetLayoutView().Layer();
   auto* container1_layer = ToLayoutBoxModelObject(container1).Layer();
   auto* filler1_layer = ToLayoutBoxModelObject(filler1).Layer();
@@ -153,41 +148,19 @@
                      "background-color: green");
   GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
   EXPECT_TRUE(PaintWithoutCommit());
-
-  // With RLS and SPv1, the LayoutView is painted into a separate GraphicsLayer
-  // so it doesn't contribute to NumCachedNewItems since it isn't invalidated.
-  if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
-      RuntimeEnabledFeatures::RootLayerScrollingEnabled())
-    EXPECT_EQ(5, NumCachedNewItems());
-  else
-    EXPECT_EQ(6, NumCachedNewItems());
+  EXPECT_EQ(6, NumCachedNewItems());
 
   Commit();
 
-  if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
-      RuntimeEnabledFeatures::RootLayerScrollingEnabled()) {
-    EXPECT_DISPLAY_LIST(
-        MainGraphicsLayerPaintController().GetDisplayItemList(), 1,
-        TestDisplayItem(GetLayoutView(), kDocumentBackgroundType));
-
-    EXPECT_DISPLAY_LIST(RootPaintController().GetDisplayItemList(), 6,
-                        TestDisplayItem(container1, kBackgroundType),
-                        TestDisplayItem(content1, kBackgroundType),
-                        TestDisplayItem(filler1, kBackgroundType),
-                        TestDisplayItem(container2, kBackgroundType),
-                        TestDisplayItem(content2, kBackgroundType),
-                        TestDisplayItem(filler2, kBackgroundType));
-  } else {
-    EXPECT_DISPLAY_LIST(
-        RootPaintController().GetDisplayItemList(), 7,
-        TestDisplayItem(GetLayoutView(), kDocumentBackgroundType),
-        TestDisplayItem(container1, kBackgroundType),
-        TestDisplayItem(content1, kBackgroundType),
-        TestDisplayItem(filler1, kBackgroundType),
-        TestDisplayItem(container2, kBackgroundType),
-        TestDisplayItem(content2, kBackgroundType),
-        TestDisplayItem(filler2, kBackgroundType));
-  }
+  EXPECT_DISPLAY_LIST(
+      RootPaintController().GetDisplayItemList(), 7,
+      TestDisplayItem(*background_display_item_client, kDocumentBackgroundType),
+      TestDisplayItem(container1, kBackgroundType),
+      TestDisplayItem(content1, kBackgroundType),
+      TestDisplayItem(filler1, kBackgroundType),
+      TestDisplayItem(container2, kBackgroundType),
+      TestDisplayItem(content2, kBackgroundType),
+      TestDisplayItem(filler2, kBackgroundType));
 
   if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
     // We should still have the paint chunks forced by the cached subsequences.
@@ -248,35 +221,31 @@
   IntRect interest_rect(0, 0, 400, 300);
   Paint(&interest_rect);
 
+  DisplayItemClient* background_display_item_client = nullptr;
+
+  if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+      RuntimeEnabledFeatures::RootLayerScrollingEnabled()) {
+    // With SPv1 and RLS, the document background uses the scrolling contents
+    // layer as its DisplayItemClient.
+    background_display_item_client =
+        GetLayoutView().Layer()->GraphicsLayerBacking();
+  } else {
+    background_display_item_client = &GetLayoutView();
+  }
+
   // Container1 is fully in the interest rect;
   // Container2 is partly (including its stacking chidren) in the interest rect;
   // Content2b is out of the interest rect and output nothing;
   // Container3 is partly in the interest rect.
-  if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
-      RuntimeEnabledFeatures::RootLayerScrollingEnabled()) {
-    // With SPv1 and RLS, the LayoutView gets painted into the
-    // MainGraphicsLayer while the rest into the ScrollingContentsLayer
-    EXPECT_DISPLAY_LIST(
-        MainGraphicsLayerPaintController().GetDisplayItemList(), 1,
-        TestDisplayItem(GetLayoutView(), kDocumentBackgroundType));
-    EXPECT_DISPLAY_LIST(RootPaintController().GetDisplayItemList(), 6,
-                        TestDisplayItem(container1, kBackgroundType),
-                        TestDisplayItem(content1, kBackgroundType),
-                        TestDisplayItem(container2, kBackgroundType),
-                        TestDisplayItem(content2a, kBackgroundType),
-                        TestDisplayItem(container3, kBackgroundType),
-                        TestDisplayItem(content3, kBackgroundType));
-  } else {
-    EXPECT_DISPLAY_LIST(
-        RootPaintController().GetDisplayItemList(), 7,
-        TestDisplayItem(GetLayoutView(), kDocumentBackgroundType),
-        TestDisplayItem(container1, kBackgroundType),
-        TestDisplayItem(content1, kBackgroundType),
-        TestDisplayItem(container2, kBackgroundType),
-        TestDisplayItem(content2a, kBackgroundType),
-        TestDisplayItem(container3, kBackgroundType),
-        TestDisplayItem(content3, kBackgroundType));
-  }
+  EXPECT_DISPLAY_LIST(
+      RootPaintController().GetDisplayItemList(), 7,
+      TestDisplayItem(*background_display_item_client, kDocumentBackgroundType),
+      TestDisplayItem(container1, kBackgroundType),
+      TestDisplayItem(content1, kBackgroundType),
+      TestDisplayItem(container2, kBackgroundType),
+      TestDisplayItem(content2a, kBackgroundType),
+      TestDisplayItem(container3, kBackgroundType),
+      TestDisplayItem(content3, kBackgroundType));
 
   GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
   IntRect new_interest_rect(0, 100, 300, 1000);
@@ -288,35 +257,18 @@
   // Content2b is out of the interest rect and outputs nothing;
   // Container3 becomes out of the interest rect and outputs empty subsequence
   // pair.
-  if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
-      RuntimeEnabledFeatures::RootLayerScrollingEnabled())
-    EXPECT_EQ(4, NumCachedNewItems());
-  else
-    EXPECT_EQ(5, NumCachedNewItems());
+  EXPECT_EQ(5, NumCachedNewItems());
 
   Commit();
 
-  if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
-      RuntimeEnabledFeatures::RootLayerScrollingEnabled()) {
-    EXPECT_DISPLAY_LIST(
-        MainGraphicsLayerPaintController().GetDisplayItemList(), 1,
-        TestDisplayItem(GetLayoutView(), kDocumentBackgroundType));
-    EXPECT_DISPLAY_LIST(RootPaintController().GetDisplayItemList(), 5,
-                        TestDisplayItem(container1, kBackgroundType),
-                        TestDisplayItem(content1, kBackgroundType),
-                        TestDisplayItem(container2, kBackgroundType),
-                        TestDisplayItem(content2a, kBackgroundType),
-                        TestDisplayItem(content2b, kBackgroundType));
-  } else {
-    EXPECT_DISPLAY_LIST(
-        RootPaintController().GetDisplayItemList(), 6,
-        TestDisplayItem(GetLayoutView(), kDocumentBackgroundType),
-        TestDisplayItem(container1, kBackgroundType),
-        TestDisplayItem(content1, kBackgroundType),
-        TestDisplayItem(container2, kBackgroundType),
-        TestDisplayItem(content2a, kBackgroundType),
-        TestDisplayItem(content2b, kBackgroundType));
-  }
+  EXPECT_DISPLAY_LIST(
+      RootPaintController().GetDisplayItemList(), 6,
+      TestDisplayItem(*background_display_item_client, kDocumentBackgroundType),
+      TestDisplayItem(container1, kBackgroundType),
+      TestDisplayItem(content1, kBackgroundType),
+      TestDisplayItem(container2, kBackgroundType),
+      TestDisplayItem(content2a, kBackgroundType),
+      TestDisplayItem(content2b, kBackgroundType));
 }
 
 TEST_P(PaintLayerPainterTest,
@@ -346,62 +298,43 @@
   LayoutObject& content2 =
       *GetDocument().getElementById("content2")->GetLayoutObject();
 
+  DisplayItemClient* background_display_item_client = nullptr;
+
   if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
       RuntimeEnabledFeatures::RootLayerScrollingEnabled()) {
-    // With SPv1 and RLS, the LayoutView gets painted into the
-    // MainGraphicsLayer while the rest into the ScrollingContentsLayer
-    EXPECT_DISPLAY_LIST(
-        MainGraphicsLayerPaintController().GetDisplayItemList(), 1,
-        TestDisplayItem(GetLayoutView(), kDocumentBackgroundType));
-    EXPECT_DISPLAY_LIST(RootPaintController().GetDisplayItemList(), 4,
-                        TestDisplayItem(container1, kBackgroundType),
-                        TestDisplayItem(content1, kBackgroundType),
-                        TestDisplayItem(container2, kBackgroundType),
-                        TestDisplayItem(content2, kBackgroundType));
+    // With SPv1 and RLS, the document background uses the scrolling contents
+    // layer as its DisplayItemClient.
+    background_display_item_client =
+        GetLayoutView().Layer()->GraphicsLayerBacking();
   } else {
-    EXPECT_DISPLAY_LIST(
-        RootPaintController().GetDisplayItemList(), 5,
-        TestDisplayItem(GetLayoutView(), kDocumentBackgroundType),
-        TestDisplayItem(container1, kBackgroundType),
-        TestDisplayItem(content1, kBackgroundType),
-        TestDisplayItem(container2, kBackgroundType),
-        TestDisplayItem(content2, kBackgroundType));
+    background_display_item_client = &GetLayoutView();
   }
 
+  EXPECT_DISPLAY_LIST(
+      RootPaintController().GetDisplayItemList(), 5,
+      TestDisplayItem(*background_display_item_client, kDocumentBackgroundType),
+      TestDisplayItem(container1, kBackgroundType),
+      TestDisplayItem(content1, kBackgroundType),
+      TestDisplayItem(container2, kBackgroundType),
+      TestDisplayItem(content2, kBackgroundType));
+
   ToHTMLElement(content1.GetNode())
       ->setAttribute(HTMLNames::styleAttr,
                      "position: absolute; width: 100px; height: 100px; "
                      "background-color: green");
   GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
   EXPECT_TRUE(PaintWithoutCommit(&interest_rect));
-
-  if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
-      RuntimeEnabledFeatures::RootLayerScrollingEnabled())
-    EXPECT_EQ(3, NumCachedNewItems());
-  else
-    EXPECT_EQ(4, NumCachedNewItems());
+  EXPECT_EQ(4, NumCachedNewItems());
 
   Commit();
 
-  if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
-      RuntimeEnabledFeatures::RootLayerScrollingEnabled()) {
-    EXPECT_DISPLAY_LIST(
-        MainGraphicsLayerPaintController().GetDisplayItemList(), 1,
-        TestDisplayItem(GetLayoutView(), kDocumentBackgroundType));
-    EXPECT_DISPLAY_LIST(RootPaintController().GetDisplayItemList(), 4,
-                        TestDisplayItem(container1, kBackgroundType),
-                        TestDisplayItem(content1, kBackgroundType),
-                        TestDisplayItem(container2, kBackgroundType),
-                        TestDisplayItem(content2, kBackgroundType));
-  } else {
-    EXPECT_DISPLAY_LIST(
-        RootPaintController().GetDisplayItemList(), 5,
-        TestDisplayItem(GetLayoutView(), kDocumentBackgroundType),
-        TestDisplayItem(container1, kBackgroundType),
-        TestDisplayItem(content1, kBackgroundType),
-        TestDisplayItem(container2, kBackgroundType),
-        TestDisplayItem(content2, kBackgroundType));
-  }
+  EXPECT_DISPLAY_LIST(
+      RootPaintController().GetDisplayItemList(), 5,
+      TestDisplayItem(*background_display_item_client, kDocumentBackgroundType),
+      TestDisplayItem(container1, kBackgroundType),
+      TestDisplayItem(content1, kBackgroundType),
+      TestDisplayItem(container2, kBackgroundType),
+      TestDisplayItem(content2, kBackgroundType));
 }
 
 TEST_P(PaintLayerPainterTest, PaintPhaseOutline) {
diff --git a/third_party/WebKit/Source/core/paint/ViewPainter.cpp b/third_party/WebKit/Source/core/paint/ViewPainter.cpp
index 8597c23..3b2645f 100644
--- a/third_party/WebKit/Source/core/paint/ViewPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/ViewPainter.cpp
@@ -77,8 +77,11 @@
         static_cast<const DisplayItemClient*>(layout_view_.Layer()
                                                   ->GetCompositedLayerMapping()
                                                   ->ScrollingContentsLayer());
-    scroll_recorder.emplace(paint_info.context, layout_view_, paint_info.phase,
-                            layout_view_.ScrolledContentOffset());
+    if (!layout_view_.ScrolledContentOffset().IsZero()) {
+      scroll_recorder.emplace(paint_info.context, layout_view_,
+                              paint_info.phase,
+                              layout_view_.ScrolledContentOffset());
+    }
   }
 
   if (DrawingRecorder::UseCachedDrawingIfPossible(
diff --git a/third_party/WebKit/Source/core/scheduler/FrameThrottlingTest.cpp b/third_party/WebKit/Source/core/scheduler/FrameThrottlingTest.cpp
index 5a4d6be..bfc7dbd9 100644
--- a/third_party/WebKit/Source/core/scheduler/FrameThrottlingTest.cpp
+++ b/third_party/WebKit/Source/core/scheduler/FrameThrottlingTest.cpp
@@ -189,6 +189,43 @@
   EXPECT_TRUE(inner_frame_document->View()->CanThrottleRendering());
 }
 
+TEST_P(FrameThrottlingTest, IntersectionObservationOverridesThrottling) {
+  // Create a document with doubly nested iframes.
+  SimRequest main_resource("https://example.com/", "text/html");
+  SimRequest frame_resource("https://example.com/iframe.html", "text/html");
+
+  LoadURL("https://example.com/");
+  main_resource.Complete("<iframe id=frame src=iframe.html></iframe>");
+  frame_resource.Complete("<iframe id=innerFrame sandbox></iframe>");
+
+  auto* frame_element =
+      toHTMLIFrameElement(GetDocument().getElementById("frame"));
+  auto* frame_document = frame_element->contentDocument();
+
+  auto* inner_frame_element =
+      toHTMLIFrameElement(frame_document->getElementById("innerFrame"));
+  auto* inner_frame_document = inner_frame_element->contentDocument();
+
+  DocumentLifecycle::AllowThrottlingScope throttling_scope(
+      GetDocument().Lifecycle());
+
+  // Hidden cross origin frames are throttled.
+  frame_element->setAttribute(styleAttr, "transform: translateY(480px)");
+  CompositeFrame();
+  EXPECT_FALSE(GetDocument().View()->CanThrottleRendering());
+  EXPECT_FALSE(frame_document->View()->CanThrottleRendering());
+  EXPECT_TRUE(inner_frame_document->View()->ShouldThrottleRendering());
+
+  // An intersection observation overrides...
+  inner_frame_document->View()->SetNeedsIntersectionObservation();
+  EXPECT_FALSE(inner_frame_document->View()->ShouldThrottleRendering());
+  inner_frame_document->View()->ScheduleAnimation();
+
+  CompositeFrame();
+  // ...but only for one frame.
+  EXPECT_TRUE(inner_frame_document->View()->ShouldThrottleRendering());
+}
+
 TEST_P(FrameThrottlingTest, HiddenCrossOriginZeroByZeroFramesAreNotThrottled) {
   // Create a document with doubly nested iframes.
   SimRequest main_resource("https://example.com/", "text/html");
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/ClearStorageView.js b/third_party/WebKit/Source/devtools/front_end/resources/ClearStorageView.js
index 3b9dca2..164c629 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/ClearStorageView.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/ClearStorageView.js
@@ -1,21 +1,23 @@
 // 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.
+
 /**
  * @implements {SDK.TargetManager.Observer}
  */
 Resources.ClearStorageView = class extends UI.ThrottledWidget {
   constructor() {
     super(true, 1000);
-    this._pieColors = [
-      'rgba(110, 161, 226, 1)',  // blue
-      'rgba(229, 113, 113, 1)',  // red
-      'rgba(239, 196, 87, 1)',   // yellow
-      'rgba(155, 127, 230, 1)',  // purple
-      'rgba(116, 178, 102, 1)',  // green
-      'rgba(255, 167, 36, 1)',   // orange
-      'rgba(203, 220, 56, 1)',   // lime
-    ];
+    var types = Protocol.Storage.StorageType;
+    this._pieColors = new Map([
+      [types.Appcache, 'rgb(110, 161, 226)'],        // blue
+      [types.Cache_storage, 'rgb(229, 113, 113)'],   // red
+      [types.Cookies, 'rgb(239, 196, 87)'],          // yellow
+      [types.Indexeddb, 'rgb(155, 127, 230)'],       // purple
+      [types.Local_storage, 'rgb(116, 178, 102)'],   // green
+      [types.Service_workers, 'rgb(255, 167, 36)'],  // orange
+      [types.Websql, 'rgb(203, 220, 56)'],           // lime
+    ]);
 
     this._reportView = new UI.ReportView(Common.UIString('Clear storage'));
     this._reportView.registerRequiredCSS('resources/clearStorageView.css');
@@ -27,11 +29,9 @@
     this._securityOrigin = null;
 
     this._settings = new Map();
-    for (var type
-             of [Protocol.Storage.StorageType.Appcache, Protocol.Storage.StorageType.Cache_storage,
-                 Protocol.Storage.StorageType.Cookies, Protocol.Storage.StorageType.Indexeddb,
-                 Protocol.Storage.StorageType.Local_storage, Protocol.Storage.StorageType.Service_workers,
-                 Protocol.Storage.StorageType.Websql])
+    for (var type of
+             [types.Appcache, types.Cache_storage, types.Cookies, types.Indexeddb, types.Local_storage,
+              types.Service_workers, types.Websql])
       this._settings.set(type, Common.settings.createSetting('clear-storage-' + type, true));
 
     var quota = this._reportView.appendSection(Common.UIString('Usage'));
@@ -201,14 +201,17 @@
     if (!this._quotaUsage || this._quotaUsage !== response.usage) {
       this._quotaUsage = response.usage;
       this._resetPieChart(response.usage);
-      var colorIndex = 0;
-      for (var usageForType of response.usageBreakdown) {
-        if (!usageForType.usage)
+      for (var usageForType of response.usageBreakdown.sort((a, b) => b.usage - a.usage)) {
+        var value = usageForType.usage;
+        if (!value)
           continue;
-        if (colorIndex === this._pieColors.length)
-          colorIndex = 0;
-        this._appendLegendRow(
-            this._getStorageTypeName(usageForType.storageType), usageForType.usage, this._pieColors[colorIndex++]);
+        var title = this._getStorageTypeName(usageForType.storageType);
+        var color = this._pieColors.get(usageForType.storageType) || '#ccc';
+        this._pieChart.addSlice(value, color);
+        var rowElement = this._pieChartLegend.createChild('div', 'usage-breakdown-legend-row');
+        rowElement.createChild('span', 'usage-breakdown-legend-value').textContent = Number.bytesToString(value);
+        rowElement.createChild('span', 'usage-breakdown-legend-swatch').style.backgroundColor = color;
+        rowElement.createChild('span', 'usage-breakdown-legend-title').textContent = title;
       }
     }
 
@@ -225,21 +228,6 @@
   }
 
   /**
-   * @param {string} title
-   * @param {number} value
-   * @param {string} color
-   */
-  _appendLegendRow(title, value, color) {
-    if (!value)
-      return;
-    this._pieChart.addSlice(value, color);
-    var rowElement = this._pieChartLegend.createChild('div');
-    rowElement.createChild('span', 'usage-breakdown-legend-value').textContent = Number.bytesToString(value);
-    rowElement.createChild('span', 'usage-breakdown-legend-swatch').style.backgroundColor = color;
-    rowElement.createChild('span', 'usage-breakdown-legend-title').textContent = title;
-  }
-
-  /**
    * @param {string} type
    * @return {string}
    */
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/clearStorageView.css b/third_party/WebKit/Source/devtools/front_end/resources/clearStorageView.css
index ae8e397..abbed68 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/clearStorageView.css
+++ b/third_party/WebKit/Source/devtools/front_end/resources/clearStorageView.css
@@ -27,6 +27,10 @@
     min-width: fit-content;
 }
 
+.usage-breakdown-legend-row {
+    margin: 5px auto;
+}
+
 .usage-breakdown-legend-title {
     display: inline-block;
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js b/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js
index 43e5444f..d8b9b53 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js
@@ -188,12 +188,10 @@
     var nextSelectedElement = this.selectedTreeElement.traversePreviousTreeElement(true);
     while (nextSelectedElement && !nextSelectedElement.selectable)
       nextSelectedElement = nextSelectedElement.traversePreviousTreeElement(!this.expandTreeElementsWhenArrowing);
-    if (nextSelectedElement) {
-      nextSelectedElement.reveal();
-      nextSelectedElement.select(false, true);
-      return true;
-    }
-    return false;
+    if (!nextSelectedElement)
+      return false;
+    nextSelectedElement.select(false, true);
+    return true;
   }
 
   /**
@@ -203,12 +201,10 @@
     var nextSelectedElement = this.selectedTreeElement.traverseNextTreeElement(true);
     while (nextSelectedElement && !nextSelectedElement.selectable)
       nextSelectedElement = nextSelectedElement.traverseNextTreeElement(!this.expandTreeElementsWhenArrowing);
-    if (nextSelectedElement) {
-      nextSelectedElement.reveal();
-      nextSelectedElement.select(false, true);
-      return true;
-    }
-    return false;
+    if (!nextSelectedElement)
+      return false;
+    nextSelectedElement.select(false, true);
+    return true;
   }
 
   /**
@@ -929,13 +925,10 @@
     while (nextSelectedElement && !nextSelectedElement.selectable)
       nextSelectedElement = nextSelectedElement.parent;
 
-    if (nextSelectedElement) {
-      nextSelectedElement.reveal();
-      nextSelectedElement.select(false, true);
-      return true;
-    }
-
-    return false;
+    if (!nextSelectedElement)
+      return false;
+    nextSelectedElement.select(false, true);
+    return true;
   }
 
   /**
@@ -958,13 +951,10 @@
     while (nextSelectedElement && !nextSelectedElement.selectable)
       nextSelectedElement = nextSelectedElement.nextSibling;
 
-    if (nextSelectedElement) {
-      nextSelectedElement.reveal();
-      nextSelectedElement.select(false, true);
-      return true;
-    }
-
-    return false;
+    if (!nextSelectedElement)
+      return false;
+    nextSelectedElement.select(false, true);
+    return true;
   }
 
   /**
diff --git a/third_party/WebKit/Source/modules/BUILD.gn b/third_party/WebKit/Source/modules/BUILD.gn
index 4a97883..02783e7 100644
--- a/third_party/WebKit/Source/modules/BUILD.gn
+++ b/third_party/WebKit/Source/modules/BUILD.gn
@@ -264,6 +264,7 @@
     "filesystem/DOMFileSystemBaseTest.cpp",
     "indexeddb/IDBKeyPathTest.cpp",
     "indexeddb/IDBRequestTest.cpp",
+    "indexeddb/IDBTestHelper.cpp",
     "indexeddb/IDBTransactionTest.cpp",
     "indexeddb/IDBValueWrappingTest.cpp",
     "indexeddb/MockWebIDBDatabase.cpp",
diff --git a/third_party/WebKit/Source/modules/compositorworker/OWNERS b/third_party/WebKit/Source/modules/compositorworker/OWNERS
index 331e182..6b80165b 100644
--- a/third_party/WebKit/Source/modules/compositorworker/OWNERS
+++ b/third_party/WebKit/Source/modules/compositorworker/OWNERS
@@ -4,4 +4,5 @@
 kinuko@chromium.org
 nhiroki@chromium.org
 
+# TEAM: threaded-rendering-dev@chromium.org
 # COMPONENT: Internals>Compositing>Animation
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBRequestTest.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBRequestTest.cpp
index f6f063b..8d801dd 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBRequestTest.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBRequestTest.cpp
@@ -40,6 +40,7 @@
 #include "modules/indexeddb/IDBMetadata.h"
 #include "modules/indexeddb/IDBObjectStore.h"
 #include "modules/indexeddb/IDBOpenDBRequest.h"
+#include "modules/indexeddb/IDBTestHelper.h"
 #include "modules/indexeddb/IDBTransaction.h"
 #include "modules/indexeddb/IDBValue.h"
 #include "modules/indexeddb/IDBValueWrapping.h"
@@ -99,38 +100,6 @@
   static constexpr int64_t kStoreId = 5678;
 };
 
-// The created value is an array of true. If create_wrapped_value is true, the
-// IDBValue's byte array will be wrapped in a Blob, otherwise it will not be.
-RefPtr<IDBValue> CreateIDBValue(v8::Isolate* isolate,
-                                bool create_wrapped_value) {
-  size_t element_count = create_wrapped_value ? 16 : 2;
-  v8::Local<v8::Array> v8_array = v8::Array::New(isolate, element_count);
-  for (size_t i = 0; i < element_count; ++i)
-    v8_array->Set(i, v8::True(isolate));
-
-  NonThrowableExceptionState non_throwable_exception_state;
-  IDBValueWrapper wrapper(isolate, v8_array,
-                          SerializedScriptValue::SerializeOptions::kSerialize,
-                          non_throwable_exception_state);
-  wrapper.WrapIfBiggerThan(create_wrapped_value ? 0 : 1024 * element_count);
-
-  std::unique_ptr<Vector<RefPtr<BlobDataHandle>>> blob_data_handles =
-      WTF::MakeUnique<Vector<RefPtr<BlobDataHandle>>>();
-  wrapper.ExtractBlobDataHandles(blob_data_handles.get());
-  Vector<WebBlobInfo>& blob_infos = wrapper.WrappedBlobInfo();
-  RefPtr<SharedBuffer> wrapped_marker_buffer = wrapper.ExtractWireBytes();
-  IDBKey* key = IDBKey::CreateNumber(42.0);
-  IDBKeyPath key_path(String("primaryKey"));
-
-  RefPtr<IDBValue> idb_value = IDBValue::Create(
-      std::move(wrapped_marker_buffer), std::move(blob_data_handles),
-      WTF::MakeUnique<Vector<WebBlobInfo>>(blob_infos), key, key_path);
-
-  DCHECK_EQ(create_wrapped_value,
-            IDBValueUnwrapper::IsWrapped(idb_value.Get()));
-  return idb_value;
-}
-
 void EnsureIDBCallbacksDontThrow(IDBRequest* request,
                                  ExceptionState& exception_state) {
   ASSERT_TRUE(request->transaction());
@@ -185,7 +154,7 @@
                          transaction_.Get(), IDBRequest::AsyncTraceState());
   ASSERT_TRUE(!scope.GetExceptionState().HadException());
   ASSERT_TRUE(request->transaction());
-  request->HandleResponse(CreateIDBValue(scope.GetIsolate(), false));
+  request->HandleResponse(CreateIDBValueForTesting(scope.GetIsolate(), false));
   scope.GetExecutionContext()->NotifyContextDestroyed();
 
   EnsureIDBCallbacksDontThrow(request, scope.GetExceptionState());
@@ -206,7 +175,7 @@
   EXPECT_EQ(request->readyState(), "pending");
   ASSERT_TRUE(!scope.GetExceptionState().HadException());
   ASSERT_TRUE(request->transaction());
-  request->HandleResponse(CreateIDBValue(scope.GetIsolate(), true));
+  request->HandleResponse(CreateIDBValueForTesting(scope.GetIsolate(), true));
   scope.GetExecutionContext()->NotifyContextDestroyed();
 
   EnsureIDBCallbacksDontThrow(request, scope.GetExceptionState());
@@ -234,8 +203,8 @@
   ASSERT_TRUE(!scope.GetExceptionState().HadException());
   ASSERT_TRUE(request1->transaction());
   ASSERT_TRUE(request2->transaction());
-  request1->HandleResponse(CreateIDBValue(scope.GetIsolate(), true));
-  request2->HandleResponse(CreateIDBValue(scope.GetIsolate(), true));
+  request1->HandleResponse(CreateIDBValueForTesting(scope.GetIsolate(), true));
+  request2->HandleResponse(CreateIDBValueForTesting(scope.GetIsolate(), true));
   scope.GetExecutionContext()->NotifyContextDestroyed();
 
   EnsureIDBCallbacksDontThrow(request1, scope.GetExceptionState());
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBTestHelper.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBTestHelper.cpp
new file mode 100644
index 0000000..2e79ccf4
--- /dev/null
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBTestHelper.cpp
@@ -0,0 +1,48 @@
+// Copyright 2017 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 "modules/indexeddb/IDBTestHelper.h"
+
+#include <utility>
+#include "modules/indexeddb/IDBKey.h"
+#include "modules/indexeddb/IDBKeyPath.h"
+#include "modules/indexeddb/IDBValueWrapping.h"
+#include "platform/SharedBuffer.h"
+#include "platform/blob/BlobData.h"
+#include "platform/wtf/Vector.h"
+#include "public/platform/WebBlobInfo.h"
+
+namespace blink {
+
+RefPtr<IDBValue> CreateIDBValueForTesting(v8::Isolate* isolate,
+                                          bool create_wrapped_value) {
+  size_t element_count = create_wrapped_value ? 16 : 2;
+  v8::Local<v8::Array> v8_array = v8::Array::New(isolate, element_count);
+  for (size_t i = 0; i < element_count; ++i)
+    v8_array->Set(i, v8::True(isolate));
+
+  NonThrowableExceptionState non_throwable_exception_state;
+  IDBValueWrapper wrapper(isolate, v8_array,
+                          SerializedScriptValue::SerializeOptions::kSerialize,
+                          non_throwable_exception_state);
+  wrapper.WrapIfBiggerThan(create_wrapped_value ? 0 : 1024 * element_count);
+
+  std::unique_ptr<Vector<RefPtr<BlobDataHandle>>> blob_data_handles =
+      WTF::MakeUnique<Vector<RefPtr<BlobDataHandle>>>();
+  wrapper.ExtractBlobDataHandles(blob_data_handles.get());
+  Vector<WebBlobInfo>& blob_infos = wrapper.WrappedBlobInfo();
+  RefPtr<SharedBuffer> wrapped_marker_buffer = wrapper.ExtractWireBytes();
+  IDBKey* key = IDBKey::CreateNumber(42.0);
+  IDBKeyPath key_path(String("primaryKey"));
+
+  RefPtr<IDBValue> idb_value = IDBValue::Create(
+      std::move(wrapped_marker_buffer), std::move(blob_data_handles),
+      WTF::MakeUnique<Vector<WebBlobInfo>>(blob_infos), key, key_path);
+
+  DCHECK_EQ(create_wrapped_value,
+            IDBValueUnwrapper::IsWrapped(idb_value.Get()));
+  return idb_value;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBTestHelper.h b/third_party/WebKit/Source/modules/indexeddb/IDBTestHelper.h
new file mode 100644
index 0000000..f8311f8
--- /dev/null
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBTestHelper.h
@@ -0,0 +1,21 @@
+// Copyright 2017 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 IDBTestHelper_h
+#define IDBTestHelper_h
+
+#include "modules/indexeddb/IDBValue.h"
+#include "platform/wtf/RefPtr.h"
+#include "v8/include/v8.h"
+
+namespace blink {
+
+// The created value is an array of true. If create_wrapped_value is true, the
+// IDBValue's byte array will be wrapped in a Blob, otherwise it will not be.
+RefPtr<IDBValue> CreateIDBValueForTesting(v8::Isolate*,
+                                          bool create_wrapped_value);
+
+}  // namespace blink
+
+#endif  // IDBTestHelper_h
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBTransactionTest.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBTransactionTest.cpp
index 683d45b9..9eda221 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBTransactionTest.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBTransactionTest.cpp
@@ -43,6 +43,7 @@
 #include "modules/indexeddb/IDBKeyPath.h"
 #include "modules/indexeddb/IDBMetadata.h"
 #include "modules/indexeddb/IDBObjectStore.h"
+#include "modules/indexeddb/IDBTestHelper.h"
 #include "modules/indexeddb/IDBValue.h"
 #include "modules/indexeddb/IDBValueWrapping.h"
 #include "modules/indexeddb/MockWebIDBDatabase.h"
@@ -117,38 +118,6 @@
   static constexpr int64_t kStoreId = 5678;
 };
 
-// The created value is an array of true. If create_wrapped_value is true, the
-// IDBValue's byte array will be wrapped in a Blob, otherwise it will not be.
-RefPtr<IDBValue> CreateIDBValue(v8::Isolate* isolate,
-                                bool create_wrapped_value) {
-  size_t element_count = create_wrapped_value ? 16 : 2;
-  v8::Local<v8::Array> v8_array = v8::Array::New(isolate, element_count);
-  for (size_t i = 0; i < element_count; ++i)
-    v8_array->Set(i, v8::True(isolate));
-
-  NonThrowableExceptionState non_throwable_exception_state;
-  IDBValueWrapper wrapper(isolate, v8_array,
-                          SerializedScriptValue::SerializeOptions::kSerialize,
-                          non_throwable_exception_state);
-  wrapper.WrapIfBiggerThan(create_wrapped_value ? 0 : 1024 * element_count);
-
-  std::unique_ptr<Vector<RefPtr<BlobDataHandle>>> blob_data_handles =
-      WTF::MakeUnique<Vector<RefPtr<BlobDataHandle>>>();
-  wrapper.ExtractBlobDataHandles(blob_data_handles.get());
-  Vector<WebBlobInfo>& blob_infos = wrapper.WrappedBlobInfo();
-  RefPtr<SharedBuffer> wrapped_marker_buffer = wrapper.ExtractWireBytes();
-  IDBKey* key = IDBKey::CreateNumber(42.0);
-  IDBKeyPath key_path(String("primaryKey"));
-
-  RefPtr<IDBValue> idb_value = IDBValue::Create(
-      std::move(wrapped_marker_buffer), std::move(blob_data_handles),
-      WTF::MakeUnique<Vector<WebBlobInfo>>(blob_infos), key, key_path);
-
-  DCHECK_EQ(create_wrapped_value,
-            IDBValueUnwrapper::IsWrapped(idb_value.Get()));
-  return idb_value;
-}
-
 TEST_F(IDBTransactionTest, ContextDestroyedEarlyDeath) {
   V8TestingScope scope;
   std::unique_ptr<MockWebIDBDatabase> backend = MockWebIDBDatabase::Create();
@@ -200,7 +169,7 @@
   DeactivateNewTransactions(scope.GetIsolate());
 
   // This response should result in an event being enqueued immediately.
-  request->HandleResponse(CreateIDBValue(scope.GetIsolate(), false));
+  request->HandleResponse(CreateIDBValueForTesting(scope.GetIsolate(), false));
 
   request.Clear();  // The transaction is holding onto the request.
   ThreadState::Current()->CollectAllGarbage();
@@ -239,7 +208,7 @@
                          transaction_.Get(), IDBRequest::AsyncTraceState());
   DeactivateNewTransactions(scope.GetIsolate());
 
-  request->HandleResponse(CreateIDBValue(scope.GetIsolate(), true));
+  request->HandleResponse(CreateIDBValueForTesting(scope.GetIsolate(), true));
 
   request.Clear();  // The transaction is holding onto the request.
   ThreadState::Current()->CollectAllGarbage();
@@ -278,8 +247,8 @@
                          transaction_.Get(), IDBRequest::AsyncTraceState());
   DeactivateNewTransactions(scope.GetIsolate());
 
-  request1->HandleResponse(CreateIDBValue(scope.GetIsolate(), true));
-  request2->HandleResponse(CreateIDBValue(scope.GetIsolate(), true));
+  request1->HandleResponse(CreateIDBValueForTesting(scope.GetIsolate(), true));
+  request2->HandleResponse(CreateIDBValueForTesting(scope.GetIsolate(), true));
 
   request1.Clear();  // The transaction is holding onto the requests.
   request2.Clear();
@@ -321,8 +290,8 @@
                          transaction_.Get(), IDBRequest::AsyncTraceState());
   DeactivateNewTransactions(scope.GetIsolate());
 
-  request1->HandleResponse(CreateIDBValue(scope.GetIsolate(), true));
-  request2->HandleResponse(CreateIDBValue(scope.GetIsolate(), false));
+  request1->HandleResponse(CreateIDBValueForTesting(scope.GetIsolate(), true));
+  request2->HandleResponse(CreateIDBValueForTesting(scope.GetIsolate(), false));
 
   request1.Clear();  // The transaction is holding onto the requests.
   request2.Clear();
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioContextTest.cpp b/third_party/WebKit/Source/modules/webaudio/AudioContextTest.cpp
index 7547fba..a49e417 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioContextTest.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioContextTest.cpp
@@ -6,6 +6,7 @@
 
 #include "core/dom/Document.h"
 #include "core/testing/DummyPageHolder.h"
+#include "modules/webaudio/AudioWorkletThread.h"
 #include "platform/testing/TestingPlatformSupport.h"
 #include "platform/wtf/PtrUtil.h"
 #include "public/platform/WebAudioDevice.h"
@@ -71,6 +72,10 @@
         AudioHardwareSampleRate(), buffer_size);
   }
 
+  std::unique_ptr<WebThread> CreateThread(const char* name) override {
+    return old_platform_->CreateThread(name);
+  }
+
   double AudioHardwareSampleRate() override { return 44100; }
   size_t AudioHardwareBufferSize() override { return 128; }
 };
@@ -79,7 +84,10 @@
 
 class AudioContextTest : public ::testing::Test {
  protected:
-  void SetUp() override { dummy_page_holder_ = DummyPageHolder::Create(); }
+  void SetUp() override {
+    dummy_page_holder_ = DummyPageHolder::Create();
+    AudioWorkletThread::CreateSharedBackingThreadForTest();
+  }
 
   Document& GetDocument() { return dummy_page_holder_->GetDocument(); }
 
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioWorkletThread.cpp b/third_party/WebKit/Source/modules/webaudio/AudioWorkletThread.cpp
index e5088cb..1ce817e 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioWorkletThread.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioWorkletThread.cpp
@@ -70,6 +70,15 @@
   WorkletThreadHolder<AudioWorkletThread>::ClearInstance();
 }
 
+WebThread* AudioWorkletThread::GetSharedBackingThread() {
+  DCHECK(IsMainThread());
+  WorkletThreadHolder<AudioWorkletThread>* instance =
+      WorkletThreadHolder<AudioWorkletThread>::GetInstance();
+  if (!instance)
+    return nullptr;
+  return &(instance->GetThread()->BackingThread().PlatformThread());
+}
+
 void AudioWorkletThread::CreateSharedBackingThreadForTest() {
   WorkletThreadHolder<AudioWorkletThread>::CreateForTest("AudioWorkletThread");
 }
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioWorkletThread.h b/third_party/WebKit/Source/modules/webaudio/AudioWorkletThread.h
index 3bb11d6..8c6ab9a 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioWorkletThread.h
+++ b/third_party/WebKit/Source/modules/webaudio/AudioWorkletThread.h
@@ -37,6 +37,11 @@
 
   static void CreateSharedBackingThreadForTest();
 
+  // This only can be called after EnsureSharedBackingThread() is performed.
+  // Currently AudioWorkletThread owns only one thread and it is shared by all
+  // the customers.
+  static WebThread* GetSharedBackingThread();
+
  protected:
   WorkerOrWorkletGlobalScope* CreateWorkerGlobalScope(
       std::unique_ptr<GlobalScopeCreationParams>) final;
diff --git a/third_party/WebKit/Source/modules/webaudio/BaseAudioContextTest.cpp b/third_party/WebKit/Source/modules/webaudio/BaseAudioContextTest.cpp
index aedc6c9..3f7baf0c 100644
--- a/third_party/WebKit/Source/modules/webaudio/BaseAudioContextTest.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/BaseAudioContextTest.cpp
@@ -16,9 +16,11 @@
 #include "core/loader/EmptyClients.h"
 #include "core/testing/DummyPageHolder.h"
 #include "modules/webaudio/AudioContextOptions.h"
+#include "modules/webaudio/AudioWorkletThread.h"
 #include "platform/testing/HistogramTester.h"
 #include "platform/testing/TestingPlatformSupport.h"
 #include "platform/wtf/PtrUtil.h"
+#include "public/platform/Platform.h"
 #include "public/platform/WebAudioDevice.h"
 #include "public/platform/WebAudioLatencyHint.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -80,6 +82,10 @@
         AudioHardwareSampleRate(), AudioHardwareBufferSize());
   }
 
+  std::unique_ptr<WebThread> CreateThread(const char* name) override {
+    return old_platform_->CreateThread(name);
+  }
+
   double AudioHardwareSampleRate() override { return 44100; }
   size_t AudioHardwareBufferSize() override { return 128; }
 };
@@ -101,9 +107,12 @@
 
     GetDocument().GetSettings()->SetAutoplayPolicy(GetParam());
     ChildDocument().GetSettings()->SetAutoplayPolicy(GetParam());
+
+    AudioWorkletThread::CreateSharedBackingThreadForTest();
   }
 
   void TearDown() override {
+    AudioWorkletThread::ClearSharedBackingThread();
     if (child_frame_)
       child_frame_->Detach(FrameDetachType::kRemove);
   }
diff --git a/third_party/WebKit/Source/modules/webaudio/DefaultAudioDestinationNode.cpp b/third_party/WebKit/Source/modules/webaudio/DefaultAudioDestinationNode.cpp
index b3cab7b..8b952b0 100644
--- a/third_party/WebKit/Source/modules/webaudio/DefaultAudioDestinationNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/DefaultAudioDestinationNode.cpp
@@ -27,6 +27,7 @@
 #include "bindings/core/v8/ExceptionMessages.h"
 #include "bindings/core/v8/ExceptionState.h"
 #include "core/dom/ExceptionCode.h"
+#include "modules/webaudio/AudioWorkletThread.h"
 #include "modules/webaudio/BaseAudioContext.h"
 
 namespace blink {
@@ -73,9 +74,8 @@
   if (!IsInitialized())
     return;
 
-  destination_->Stop();
+  StopDestination();
   number_of_input_channels_ = 0;
-
   AudioHandler::Uninitialize();
 }
 
@@ -84,11 +84,27 @@
                                           Context()->GetSecurityOrigin());
 }
 
+void DefaultAudioDestinationHandler::StartDestination() {
+  // Use Experimental AudioWorkletThread only when AudioWorklet is enabled.
+  if (RuntimeEnabledFeatures::AudioWorkletEnabled()) {
+    AudioWorkletThread::EnsureSharedBackingThread();
+    DCHECK(AudioWorkletThread::GetSharedBackingThread());
+    destination_->StartWithWorkletThread(
+        AudioWorkletThread::GetSharedBackingThread());
+  } else {
+    destination_->Start();
+  }
+}
+
+void DefaultAudioDestinationHandler::StopDestination() {
+  destination_->Stop();
+}
+
 void DefaultAudioDestinationHandler::StartRendering() {
   DCHECK(IsInitialized());
   if (IsInitialized()) {
     DCHECK(!destination_->IsPlaying());
-    destination_->Start();
+    StartDestination();
   }
 }
 
@@ -96,7 +112,7 @@
   DCHECK(IsInitialized());
   if (IsInitialized()) {
     DCHECK(destination_->IsPlaying());
-    destination_->Stop();
+    StopDestination();
   }
 }
 
@@ -132,10 +148,10 @@
 
   if (!exception_state.HadException() &&
       this->ChannelCount() != old_channel_count && IsInitialized()) {
-    // Re-create destination.
-    destination_->Stop();
+    // Recreate/restart destination.
+    StopDestination();
     CreateDestination();
-    destination_->Start();
+    StartDestination();
   }
 }
 
diff --git a/third_party/WebKit/Source/modules/webaudio/DefaultAudioDestinationNode.h b/third_party/WebKit/Source/modules/webaudio/DefaultAudioDestinationNode.h
index 8e82a797..a7ceeb8c 100644
--- a/third_party/WebKit/Source/modules/webaudio/DefaultAudioDestinationNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/DefaultAudioDestinationNode.h
@@ -68,6 +68,12 @@
                                           const WebAudioLatencyHint&);
   void CreateDestination();
 
+  // Starts platform/AudioDestination. If the runtime flag for AudioWorklet is
+  // set, uses the AudioWorkletThread's backing thread for the rendering.
+  void StartDestination();
+
+  void StopDestination();
+
   std::unique_ptr<AudioDestination> destination_;
   String input_device_id_;
   unsigned number_of_input_channels_;
diff --git a/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.cpp b/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.cpp
index 4e91115..9e6fc0c 100644
--- a/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.cpp
@@ -29,6 +29,7 @@
 #include "core/dom/TaskRunnerHelper.h"
 #include "modules/webaudio/AudioNodeInput.h"
 #include "modules/webaudio/AudioNodeOutput.h"
+#include "modules/webaudio/AudioWorkletThread.h"
 #include "modules/webaudio/BaseAudioContext.h"
 #include "modules/webaudio/OfflineAudioContext.h"
 #include "platform/CrossThreadFunctional.h"
@@ -85,8 +86,8 @@
   if (!IsInitialized())
     return;
 
-  if (render_thread_)
-    render_thread_.reset();
+  render_thread_.reset();
+  worklet_backing_thread_ = nullptr;
 
   AudioHandler::Uninitialize();
 }
@@ -101,7 +102,7 @@
 
 void OfflineAudioDestinationHandler::StartRendering() {
   DCHECK(IsMainThread());
-  DCHECK(render_thread_);
+  DCHECK(GetRenderingThread());
   DCHECK(render_target_);
 
   if (!render_target_)
@@ -110,7 +111,7 @@
   // Rendering was not started. Starting now.
   if (!is_rendering_started_) {
     is_rendering_started_ = true;
-    render_thread_->GetWebTaskRunner()->PostTask(
+    GetRenderingThread()->GetWebTaskRunner()->PostTask(
         BLINK_FROM_HERE,
         CrossThreadBind(&OfflineAudioDestinationHandler::StartOfflineRendering,
                         WrapPassRefPtr(this)));
@@ -119,7 +120,7 @@
 
   // Rendering is already started, which implicitly means we resume the
   // rendering by calling |doOfflineRendering| on the render thread.
-  render_thread_->GetWebTaskRunner()->PostTask(
+  GetRenderingThread()->GetWebTaskRunner()->PostTask(
       BLINK_FROM_HERE,
       CrossThreadBind(&OfflineAudioDestinationHandler::DoOfflineRendering,
                       WrapPassRefPtr(this)));
@@ -138,7 +139,14 @@
 
 void OfflineAudioDestinationHandler::InitializeOfflineRenderThread() {
   DCHECK(IsMainThread());
-  render_thread_ = Platform::Current()->CreateThread("offline audio renderer");
+
+  if (RuntimeEnabledFeatures::AudioWorkletEnabled()) {
+    AudioWorkletThread::EnsureSharedBackingThread();
+    worklet_backing_thread_ = AudioWorkletThread::GetSharedBackingThread();
+  } else {
+    render_thread_ =
+        Platform::Current()->CreateThread("offline audio renderer");
+  }
 }
 
 void OfflineAudioDestinationHandler::StartOfflineRendering() {
@@ -347,6 +355,18 @@
   return false;
 }
 
+WebThread* OfflineAudioDestinationHandler::GetRenderingThread() {
+  DCHECK(IsInitialized());
+
+  if (RuntimeEnabledFeatures::AudioWorkletEnabled()) {
+    DCHECK(!render_thread_ && worklet_backing_thread_);
+    return worklet_backing_thread_;
+  }
+
+  DCHECK(render_thread_ && !worklet_backing_thread_);
+  return render_thread_.get();
+}
+
 // ----------------------------------------------------------------
 
 OfflineAudioDestinationNode::OfflineAudioDestinationNode(
diff --git a/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.h b/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.h
index dc5a886..0abd47c 100644
--- a/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.h
+++ b/third_party/WebKit/Source/modules/webaudio/OfflineAudioDestinationNode.h
@@ -108,6 +108,12 @@
                             AudioBus* destination_bus,
                             size_t number_of_frames);
 
+  // The context can run on two types of threads: when the AudioWorklet is
+  // enabled, the context runs on AudioWorkletThread whereas it runs on the
+  // normal WebThread owned by AudioDestination without AudioWorklet feature.
+  // This method returns the current thread regardless of the thread type.
+  WebThread* GetRenderingThread();
+
   // This AudioHandler renders into this AudioBuffer.
   // This Persistent doesn't make a reference cycle including the owner
   // OfflineAudioDestinationNode. It is accessed by both audio and main thread.
@@ -118,6 +124,10 @@
   // Rendering thread.
   std::unique_ptr<WebThread> render_thread_;
 
+  // The experimental worklet rendering thread. Points the thread borrowed from
+  // AudioWorkletThread.
+  WebThread* worklet_backing_thread_ = nullptr;
+
   // These variables are for counting the number of frames for the current
   // progress and the remaining frames to be processed.
   size_t frames_processed_;
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index 76e8f75..6d6bb6b 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -745,6 +745,7 @@
     "fonts/shaping/HarfBuzzShaper.h",
     "fonts/shaping/RunSegmenter.cpp",
     "fonts/shaping/RunSegmenter.h",
+    "fonts/shaping/ShapeCache.cpp",
     "fonts/shaping/ShapeCache.h",
     "fonts/shaping/ShapeResult.cpp",
     "fonts/shaping/ShapeResult.h",
diff --git a/third_party/WebKit/Source/platform/audio/AudioDestination.cpp b/third_party/WebKit/Source/platform/audio/AudioDestination.cpp
index 75aaa58..6e873dd06 100644
--- a/third_party/WebKit/Source/platform/audio/AudioDestination.cpp
+++ b/third_party/WebKit/Source/platform/audio/AudioDestination.cpp
@@ -31,6 +31,7 @@
 #include <memory>
 #include "platform/CrossThreadFunctional.h"
 #include "platform/Histogram.h"
+#include "platform/RuntimeEnabledFeatures.h"
 #include "platform/WebTaskRunner.h"
 #include "platform/audio/AudioUtilities.h"
 #include "platform/audio/PushPullFIFO.h"
@@ -40,7 +41,6 @@
 #include "public/platform/Platform.h"
 #include "public/platform/WebAudioLatencyHint.h"
 #include "public/platform/WebSecurityOrigin.h"
-#include "public/platform/WebThread.h"
 
 namespace blink {
 
@@ -130,8 +130,8 @@
   size_t frames_to_render = fifo_->Pull(output_bus_.Get(), number_of_frames);
 
   // TODO(hongchan): this check might be redundant, so consider removing later.
-  if (frames_to_render != 0 && rendering_thread_) {
-    rendering_thread_->GetWebTaskRunner()->PostTask(
+  if (frames_to_render != 0 && GetRenderingThread()) {
+    GetRenderingThread()->GetWebTaskRunner()->PostTask(
         BLINK_FROM_HERE,
         CrossThreadBind(&AudioDestination::RequestRenderOnWebThread,
                         CrossThreadUnretained(this), number_of_frames,
@@ -197,6 +197,19 @@
   }
 }
 
+void AudioDestination::StartWithWorkletThread(
+    WebThread* worklet_backing_thread) {
+  DCHECK(IsMainThread());
+  DCHECK(RuntimeEnabledFeatures::AudioWorkletEnabled());
+
+  if (web_audio_device_ && !is_playing_) {
+    TRACE_EVENT0("webaudio", "AudioDestination::Start");
+    worklet_backing_thread_ = worklet_backing_thread;
+    web_audio_device_->Start();
+    is_playing_ = true;
+  }
+}
+
 void AudioDestination::Stop() {
   DCHECK(IsMainThread());
 
@@ -205,7 +218,7 @@
   if (web_audio_device_ && is_playing_) {
     TRACE_EVENT0("webaudio", "AudioDestination::Stop");
     web_audio_device_->Stop();
-    rendering_thread_.reset();
+    ClearRenderingThread();
     is_playing_ = false;
   }
 }
@@ -261,8 +274,22 @@
 }
 
 bool AudioDestination::IsRenderingThread() {
-  return static_cast<ThreadIdentifier>(rendering_thread_->ThreadId()) ==
-         CurrentThread();
+  return GetRenderingThread()->IsCurrentThread();
+}
+
+WebThread* AudioDestination::GetRenderingThread() {
+  if (RuntimeEnabledFeatures::AudioWorkletEnabled()) {
+    DCHECK(!rendering_thread_ && worklet_backing_thread_);
+    return worklet_backing_thread_;
+  }
+
+  DCHECK(rendering_thread_ && !worklet_backing_thread_);
+  return rendering_thread_.get();
+}
+
+void AudioDestination::ClearRenderingThread() {
+  rendering_thread_.reset();
+  worklet_backing_thread_ = nullptr;
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/audio/AudioDestination.h b/third_party/WebKit/Source/platform/audio/AudioDestination.h
index a071206..c1343d7 100644
--- a/third_party/WebKit/Source/platform/audio/AudioDestination.h
+++ b/third_party/WebKit/Source/platform/audio/AudioDestination.h
@@ -36,6 +36,7 @@
 #include "platform/wtf/Noncopyable.h"
 #include "platform/wtf/text/WTFString.h"
 #include "public/platform/WebAudioDevice.h"
+#include "public/platform/WebThread.h"
 #include "public/platform/WebVector.h"
 
 namespace blink {
@@ -43,7 +44,6 @@
 class PushPullFIFO;
 class SecurityOrigin;
 class WebAudioLatencyHint;
-class WebThread;
 
 // The AudioDestination class is an audio sink interface between the media
 // renderer and the Blink's WebAudio module. It has a FIFO to adapt the
@@ -85,6 +85,9 @@
   virtual void Start();
   virtual void Stop();
 
+  // For AudioWorklet experimental threading.
+  void StartWithWorkletThread(WebThread* worklet_backing_thread);
+
   // Getters must be accessed from the main thread.
   size_t CallbackBufferSize() const;
   bool IsPlaying();
@@ -108,6 +111,12 @@
 
   bool IsRenderingThread();
 
+  // Because the alternative thread can exist, this method returns what is
+  // currently valid/available.
+  WebThread* GetRenderingThread();
+
+  void ClearRenderingThread();
+
   // Accessed by the main thread.
   std::unique_ptr<WebAudioDevice> web_audio_device_;
   const unsigned number_of_output_channels_;
@@ -117,6 +126,9 @@
   // Accessed by the device thread. Rendering thread for WebAudio graph.
   std::unique_ptr<WebThread> rendering_thread_;
 
+  // The experimental worklet rendering thread.
+  WebThread* worklet_backing_thread_ = nullptr;
+
   // Accessed by both threads: resolves the buffer size mismatch between the
   // WebAudio engine and the callback function from the actual audio device.
   std::unique_ptr<PushPullFIFO> fifo_;
diff --git a/third_party/WebKit/Source/platform/bindings/V8PrivateProperty.h b/third_party/WebKit/Source/platform/bindings/V8PrivateProperty.h
index 615c50d..1bb3012f 100644
--- a/third_party/WebKit/Source/platform/bindings/V8PrivateProperty.h
+++ b/third_party/WebKit/Source/platform/bindings/V8PrivateProperty.h
@@ -56,6 +56,8 @@
   X(SameObject, NotificationVibrate)                  \
   X(SameObject, PerformanceLongTaskTimingAttribution) \
   X(SameObject, PushManagerSupportedContentEncodings) \
+  X(V8EventListener, AttributeListener)               \
+  X(V8EventListener, Listener)                        \
   SCRIPT_PROMISE_PROPERTIES(X, Promise)               \
   SCRIPT_PROMISE_PROPERTIES(X, Resolver)
 
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.cpp b/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.cpp
new file mode 100644
index 0000000..9899605
--- /dev/null
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012, 2017 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:
+ *
+ *     * 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 Google Inc. 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.
+ */
+
+#include "platform/fonts/shaping/ShapeCache.h"
+#include "platform/wtf/StringHasher.h"
+
+namespace blink {
+
+void ShapeCache::SmallStringKey::HashString() {
+  // TODO(cavalcantii): replace this for a better hash function,
+  // see crbug.com/735674.
+  hash_ = StringHasher::ComputeHash(characters_, length_);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h
index 37498c9..49cbb72 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h
@@ -33,7 +33,6 @@
 #include "platform/wtf/HashFunctions.h"
 #include "platform/wtf/HashSet.h"
 #include "platform/wtf/HashTableDeletedValueType.h"
-#include "platform/wtf/StringHasher.h"
 #include "platform/wtf/WeakPtr.h"
 
 namespace blink {
@@ -47,13 +46,13 @@
 class ShapeCache {
   USING_FAST_MALLOC(ShapeCache);
   WTF_MAKE_NONCOPYABLE(ShapeCache);
-
- private:
   // Used to optimize small strings as hash table keys. Avoids malloc'ing an
   // out-of-line StringImpl.
   class SmallStringKey {
     DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
 
+    void HashString();
+
    public:
     static unsigned Capacity() { return kCapacity; }
 
@@ -65,32 +64,26 @@
         : length_(kDeletedValueLength),
           direction_(static_cast<unsigned>(TextDirection::kLtr)) {}
 
-    template <typename CharacterType>
-    SmallStringKey(CharacterType* characters,
+    SmallStringKey(const LChar* characters,
                    unsigned short length,
                    TextDirection direction)
         : length_(length), direction_(static_cast<unsigned>(direction)) {
       DCHECK(length <= kCapacity);
-
-      StringHasher hasher;
-
-      bool remainder = length & 1;
-      length >>= 1;
-
-      unsigned i = 0;
-      while (length--) {
+      // Up-convert from LChar to UChar.
+      for (unsigned short i = 0; i < length; ++i) {
         characters_[i] = characters[i];
-        characters_[i + 1] = characters[i + 1];
-        hasher.AddCharactersAssumingAligned(characters[i], characters[i + 1]);
-        i += 2;
       }
 
-      if (remainder) {
-        characters_[i] = characters[i];
-        hasher.AddCharacter(characters[i]);
-      }
+      HashString();
+    }
 
-      hash_ = hasher.GetHash();
+    SmallStringKey(const UChar* characters,
+                   unsigned short length,
+                   TextDirection direction)
+        : length_(length), direction_(static_cast<unsigned>(direction)) {
+      DCHECK(length <= kCapacity);
+      memcpy(characters_, characters, length * sizeof(UChar));
+      HashString();
     }
 
     const UChar* Characters() const { return characters_; }
@@ -116,30 +109,12 @@
     UChar characters_[kCapacity];
   };
 
-  struct SmallStringKeyHash {
-    STATIC_ONLY(SmallStringKeyHash);
-    static unsigned GetHash(const SmallStringKey& key) { return key.GetHash(); }
-    static bool Equal(const SmallStringKey& a, const SmallStringKey& b) {
-      return a == b;
-    }
-    // Empty and deleted values have lengths that are not equal to any valid
-    // length.
-    static const bool safe_to_compare_to_empty_or_deleted = true;
-  };
-
-  struct SmallStringKeyHashTraits : WTF::SimpleClassHashTraits<SmallStringKey> {
-    STATIC_ONLY(SmallStringKeyHashTraits);
-    static const bool kHasIsEmptyValueFunction = true;
-    static bool IsEmptyValue(const SmallStringKey& key) {
-      return key.IsHashTableEmptyValue();
-    }
-    static const unsigned kMinimumTableSize = 16;
-  };
-
-  friend bool operator==(const SmallStringKey&, const SmallStringKey&);
-
  public:
-  ShapeCache() : weak_factory_(this), version_(0) {}
+  ShapeCache() : weak_factory_(this), version_(0) {
+    // We use 5% of the maximum word cache size as start value
+    // for the HashTable.
+    short_string_map_.ReserveCapacityForSize(500);
+  }
 
   ShapeCacheEntry* Add(const TextRun& run, ShapeCacheEntry entry) {
     if (run.length() > SmallStringKey::Capacity())
@@ -184,8 +159,8 @@
     ShapeCacheEntry* value;
     if (length == 1) {
       uint32_t key = run[0];
-      // All current codepointsin UTF-32 are bewteen 0x0 and 0x10FFFF,
-      // as such use bit 32 to indicate direction.
+      // All current codepoints in UTF-32 are bewteen 0x0 and 0x10FFFF,
+      // as such use bit 31 (zero-based) to indicate direction.
       if (run.Direction() == TextDirection::kRtl)
         key |= (1u << 31);
       SingleCharMap::AddResult add_result = single_char_map_.insert(key, entry);
@@ -193,12 +168,13 @@
       value = &add_result.stored_value->value;
     } else {
       SmallStringKey small_string_key;
-      if (run.Is8Bit())
+      if (run.Is8Bit()) {
         small_string_key =
             SmallStringKey(run.Characters8(), length, run.Direction());
-      else
+      } else {
         small_string_key =
             SmallStringKey(run.Characters16(), length, run.Direction());
+      }
 
       SmallStringMap::AddResult add_result =
           short_string_map_.insert(small_string_key, entry);
@@ -206,19 +182,39 @@
       value = &add_result.stored_value->value;
     }
 
-    if (!is_new_entry)
+    if ((!is_new_entry) || (size() < kMaxSize)) {
       return value;
-
-    if (size() < kMaxSize)
-      return value;
+    }
 
     // No need to be fancy: we're just trying to avoid pathological growth.
     single_char_map_.clear();
     short_string_map_.clear();
 
-    return 0;
+    return nullptr;
   }
 
+  struct SmallStringKeyHash {
+    STATIC_ONLY(SmallStringKeyHash);
+    static unsigned GetHash(const SmallStringKey& key) { return key.GetHash(); }
+    static bool Equal(const SmallStringKey& a, const SmallStringKey& b) {
+      return a == b;
+    }
+    // Empty and deleted values have lengths that are not equal to any valid
+    // length.
+    static const bool safe_to_compare_to_empty_or_deleted = true;
+  };
+
+  struct SmallStringKeyHashTraits : WTF::SimpleClassHashTraits<SmallStringKey> {
+    STATIC_ONLY(SmallStringKeyHashTraits);
+    static const bool kHasIsEmptyValueFunction = true;
+    static bool IsEmptyValue(const SmallStringKey& key) {
+      return key.IsHashTableEmptyValue();
+    }
+    static const unsigned kMinimumTableSize = 16;
+  };
+
+  friend bool operator==(const SmallStringKey&, const SmallStringKey&);
+
   typedef HashMap<SmallStringKey,
                   ShapeCacheEntry,
                   SmallStringKeyHash,
diff --git a/third_party/WebKit/Source/platform/graphics/InterpolationSpace.cpp b/third_party/WebKit/Source/platform/graphics/InterpolationSpace.cpp
index 0ee40d7..7f5270121 100644
--- a/third_party/WebKit/Source/platform/graphics/InterpolationSpace.cpp
+++ b/third_party/WebKit/Source/platform/graphics/InterpolationSpace.cpp
@@ -32,92 +32,48 @@
 
 #include "platform/graphics/InterpolationSpace.h"
 
-#include <algorithm>
-#include "platform/graphics/skia/SkiaUtils.h"
-#include "platform/wtf/MathExtras.h"
-#include "third_party/skia/include/effects/SkTableColorFilter.h"
+#include "third_party/skia/include/core/SkColorFilter.h"
 
 namespace blink {
 
 namespace InterpolationSpaceUtilities {
 
-static const uint8_t* GetLinearRgbLUT() {
-  static uint8_t linear_rgb_lut[256];
-  static bool initialized;
-  if (!initialized) {
-    for (unsigned i = 0; i < 256; i++) {
-      float color = i / 255.0f;
-      color = (color <= 0.04045f ? color / 12.92f
-                                 : pow((color + 0.055f) / 1.055f, 2.4f));
-      color = std::max(0.0f, color);
-      color = std::min(1.0f, color);
-      linear_rgb_lut[i] = static_cast<uint8_t>(round(color * 255));
-    }
-    initialized = true;
-  }
-  return linear_rgb_lut;
-}
+namespace {
 
-static const uint8_t* GetDeviceRgbLUT() {
-  static uint8_t device_rgb_lut[256];
-  static bool initialized;
-  if (!initialized) {
-    for (unsigned i = 0; i < 256; i++) {
-      float color = i / 255.0f;
-      color = (powf(color, 1.0f / 2.4f) * 1.055f) - 0.055f;
-      color = std::max(0.0f, color);
-      color = std::min(1.0f, color);
-      device_rgb_lut[i] = static_cast<uint8_t>(round(color * 255));
-    }
-    initialized = true;
-  }
-  return device_rgb_lut;
-}
-
-const uint8_t* GetConversionLUT(InterpolationSpace dst_interpolation_space,
-                                InterpolationSpace src_interpolation_space) {
+sk_sp<SkColorFilter> GetConversionFilter(
+    InterpolationSpace dst_interpolation_space,
+    InterpolationSpace src_interpolation_space) {
   // Identity.
   if (src_interpolation_space == dst_interpolation_space)
-    return 0;
+    return nullptr;
 
-  // Only sRGB/DeviceRGB <-> linearRGB are supported at the moment.
-  if ((src_interpolation_space != kInterpolationSpaceLinear &&
-       src_interpolation_space != kInterpolationSpaceSRGB) ||
-      (dst_interpolation_space != kInterpolationSpaceLinear &&
-       dst_interpolation_space != kInterpolationSpaceSRGB))
-    return 0;
-
-  if (dst_interpolation_space == kInterpolationSpaceLinear)
-    return GetLinearRgbLUT();
-  if (dst_interpolation_space == kInterpolationSpaceSRGB)
-    return GetDeviceRgbLUT();
+  switch (dst_interpolation_space) {
+    case kInterpolationSpaceLinear:
+      return SkColorFilter::MakeSRGBToLinearGamma();
+    case kInterpolationSpaceSRGB:
+      return SkColorFilter::MakeLinearToSRGBGamma();
+  }
 
   NOTREACHED();
-  return 0;
+  return nullptr;
 }
 
+}  // namespace
+
 Color ConvertColor(const Color& src_color,
                    InterpolationSpace dst_interpolation_space,
                    InterpolationSpace src_interpolation_space) {
-  const uint8_t* lookup_table =
-      GetConversionLUT(dst_interpolation_space, src_interpolation_space);
-  if (!lookup_table)
-    return src_color;
-
-  return Color(lookup_table[src_color.Red()], lookup_table[src_color.Green()],
-               lookup_table[src_color.Blue()], src_color.Alpha());
+  sk_sp<SkColorFilter> conversion_filter =
+      GetConversionFilter(dst_interpolation_space, src_interpolation_space);
+  return conversion_filter
+             ? Color(conversion_filter->filterColor(src_color.Rgb()))
+             : src_color;
 }
 
 sk_sp<SkColorFilter> CreateInterpolationSpaceFilter(
     InterpolationSpace src_interpolation_space,
     InterpolationSpace dst_interpolation_space) {
-  const uint8_t* lookup_table =
-      GetConversionLUT(dst_interpolation_space, src_interpolation_space);
-  if (!lookup_table)
-    return nullptr;
-
-  return SkTableColorFilter::MakeARGB(0, lookup_table, lookup_table,
-                                      lookup_table);
+  return GetConversionFilter(dst_interpolation_space, src_interpolation_space);
 }
 
 }  // namespace InterpolationSpaceUtilities
diff --git a/third_party/WebKit/Source/platform/graphics/InterpolationSpace.h b/third_party/WebKit/Source/platform/graphics/InterpolationSpace.h
index c276871..1a4ee78 100644
--- a/third_party/WebKit/Source/platform/graphics/InterpolationSpace.h
+++ b/third_party/WebKit/Source/platform/graphics/InterpolationSpace.h
@@ -44,15 +44,6 @@
 
 namespace InterpolationSpaceUtilities {
 
-// Get a pointer to a 8-bit lookup table that will convert color components
-// in the |src_interpolation_space| to the |dst_interpolation_space|.
-// If the conversion cannot be performed, or is a no-op (identity transform),
-// then 0 is returned.
-// (Note that a round-trip - f(B,A)[f(A,B)[x]] - is not lossless in general.)
-const uint8_t* GetConversionLUT(
-    InterpolationSpace dst_interpolation_space,
-    InterpolationSpace src_interpolation_space = kInterpolationSpaceSRGB);
-
 // Convert a Color assumed to be in the |src_interpolation_space| into the
 // |dst_interpolation_space|.
 Color ConvertColor(
diff --git a/third_party/WebKit/Source/platform/text/BidiContext.cpp b/third_party/WebKit/Source/platform/text/BidiContext.cpp
index 9388d319..c8c6080 100644
--- a/third_party/WebKit/Source/platform/text/BidiContext.cpp
+++ b/third_party/WebKit/Source/platform/text/BidiContext.cpp
@@ -29,7 +29,8 @@
 
 using namespace WTF::Unicode;
 
-struct SameSizeAsBidiContext : public RefCounted<SameSizeAsBidiContext> {
+struct SameSizeAsBidiContext
+    : public ThreadSafeRefCounted<SameSizeAsBidiContext> {
   uint32_t bitfields : 16;
   void* parent;
 };
diff --git a/third_party/WebKit/Source/platform/text/BidiContext.h b/third_party/WebKit/Source/platform/text/BidiContext.h
index 4774856..f8c530a6 100644
--- a/third_party/WebKit/Source/platform/text/BidiContext.h
+++ b/third_party/WebKit/Source/platform/text/BidiContext.h
@@ -25,8 +25,8 @@
 
 #include "platform/PlatformExport.h"
 #include "platform/wtf/Assertions.h"
-#include "platform/wtf/RefCounted.h"
 #include "platform/wtf/RefPtr.h"
+#include "platform/wtf/ThreadSafeRefCounted.h"
 #include "platform/wtf/text/Unicode.h"
 
 namespace blink {
@@ -34,7 +34,7 @@
 enum BidiEmbeddingSource { kFromStyleOrDOM, kFromUnicode };
 
 // Used to keep track of explicit embeddings.
-class PLATFORM_EXPORT BidiContext : public RefCounted<BidiContext> {
+class PLATFORM_EXPORT BidiContext : public ThreadSafeRefCounted<BidiContext> {
  public:
   static RefPtr<BidiContext> Create(unsigned char level,
                                     WTF::Unicode::CharDirection,
diff --git a/third_party/WebKit/Source/web/AssertMatchingEnums.cpp b/third_party/WebKit/Source/web/AssertMatchingEnums.cpp
index b81ff82a..04746bc 100644
--- a/third_party/WebKit/Source/web/AssertMatchingEnums.cpp
+++ b/third_party/WebKit/Source/web/AssertMatchingEnums.cpp
@@ -419,11 +419,6 @@
                    kSandboxPropagatesToAuxiliaryBrowsingContexts);
 STATIC_ASSERT_ENUM(WebSandboxFlags::kModals, kSandboxModals);
 
-STATIC_ASSERT_ENUM(LocalFrameClient::kBeforeUnloadHandler,
-                   WebFrameClient::kBeforeUnloadHandler);
-STATIC_ASSERT_ENUM(LocalFrameClient::kUnloadHandler,
-                   WebFrameClient::kUnloadHandler);
-
 STATIC_ASSERT_ENUM(WebFrameLoadType::kStandard, kFrameLoadTypeStandard);
 STATIC_ASSERT_ENUM(WebFrameLoadType::kBackForward, kFrameLoadTypeBackForward);
 STATIC_ASSERT_ENUM(WebFrameLoadType::kReload, kFrameLoadTypeReload);
diff --git a/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp b/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp
index 10c2fe5..cac5d29 100644
--- a/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp
+++ b/third_party/WebKit/Source/web/LocalFrameClientImpl.cpp
@@ -989,11 +989,9 @@
 
 void LocalFrameClientImpl::SuddenTerminationDisablerChanged(
     bool present,
-    SuddenTerminationDisablerType type) {
+    WebSuddenTerminationDisablerType type) {
   if (web_frame_->Client()) {
-    web_frame_->Client()->SuddenTerminationDisablerChanged(
-        present,
-        static_cast<WebFrameClient::SuddenTerminationDisablerType>(type));
+    web_frame_->Client()->SuddenTerminationDisablerChanged(present, type);
   }
 }
 
diff --git a/third_party/WebKit/Source/web/LocalFrameClientImpl.h b/third_party/WebKit/Source/web/LocalFrameClientImpl.h
index c6a7dc4..c02c52d3 100644
--- a/third_party/WebKit/Source/web/LocalFrameClientImpl.h
+++ b/third_party/WebKit/Source/web/LocalFrameClientImpl.h
@@ -210,8 +210,9 @@
 
   unsigned BackForwardLength() override;
 
-  void SuddenTerminationDisablerChanged(bool present,
-                                        SuddenTerminationDisablerType) override;
+  void SuddenTerminationDisablerChanged(
+      bool present,
+      WebSuddenTerminationDisablerType) override;
 
   BlameContext* GetFrameBlameContext() override;
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter.py
index 097417da..09b4193c 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter.py
@@ -253,14 +253,14 @@
 
         Returns the pull_request if found, else returns None.
         """
-        # Check for PRs created by commits on master.
-        pull_request = self.wpt_github.pr_with_position(exportable_commit.position)
-        if pull_request:
-            return pull_request
-
         # Check for PRs created by open Gerrit CLs.
         change_id = exportable_commit.change_id()
         if change_id:
             return self.wpt_github.pr_with_change_id(change_id)
 
+        # Check for PRs created by commits on master.
+        pull_request = self.wpt_github.pr_with_position(exportable_commit.position)
+        if pull_request:
+            return pull_request
+
         return None
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter_unittest.py
index 0355827..e4a5855 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter_unittest.py
@@ -80,15 +80,12 @@
             'pr_with_change_id',
             'pr_with_change_id',
             'pr_with_change_id',
-            'pr_with_position',
             'pr_with_change_id',
             'create_pr',
             'add_label "chromium-export"',
-            'pr_with_position',
             'pr_with_change_id',
             'create_pr',
             'add_label "chromium-export"',
-            'pr_with_position',
             'pr_with_change_id',
             'create_pr',
             'add_label "chromium-export"',
@@ -294,7 +291,6 @@
         test_exporter.run()
 
         self.assertEqual(test_exporter.wpt_github.calls, [
-            'pr_with_position',
             'pr_with_change_id',
             'remove_label "do not merge yet"',
             'get_pr_branch',
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
index 64f15942..7adb155 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
@@ -298,7 +298,7 @@
         # First, try on Blink try bots in order to get any new baselines.
         # TODO(qyearsley): Make this faster by triggering all try jobs in
         # one invocation.
-        _log.info('Triggering try jobs.')
+        _log.info('Triggering try jobs for updating expectations.')
         self.git_cl.trigger_try_jobs()
         try_results = self.git_cl.wait_for_try_jobs(
             poll_delay_seconds=POLL_DELAY_SECONDS, timeout_seconds=TIMEOUT_SECONDS)
@@ -316,6 +316,7 @@
                 self._upload_patchset(message)
 
         # Trigger CQ and wait for CQ try jobs to finish.
+        _log.info('Triggering CQ try jobs.')
         self.git_cl.run(['try'])
         try_results = self.git_cl.wait_for_try_jobs(
             poll_delay_seconds=POLL_DELAY_SECONDS,
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py
index 0cc9e8e..bea854de 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py
@@ -79,7 +79,7 @@
             'INFO: Uploading change list.\n',
             'INFO: Gathering directory owners emails to CC.\n',
             'INFO: Issue: mock output\n',
-            'INFO: Triggering try jobs.\n',
+            'INFO: Triggering try jobs for updating expectations.\n',
             'ERROR: No initial try job results, aborting.\n',
         ])
         self.assertEqual(importer.git_cl.calls[-1], ['git', 'cl', 'set-close'])
@@ -98,7 +98,8 @@
             'INFO: Uploading change list.\n',
             'INFO: Gathering directory owners emails to CC.\n',
             'INFO: Issue: mock output\n',
-            'INFO: Triggering try jobs.\n',
+            'INFO: Triggering try jobs for updating expectations.\n',
+            'INFO: Triggering CQ try jobs.\n',
             'INFO: CQ appears to have passed; trying to commit.\n',
             'INFO: Update completed.\n',
         ])
@@ -119,7 +120,8 @@
             'INFO: Uploading change list.\n',
             'INFO: Gathering directory owners emails to CC.\n',
             'INFO: Issue: mock output\n',
-            'INFO: Triggering try jobs.\n',
+            'INFO: Triggering try jobs for updating expectations.\n',
+            'INFO: Triggering CQ try jobs.\n',
             'ERROR: CQ appears to have failed; aborting.\n',
         ])
         self.assertEqual(importer.git_cl.calls[-1], ['git', 'cl', 'set-close'])
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater.py
index 9becbd3..360192b 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater.py
@@ -394,67 +394,76 @@
         return sorted(specifier.capitalize() for specifier in specifiers)
 
     def write_to_test_expectations(self, line_list):
-        """Writes to TestExpectations.
+        """Writes the given lines to the TestExpectations file.
 
-        The place in the file where the new lines are inserted is after a
-        marker comment line. If this marker comment line is not found, it will
-        be added to the end of the file.
+        The place in the file where the new lines are inserted is after a marker
+        comment line. If this marker comment line is not found, then everything
+        including the marker line is appended to the end of the file.
 
         Args:
             line_list: A list of lines to add to the TestExpectations file.
         """
+        if not line_list:
+            _log.info('No lines to write to TestExpectations.')
+            return
         _log.info('Lines to write to TestExpectations:')
         for line in line_list:
             _log.info('  %s', line)
+
         expectations_file_path = self.port.path_to_generic_test_expectations_file()
         file_contents = self.host.filesystem.read_text_file(expectations_file_path)
-        marker_comment_index = file_contents.find(MARKER_COMMENT)
+
         line_list = [line for line in line_list if self._test_name_from_expectation_string(line) not in file_contents]
         if not line_list:
             return
+
+        marker_comment_index = file_contents.find(MARKER_COMMENT)
         if marker_comment_index == -1:
             file_contents += '\n%s\n' % MARKER_COMMENT
             file_contents += '\n'.join(line_list)
         else:
             end_of_marker_line = (file_contents[marker_comment_index:].find('\n')) + marker_comment_index
             file_contents = file_contents[:end_of_marker_line + 1] + '\n'.join(line_list) + file_contents[end_of_marker_line:]
+
         self.host.filesystem.write_text_file(expectations_file_path, file_contents)
 
     @staticmethod
     def _test_name_from_expectation_string(expectation_string):
         return TestExpectationLine.tokenize_line(filename='', expectation_string=expectation_string, line_number=0).name
 
-    def download_text_baselines(self, tests_results):
+    def download_text_baselines(self, test_results):
         """Fetches new baseline files for tests that should be rebaselined.
 
         Invokes `webkit-patch rebaseline-cl` in order to download new baselines
         (-expected.txt files) for testharness.js tests that did not crash or
         time out. Then, the platform-specific test is removed from the overall
-        failure test dictionary.
+        failure test dictionary and the resulting dictionary is returned.
 
         Args:
-            tests_results: A dict mapping test name to platform to test results.
+            test_results: A dict mapping test name to platform to test results.
 
         Returns:
-            An updated tests_results dictionary without the platform-specific
-            testharness.js tests that required new baselines to be downloaded
-            from `webkit-patch rebaseline-cl`.
+            An updated test_results dictionary which should only contain
+            test failures for tests that couldn't be rebaselined.
         """
-        tests_to_rebaseline, tests_results = self.get_tests_to_rebaseline(tests_results)
+        tests_to_rebaseline, test_results = self.get_tests_to_rebaseline(test_results)
+        if not tests_to_rebaseline:
+            _log.info('No tests to rebaseline.')
+            return test_results
         _log.info('Tests to rebaseline:')
         for test in tests_to_rebaseline:
             _log.info('  %s', test)
-        if tests_to_rebaseline:
-            webkit_patch = self.finder.path_from_tools_scripts('webkit-patch')
-            self.host.executive.run_command([
-                'python',
-                webkit_patch,
-                'rebaseline-cl',
-                '--verbose',
-                '--no-trigger-jobs',
-                '--fill-missing',
-            ] + tests_to_rebaseline)
-        return tests_results
+
+        webkit_patch = self.finder.path_from_tools_scripts('webkit-patch')
+        self.host.executive.run_command([
+            'python',
+            webkit_patch,
+            'rebaseline-cl',
+            '--verbose',
+            '--no-trigger-jobs',
+            '--fill-missing',
+        ] + tests_to_rebaseline)
+        return test_results
 
     def get_tests_to_rebaseline(self, test_results):
         """Returns a list of tests to download new baselines for.
diff --git a/third_party/WebKit/public/platform/WebSuddenTerminationDisablerType.h b/third_party/WebKit/public/platform/WebSuddenTerminationDisablerType.h
new file mode 100644
index 0000000..437308dd
--- /dev/null
+++ b/third_party/WebKit/public/platform/WebSuddenTerminationDisablerType.h
@@ -0,0 +1,18 @@
+// Copyright 2017 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 WebSuddenTerminationDisablerType_h
+#define WebSuddenTerminationDisablerType_h
+
+namespace blink {
+
+// Used when elements preventing the sudden termination of the frame become
+// present or become absent.
+using WebSuddenTerminationDisablerType = uint8_t;
+const WebSuddenTerminationDisablerType kBeforeUnloadHandler = 1 << 0;
+const WebSuddenTerminationDisablerType kUnloadHandler = 1 << 1;
+
+}  // namespace blink
+
+#endif  // WebSuddenTerminationDisablerType_h
diff --git a/third_party/WebKit/public/web/WebFrameClient.h b/third_party/WebKit/public/web/WebFrameClient.h
index c0a14fd6..5c48b2d 100644
--- a/third_party/WebKit/public/web/WebFrameClient.h
+++ b/third_party/WebKit/public/web/WebFrameClient.h
@@ -68,6 +68,7 @@
 #include "public/platform/WebSourceLocation.h"
 #include "public/platform/WebStorageQuotaCallbacks.h"
 #include "public/platform/WebStorageQuotaType.h"
+#include "public/platform/WebSuddenTerminationDisablerType.h"
 #include "public/platform/WebURLError.h"
 #include "public/platform/WebURLLoader.h"
 #include "public/platform/WebURLRequest.h"
@@ -769,13 +770,9 @@
   // Called when elements preventing the sudden termination of the frame
   // become present or stop being present. |type| is the type of element
   // (BeforeUnload handler, Unload handler).
-  enum SuddenTerminationDisablerType {
-    kBeforeUnloadHandler,
-    kUnloadHandler,
-  };
-  virtual void SuddenTerminationDisablerChanged(bool present,
-                                                SuddenTerminationDisablerType) {
-  }
+  virtual void SuddenTerminationDisablerChanged(
+      bool present,
+      WebSuddenTerminationDisablerType) {}
 
   // Navigator Content Utils  --------------------------------------------
 
diff --git a/third_party/WebKit/public/web/WebWindowFeatures.h b/third_party/WebKit/public/web/WebWindowFeatures.h
index fdb6b0d..cf213a9 100644
--- a/third_party/WebKit/public/web/WebWindowFeatures.h
+++ b/third_party/WebKit/public/web/WebWindowFeatures.h
@@ -49,6 +49,7 @@
   // string, we don't distinguish between the two.
   bool tool_bar_visible = true;
   bool scrollbars_visible = true;
+  bool resizable = true;
 
   bool noopener = false;
   bool background = false;
diff --git a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/compiled_resources2.gyp b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/compiled_resources2.gyp
deleted file mode 100644
index b1f81fe..0000000
--- a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/compiled_resources2.gyp
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright 2017 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.
-#
-# NOTE: Created with generate_compiled_resources_gyp.py, please do not edit.
-{
-  'targets': [
-    {
-      'target_name': 'iron-flex-layout-extracted',
-      'dependencies': [
-        'iron-shadow-flex-layout-extracted',
-      ],
-      'includes': ['../../../../../closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'iron-shadow-flex-layout-extracted',
-      'includes': ['../../../../../closure_compiler/compile_js2.gypi'],
-    },
-  ],
-}
diff --git a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-flex-layout-extracted.js b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-flex-layout-extracted.js
deleted file mode 100644
index 418f5a5..0000000
--- a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-flex-layout-extracted.js
+++ /dev/null
@@ -1 +0,0 @@
-console.warn('This file is deprecated. Please use `iron-flex-layout/iron-flex-layout-classes.html`, and one of the specific dom-modules instead');
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-flex-layout.html b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-flex-layout.html
deleted file mode 100644
index 1d0cab5..0000000
--- a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-flex-layout.html
+++ /dev/null
@@ -1,306 +0,0 @@
-<!--
-@license
-Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
-This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
-The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
-The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
-Code distributed by Google as part of the polymer project is also
-subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
---><html><head><link rel="import" href="iron-shadow-flex-layout.html">
-
-<style>
-
-  /*******************************
-            Flex Layout
-  *******************************/
-
-  .layout.horizontal,
-  .layout.horizontal-reverse,
-  .layout.vertical,
-  .layout.vertical-reverse {
-    display: -ms-flexbox;
-    display: -webkit-flex;
-    display: flex;
-  }
-
-  .layout.inline {
-    display: -ms-inline-flexbox;
-    display: -webkit-inline-flex;
-    display: inline-flex;
-  }
-
-  .layout.horizontal {
-    -ms-flex-direction: row;
-    -webkit-flex-direction: row;
-    flex-direction: row;
-  }
-
-  .layout.horizontal-reverse {
-    -ms-flex-direction: row-reverse;
-    -webkit-flex-direction: row-reverse;
-    flex-direction: row-reverse;
-  }
-
-  .layout.vertical {
-    -ms-flex-direction: column;
-    -webkit-flex-direction: column;
-    flex-direction: column;
-  }
-
-  .layout.vertical-reverse {
-    -ms-flex-direction: column-reverse;
-    -webkit-flex-direction: column-reverse;
-    flex-direction: column-reverse;
-  }
-
-  .layout.wrap {
-    -ms-flex-wrap: wrap;
-    -webkit-flex-wrap: wrap;
-    flex-wrap: wrap;
-  }
-
-  .layout.wrap-reverse {
-    -ms-flex-wrap: wrap-reverse;
-    -webkit-flex-wrap: wrap-reverse;
-    flex-wrap: wrap-reverse;
-  }
-
-  .flex-auto {
-    -ms-flex: 1 1 auto;
-    -webkit-flex: 1 1 auto;
-    flex: 1 1 auto;
-  }
-
-  .flex-none {
-    -ms-flex: none;
-    -webkit-flex: none;
-    flex: none;
-  }
-
-  .flex,
-  .flex-1 {
-    -ms-flex: 1;
-    -webkit-flex: 1;
-    flex: 1;
-  }
-
-  .flex-2 {
-    -ms-flex: 2;
-    -webkit-flex: 2;
-    flex: 2;
-  }
-
-  .flex-3 {
-    -ms-flex: 3;
-    -webkit-flex: 3;
-    flex: 3;
-  }
-
-  .flex-4 {
-    -ms-flex: 4;
-    -webkit-flex: 4;
-    flex: 4;
-  }
-
-  .flex-5 {
-    -ms-flex: 5;
-    -webkit-flex: 5;
-    flex: 5;
-  }
-
-  .flex-6 {
-    -ms-flex: 6;
-    -webkit-flex: 6;
-    flex: 6;
-  }
-
-  .flex-7 {
-    -ms-flex: 7;
-    -webkit-flex: 7;
-    flex: 7;
-  }
-
-  .flex-8 {
-    -ms-flex: 8;
-    -webkit-flex: 8;
-    flex: 8;
-  }
-
-  .flex-9 {
-    -ms-flex: 9;
-    -webkit-flex: 9;
-    flex: 9;
-  }
-
-  .flex-10 {
-    -ms-flex: 10;
-    -webkit-flex: 10;
-    flex: 10;
-  }
-
-  .flex-11 {
-    -ms-flex: 11;
-    -webkit-flex: 11;
-    flex: 11;
-  }
-
-  .flex-12 {
-    -ms-flex: 12;
-    -webkit-flex: 12;
-    flex: 12;
-  }
-
-  /* alignment in cross axis */
-
-  .layout.start {
-    -ms-flex-align: start;
-    -webkit-align-items: flex-start;
-    align-items: flex-start;
-  }
-
-  .layout.center,
-  .layout.center-center {
-    -ms-flex-align: center;
-    -webkit-align-items: center;
-    align-items: center;
-  }
-
-  .layout.end {
-    -ms-flex-align: end;
-    -webkit-align-items: flex-end;
-    align-items: flex-end;
-  }
-
-  /* alignment in main axis */
-
-  .layout.start-justified {
-    -ms-flex-pack: start;
-    -webkit-justify-content: flex-start;
-    justify-content: flex-start;
-  }
-
-  .layout.center-justified,
-  .layout.center-center {
-    -ms-flex-pack: center;
-    -webkit-justify-content: center;
-    justify-content: center;
-  }
-
-  .layout.end-justified {
-    -ms-flex-pack: end;
-    -webkit-justify-content: flex-end;
-    justify-content: flex-end;
-  }
-
-  .layout.around-justified {
-    -ms-flex-pack: around;
-    -webkit-justify-content: space-around;
-    justify-content: space-around;
-  }
-
-  .layout.justified {
-    -ms-flex-pack: justify;
-    -webkit-justify-content: space-between;
-    justify-content: space-between;
-  }
-
-  /* self alignment */
-
-  .self-start {
-    -ms-align-self: flex-start;
-    -webkit-align-self: flex-start;
-    align-self: flex-start;
-  }
-
-  .self-center {
-    -ms-align-self: center;
-    -webkit-align-self: center;
-    align-self: center;
-  }
-
-  .self-end {
-    -ms-align-self: flex-end;
-    -webkit-align-self: flex-end;
-    align-self: flex-end;
-  }
-
-  .self-stretch {
-    -ms-align-self: stretch;
-    -webkit-align-self: stretch;
-    align-self: stretch;
-  }
-
-  /*******************************
-            Other Layout
-  *******************************/
-
-  .block {
-    display: block;
-  }
-
-  /* IE 10 support for HTML5 hidden attr */
-  [hidden] {
-    display: none !important;
-  }
-
-  .invisible {
-    visibility: hidden !important;
-  }
-
-  .relative {
-    position: relative;
-  }
-
-  .fit {
-    position: absolute;
-    top: 0;
-    right: 0;
-    bottom: 0;
-    left: 0;
-  }
-
-  body.fullbleed {
-    margin: 0;
-    height: 100vh;
-  }
-
-  .scroll {
-    -webkit-overflow-scrolling: touch;
-    overflow: auto;
-  }
-
-  /* fixed position */
-
-  .fixed-bottom,
-  .fixed-left,
-  .fixed-right,
-  .fixed-top {
-    position: fixed;
-  }
-
-  .fixed-top {
-    top: 0;
-    left: 0;
-    right: 0;
-  }
-
-  .fixed-right {
-    top: 0;
-    right: 0;
-    bottom: 0;
-  }
-
-  .fixed-bottom {
-    right: 0;
-    bottom: 0;
-    left: 0;
-  }
-
-  .fixed-left {
-    top: 0;
-    bottom: 0;
-    left: 0;
-  }
-
-</style>
-</head><body><script src="iron-flex-layout-extracted.js"></script></body></html>
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-shadow-flex-layout-extracted.js b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-shadow-flex-layout-extracted.js
deleted file mode 100644
index 418f5a5..0000000
--- a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-shadow-flex-layout-extracted.js
+++ /dev/null
@@ -1 +0,0 @@
-console.warn('This file is deprecated. Please use `iron-flex-layout/iron-flex-layout-classes.html`, and one of the specific dom-modules instead');
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-shadow-flex-layout.html b/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-shadow-flex-layout.html
deleted file mode 100644
index ce7bb4e..0000000
--- a/third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-shadow-flex-layout.html
+++ /dev/null
@@ -1,302 +0,0 @@
-<!--
-@license
-Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
-This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
-The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
-The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
-Code distributed by Google as part of the polymer project is also
-subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
---><html><head><style>
-
-  /*******************************
-            Flex Layout
-  *******************************/
-
-  html /deep/ .layout.horizontal,
-  html /deep/ .layout.horizontal-reverse,
-  html /deep/ .layout.vertical,
-  html /deep/ .layout.vertical-reverse {
-    display: -ms-flexbox;
-    display: -webkit-flex;
-    display: flex;
-  }
-
-  html /deep/ .layout.inline {
-    display: -ms-inline-flexbox;
-    display: -webkit-inline-flex;
-    display: inline-flex;
-  }
-
-  html /deep/ .layout.horizontal {
-    -ms-flex-direction: row;
-    -webkit-flex-direction: row;
-    flex-direction: row;
-  }
-
-  html /deep/ .layout.horizontal-reverse {
-    -ms-flex-direction: row-reverse;
-    -webkit-flex-direction: row-reverse;
-    flex-direction: row-reverse;
-  }
-
-  html /deep/ .layout.vertical {
-    -ms-flex-direction: column;
-    -webkit-flex-direction: column;
-    flex-direction: column;
-  }
-
-  html /deep/ .layout.vertical-reverse {
-    -ms-flex-direction: column-reverse;
-    -webkit-flex-direction: column-reverse;
-    flex-direction: column-reverse;
-  }
-
-  html /deep/ .layout.wrap {
-    -ms-flex-wrap: wrap;
-    -webkit-flex-wrap: wrap;
-    flex-wrap: wrap;
-  }
-
-  html /deep/ .layout.wrap-reverse {
-    -ms-flex-wrap: wrap-reverse;
-    -webkit-flex-wrap: wrap-reverse;
-    flex-wrap: wrap-reverse;
-  }
-
-  html /deep/ .flex-auto {
-    -ms-flex: 1 1 auto;
-    -webkit-flex: 1 1 auto;
-    flex: 1 1 auto;
-  }
-
-  html /deep/ .flex-none {
-    -ms-flex: none;
-    -webkit-flex: none;
-    flex: none;
-  }
-
-  html /deep/ .flex,
-  html /deep/ .flex-1 {
-    -ms-flex: 1;
-    -webkit-flex: 1;
-    flex: 1;
-  }
-
-  html /deep/ .flex-2 {
-    -ms-flex: 2;
-    -webkit-flex: 2;
-    flex: 2;
-  }
-
-  html /deep/ .flex-3 {
-    -ms-flex: 3;
-    -webkit-flex: 3;
-    flex: 3;
-  }
-
-  html /deep/ .flex-4 {
-    -ms-flex: 4;
-    -webkit-flex: 4;
-    flex: 4;
-  }
-
-  html /deep/ .flex-5 {
-    -ms-flex: 5;
-    -webkit-flex: 5;
-    flex: 5;
-  }
-
-  html /deep/ .flex-6 {
-    -ms-flex: 6;
-    -webkit-flex: 6;
-    flex: 6;
-  }
-
-  html /deep/ .flex-7 {
-    -ms-flex: 7;
-    -webkit-flex: 7;
-    flex: 7;
-  }
-
-  html /deep/ .flex-8 {
-    -ms-flex: 8;
-    -webkit-flex: 8;
-    flex: 8;
-  }
-
-  html /deep/ .flex-9 {
-    -ms-flex: 9;
-    -webkit-flex: 9;
-    flex: 9;
-  }
-
-  html /deep/ .flex-10 {
-    -ms-flex: 10;
-    -webkit-flex: 10;
-    flex: 10;
-  }
-
-  html /deep/ .flex-11 {
-    -ms-flex: 11;
-    -webkit-flex: 11;
-    flex: 11;
-  }
-
-  html /deep/ .flex-12 {
-    -ms-flex: 12;
-    -webkit-flex: 12;
-    flex: 12;
-  }
-
-  /* alignment in cross axis */
-
-  html /deep/ .layout.start {
-    -ms-flex-align: start;
-    -webkit-align-items: flex-start;
-    align-items: flex-start;
-  }
-
-  html /deep/ .layout.center,
-  html /deep/ .layout.center-center {
-    -ms-flex-align: center;
-    -webkit-align-items: center;
-    align-items: center;
-  }
-
-  html /deep/ .layout.end {
-    -ms-flex-align: end;
-    -webkit-align-items: flex-end;
-    align-items: flex-end;
-  }
-
-  /* alignment in main axis */
-
-  html /deep/ .layout.start-justified {
-    -ms-flex-pack: start;
-    -webkit-justify-content: flex-start;
-    justify-content: flex-start;
-  }
-
-  html /deep/ .layout.center-justified,
-  html /deep/ .layout.center-center {
-    -ms-flex-pack: center;
-    -webkit-justify-content: center;
-    justify-content: center;
-  }
-
-  html /deep/ .layout.end-justified {
-    -ms-flex-pack: end;
-    -webkit-justify-content: flex-end;
-    justify-content: flex-end;
-  }
-
-  html /deep/ .layout.around-justified {
-    -ms-flex-pack: around;
-    -webkit-justify-content: space-around;
-    justify-content: space-around;
-  }
-
-  html /deep/ .layout.justified {
-    -ms-flex-pack: justify;
-    -webkit-justify-content: space-between;
-    justify-content: space-between;
-  }
-
-  /* self alignment */
-
-  html /deep/ .self-start {
-    -ms-align-self: flex-start;
-    -webkit-align-self: flex-start;
-    align-self: flex-start;
-  }
-
-  html /deep/ .self-center {
-    -ms-align-self: center;
-    -webkit-align-self: center;
-    align-self: center;
-  }
-
-  html /deep/ .self-end {
-    -ms-align-self: flex-end;
-    -webkit-align-self: flex-end;
-    align-self: flex-end;
-  }
-
-  html /deep/ .self-stretch {
-    -ms-align-self: stretch;
-    -webkit-align-self: stretch;
-    align-self: stretch;
-  }
-
-  /*******************************
-            Other Layout
-  *******************************/
-
-  html /deep/ .block {
-    display: block;
-  }
-
-  /* IE 10 support for HTML5 hidden attr */
-  html /deep/ [hidden] {
-    display: none !important;
-  }
-
-  html /deep/ .invisible {
-    visibility: hidden !important;
-  }
-
-  html /deep/ .relative {
-    position: relative;
-  }
-
-  html /deep/ .fit {
-    position: absolute;
-    top: 0;
-    right: 0;
-    bottom: 0;
-    left: 0;
-  }
-
-  body.fullbleed {
-    margin: 0;
-    height: 100vh;
-  }
-
-  html /deep/ .scroll {
-    -webkit-overflow-scrolling: touch;
-    overflow: auto;
-  }
-
-  .fixed-bottom,
-  .fixed-left,
-  .fixed-right,
-  .fixed-top {
-    position: fixed;
-  }
-
-  html /deep/ .fixed-top {
-    top: 0;
-    left: 0;
-    right: 0;
-  }
-
-  html /deep/ .fixed-right {
-    top: 0;
-    right: 0;
-    bottom: 0;
-  }
-
-  html /deep/ .fixed-bottom {
-    right: 0;
-    bottom: 0;
-    left: 0;
-  }
-
-  html /deep/ .fixed-left {
-    top: 0;
-    bottom: 0;
-    left: 0;
-  }
-
-</style>
-</head><body><script src="iron-shadow-flex-layout-extracted.js"></script></body></html>
\ No newline at end of file
diff --git a/tools/determinism/remove_build_metadata.py b/tools/determinism/remove_build_metadata.py
index f3205aa5..ecf1765 100755
--- a/tools/determinism/remove_build_metadata.py
+++ b/tools/determinism/remove_build_metadata.py
@@ -8,6 +8,7 @@
 import multiprocessing
 import optparse
 import os
+import platform
 import Queue
 import shutil
 import subprocess
@@ -25,6 +26,35 @@
   'mini_installer.exe',
 }
 
+
+def build_bitness(build_dir):
+  # This function checks whether the target (not host) word size is 64-bits.
+  # Since 64-bit hosts can cross-compile 32-bit binaries, check the GN args to
+  # see what CPU we're targetting.
+  try:
+    args_gn = os.path.join(build_dir, 'args.gn')
+    with open(args_gn) as f:
+      for line in f:
+        decommented = line.split('#', 1)[0]
+        key_and_value = decommented.split('=', 1)
+        if len(key_and_value) != 2:
+          continue
+        key = key_and_value[0].strip()
+        value = key_and_value[1].strip()
+        if key == 'target_cpu':
+          if value.endswith('64'):
+            return 64
+          else:
+            return 32
+  except:
+    pass
+  # If we don't find anything, or if there is no GN args file, default to the
+  # host architecture.
+  if platform.machine().endswith('64'):
+    return 64
+  return 32
+
+
 def get_files_to_clean(build_dir, recursive=False):
   """Get the list of files to clean."""
   allowed = frozenset(
@@ -67,12 +97,12 @@
   return proc.returncode
 
 
-def remove_pe_metadata(filename):
+def remove_pe_metadata(filename, bitness):
   """Remove the build metadata from a PE file."""
-  # Only run zap_timestamp on the PE files for which we have a PDB.
+  # Only run zap_timestamp on the 32-bit PE files for which we have a PDB.
   ret = 0
   if ((not os.path.basename(filename) in _ZAP_TIMESTAMP_BLACKLIST) and
-      os.path.exists(filename + '.pdb')):
+      os.path.exists(filename + '.pdb') and bitness != 64):
     ret = run_zap_timestamp(filename)
   return ret
 
@@ -99,19 +129,19 @@
         os.remove(out_filename)
 
 
-def remove_metadata_worker(file_queue, failed_queue, build_dir):
+def remove_metadata_worker(file_queue, failed_queue, build_dir, bitness):
   """Worker thread for the remove_metadata function."""
   while True:
     f = file_queue.get()
     if f.endswith(('.dll', '.exe')):
-      if remove_pe_metadata(os.path.join(build_dir, f)):
+      if remove_pe_metadata(os.path.join(build_dir, f), bitness):
         failed_queue.put(f)
     elif f.endswith('.jar'):
       remove_zip_timestamps(os.path.join(build_dir, f))
     file_queue.task_done()
 
 
-def remove_metadata(build_dir, recursive):
+def remove_metadata(build_dir, recursive, bitness):
   """Remove the build metadata from the artifacts of a build."""
   with open(os.path.join(BASE_DIR, 'deterministic_build_blacklist.json')) as f:
     blacklist = frozenset(json.load(f))
@@ -124,7 +154,8 @@
     worker = threading.Thread(target=remove_metadata_worker,
                               args=(files,
                                     failed_files,
-                                    build_dir))
+                                    build_dir,
+                                    bitness))
     worker.daemon = True
     worker.start()
 
@@ -152,7 +183,9 @@
   if not options.build_dir:
     parser.error('--build-dir is required')
 
-  return remove_metadata(options.build_dir, options.recursive)
+  bitness = build_bitness(options.build_dir)
+
+  return remove_metadata(options.build_dir, options.recursive, bitness)
 
 
 if __name__ == '__main__':
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 8932ae2..20cfee2 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -17513,6 +17513,13 @@
   </description>
 </action>
 
+<action name="VoiceInteraction.Started.Assistant">
+  <owner>muyuanli@chromium.org</owner>
+  <description>
+    User launched voice interaction session through Assistant key.
+  </description>
+</action>
+
 <action name="VoiceInteraction.Started.Search_A">
   <owner>muyuanli@chromium.org</owner>
   <description>
diff --git a/tools/metrics/histograms/extract_histograms.py b/tools/metrics/histograms/extract_histograms.py
index 879a749..2144ecc 100644
--- a/tools/metrics/histograms/extract_histograms.py
+++ b/tools/metrics/histograms/extract_histograms.py
@@ -1,7 +1,6 @@
 # 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.
-
 """Extract histogram names from the description XML file.
 
 For more information on the format of the XML file, which is self-documenting,
@@ -55,6 +54,7 @@
 """
 
 import bisect
+import datetime
 import copy
 import logging
 import xml.dom.minidom
@@ -67,6 +67,8 @@
 DEFAULT_BASE_HISTOGRAM_OBSOLETE_REASON = (
     'Base histogram. Use suffixes of this histogram instead.')
 
+EXPIRY_DATE_PATTERN = "%Y/%m/%d"
+
 
 class Error(Exception):
   pass
@@ -167,8 +169,8 @@
     logging.error(
         'Prefix histogram_suffixes expansions require histogram names which '
         'include a dot separator. Histogram name is %s, histogram_suffixes is '
-        '%s, and placment is %d',
-        histogram_name, histogram_suffixes_node.getAttribute('name'), placement)
+        '%s, and placment is %d', histogram_name,
+        histogram_suffixes_node.getAttribute('name'), placement)
     raise Error()
 
   cluster = '.'.join(sections[0:placement]) + '.'
@@ -186,8 +188,8 @@
   for enum in tree.getElementsByTagName('enum'):
     name = enum.getAttribute('name')
     if last_name is not None and name.lower() < last_name.lower():
-      logging.error('Enums %s and %s are not in alphabetical order',
-                    last_name, name)
+      logging.error('Enums %s and %s are not in alphabetical order', last_name,
+                    name)
       have_errors = True
     last_name = name
 
@@ -226,8 +228,8 @@
         else:
           left_int_value = enum_int_values[left_item_index - 1]
           left_label = enum_dict['values'][left_int_value]['label']
-          logging.warning('Insert value %d after %d ("%s")',
-                          int_value, left_int_value, left_label)
+          logging.warning('Insert value %d after %d ("%s")', int_value,
+                          left_int_value, left_label)
       else:
         last_int_value = int_value
 
@@ -250,6 +252,17 @@
   return owners
 
 
+def _GetDateFromString(date_str):
+  """Converts |date_str| to datetime.date object if the string matches
+  'YYYY/MM/DD' format. Otherwise returns None.
+  """
+  try:
+    date = datetime.datetime.strptime(date_str, EXPIRY_DATE_PATTERN).date()
+  except ValueError:
+    date = None
+  return date
+
+
 def _ProcessBaseHistogramAttribute(node, histogram_entry):
   if node.hasAttribute('base'):
     is_base = node.getAttribute('base').lower() == 'true'
@@ -278,6 +291,18 @@
       continue
     histograms[name] = histogram_entry = {}
 
+    # Handle expiry dates.
+    if histogram.hasAttribute('expiry_date'):
+      expiry_date_str = histogram.getAttribute('expiry_date')
+      expiry_date = _GetDateFromString(expiry_date_str)
+      if expiry_date is None:
+        logging.error(
+            'Expiry date of histogram %s does not match expected format: "%s",'
+            ' found %s.',
+            name, EXPIRY_DATE_PATTERN, expiry_date_str)
+        have_errors = True
+      histograms[expiry_date] = expiry_date
+
     # Find <owner> tag.
     owners = _ExtractOwners(histogram)
     if owners:
@@ -366,6 +391,7 @@
   # queue. histogram_suffixes whose dependencies have not yet been processed
   # will get relegated to the back of the queue to be processed later.
   reprocess_queue = []
+
   def GenerateHistogramSuffixes():
     for f in tree.getElementsByTagName(histogram_suffix_tag):
       yield 0, f
@@ -410,11 +436,11 @@
     last_histogram_name = None
     for affected_histogram in affected_histograms:
       histogram_name = affected_histogram.getAttribute('name')
-      if (last_histogram_name is not None
-          and histogram_name.lower() < last_histogram_name.lower()):
+      if (last_histogram_name is not None and
+          histogram_name.lower() < last_histogram_name.lower()):
         logging.error('Affected histograms %s and %s of histogram_suffixes %s '
-                      'are not in alphabetical order',
-                      last_histogram_name, histogram_name, name)
+                      'are not in alphabetical order', last_histogram_name,
+                      histogram_name, name)
         have_errors = True
       last_histogram_name = histogram_name
       with_suffixes = affected_histogram.getElementsByTagName(with_tag)
@@ -435,8 +461,8 @@
             # histograms.
             if new_histogram.get('base', False):
               del new_histogram['base']
-              if (new_histogram.get('obsolete', '') ==
-                  DEFAULT_BASE_HISTOGRAM_OBSOLETE_REASON):
+              if (new_histogram.get(
+                  'obsolete', '') == DEFAULT_BASE_HISTOGRAM_OBSOLETE_REASON):
                 del new_histogram['obsolete']
             histograms[new_histogram_name] = new_histogram
 
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index fc5e0624..acf9b9b 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -32056,6 +32056,14 @@
   </summary>
 </histogram>
 
+<histogram name="Memory.Browser.PrivateMemoryFootprint" units="MB">
+  <owner>erikchen@chromium.org</owner>
+  <summary>
+    A rough estimate of the private memory footprint of the browser process.
+    Recorded once per UMA ping.
+  </summary>
+</histogram>
+
 <histogram name="Memory.CachedFontAndDC">
   <owner>hajimehoshi@chromium.org</owner>
   <owner>kenjibaheux@google.com</owner>
@@ -32398,6 +32406,14 @@
   </summary>
 </histogram>
 
+<histogram name="Memory.Gpu.PrivateMemoryFootprint" units="MB">
+  <owner>erikchen@chromium.org</owner>
+  <summary>
+    A rough estimate of the private memory footprint of the gpu process.
+    Recorded once per UMA ping.
+  </summary>
+</histogram>
+
 <histogram name="Memory.Graphics" units="MB">
   <owner>hajimehoshi@chromium.org</owner>
   <owner>jamescook@chromium.org</owner>
@@ -32691,6 +32707,14 @@
   </summary>
 </histogram>
 
+<histogram name="Memory.Renderer.PrivateMemoryFootprint" units="MB">
+  <owner>erikchen@chromium.org</owner>
+  <summary>
+    A rough estimate of the private memory footprint of the renderer process.
+    Recorded once per UMA ping.
+  </summary>
+</histogram>
+
 <histogram name="Memory.RendererAll" units="MB">
   <owner>bashi@chromium.org</owner>
   <owner>hajimehoshi@chromium.org</owner>
@@ -33164,6 +33188,14 @@
   </summary>
 </histogram>
 
+<histogram name="Memory.Total.PrivateMemoryFootprint" units="MB">
+  <owner>erikchen@chromium.org</owner>
+  <summary>
+    A rough estimate of the private memory footprint of all processes. Recorded
+    once per UMA ping.
+  </summary>
+</histogram>
+
 <histogram name="Memory.Total2" units="MiB">
   <owner>hajimehoshi@chromium.org</owner>
   <owner>kenjibaheux@google.com</owner>
diff --git a/tools/metrics/histograms/print_style.py b/tools/metrics/histograms/print_style.py
index 77b9f54c..ecf9a6f 100644
--- a/tools/metrics/histograms/print_style.py
+++ b/tools/metrics/histograms/print_style.py
@@ -19,7 +19,7 @@
     'details': [],
     'enum': ['name'],
     'enums': [],
-    'histogram': ['base', 'name', 'enum', 'units'],
+    'histogram': ['base', 'name', 'enum', 'units', 'expiry_date'],
     'histogram-configuration': ['logsource'],
     'histogram_suffixes': ['name', 'separator', 'ordering'],
     'histogram_suffixes_list': [],
diff --git a/ui/android/delegated_frame_host_android.cc b/ui/android/delegated_frame_host_android.cc
index e5197e7..6f566a9 100644
--- a/ui/android/delegated_frame_host_android.cc
+++ b/ui/android/delegated_frame_host_android.cc
@@ -45,7 +45,7 @@
     cc::CopyOutputRequest::CopyOutputRequestCallback result_callback,
     std::unique_ptr<cc::CopyOutputResult> copy_output_result) {
   readback_layer->RemoveFromParent();
-  result_callback.Run(std::move(copy_output_result));
+  std::move(result_callback).Run(std::move(copy_output_result));
 }
 
 }  // namespace
@@ -124,8 +124,9 @@
   readback_layer->SetHideLayerAndSubtree(true);
   compositor->AttachLayerForReadback(readback_layer);
   std::unique_ptr<cc::CopyOutputRequest> copy_output_request =
-      cc::CopyOutputRequest::CreateRequest(base::Bind(
-          &CopyOutputRequestCallback, readback_layer, result_callback));
+      cc::CopyOutputRequest::CreateRequest(
+          base::BindOnce(&CopyOutputRequestCallback, readback_layer,
+                         std::move(result_callback)));
 
   if (!src_subrect_in_pixel.IsEmpty())
     copy_output_request->set_area(src_subrect_in_pixel);
diff --git a/ui/app_list/app_list_constants.cc b/ui/app_list/app_list_constants.cc
index d97a15dc..4cefb83 100644
--- a/ui/app_list/app_list_constants.cc
+++ b/ui/app_list/app_list_constants.cc
@@ -127,9 +127,6 @@
 const int kSearchBoxTopPadding = 24;
 const int kSearchBoxBottomPadding = 21;
 
-// The preferred height of the search box.
-const int kSearchBoxPreferredHeight = 48;
-
 // The background border corner radius of the search box in fullscreen mode.
 const int kSearchBoxBorderCornerRadiusFullscreen = 24;
 
@@ -164,7 +161,7 @@
     "Apps.AppListSearchResultDistanceFromOrigin";
 
 // The height of tiles in search result.
-const int kSearchTileHeight = 92;
+const int kSearchTileHeight = 90;
 
 // The size of the search icon in the search box.
 const int kSearchIconSize = 24;
diff --git a/ui/app_list/app_list_constants.h b/ui/app_list/app_list_constants.h
index 36d0be2..3f8cddb 100644
--- a/ui/app_list/app_list_constants.h
+++ b/ui/app_list/app_list_constants.h
@@ -96,7 +96,6 @@
 APP_LIST_EXPORT extern const int kSearchBoxPadding;
 APP_LIST_EXPORT extern const int kSearchBoxTopPadding;
 APP_LIST_EXPORT extern const int kSearchBoxBottomPadding;
-APP_LIST_EXPORT extern const int kSearchBoxPreferredHeight;
 APP_LIST_EXPORT extern const int kSearchBoxBorderCornerRadiusFullscreen;
 
 APP_LIST_EXPORT extern size_t kMaxFolderItems;
diff --git a/ui/app_list/vector_icons/BUILD.gn b/ui/app_list/vector_icons/BUILD.gn
index 7eea6079..03a615d 100644
--- a/ui/app_list/vector_icons/BUILD.gn
+++ b/ui/app_list/vector_icons/BUILD.gn
@@ -20,6 +20,8 @@
     "ic_close.icon",
     "ic_google_black.1x.icon",
     "ic_google_black.icon",
+    "ic_google_color.1x.icon",
+    "ic_google_color.icon",
     "ic_mic_black.1x.icon",
     "ic_mic_black.icon",
     "ic_search_engine_not_google.1x.icon",
diff --git a/ui/app_list/vector_icons/ic_google_color.1x.icon b/ui/app_list/vector_icons/ic_google_color.1x.icon
new file mode 100644
index 0000000..317fe5c6
--- /dev/null
+++ b/ui/app_list/vector_icons/ic_google_color.1x.icon
@@ -0,0 +1,50 @@
+// Copyright 2017 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.
+
+CANVAS_DIMENSIONS, 24,
+PATH_COLOR_ARGB, 0xFF, 0x42, 0x85, 0xF4,
+MOVE_TO, 21.73f, 10,
+LINE_TO, 12, 10,
+LINE_TO, 12, 14,
+LINE_TO, 17.82f, 14,
+CUBIC_TO, 17.58f, 15.25f, 16.73f, 16.35f, 15.65f, 17.06f,
+LINE_TO, 15.65f, 19.58f,
+LINE_TO, 18.96f, 19.58f,
+CUBIC_TO, 20.89f, 17.84f, 22, 15.27f, 22, 12.23f,
+CUBIC_TO, 22, 11.52f, 21.85f, 10.65f, 21.73f, 10,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x0F, 0x9D, 0x58,
+MOVE_TO, 12.2f, 22,
+CUBIC_TO, 14.96f, 22, 17.27f, 21.11f, 18.96f, 19.58f,
+LINE_TO, 15.65f, 17.06f,
+CUBIC_TO, 14.74f, 17.66f, 13.58f, 18.03f, 12.2f, 18.03f,
+CUBIC_TO, 9.55f, 18.03f, 7.3f, 16.27f, 6.49f, 13.91f,
+LINE_TO, 3.09f, 13.91f,
+LINE_TO, 3.09f, 16.49f,
+CUBIC_TO, 4.77f, 19.75f, 8.22f, 22, 12.2f, 22,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xFF, 0xCD, 0x40,
+MOVE_TO, 6.49f, 13.9f,
+CUBIC_TO, 6.29f, 13.3f, 6.17f, 12.66f, 6.17f, 12,
+CUBIC_TO, 6.17f, 11.34f, 6.29f, 10.7f, 6.49f, 10.1f,
+LINE_TO, 6.49f, 7.52f,
+LINE_TO, 3.09f, 7.52f,
+CUBIC_TO, 2.4f, 8.86f, 2, 10.38f, 2, 12,
+CUBIC_TO, 2, 13.62f, 2.4f, 15.14f, 3.09f, 16.48f,
+LINE_TO, 5.74f, 14.46f,
+LINE_TO, 6.49f, 13.9f,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xDB, 0x44, 0x37,
+MOVE_TO, 12.2f, 5.98f,
+CUBIC_TO, 13.71f, 5.98f, 15.04f, 6.49f, 16.11f, 7.47f,
+LINE_TO, 19.03f, 4.61f,
+CUBIC_TO, 17.26f, 2.99f, 14.96f, 2, 12.2f, 2,
+CUBIC_TO, 8.22f, 2, 4.77f, 4.25f, 3.09f, 7.52f,
+LINE_TO, 6.49f, 10.1f,
+CUBIC_TO, 7.3f, 7.74f, 9.55f, 5.98f, 12.2f, 5.98f,
+CLOSE,
+END
diff --git a/ui/app_list/vector_icons/ic_google_color.icon b/ui/app_list/vector_icons/ic_google_color.icon
new file mode 100644
index 0000000..564966d
--- /dev/null
+++ b/ui/app_list/vector_icons/ic_google_color.icon
@@ -0,0 +1,50 @@
+// Copyright 2017 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.
+
+PATH_COLOR_ARGB, 0xFF, 0x42, 0x85, 0xF4,
+MOVE_TO, 43.5f, 20,
+H_LINE_TO, 24,
+R_V_LINE_TO, 8,
+R_H_LINE_TO, 11.6f,
+R_CUBIC_TO, -0.5f, 2.5f, -2.2f, 4.7f, -4.3f, 6.1f,
+R_LINE_TO, 6.6f, 5,
+R_CUBIC_TO, 3.9f, -3.5f, 6.1f, -8.6f, 6.1f, -14.7f,
+CUBIC_TO, 44, 23, 43.7f, 21.3f, 43.5f, 20,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0x0F, 0x9D, 0x58,
+MOVE_TO, 24.4f, 36.1f,
+R_CUBIC_TO, -5.3f, 0, -9.8f, -3.5f, -11.4f, -8.2f,
+R_H_LINE_TO, 0,
+R_LINE_TO, -1.5f, 1.1f,
+R_LINE_TO, -5.3f, 4,
+R_V_LINE_TO, 0,
+R_CUBIC_TO, 3.4f, 6.5f, 10.2f, 11, 18.2f, 11,
+R_CUBIC_TO, 5.5f, 0, 10.1f, -1.8f, 13.5f, -4.8f,
+R_LINE_TO, -6.6f, -5,
+CUBIC_TO, 29.5f, 35.3f, 27.2f, 36.1f, 24.4f, 36.1f,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xFF, 0xCD, 0x40,
+MOVE_TO, 13, 27.8f,
+LINE_TO, 13, 27.8f,
+R_CUBIC_TO, -0.4f, -1.2f, -0.6f, -2.5f, -0.6f, -3.8f,
+R_CUBIC_TO, 0, -1.3f, 0.2f, -2.6f, 0.6f, -3.8f,
+LINE_TO, 6.2f, 15,
+CUBIC_TO, 4.8f, 17.7f, 4, 20.8f, 4, 24,
+R_CUBIC_TO, 0, 3.2f, 0.8f, 6.3f, 2.2f, 9,
+R_LINE_TO, 5.3f, -4,
+LINE_TO, 13, 27.8f,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xDB, 0x44, 0x37,
+MOVE_TO, 24.4f, 4,
+R_CUBIC_TO, -8, 0, -14.9f, 4.5f, -18.2f, 11,
+R_LINE_TO, 6.8f, 5.2f,
+R_CUBIC_TO, 1.6f, -4.7f, 6.1f, -8.2f, 11.4f, -8.2f,
+R_CUBIC_TO, 3, 0, 5.7f, 1, 7.8f, 3,
+R_LINE_TO, 5.8f, -5.7f,
+CUBIC_TO, 34.5f, 6, 29.9f, 4, 24.4f, 4,
+CLOSE,
+END
diff --git a/ui/app_list/views/app_list_view.cc b/ui/app_list/views/app_list_view.cc
index 9d9a5bb..e915f69 100644
--- a/ui/app_list/views/app_list_view.cc
+++ b/ui/app_list/views/app_list_view.cc
@@ -846,9 +846,12 @@
   // Make sure to layout |app_list_main_view_| and |speech_view_| at the
   // center of the widget.
   gfx::Rect centered_bounds = contents_bounds;
-  centered_bounds.ClampToCenteredSize(gfx::Size(
-      app_list_main_view_->contents_view()->GetDefaultContentsBounds().width(),
-      contents_bounds.height()));
+  ContentsView* contents_view = app_list_main_view_->contents_view();
+  centered_bounds.ClampToCenteredSize(
+      gfx::Size(is_fullscreen_app_list_enabled_
+                    ? contents_view->GetMaximumContentsSize().width()
+                    : contents_view->GetDefaultContentsBounds().width(),
+                contents_bounds.height()));
 
   app_list_main_view_->SetBoundsRect(centered_bounds);
 
@@ -862,10 +865,10 @@
     speech_view_->SetBoundsRect(speech_bounds);
   }
 
-  if (is_fullscreen_app_list_enabled_) {
-    app_list_main_view_->contents_view()->Layout();
-    app_list_background_shield_->SetBoundsRect(contents_bounds);
-  }
+  if (!is_fullscreen_app_list_enabled_)
+    return;
+  contents_view->Layout();
+  app_list_background_shield_->SetBoundsRect(contents_bounds);
 }
 
 void AppListView::SchedulePaintInRect(const gfx::Rect& rect) {
diff --git a/ui/app_list/views/apps_grid_view.cc b/ui/app_list/views/apps_grid_view.cc
index c4c5c44..e1f4127 100644
--- a/ui/app_list/views/apps_grid_view.cc
+++ b/ui/app_list/views/apps_grid_view.cc
@@ -693,25 +693,25 @@
     bounds_animator_.Cancel();
 
   gfx::Rect rect(GetContentsBounds());
-  const gfx::Vector2d page_zero_offset = CalculateTransitionOffset(0);
 
   if (!folder_delegate_) {
-    LayoutSuggestedAppsIndicator(&rect);
+    gfx::Rect indicator_rect(rect);
+    LayoutSuggestedAppsIndicator(&indicator_rect);
     if (suggestions_container_) {
-      gfx::Rect suggestions_rect(rect);
+      gfx::Rect suggestions_rect(indicator_rect);
       suggestions_rect.set_height(
           suggestions_container_->GetHeightForWidth(suggestions_rect.width()));
       suggestions_rect.Offset((suggestions_rect.width() - kGridTileWidth) / 2 -
                                   (kGridTileWidth + kGridTileSpacing) * 2,
                               0);
-      suggestions_rect.Offset(page_zero_offset.x(), page_zero_offset.y());
+      suggestions_rect.Offset(CalculateTransitionOffset(0));
       suggestions_container_->SetBoundsRect(suggestions_rect);
-      rect.Inset(0,
-                 suggestions_container_->GetPreferredSize().height() +
-                     kSuggestionsAllAppsIndicatorPadding,
-                 0, 0);
+      indicator_rect.Inset(0,
+                           suggestions_container_->GetPreferredSize().height() +
+                               kSuggestionsAllAppsIndicatorPadding,
+                           0, 0);
     }
-    LayoutAllAppsIndicator(&rect);
+    LayoutAllAppsIndicator(&indicator_rect);
   }
 
   CalculateIdealBounds();
diff --git a/ui/app_list/views/contents_view.cc b/ui/app_list/views/contents_view.cc
index 23a4465..07bb8a78 100644
--- a/ui/app_list/views/contents_view.cc
+++ b/ui/app_list/views/contents_view.cc
@@ -372,8 +372,8 @@
   gfx::Rect search_box_bounds;
   if (is_fullscreen_app_list_enabled_) {
     search_box_bounds.set_size(GetSearchBoxView()->GetPreferredSize());
-    search_box_bounds.Offset(
-        (GetDefaultContentsSize().width() - search_box_bounds.width()) / 2, 0);
+    search_box_bounds.Offset((bounds().width() - search_box_bounds.width()) / 2,
+                             0);
     search_box_bounds.set_y(kSearchBoxTopPadding);
   } else {
     search_box_bounds =
@@ -392,12 +392,24 @@
 }
 
 gfx::Rect ContentsView::GetDefaultContentsBounds() const {
-  gfx::Rect bounds(gfx::Point(0, GetDefaultSearchBoxBounds().bottom() +
-                                     (is_fullscreen_app_list_enabled_
-                                          ? kSearchBoxBottomPadding
-                                          : 0)),
-                   GetDefaultContentsSize());
-  return bounds;
+  const gfx::Size contents_size(GetDefaultContentsSize());
+  gfx::Point origin(0, GetDefaultSearchBoxBounds().bottom());
+  if (is_fullscreen_app_list_enabled_) {
+    origin.Offset((bounds().width() - contents_size.width()) / 2,
+                  kSearchBoxBottomPadding);
+  }
+  return gfx::Rect(origin, contents_size);
+}
+
+gfx::Size ContentsView::GetMaximumContentsSize() const {
+  int max_width = 0;
+  int max_height = 0;
+  for (AppListPage* page : app_list_pages_) {
+    const gfx::Size size(page->GetPreferredSize());
+    max_width = std::max(size.width(), max_width);
+    max_height = std::max(size.height(), max_height);
+  }
+  return gfx::Size(max_width, max_height);
 }
 
 bool ContentsView::Back() {
diff --git a/ui/app_list/views/contents_view.h b/ui/app_list/views/contents_view.h
index 277a09460..e723e55 100644
--- a/ui/app_list/views/contents_view.h
+++ b/ui/app_list/views/contents_view.h
@@ -119,6 +119,9 @@
   // specify their own custom layout.
   gfx::Rect GetDefaultContentsBounds() const;
 
+  // Returns the maximum preferred size of the all pages.
+  gfx::Size GetMaximumContentsSize() const;
+
   // Performs the 'back' action for the active page. Returns whether the action
   // was handled.
   bool Back();
diff --git a/ui/app_list/views/search_box_view.cc b/ui/app_list/views/search_box_view.cc
index bfd701e..c17d69b4 100644
--- a/ui/app_list/views/search_box_view.cc
+++ b/ui/app_list/views/search_box_view.cc
@@ -52,6 +52,7 @@
 constexpr int kInnerPadding = 24;
 constexpr int kPreferredWidth = 360;
 constexpr int kPreferredWidthFullscreen = 544;
+constexpr int kSearchBoxPreferredHeight = 48;
 
 constexpr SkColor kHintTextColor = SkColorSetARGBMacro(0xFF, 0xA0, 0xA0, 0xA0);
 
@@ -161,7 +162,7 @@
 
   SetShadow(GetShadowForZHeight(2));
   content_container_->SetBackground(
-      base::MakeUnique<SearchBoxBackground>(kSearchBoxBackgroundDefault));
+      base::MakeUnique<SearchBoxBackground>(background_color_));
 
   views::BoxLayout* layout = new views::BoxLayout(
       views::BoxLayout::kHorizontal, gfx::Insets(0, kPadding),
@@ -173,7 +174,7 @@
 
   search_box_->SetBorder(views::NullBorder());
   search_box_->SetTextColor(kSearchTextColor);
-  search_box_->SetBackgroundColor(kSearchBoxBackgroundDefault);
+  search_box_->SetBackgroundColor(background_color_);
   search_box_->set_controller(this);
   search_box_->SetTextInputType(ui::TEXT_INPUT_TYPE_SEARCH);
   search_box_->SetTextInputFlags(ui::TEXT_INPUT_FLAG_AUTOCORRECT_OFF);
@@ -188,10 +189,8 @@
 
   if (is_fullscreen_app_list_enabled_) {
     search_icon_ = new views::ImageView();
-    UpdateSearchIcon(view_delegate_->GetModel()->search_engine_is_google(),
-                     kDefaultSearchboxColor);
     content_container_->AddChildView(search_icon_);
-    search_box_->set_placeholder_text_color(kDefaultSearchboxColor);
+    search_box_->set_placeholder_text_color(search_box_color_);
     search_box_->set_placeholder_text_draw_flags(
         gfx::Canvas::TEXT_ALIGN_CENTER);
     search_box_->SetFontList(search_box_->GetFontList().DeriveWithSizeDelta(2));
@@ -205,9 +204,9 @@
 
   if (is_fullscreen_app_list_enabled_) {
     close_button_ = new SearchBoxImageButton(this);
-    close_button_->SetImage(views::ImageButton::STATE_NORMAL,
-                            gfx::CreateVectorIcon(kIcCloseIcon, kCloseIconSize,
-                                                  kDefaultSearchboxColor));
+    close_button_->SetImage(
+        views::ImageButton::STATE_NORMAL,
+        gfx::CreateVectorIcon(kIcCloseIcon, kCloseIconSize, search_box_color_));
     close_button_->SetVisible(false);
     content_container_->AddChildView(close_button_);
   }
@@ -228,7 +227,7 @@
   model_ = view_delegate_->GetModel();
   DCHECK(model_);
   if (is_fullscreen_app_list_enabled_)
-    UpdateSearchIcon(model_->search_engine_is_google(), kDefaultSearchboxColor);
+    UpdateSearchIcon();
   model_->search_box()->AddObserver(this);
   SpeechRecognitionButtonPropChanged();
   HintTextChanged();
@@ -388,10 +387,11 @@
     return;
 
   is_search_box_active_ = active;
+  UpdateSearchIcon();
   search_box_->set_placeholder_text_draw_flags(
       active ? gfx::Canvas::TEXT_ALIGN_LEFT : gfx::Canvas::TEXT_ALIGN_CENTER);
   search_box_->set_placeholder_text_color(active ? kZeroQuerySearchboxColor
-                                                 : kDefaultSearchboxColor);
+                                                 : search_box_color_);
   search_box_->SetCursorEnabled(active);
   search_box_->SchedulePaint();
 
@@ -471,25 +471,11 @@
   return kSearchBoxBorderCornerRadiusFullscreen;
 }
 
-SkColor SearchBoxView::GetSearchBoxColorForState(
+SkColor SearchBoxView::GetBackgroundColorForState(
     AppListModel::State state) const {
   if (state == AppListModel::STATE_SEARCH_RESULTS)
     return kSearchBoxBackgroundDefault;
-
-  // Uses wallpaper prominent color for other states.
-  const std::vector<SkColor> prominent_colors =
-      model_->search_box()->wallpaper_prominent_colors();
-  if (prominent_colors.empty())
-    return kSearchBoxBackgroundDefault;
-
-  DCHECK_EQ(static_cast<size_t>(ColorProfileType::NUM_OF_COLOR_PROFILES),
-            prominent_colors.size());
-  const SkColor light_vibrant =
-      prominent_colors[static_cast<int>(ColorProfileType::LIGHT_VIBRANT)];
-  const SkColor light_vibrant_mixed = color_utils::AlphaBlend(
-      SK_ColorWHITE, light_vibrant, kLightVibrantBlendAlpha);
-  return SK_ColorTRANSPARENT == light_vibrant ? kSearchBoxBackgroundDefault
-                                              : light_vibrant_mixed;
+  return background_color_;
 }
 
 void SearchBoxView::UpdateBackground(double progress,
@@ -501,8 +487,8 @@
       progress, GetSearchBoxBorderCornerRadiusForState(current_state),
       GetSearchBoxBorderCornerRadiusForState(target_state)));
   const SkColor color = gfx::Tween::ColorValueBetween(
-      progress, GetSearchBoxColorForState(current_state),
-      GetSearchBoxColorForState(target_state));
+      progress, GetBackgroundColorForState(current_state),
+      GetBackgroundColorForState(target_state));
   background->set_color(color);
   search_box_->SetBackgroundColor(color);
 }
@@ -681,36 +667,28 @@
   if (!is_fullscreen_app_list_enabled_)
     return;
 
-  const std::vector<SkColor> prominent_colors =
-      model_->search_box()->wallpaper_prominent_colors();
+  const std::vector<SkColor> prominent_colors = GetWallpaperProminentColors();
   if (prominent_colors.empty())
     return;
-
   DCHECK_EQ(static_cast<size_t>(ColorProfileType::NUM_OF_COLOR_PROFILES),
             prominent_colors.size());
-  const SkColor dark_muted =
-      prominent_colors[static_cast<int>(ColorProfileType::DARK_MUTED)];
-  const SkColor search_box_color =
-      SK_ColorTRANSPARENT == dark_muted ? kDefaultSearchboxColor : dark_muted;
-  UpdateSearchIcon(model_->search_engine_is_google(), search_box_color);
+
+  SetSearchBoxColor(
+      prominent_colors[static_cast<int>(ColorProfileType::DARK_MUTED)]);
+  SetBackgroundColor(
+      prominent_colors[static_cast<int>(ColorProfileType::LIGHT_VIBRANT)]);
+  UpdateSearchIcon();
   speech_button_->SetImage(
       views::Button::STATE_NORMAL,
-      gfx::CreateVectorIcon(kIcMicBlackIcon, kMicIconSize, search_box_color));
+      gfx::CreateVectorIcon(kIcMicBlackIcon, kMicIconSize, search_box_color_));
   close_button_->SetImage(
       views::Button::STATE_NORMAL,
-      gfx::CreateVectorIcon(kIcCloseIcon, kCloseIconSize, search_box_color));
-  search_box_->set_placeholder_text_color(search_box_color);
-  const SkColor light_vibrant =
-      prominent_colors[static_cast<int>(ColorProfileType::LIGHT_VIBRANT)];
-  const SkColor light_vibrant_mixed = color_utils::AlphaBlend(
-      SK_ColorWHITE, light_vibrant, kLightVibrantBlendAlpha);
-  const SkColor background_color = SK_ColorTRANSPARENT == light_vibrant
-                                       ? kSearchBoxBackgroundDefault
-                                       : light_vibrant_mixed;
+      gfx::CreateVectorIcon(kIcCloseIcon, kCloseIconSize, search_box_color_));
+  search_box_->set_placeholder_text_color(search_box_color_);
   SearchBoxBackground* background =
       static_cast<SearchBoxBackground*>(content_container_->background());
-  background->set_color(background_color);
-  search_box_->SetBackgroundColor(background_color);
+  background->set_color(background_color_);
+  search_box_->SetBackgroundColor(background_color_);
   SchedulePaint();
 }
 
@@ -720,12 +698,31 @@
   SchedulePaint();
 }
 
-void SearchBoxView::UpdateSearchIcon(bool is_google,
-                                     const SkColor& search_box_color) {
-  const gfx::VectorIcon& icon =
-      is_google ? kIcGoogleBlackIcon : kIcSearchEngineNotGoogleIcon;
+void SearchBoxView::UpdateSearchIcon() {
+  const gfx::VectorIcon& google_icon =
+      is_search_box_active() ? kIcGoogleColorIcon : kIcGoogleBlackIcon;
+  const gfx::VectorIcon& icon = model_->search_engine_is_google()
+                                    ? google_icon
+                                    : kIcSearchEngineNotGoogleIcon;
   search_icon_->SetImage(
-      gfx::CreateVectorIcon(icon, kSearchIconSize, search_box_color));
+      gfx::CreateVectorIcon(icon, kSearchIconSize, search_box_color_));
+}
+
+const std::vector<SkColor>& SearchBoxView::GetWallpaperProminentColors() const {
+  return model_->search_box()->wallpaper_prominent_colors();
+}
+
+void SearchBoxView::SetBackgroundColor(SkColor light_vibrant) {
+  const SkColor light_vibrant_mixed = color_utils::AlphaBlend(
+      SK_ColorWHITE, light_vibrant, kLightVibrantBlendAlpha);
+  background_color_ = SK_ColorTRANSPARENT == light_vibrant
+                          ? kSearchBoxBackgroundDefault
+                          : light_vibrant_mixed;
+}
+
+void SearchBoxView::SetSearchBoxColor(SkColor color) {
+  search_box_color_ =
+      SK_ColorTRANSPARENT == color ? kDefaultSearchboxColor : color;
 }
 
 }  // namespace app_list
diff --git a/ui/app_list/views/search_box_view.h b/ui/app_list/views/search_box_view.h
index d7d8ecd..04d315a 100644
--- a/ui/app_list/views/search_box_view.h
+++ b/ui/app_list/views/search_box_view.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/macros.h"
+#include "ui/app_list/app_list_constants.h"
 #include "ui/app_list/app_list_model.h"
 #include "ui/app_list/search_box_model_observer.h"
 #include "ui/app_list/speech_ui_model_observer.h"
@@ -112,8 +113,8 @@
   // Returns background border corner radius in the given state.
   static int GetSearchBoxBorderCornerRadiusForState(AppListModel::State state);
 
-  // Returns search box color in the given state.
-  SkColor GetSearchBoxColorForState(AppListModel::State state) const;
+  // Returns background color for the given state.
+  SkColor GetBackgroundColorForState(AppListModel::State state) const;
 
   // Updates the search box's background corner radius and color.
   void UpdateBackground(double progress,
@@ -131,7 +132,16 @@
   void NotifyQueryChanged();
 
   // Updates the search icon.
-  void UpdateSearchIcon(bool is_google, const SkColor& search_box_color);
+  void UpdateSearchIcon();
+
+  // Gets the wallpaper prominent colors, returning empty if there aren't any.
+  const std::vector<SkColor>& GetWallpaperProminentColors() const;
+
+  // Sets the background color.
+  void SetBackgroundColor(SkColor light_vibrant);
+
+  // Sets the search box color.
+  void SetSearchBoxColor(SkColor color);
 
   // Overridden from views::TextfieldController:
   void ContentsChanged(views::Textfield* sender,
@@ -178,6 +188,10 @@
   const bool is_fullscreen_app_list_enabled_;
   // Whether the search box is active.
   bool is_search_box_active_ = false;
+  // The current background color.
+  SkColor background_color_ = kSearchBoxBackgroundDefault;
+  // The current search box color.
+  SkColor search_box_color_ = kDefaultSearchboxColor;
 
   DISALLOW_COPY_AND_ASSIGN(SearchBoxView);
 };
diff --git a/ui/app_list/views/search_box_view_unittest.cc b/ui/app_list/views/search_box_view_unittest.cc
index 672a5fbd..0410a59 100644
--- a/ui/app_list/views/search_box_view_unittest.cc
+++ b/ui/app_list/views/search_box_view_unittest.cc
@@ -198,6 +198,8 @@
     view_delegate_.SetSearchEngineIsGoogle(is_google);
   }
 
+  void SetSearchBoxActive(bool active) { view()->SetSearchBoxActive(active); }
+
   void KeyPress(ui::KeyboardCode key_code) {
     ui::KeyEvent event(ui::ET_KEY_PRESSED, key_code, ui::EF_NONE);
     view()->search_box()->OnKeyEvent(&event);
@@ -275,25 +277,66 @@
   EXPECT_FALSE(view()->IsCloseButtonVisible());
 }
 
-TEST_F(SearchBoxViewFullscreenTest, SearchEngineGoogle) {
+// Tests that the search box is inactive by default.
+TEST_F(SearchBoxViewFullscreenTest, SearchBoxInactiveByDefault) {
+  ASSERT_FALSE(view()->is_search_box_active());
+}
+
+// Tests that the black Google icon is used for an inactive Google search.
+TEST_F(SearchBoxViewFullscreenTest, SearchBoxInactiveSearchBoxGoogle) {
   SetSearchEngineIsGoogle(true);
-  gfx::ImageSkia expected_icon = gfx::CreateVectorIcon(
+  SetSearchBoxActive(false);
+  const gfx::ImageSkia expected_icon = gfx::CreateVectorIcon(
       kIcGoogleBlackIcon, kSearchIconSize, kDefaultSearchboxColor);
   view()->ModelChanged();
 
-  gfx::ImageSkia actual_icon = view()->get_search_icon_for_test()->GetImage();
+  const gfx::ImageSkia actual_icon =
+      view()->get_search_icon_for_test()->GetImage();
 
   EXPECT_TRUE(gfx::test::AreBitmapsEqual(*expected_icon.bitmap(),
                                          *actual_icon.bitmap()));
 }
 
-TEST_F(SearchBoxViewFullscreenTest, SearchEngineNotGoogle) {
+// Tests that the colored Google icon is used for an active Google search.
+TEST_F(SearchBoxViewFullscreenTest, SearchBoxActiveSearchEngineGoogle) {
+  SetSearchEngineIsGoogle(true);
+  SetSearchBoxActive(true);
+  const gfx::ImageSkia expected_icon = gfx::CreateVectorIcon(
+      kIcGoogleColorIcon, kSearchIconSize, kDefaultSearchboxColor);
+  view()->ModelChanged();
+
+  const gfx::ImageSkia actual_icon =
+      view()->get_search_icon_for_test()->GetImage();
+
+  EXPECT_TRUE(gfx::test::AreBitmapsEqual(*expected_icon.bitmap(),
+                                         *actual_icon.bitmap()));
+}
+
+// Tests that the non-Google icon is used for an inactive non-Google search.
+TEST_F(SearchBoxViewFullscreenTest, SearchBoxInactiveSearchEngineNotGoogle) {
   SetSearchEngineIsGoogle(false);
-  gfx::ImageSkia expected_icon = gfx::CreateVectorIcon(
+  SetSearchBoxActive(false);
+  const gfx::ImageSkia expected_icon = gfx::CreateVectorIcon(
       kIcSearchEngineNotGoogleIcon, kSearchIconSize, kDefaultSearchboxColor);
   view()->ModelChanged();
 
-  gfx::ImageSkia actual_icon = view()->get_search_icon_for_test()->GetImage();
+  const gfx::ImageSkia actual_icon =
+      view()->get_search_icon_for_test()->GetImage();
+
+  EXPECT_TRUE(gfx::test::AreBitmapsEqual(*expected_icon.bitmap(),
+                                         *actual_icon.bitmap()));
+}
+
+// Tests that the non-Google icon is used for an active non-Google search.
+TEST_F(SearchBoxViewFullscreenTest, SearchBoxActiveSearchEngineNotGoogle) {
+  SetSearchEngineIsGoogle(false);
+  SetSearchBoxActive(true);
+  const gfx::ImageSkia expected_icon = gfx::CreateVectorIcon(
+      kIcSearchEngineNotGoogleIcon, kSearchIconSize, kDefaultSearchboxColor);
+  view()->ModelChanged();
+
+  const gfx::ImageSkia actual_icon =
+      view()->get_search_icon_for_test()->GetImage();
 
   EXPECT_TRUE(gfx::test::AreBitmapsEqual(*expected_icon.bitmap(),
                                          *actual_icon.bitmap()));
diff --git a/ui/app_list/views/search_result_list_view.cc b/ui/app_list/views/search_result_list_view.cc
index 1f820a44..3642e54 100644
--- a/ui/app_list/views/search_result_list_view.cc
+++ b/ui/app_list/views/search_result_list_view.cc
@@ -11,6 +11,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/time/time.h"
 #include "third_party/skia/include/core/SkColor.h"
+#include "ui/app_list/app_list_features.h"
 #include "ui/app_list/app_list_switches.h"
 #include "ui/app_list/app_list_view_delegate.h"
 #include "ui/app_list/search_result.h"
@@ -24,10 +25,12 @@
 
 namespace {
 
-const int kMaxResults = 6;
-const int kTimeoutIndicatorHeight = 2;
-const int kTimeoutFramerate = 60;
-const SkColor kTimeoutIndicatorColor = SkColorSetRGB(30, 144, 255);
+constexpr int kMaxResults = 6;
+constexpr int kMaxResultsFullscreen = 5;
+constexpr int kTimeoutIndicatorHeight = 2;
+constexpr int kTimeoutFramerate = 60;
+constexpr SkColor kTimeoutIndicatorColor =
+    SkColorSetARGBMacro(255, 30, 144, 255);
 
 }  // namespace
 
@@ -43,7 +46,10 @@
   results_container_->SetLayoutManager(
       new views::BoxLayout(views::BoxLayout::kVertical));
 
-  for (int i = 0; i < kMaxResults; ++i)
+  const int max_results = features::IsFullscreenAppListEnabled()
+                              ? kMaxResultsFullscreen
+                              : kMaxResults;
+  for (int i = 0; i < max_results; ++i)
     results_container_->AddChildView(new SearchResultView(this));
   AddChildView(results_container_);
 
diff --git a/ui/app_list/views/search_result_page_view.cc b/ui/app_list/views/search_result_page_view.cc
index 6052175..1d1210f 100644
--- a/ui/app_list/views/search_result_page_view.cc
+++ b/ui/app_list/views/search_result_page_view.cc
@@ -34,6 +34,7 @@
 constexpr int kGroupSpacing = 6;
 constexpr int kTopPadding = 8;
 constexpr int kFullscreenHeight = 440;
+constexpr int kFullscreenWidth = 640;
 
 // The z-height of the search box and cards in this view.
 constexpr int kSearchResultZHeight = 1;
@@ -42,6 +43,9 @@
 constexpr int kSeparatorPadding = 12;
 constexpr int kSeparatorThickness = 1;
 
+// The height of the search box in this page.
+constexpr int kSearchBoxHeight = 56;
+
 constexpr SkColor kSeparatorColor = SkColorSetARGBMacro(0x1F, 0x00, 0x00, 0x00);
 
 // A container view that ensures the card background and the shadow are painted
@@ -91,8 +95,8 @@
     flags.setColor(color_);
     canvas->DrawRoundRect(bounds, corner_radius_, flags);
 
-    // Draws a separator between SearchBoxView and SearchResultPageView.
-    bounds.set_y(kSearchBoxPreferredHeight);
+    // Draw a separator between SearchBoxView and SearchResultPageView.
+    bounds.set_y(kSearchBoxHeight);
     bounds.set_height(kSeparatorThickness);
     canvas->FillRect(bounds, kSeparatorColor);
   }
@@ -164,7 +168,7 @@
   if (is_fullscreen_app_list_enabled_) {
     // Leaves a placeholder area for the search box and the separator below it.
     scroller->SetBorder(views::CreateEmptyBorder(
-        gfx::Insets(kSearchBoxPreferredHeight + kSeparatorThickness, 0, 0, 0)));
+        gfx::Insets(kSearchBoxHeight + kSeparatorThickness, 0, 0, 0)));
   }
   scroller->SetContents(contents_view_);
   // Setting clip height is necessary to make ScrollView take into account its
@@ -245,6 +249,12 @@
   return "SearchResultPageView";
 }
 
+gfx::Size SearchResultPageView::CalculatePreferredSize() const {
+  if (!is_fullscreen_app_list_enabled_)
+    return GetDefaultContentsBounds().size();
+  return gfx::Size(kFullscreenWidth, kFullscreenHeight);
+}
+
 void SearchResultPageView::ClearSelectedIndex() {
   if (HasSelection())
     result_container_views_[selected_index_]->ClearSelectedIndex();
@@ -359,9 +369,9 @@
     return AppListPage::contents_view()->GetSearchBoxBoundsForState(state);
   }
 
-  gfx::Rect onscreen_bounds(GetDefaultContentsBounds());
-  onscreen_bounds.set_y(AppListPage::GetSearchBoxBounds().y());
-  onscreen_bounds.set_height(kFullscreenHeight);
+  gfx::Rect onscreen_bounds(AppListPage::GetSearchBoxBounds());
+  onscreen_bounds.Offset((onscreen_bounds.width() - kFullscreenWidth) / 2, 0);
+  onscreen_bounds.set_size(GetPreferredSize());
   return onscreen_bounds;
 }
 
@@ -377,8 +387,8 @@
     const SearchBoxView* search_box =
         AppListPage::contents_view()->GetSearchBoxView();
     const SkColor color = gfx::Tween::ColorValueBetween(
-        progress, search_box->GetSearchBoxColorForState(from_state),
-        search_box->GetSearchBoxColorForState(to_state));
+        progress, search_box->GetBackgroundColorForState(from_state),
+        search_box->GetBackgroundColorForState(to_state));
 
     // Grows this view in the same pace as the search box to make them look
     // like a single view.
@@ -409,9 +419,8 @@
 gfx::Rect SearchResultPageView::GetSearchBoxBounds() const {
   gfx::Rect rect(AppListPage::GetSearchBoxBounds());
   if (is_fullscreen_app_list_enabled_) {
-    gfx::Rect contents_bounds(GetDefaultContentsBounds());
-    rect.set_x(contents_bounds.x());
-    rect.set_width(contents_bounds.width());
+    rect.Offset((rect.width() - kFullscreenWidth) / 2, 0);
+    rect.set_size(gfx::Size(kFullscreenWidth, kSearchBoxHeight));
   }
   return rect;
 }
diff --git a/ui/app_list/views/search_result_page_view.h b/ui/app_list/views/search_result_page_view.h
index 238eb707..c60e900 100644
--- a/ui/app_list/views/search_result_page_view.h
+++ b/ui/app_list/views/search_result_page_view.h
@@ -39,6 +39,7 @@
   // Overridden from views::View:
   bool OnKeyPressed(const ui::KeyEvent& event) override;
   const char* GetClassName() const override;
+  gfx::Size CalculatePreferredSize() const override;
 
   // AppListPage overrides:
   gfx::Rect GetPageBoundsForState(AppListModel::State state) const override;
diff --git a/ui/base/l10n/l10n_util.cc b/ui/base/l10n/l10n_util.cc
index 6563ee0..5100c0c 100644
--- a/ui/base/l10n/l10n_util.cc
+++ b/ui/base/l10n/l10n_util.cc
@@ -117,6 +117,7 @@
     "haw",     // Hawaiian
     "he",      // Hebrew
     "hi",      // Hindi
+    "hmn",     // Hmong
     "hr",      // Croatian
     "hu",      // Hungarian
     "hy",      // Armenian
@@ -127,7 +128,7 @@
     "it-CH",   // Italian (Switzerland)
     "it-IT",   // Italian (Italy)
     "ja",      // Japanese
-    "jw",      // Javanese
+    "jv",      // Javanese
     "ka",      // Georgian
     "kk",      // Kazakh
     "km",      // Cambodian
@@ -136,6 +137,7 @@
     "ku",      // Kurdish
     "ky",      // Kyrgyz
     "la",      // Latin
+    "lb",      // Luxembourgish
     "ln",      // Lingala
     "lo",      // Laothian
     "lt",      // Lithuanian
@@ -170,6 +172,7 @@
     "si",      // Sinhalese
     "sk",      // Slovak
     "sl",      // Slovenian
+    "sm",      // Samoan
     "sn",      // Shona
     "so",      // Somali
     "sq",      // Albanian
diff --git a/ui/compositor/layer_unittest.cc b/ui/compositor/layer_unittest.cc
index ed147083..9f2f1d5 100644
--- a/ui/compositor/layer_unittest.cc
+++ b/ui/compositor/layer_unittest.cc
@@ -199,7 +199,7 @@
     scoped_refptr<ReadbackHolder> holder(new ReadbackHolder);
     std::unique_ptr<cc::CopyOutputRequest> request =
         cc::CopyOutputRequest::CreateBitmapRequest(
-            base::Bind(&ReadbackHolder::OutputRequestCallback, holder));
+            base::BindOnce(&ReadbackHolder::OutputRequestCallback, holder));
     request->set_area(source_rect);
 
     GetCompositor()->root_layer()->RequestCopyOfOutput(std::move(request));
diff --git a/ui/gfx/animation/OWNERS b/ui/gfx/animation/OWNERS
new file mode 100644
index 0000000..03d2109
--- /dev/null
+++ b/ui/gfx/animation/OWNERS
@@ -0,0 +1,5 @@
+flackr@chromium.org
+vollick@chromium.org
+
+# TEAM: threaded-rendering-dev@chromium.org
+# COMPONENT: Internals>Compositing>Animation
diff --git a/ui/ozone/common/gpu/ozone_gpu_message_params.h b/ui/ozone/common/gpu/ozone_gpu_message_params.h
index 0ad90a8..67d138e 100644
--- a/ui/ozone/common/gpu/ozone_gpu_message_params.h
+++ b/ui/ozone/common/gpu/ozone_gpu_message_params.h
@@ -17,6 +17,7 @@
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/overlay_transform.h"
 #include "ui/ozone/public/overlay_candidates_ozone.h"
+#include "ui/ozone/public/overlay_surface_candidate.h"
 
 namespace ui {
 class OverlaySurfaceCandidate;
@@ -78,8 +79,7 @@
   OverlayCheckReturn_Params(const OverlayCheckReturn_Params& other) = default;
   ~OverlayCheckReturn_Params() = default;
 
-  enum Status { PENDING, ABLE, NOT, LAST = NOT };
-  Status status = Status::PENDING;
+  OverlayStatus status = OVERLAY_STATUS_PENDING;
 };
 
 }  // namespace ui
diff --git a/ui/ozone/common/gpu/ozone_gpu_messages.h b/ui/ozone/common/gpu/ozone_gpu_messages.h
index b18c489..c20cc08 100644
--- a/ui/ozone/common/gpu/ozone_gpu_messages.h
+++ b/ui/ozone/common/gpu/ozone_gpu_messages.h
@@ -34,8 +34,7 @@
 
 IPC_ENUM_TRAITS_MAX_VALUE(gfx::OverlayTransform, gfx::OVERLAY_TRANSFORM_LAST)
 
-IPC_ENUM_TRAITS_MAX_VALUE(ui::OverlayCheckReturn_Params::Status,
-                          ui::OverlayCheckReturn_Params::Status::LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(ui::OverlayStatus, ui::OVERLAY_STATUS_LAST)
 
 // clang-format off
 IPC_STRUCT_TRAITS_BEGIN(ui::DisplayMode_Params)
diff --git a/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc b/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc
index ed3ee76..bd97c2e 100644
--- a/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc
+++ b/ui/ozone/platform/drm/gpu/drm_overlay_validator.cc
@@ -56,7 +56,7 @@
   if (!controller) {
     // The controller is not yet installed.
     for (auto& param : returns)
-      param.status = OverlayCheckReturn_Params::Status::NOT;
+      param.status = OVERLAY_STATUS_NOT;
 
     return returns;
   }
@@ -70,7 +70,7 @@
 
   for (size_t i = 0; i < params.size(); ++i) {
     if (!params[i].is_overlay_candidate) {
-      returns[i].status = OverlayCheckReturn_Params::Status::NOT;
+      returns[i].status = OVERLAY_STATUS_NOT;
       continue;
     }
 
@@ -80,7 +80,7 @@
             : GetFourCCFormatForOpaqueFramebuffer(params[i].format);
     if (!controller->IsFormatSupported(original_format,
                                        params[i].plane_z_order)) {
-      returns[i].status = OverlayCheckReturn_Params::Status::NOT;
+      returns[i].status = OVERLAY_STATUS_NOT;
       continue;
     }
 
@@ -93,7 +93,7 @@
     test_list.push_back(plane);
 
     if (buffer && controller->TestPageFlip(test_list)) {
-      returns[i].status = OverlayCheckReturn_Params::Status::ABLE;
+      returns[i].status = OVERLAY_STATUS_ABLE;
     } else {
       // If test failed here, platform cannot support this configuration
       // with current combination of layers. This is usually the case when this
@@ -101,7 +101,7 @@
       // hardware resources and they might be already in use by other planes.
       // For example this plane has requested scaling capabilities and all
       // available scalars are already in use by other planes.
-      returns[i].status = OverlayCheckReturn_Params::Status::NOT;
+      returns[i].status = OVERLAY_STATUS_NOT;
       test_list.pop_back();
     }
   }
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 c3dfd1a..8bd1bd1 100644
--- a/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc
+++ b/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc
@@ -155,17 +155,16 @@
   window_->SetController(nullptr);
   std::vector<ui::OverlayCheckReturn_Params> returns =
       overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList());
-  EXPECT_EQ(returns.front().status, ui::OverlayCheckReturn_Params::Status::NOT);
-  EXPECT_EQ(returns.back().status, ui::OverlayCheckReturn_Params::Status::NOT);
+  EXPECT_EQ(returns.front().status, ui::OVERLAY_STATUS_NOT);
+  EXPECT_EQ(returns.back().status, ui::OVERLAY_STATUS_NOT);
   window_->SetController(controller);
 }
 
 TEST_F(DrmOverlayValidatorTest, DontPromoteMoreLayersThanAvailablePlanes) {
   std::vector<ui::OverlayCheckReturn_Params> returns =
       overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList());
-  EXPECT_EQ(returns.front().status,
-            ui::OverlayCheckReturn_Params::Status::ABLE);
-  EXPECT_EQ(returns.back().status, ui::OverlayCheckReturn_Params::Status::NOT);
+  EXPECT_EQ(returns.front().status, ui::OVERLAY_STATUS_ABLE);
+  EXPECT_EQ(returns.back().status, ui::OVERLAY_STATUS_NOT);
 }
 
 TEST_F(DrmOverlayValidatorTest, DontCollapseOverlayToPrimaryInFullScreen) {
@@ -178,9 +177,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(returns.front().status,
-            ui::OverlayCheckReturn_Params::Status::ABLE);
-  EXPECT_EQ(returns.back().status, ui::OverlayCheckReturn_Params::Status::NOT);
+  EXPECT_EQ(returns.front().status, ui::OVERLAY_STATUS_ABLE);
+  EXPECT_EQ(returns.back().status, ui::OVERLAY_STATUS_NOT);
 }
 
 TEST_F(DrmOverlayValidatorTest, OverlayFormat_XRGB) {
@@ -203,7 +201,7 @@
       overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList());
   EXPECT_EQ(3, plane_manager_->plane_count());
   for (const auto& param : returns)
-    EXPECT_EQ(param.status, ui::OverlayCheckReturn_Params::Status::ABLE);
+    EXPECT_EQ(param.status, ui::OVERLAY_STATUS_ABLE);
 
   EXPECT_EQ(3, plane_manager_->plane_count());
 }
@@ -233,7 +231,7 @@
       overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList());
 
   for (const auto& param : returns)
-    EXPECT_EQ(param.status, ui::OverlayCheckReturn_Params::Status::ABLE);
+    EXPECT_EQ(param.status, ui::OVERLAY_STATUS_ABLE);
 
   EXPECT_EQ(3, plane_manager_->plane_count());
 }
@@ -261,7 +259,7 @@
       overlay_validator_->TestPageFlip(validated_params,
                                        ui::OverlayPlaneList());
 
-  EXPECT_EQ(returns.back().status, ui::OverlayCheckReturn_Params::Status::NOT);
+  EXPECT_EQ(returns.back().status, ui::OVERLAY_STATUS_NOT);
 }
 
 TEST_F(DrmOverlayValidatorTest,
@@ -304,7 +302,7 @@
       overlay_validator_->TestPageFlip(validated_params,
                                        ui::OverlayPlaneList());
 
-  EXPECT_EQ(returns.back().status, ui::OverlayCheckReturn_Params::Status::ABLE);
+  EXPECT_EQ(returns.back().status, ui::OVERLAY_STATUS_ABLE);
 
   // This configuration should not be promoted to Overlay when either of the
   // controllers dont support UYVY format.
@@ -315,7 +313,7 @@
 
   returns = overlay_validator_->TestPageFlip(validated_params,
                                              ui::OverlayPlaneList());
-  EXPECT_EQ(returns.back().status, ui::OverlayCheckReturn_Params::Status::NOT);
+  EXPECT_EQ(returns.back().status, ui::OVERLAY_STATUS_NOT);
 
   // Check case where we dont have support for packed formats in primary
   // display.
@@ -325,7 +323,7 @@
 
   returns = overlay_validator_->TestPageFlip(validated_params,
                                              ui::OverlayPlaneList());
-  EXPECT_EQ(returns.back().status, ui::OverlayCheckReturn_Params::Status::NOT);
+  EXPECT_EQ(returns.back().status, ui::OVERLAY_STATUS_NOT);
   controller->RemoveCrtc(drm_, kSecondaryCrtc);
 }
 
@@ -362,7 +360,7 @@
   std::vector<ui::OverlayCheckReturn_Params> returns =
       overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList());
 
-  EXPECT_EQ(returns.back().status, ui::OverlayCheckReturn_Params::Status::ABLE);
+  EXPECT_EQ(returns.back().status, ui::OVERLAY_STATUS_ABLE);
 
   // Check case where we dont have support for packed formats in Mirrored CRTC.
   planes_info.back().allowed_formats = only_rgb_format;
@@ -370,7 +368,7 @@
 
   returns =
       overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList());
-  EXPECT_EQ(returns.back().status, ui::OverlayCheckReturn_Params::Status::ABLE);
+  EXPECT_EQ(returns.back().status, ui::OVERLAY_STATUS_ABLE);
 
   // Check case where we dont have support for packed formats in primary
   // display.
@@ -380,7 +378,7 @@
 
   returns =
       overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList());
-  EXPECT_EQ(returns.back().status, ui::OverlayCheckReturn_Params::Status::ABLE);
+  EXPECT_EQ(returns.back().status, ui::OVERLAY_STATUS_ABLE);
 
   controller->RemoveCrtc(drm_, kSecondaryCrtc);
 }
@@ -392,5 +390,5 @@
 
   std::vector<ui::OverlayCheckReturn_Params> returns =
       overlay_validator_->TestPageFlip(overlay_params_, ui::OverlayPlaneList());
-  EXPECT_EQ(returns.front().status, ui::OverlayCheckReturn_Params::Status::NOT);
+  EXPECT_EQ(returns.front().status, ui::OVERLAY_STATUS_NOT);
 }
diff --git a/ui/ozone/platform/drm/host/drm_overlay_manager.cc b/ui/ozone/platform/drm/host/drm_overlay_manager.cc
index b03f6f3e..a28b272 100644
--- a/ui/ozone/platform/drm/host/drm_overlay_manager.cc
+++ b/ui/ozone/platform/drm/host/drm_overlay_manager.cc
@@ -73,18 +73,16 @@
   const auto& iter = cache_.Get(overlay_params);
   if (iter != cache_.end()) {
     // We are still waiting on results for this candidate list from GPU.
-    if (iter->second.back().status ==
-        OverlayCheckReturn_Params::Status::PENDING)
+    if (iter->second.back().status == OVERLAY_STATUS_PENDING)
       return;
 
     const std::vector<OverlayCheckReturn_Params>& returns = iter->second;
     DCHECK(size == returns.size());
     for (size_t i = 0; i < size; i++) {
-      DCHECK(returns[i].status == OverlayCheckReturn_Params::Status::ABLE ||
-             returns[i].status == OverlayCheckReturn_Params::Status::NOT);
+      DCHECK(returns[i].status == OVERLAY_STATUS_ABLE ||
+             returns[i].status == OVERLAY_STATUS_NOT);
       candidates->at(i).overlay_handled =
-          returns[i].status == OverlayCheckReturn_Params::Status::ABLE ? true
-                                                                       : false;
+          returns[i].status == OVERLAY_STATUS_ABLE ? true : false;
     }
     return;
   }
@@ -101,7 +99,7 @@
   std::vector<OverlayCheckReturn_Params> returns(overlay_params.size());
   if (needs_gpu_validation) {
     for (auto param : returns) {
-      param.status = OverlayCheckReturn_Params::Status::NOT;
+      param.status = OVERLAY_STATUS_NOT;
     }
   }
 
diff --git a/ui/ozone/public/interfaces/overlay_surface_candidate.mojom b/ui/ozone/public/interfaces/overlay_surface_candidate.mojom
index 4903dce6..e65e0d9 100644
--- a/ui/ozone/public/interfaces/overlay_surface_candidate.mojom
+++ b/ui/ozone/public/interfaces/overlay_surface_candidate.mojom
@@ -8,6 +8,13 @@
 import "ui/gfx/mojo/buffer_types.mojom";
 import "ui/gfx/mojo/overlay_transform.mojom";
 
+// ui::OverlayStatus
+enum OverlayStatus {
+  OVERLAY_STATUS_PENDING,
+  OVERLAY_STATUS_ABLE,
+  OVERLAY_STATUS_NOT,
+};
+
 struct OverlaySurfaceCandidate {
   // Transformation to apply to layer during composition.
   gfx.mojom.OverlayTransform transform;
diff --git a/ui/ozone/public/interfaces/overlay_surface_candidate.typemap b/ui/ozone/public/interfaces/overlay_surface_candidate.typemap
index 6c9f347..d946169d1a 100644
--- a/ui/ozone/public/interfaces/overlay_surface_candidate.typemap
+++ b/ui/ozone/public/interfaces/overlay_surface_candidate.typemap
@@ -9,5 +9,7 @@
 ]
 traits_headers =
     [ "//ui/ozone/public/interfaces/overlay_surface_candidate_struct_traits.h" ]
-type_mappings =
-    [ "ui.ozone.mojom.OverlaySurfaceCandidate=ui::OverlaySurfaceCandidate" ]
+type_mappings = [
+  "ui.ozone.mojom.OverlaySurfaceCandidate=ui::OverlaySurfaceCandidate",
+  "ui.ozone.mojom.OverlayStatus=ui::OverlayStatus",
+]
diff --git a/ui/ozone/public/interfaces/overlay_surface_candidate_struct_traits.h b/ui/ozone/public/interfaces/overlay_surface_candidate_struct_traits.h
index 53c26839..d2211d9 100644
--- a/ui/ozone/public/interfaces/overlay_surface_candidate_struct_traits.h
+++ b/ui/ozone/public/interfaces/overlay_surface_candidate_struct_traits.h
@@ -14,6 +14,39 @@
 namespace mojo {
 
 template <>
+struct EnumTraits<ui::ozone::mojom::OverlayStatus, ui::OverlayStatus> {
+  static ui::ozone::mojom::OverlayStatus ToMojom(ui::OverlayStatus format) {
+    switch (format) {
+      case ui::OverlayStatus::OVERLAY_STATUS_PENDING:
+        return ui::ozone::mojom::OverlayStatus::OVERLAY_STATUS_PENDING;
+      case ui::OverlayStatus::OVERLAY_STATUS_ABLE:
+        return ui::ozone::mojom::OverlayStatus::OVERLAY_STATUS_ABLE;
+      case ui::OverlayStatus::OVERLAY_STATUS_NOT:
+        return ui::ozone::mojom::OverlayStatus::OVERLAY_STATUS_NOT;
+    }
+    NOTREACHED();
+    return ui::ozone::mojom::OverlayStatus::OVERLAY_STATUS_NOT;
+  }
+
+  static bool FromMojom(ui::ozone::mojom::OverlayStatus input,
+                        ui::OverlayStatus* out) {
+    switch (input) {
+      case ui::ozone::mojom::OverlayStatus::OVERLAY_STATUS_PENDING:
+        *out = ui::OverlayStatus::OVERLAY_STATUS_PENDING;
+        return true;
+      case ui::ozone::mojom::OverlayStatus::OVERLAY_STATUS_ABLE:
+        *out = ui::OverlayStatus::OVERLAY_STATUS_ABLE;
+        return true;
+      case ui::ozone::mojom::OverlayStatus::OVERLAY_STATUS_NOT:
+        *out = ui::OverlayStatus::OVERLAY_STATUS_NOT;
+        return true;
+    }
+    NOTREACHED();
+    return false;
+  }
+};
+
+template <>
 struct StructTraits<ui::ozone::mojom::OverlaySurfaceCandidateDataView,
                     ui::OverlaySurfaceCandidate> {
   static const gfx::OverlayTransform& transform(
diff --git a/ui/ozone/public/interfaces/overlay_surface_candidate_struct_traits_unittest.cc b/ui/ozone/public/interfaces/overlay_surface_candidate_struct_traits_unittest.cc
index 8ec1fd0c..1790d95 100644
--- a/ui/ozone/public/interfaces/overlay_surface_candidate_struct_traits_unittest.cc
+++ b/ui/ozone/public/interfaces/overlay_surface_candidate_struct_traits_unittest.cc
@@ -70,4 +70,21 @@
   EXPECT_EQ(input.overlay_handled, output.overlay_handled);
 }
 
+TEST_F(OverlaySurfaceCandidateStructTraitsTest, OverlayStatus) {
+  using OverlayStatusTraits =
+      mojo::EnumTraits<ui::ozone::mojom::OverlayStatus, ui::OverlayStatus>;
+
+  std::vector<OverlayStatus> tests = {OVERLAY_STATUS_PENDING,
+                                      OVERLAY_STATUS_ABLE, OVERLAY_STATUS_NOT};
+
+  for (const OverlayStatus& input : tests) {
+    ui::OverlayStatus output;
+    bool success = OverlayStatusTraits::FromMojom(
+        OverlayStatusTraits::ToMojom(input), &output);
+
+    EXPECT_TRUE(success);
+    EXPECT_EQ(input, output);
+  }
+}
+
 }  // namespace ui
diff --git a/ui/ozone/public/overlay_surface_candidate.h b/ui/ozone/public/overlay_surface_candidate.h
index 349ec1bd..77de90f 100644
--- a/ui/ozone/public/overlay_surface_candidate.h
+++ b/ui/ozone/public/overlay_surface_candidate.h
@@ -14,6 +14,13 @@
 
 namespace ui {
 
+enum OverlayStatus {
+  OVERLAY_STATUS_PENDING,
+  OVERLAY_STATUS_ABLE,
+  OVERLAY_STATUS_NOT,
+  OVERLAY_STATUS_LAST = OVERLAY_STATUS_NOT
+};
+
 class OZONE_BASE_EXPORT OverlaySurfaceCandidate {
  public:
   OverlaySurfaceCandidate();
diff --git a/ui/snapshot/snapshot_android.cc b/ui/snapshot/snapshot_android.cc
index 9b69012..0af3a33 100644
--- a/ui/snapshot/snapshot_android.cc
+++ b/ui/snapshot/snapshot_android.cc
@@ -38,9 +38,9 @@
 static void MakeAsyncCopyRequest(
     gfx::NativeWindow window,
     const gfx::Rect& source_rect,
-    const cc::CopyOutputRequest::CopyOutputRequestCallback& callback) {
+    cc::CopyOutputRequest::CopyOutputRequestCallback callback) {
   std::unique_ptr<cc::CopyOutputRequest> request =
-      cc::CopyOutputRequest::CreateBitmapRequest(callback);
+      cc::CopyOutputRequest::CreateBitmapRequest(std::move(callback));
 
   float scale = ui::GetScaleFactorForNativeView(window);
   request->set_area(gfx::ScaleToEnclosingRect(source_rect, scale));
@@ -53,12 +53,10 @@
     const gfx::Size& target_size,
     scoped_refptr<base::TaskRunner> background_task_runner,
     const GrabWindowSnapshotAsyncCallback& callback) {
-  MakeAsyncCopyRequest(window,
-                       source_rect,
-                       base::Bind(&SnapshotAsync::ScaleCopyOutputResult,
-                                  callback,
-                                  target_size,
-                                  background_task_runner));
+  MakeAsyncCopyRequest(
+      window, source_rect,
+      base::BindOnce(&SnapshotAsync::ScaleCopyOutputResult, callback,
+                     target_size, background_task_runner));
 }
 
 void GrabWindowSnapshotAsync(gfx::NativeWindow window,
@@ -66,7 +64,8 @@
                              const GrabWindowSnapshotAsyncCallback& callback) {
   MakeAsyncCopyRequest(
       window, source_rect,
-      base::Bind(&SnapshotAsync::RunCallbackWithCopyOutputResult, callback));
+      base::BindOnce(&SnapshotAsync::RunCallbackWithCopyOutputResult,
+                     callback));
 }
 
 void GrabViewSnapshotAsync(gfx::NativeView view,
@@ -74,7 +73,8 @@
                            const GrabWindowSnapshotAsyncCallback& callback) {
   MakeAsyncCopyRequest(
       view->GetWindowAndroid(), source_rect,
-      base::Bind(&SnapshotAsync::RunCallbackWithCopyOutputResult, callback));
+      base::BindOnce(&SnapshotAsync::RunCallbackWithCopyOutputResult,
+                     callback));
 }
 
 }  // namespace ui
diff --git a/ui/snapshot/snapshot_aura.cc b/ui/snapshot/snapshot_aura.cc
index 4a136c84..10328ee7 100644
--- a/ui/snapshot/snapshot_aura.cc
+++ b/ui/snapshot/snapshot_aura.cc
@@ -31,9 +31,9 @@
 static void MakeAsyncCopyRequest(
     Layer* layer,
     const gfx::Rect& source_rect,
-    const cc::CopyOutputRequest::CopyOutputRequestCallback& callback) {
+    cc::CopyOutputRequest::CopyOutputRequestCallback callback) {
   std::unique_ptr<cc::CopyOutputRequest> request =
-      cc::CopyOutputRequest::CreateBitmapRequest(callback);
+      cc::CopyOutputRequest::CreateBitmapRequest(std::move(callback));
   request->set_area(source_rect);
   layer->RequestCopyOfOutput(std::move(request));
 }
@@ -41,7 +41,7 @@
 static void FinishedAsyncCopyRequest(
     std::unique_ptr<aura::WindowTracker> tracker,
     const gfx::Rect& source_rect,
-    const cc::CopyOutputRequest::CopyOutputRequestCallback& callback,
+    cc::CopyOutputRequest::CopyOutputRequestCallback callback,
     int retry_count,
     std::unique_ptr<cc::CopyOutputResult> result) {
   static const int kMaxRetries = 5;
@@ -56,24 +56,24 @@
     aura::Window* window = tracker->windows()[0];
     MakeAsyncCopyRequest(
         window->layer(), source_rect,
-        base::Bind(&FinishedAsyncCopyRequest, base::Passed(&tracker),
-                   source_rect, callback, retry_count + 1));
+        base::BindOnce(&FinishedAsyncCopyRequest, base::Passed(&tracker),
+                       source_rect, std::move(callback), retry_count + 1));
     return;
   }
 
-  callback.Run(std::move(result));
+  std::move(callback).Run(std::move(result));
 }
 
 static void MakeInitialAsyncCopyRequest(
     aura::Window* window,
     const gfx::Rect& source_rect,
-    const cc::CopyOutputRequest::CopyOutputRequestCallback& callback) {
+    cc::CopyOutputRequest::CopyOutputRequestCallback callback) {
   auto tracker = base::MakeUnique<aura::WindowTracker>();
   tracker->Add(window);
   MakeAsyncCopyRequest(
       window->layer(), source_rect,
-      base::Bind(&FinishedAsyncCopyRequest, base::Passed(&tracker), source_rect,
-                 callback, 0));
+      base::BindOnce(&FinishedAsyncCopyRequest, base::Passed(&tracker),
+                     source_rect, std::move(callback), 0));
 }
 
 void GrabWindowSnapshotAndScaleAsyncAura(
@@ -84,8 +84,8 @@
     const GrabWindowSnapshotAsyncCallback& callback) {
   MakeInitialAsyncCopyRequest(
       window, source_rect,
-      base::Bind(&SnapshotAsync::ScaleCopyOutputResult, callback, target_size,
-                 background_task_runner));
+      base::BindOnce(&SnapshotAsync::ScaleCopyOutputResult, callback,
+                     target_size, background_task_runner));
 }
 
 void GrabWindowSnapshotAsyncAura(
@@ -94,7 +94,8 @@
     const GrabWindowSnapshotAsyncCallback& callback) {
   MakeInitialAsyncCopyRequest(
       window, source_rect,
-      base::Bind(&SnapshotAsync::RunCallbackWithCopyOutputResult, callback));
+      base::BindOnce(&SnapshotAsync::RunCallbackWithCopyOutputResult,
+                     callback));
 }
 
 #if !defined(OS_WIN)
@@ -138,7 +139,8 @@
                             const GrabLayerSnapshotCallback& callback) {
   MakeAsyncCopyRequest(
       layer, source_rect,
-      base::Bind(&SnapshotAsync::RunCallbackWithCopyOutputResult, callback));
+      base::BindOnce(&SnapshotAsync::RunCallbackWithCopyOutputResult,
+                     callback));
 }
 
 #endif
diff --git a/ui/views/bubble/tray_bubble_view.cc b/ui/views/bubble/tray_bubble_view.cc
index 46eebae..69bfd1d 100644
--- a/ui/views/bubble/tray_bubble_view.cc
+++ b/ui/views/bubble/tray_bubble_view.cc
@@ -169,6 +169,34 @@
 using internal::TrayBubbleContentMask;
 using internal::BottomAlignedBoxLayout;
 
+TrayBubbleView::Delegate::~Delegate() {}
+
+void TrayBubbleView::Delegate::BubbleViewDestroyed() {}
+
+void TrayBubbleView::Delegate::OnMouseEnteredView() {}
+
+void TrayBubbleView::Delegate::OnMouseExitedView() {}
+
+void TrayBubbleView::Delegate::RegisterAccelerators(
+    const std::vector<ui::Accelerator>& accelerators,
+    TrayBubbleView* tray_bubble_view) {}
+
+void TrayBubbleView::Delegate::UnregisterAllAccelerators(
+    TrayBubbleView* tray_bubble_view) {}
+
+base::string16 TrayBubbleView::Delegate::GetAccessibleNameForBubble() {
+  return base::string16();
+}
+
+bool TrayBubbleView::Delegate::ShouldEnableExtraKeyboardAccessibility() {
+  return false;
+}
+
+void TrayBubbleView::Delegate::HideBubble(const TrayBubbleView* bubble_view) {}
+
+void TrayBubbleView::Delegate::ProcessGestureEventForBubble(
+    ui::GestureEvent* event) {}
+
 TrayBubbleView::InitParams::InitParams() = default;
 
 TrayBubbleView::InitParams::InitParams(const InitParams& other) = default;
@@ -393,6 +421,14 @@
   }
 }
 
+void TrayBubbleView::OnGestureEvent(ui::GestureEvent* event) {
+  if (delegate_)
+    delegate_->ProcessGestureEventForBubble(event);
+
+  if (!event->handled())
+    BubbleDialogDelegateView::OnGestureEvent(event);
+}
+
 void TrayBubbleView::MouseMovedOutOfHost() {
   // The mouse was accidentally over the bubble when it opened and the AutoClose
   // logic was not activated. Now that the user did move the mouse we tell the
diff --git a/ui/views/bubble/tray_bubble_view.h b/ui/views/bubble/tray_bubble_view.h
index 7fa7034..592ccc3 100644
--- a/ui/views/bubble/tray_bubble_view.h
+++ b/ui/views/bubble/tray_bubble_view.h
@@ -48,17 +48,17 @@
     typedef TrayBubbleView::AnchorAlignment AnchorAlignment;
 
     Delegate() {}
-    virtual ~Delegate() {}
+    virtual ~Delegate();
 
     // Called when the view is destroyed. Any pointers to the view should be
     // cleared when this gets called.
-    virtual void BubbleViewDestroyed() = 0;
+    virtual void BubbleViewDestroyed();
 
     // Called when the mouse enters/exits the view.
     // Note: This event will only be called if the mouse gets actively moved by
     // the user to enter the view.
-    virtual void OnMouseEnteredView() = 0;
-    virtual void OnMouseExitedView() = 0;
+    virtual void OnMouseEnteredView();
+    virtual void OnMouseExitedView();
 
     // Called to register/unregister accelerators for TrayBubbleView.
     // TrayBubbleView wants to register those accelerators at the global level.
@@ -68,22 +68,25 @@
     // not called.
     virtual void RegisterAccelerators(
         const std::vector<ui::Accelerator>& accelerators,
-        TrayBubbleView* tray_bubble_view) = 0;
-    virtual void UnregisterAllAccelerators(
-        TrayBubbleView* tray_bubble_view) = 0;
+        TrayBubbleView* tray_bubble_view);
+    virtual void UnregisterAllAccelerators(TrayBubbleView* tray_bubble_view);
 
     // Called from GetAccessibleNodeData(); should return the appropriate
     // accessible name for the bubble.
-    virtual base::string16 GetAccessibleNameForBubble() = 0;
+    virtual base::string16 GetAccessibleNameForBubble();
 
     // Should return true if extra keyboard accessibility is enabled.
     // TrayBubbleView will put focus on the default item if extra keyboard
     // accessibility is enabled.
-    virtual bool ShouldEnableExtraKeyboardAccessibility() = 0;
+    virtual bool ShouldEnableExtraKeyboardAccessibility();
 
     // Called when a bubble wants to hide/destroy itself (e.g. last visible
     // child view was closed).
-    virtual void HideBubble(const TrayBubbleView* bubble_view) = 0;
+    virtual void HideBubble(const TrayBubbleView* bubble_view);
+
+    // Called to process the gesture events that happened on the TrayBubbleView.
+    // Swiping down on the opened TrayBubbleView to close the bubble.
+    virtual void ProcessGestureEventForBubble(ui::GestureEvent* event);
 
    private:
     DISALLOW_COPY_AND_ASSIGN(Delegate);
@@ -158,6 +161,7 @@
   void OnMouseEntered(const ui::MouseEvent& event) override;
   void OnMouseExited(const ui::MouseEvent& event) override;
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
+  void OnGestureEvent(ui::GestureEvent* event) override;
 
   // Overridden from MouseWatcherListener
   void MouseMovedOutOfHost() override;
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
index be21567..a9fdec6 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -410,13 +410,6 @@
   name_ = params.name;
 
   NativeWidgetAura::RegisterNativeWidgetForWindow(this, content_window_);
-  // Animations on TYPE_WINDOW are handled by the OS. Additionally if we animate
-  // these windows the size of the window gets augmented, effecting restore
-  // bounds and maximized windows in bad ways.
-  if (params.type == Widget::InitParams::TYPE_WINDOW &&
-      !params.remove_standard_frame) {
-    content_window_->SetProperty(aura::client::kAnimationsDisabledKey, true);
-  }
   content_window_->SetType(GetAuraWindowTypeForWidgetType(params.type));
   content_window_->Init(params.layer_type);
   wm::SetShadowElevation(content_window_, wm::ShadowElevation::NONE);
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
index 9393967..4d0dfbe8 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
@@ -114,6 +114,9 @@
   wants_mouse_events_when_inactive_ = params.wants_mouse_events_when_inactive;
 
   wm::SetAnimationHost(content_window_, this);
+  if (params.type == Widget::InitParams::TYPE_WINDOW &&
+      !params.remove_standard_frame)
+    content_window_->SetProperty(aura::client::kAnimationsDisabledKey, true);
 
   ConfigureWindowStyles(message_handler_.get(), params,
                         GetWidget()->widget_delegate(),
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
index 44dc502..e8a7a79 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
@@ -22,6 +22,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
 #include "third_party/skia/include/core/SkPath.h"
+#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/cursor_client.h"
 #include "ui/aura/client/focus_client.h"
 #include "ui/aura/window.h"
@@ -399,6 +400,9 @@
   content_window_ = content_window;
   activatable_ = (params.activatable == Widget::InitParams::ACTIVATABLE_YES);
 
+  if (params.type == Widget::InitParams::TYPE_WINDOW)
+    content_window_->SetProperty(aura::client::kAnimationsDisabledKey, true);
+
   // TODO(erg): Check whether we *should* be building a WindowTreeHost here, or
   // whether we should be proxying requests to another DRWHL.
 
diff --git a/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html b/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html
index 64b5c90..bdc51a6 100644
--- a/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html
+++ b/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html
@@ -32,8 +32,8 @@
 
       /* When needing to flex, force .body-container alone to shrink. */
       .top-container,
-      :host ::content .button-container,
-      :host ::content .footer {
+      :host ::slotted([slot=button-container]),
+      :host ::slotted([slot=footer]) {
         flex-shrink: 0;
       }
 
@@ -46,31 +46,31 @@
         top: 0;
       }
 
-      :host ::content .body {
+      :host ::slotted([slot=body]) {
         padding: 12px 16px;
       }
 
-      :host ::content .title {
+      :host ::slotted([slot=title]) {
         flex: 1;
         font-size: calc(15 / 13 * 100%);
         line-height: 1;
         padding: 16px 16px;
       }
 
-      :host ::content .button-container {
+      :host ::slotted([slot=button-container]) {
         display: flex;
         justify-content: flex-end;
         padding: 16px;
       }
 
-      :host ::content .footer {
+      :host ::slotted([slot=footer]) {
         border-bottom-left-radius: inherit;
         border-bottom-right-radius: inherit;
         margin: 0;
         padding: 16px 20px;
       }
 
-      :host ::content .border-top-divider {
+      :host ::slotted([slot=border-top-divider]) {
         border-top: 1px solid var(--divider-color);
       }
 
@@ -120,7 +120,7 @@
     </style>
     <div class="top-container">
       <div class="title-container" tabindex="-1">
-        <content select=".title"></content>
+        <slot name="title"></slot>
       </div>
       <button is="paper-icon-button-light" class="icon-clear" id="close"
           aria-label$="[[closeText]]" hidden$="[[noCancel]]" on-tap="cancel"
@@ -129,11 +129,11 @@
     </div>
     <div class="body-container">
       <span id="bodyTopMarker"></span>
-      <content select=".body"></content>
+      <slot name="body"></slot>
       <span id="bodyBottomMarker"></span>
     </div>
-    <content select=".button-container"></content>
-    <content select=".footer"></content>
+    <slot name="button-container"></slot>
+    <slot name="footer"></slot>
   </template>
   <script src="cr_dialog.js"></script>
 </dom-module>
diff --git a/ui/webui/resources/polymer_resources.grdp b/ui/webui/resources/polymer_resources.grdp
index 8f86138..ce7085b 100644
--- a/ui/webui/resources/polymer_resources.grdp
+++ b/ui/webui/resources/polymer_resources.grdp
@@ -89,18 +89,6 @@
   <structure name="IDR_POLYMER_1_0_IRON_FIT_BEHAVIOR_IRON_FIT_BEHAVIOR_HTML"
              file="../../../third_party/polymer/v1_0/components-chromium/iron-fit-behavior/iron-fit-behavior.html"
              type="chrome_html" />
-  <structure name="IDR_POLYMER_1_0_IRON_FLEX_LAYOUT_CLASSES_IRON_FLEX_LAYOUT_EXTRACTED_JS"
-             file="../../../third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-flex-layout-extracted.js"
-             type="chrome_html" />
-  <structure name="IDR_POLYMER_1_0_IRON_FLEX_LAYOUT_CLASSES_IRON_FLEX_LAYOUT_HTML"
-             file="../../../third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-flex-layout.html"
-             type="chrome_html" />
-  <structure name="IDR_POLYMER_1_0_IRON_FLEX_LAYOUT_CLASSES_IRON_SHADOW_FLEX_LAYOUT_EXTRACTED_JS"
-             file="../../../third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-shadow-flex-layout-extracted.js"
-             type="chrome_html" />
-  <structure name="IDR_POLYMER_1_0_IRON_FLEX_LAYOUT_CLASSES_IRON_SHADOW_FLEX_LAYOUT_HTML"
-             file="../../../third_party/polymer/v1_0/components-chromium/iron-flex-layout/classes/iron-shadow-flex-layout.html"
-             type="chrome_html" />
   <structure name="IDR_POLYMER_1_0_IRON_FLEX_LAYOUT_IRON_FLEX_LAYOUT_CLASSES_HTML"
              file="../../../third_party/polymer/v1_0/components-chromium/iron-flex-layout/iron-flex-layout-classes.html"
              type="chrome_html" />